TIENDocumentation
Docs/Workflows

CI and automation

Start with a local baseline before turning Tien into a release gate. A policy applied too early can block a team on existing noise instead of preventing regressions.

Basic CI sequence

tien scan repo --path . --format gob --policy high > tien-repo.tien
tien report --type sarif tien-repo.tien > tien.sarif
tien report --type md --min-severity med tien-repo.tien > tien.md

The scan writes findings before returning a non-zero policy result. Preserve the artifact even when the policy exits with code 3.

GitHub Actions example

name: Tien security

on:
  pull_request:
  push:
    branches: [main]

permissions:
  contents: read
  security-events: write

jobs:
  tien:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: actions/setup-go@v5
        with:
          go-version: "1.23.x"

      - name: Install Tien
        run: go install github.com/seibel777/tien.app/cmd/tien@latest

      - name: Scan repository
        run: tien scan repo --path . --format gob --policy high > tien.tien

      - name: Create SARIF
        if: always()
        run: tien report --type sarif tien.tien > tien.sarif

      - name: Upload SARIF
        if: always()
        uses: github/codeql-action/upload-sarif@v3
        with:
          sarif_file: tien.sarif

Pin Tien to a reviewed version instead of @latest in a production pipeline.

Policy mode

policy:
  enabled: true
  min_severity: "high"

Or override per run:

tien scan repo --path . --policy crit > result.tien

Exit code 3 means the scan completed and found at least one issue at or above the threshold. Exit code 1 indicates a runtime or scan error. CI logic should distinguish the two.

Baseline comparisons

Store a reviewed baseline as a protected CI artifact or in a controlled branch, then compare the current run:

tien diff baseline.tien current.tien > diff.txt

A baseline is not an ignore file. Existing findings remain visible; the diff simply makes regressions and fixes easier to identify.

Large URL target sets

Tien does not impose a fixed target-count ceiling. Use deterministic shards when they help fit the scan into runner time and concurrency budgets:

tien scan url --targets targets.txt --shard 1/4 > shard-1.tien
tien scan url --targets targets.txt --shard 2/4 > shard-2.tien
tien scan url --targets targets.txt --shard 3/4 > shard-3.tien
tien scan url --targets targets.txt --shard 4/4 > shard-4.tien
tien merge shard-*.tien > url-complete.tien

Every runner must use the same protected operator config. An explicitly selected missing, unreadable, or invalid config fails the runner instead of falling back to defaults. Each exact hostname in a shard needs a current DNS TXT authorization and its own entry in the operator hosts challenge map. Tien completes authorization preflight for the entire shard before cache access, workers, or built-in target requests start, so a missing or expired grant fails that shard without partially scanning it. If the earliest grant expires during execution, Tien aborts the shard with authorization failure; MCP reports a tool error rather than partial success. The url-scan scope covers only built-in GET/HEAD checks: a shard containing any public target fails closed when a URL plugin is enabled. URL plugins can currently run only for explicitly proof-exempt literal localhost or private-IP development targets. A hostname that resolves to RFC 1918 or IPv6 ULA space must be exactly allowlisted, use an HTTPS target, present its exact DNS TXT grant, and keep its resolved addresses pinned for the scan.

Treat DNS TXT proof as a cooperative operational guardrail, not legal or contractual authorization. Preserve written permission and rules of engagement separately. Protect and pin the config's referenced rules, binaries, ignore files, advisory inputs, and image digests because loading the config at startup does not snapshot those resources.

Metrics and history

Prometheus metrics can be exposed during longer scans:

tien scan url --targets targets.txt --metrics true --metrics-listen 127.0.0.1:9465 > url.tien

Metrics are runtime visibility, not a persistent result. Enable history for a lightweight local run index; use scan artifacts for durable evidence.