Lumen in CI

lumen is built for CI: one command, one exit-code contract, and two CI-native render formats — --format sarif (2.1.0, validated against the official schema) and --format md (a job summary). Previews on localhost work with --allow-private (the Action infers it for loopback URLs automatically).

GitHub Actions

The composite action under nitishagar/lumen/action starts an optional preview server, audits it, uploads the SARIF artifact, and writes the Markdown summary to $GITHUB_STEP_SUMMARY:


      $ - uses: nitishagar/lumen/action@v0.4.0

    
        with:

    
          url: https://example.com

    
          fail-threshold: warning

    
          baseline: lumen.baseline.json   # gate only on NEW findings

    

To surface findings as PR annotations, upload the artifact to code scanning with github/codeql-action/upload-sarif@v3 — see the action README for the full snippet and the pinning note.

Scheduled monitoring (recipe)

lumen has no daemon — the recipe is a cron workflow that commits audit history to a dedicated branch. It's yours to own (copy, adjust the schedule, pin the version):


      # .github/workflows/lumen-monitor.yml (your repo)

    
      on:

    
        schedule: [{ cron: "0 6 * * 1" }]  # weekly

    
      permissions: { contents: write }

    
      jobs:

    
        audit:

    
          runs-on: ubuntu-latest

    
          steps:

    
            - uses: actions/checkout@<pinned-sha>

    
            - run: npx -y @lumen-seo/cli@0 audit https://example.com \

    
                --max-pages 100 --fail-threshold off \

    
                && npx -y @lumen-seo/cli@0 history audit --json > trend.json

    
            - run: |

    
                git config user.name lumen-monitor && git config user.email bot@users.noreply.github.com

    
                git checkout -B lumen-history

    
                git add trend.json && git commit -m "audit $(date -u +%F)" || true

    
                git push origin lumen-history

    

Trend lines come from lumen history audit — and the branch history doubles as a shareable record. (--fail-threshold off keeps monitoring non-gating; drop it if you want the cron to alarm.)

SARIF

--format sarif emits one rule per lumen rule (with its rules-reference anchor as helpUri), one result per finding, and the run's provenance (version, budgets, started/completed, incomplete/stopReason) in run.properties. With --out, the artifact is written and stdout stays silent; without it, the document goes to stdout.


      $ npx @lumen-seo/cli audit https://example.com --format sarif --out lumen.sarif

    

--source-map site/src/pages/** adds a best-effort page-URL → source-file mapping for annotations; when the mapping is ambiguous the result stays URL-only — never guessed. The audit seed's own subpath is stripped first, so previews served under a base (Astro base: '/lumen') map to the same files; GitHub code scanning rejects http locations, so a source map is required for annotation uploads.

Job summary


      $ npx @lumen-seo/cli audit "$SITE_URL" --format md >> "$GITHUB_STEP_SUMMARY"

    

The summary carries the score, the top rule groups with fixes (linking the rules reference), and — when baselined — the new/fixed/unknown breakdown.

Baseline gate

Adopt lumen on a site with existing findings: record a baseline once, commit it, and gate only on regressions in CI:


      $ npx @lumen-seo/cli audit "$SITE_URL" --update-baseline lumen.baseline.json

    
      # commit lumen.baseline.json, then in CI:

    
      $ npx @lumen-seo/cli audit "$SITE_URL" --baseline lumen.baseline.json

    
      # exit 1 only when NEW findings appear at/above failThreshold

    

Fingerprints are rule + normalized URL + selector — message tweaks never un-baseline an issue; pages not audited in a run are unknown, never counted as fixed. Compare any two saved reports with lumen diff a.json b.json.

GitLab CI


      $ audit:

    
        script:

    
          - npx -y @lumen-seo/cli@0 audit "$SITE_URL" --format sarif --out lumen.sarif

    
        artifacts:

    
          paths: [lumen.sarif]

    

Any shell


      $ npx -y @lumen-seo/cli@0 audit https://example.com \

    
        --format sarif --out lumen.sarif --fail-threshold warning

    
      echo "exit $?  # 0 ok · 1 findings at/above threshold · 2 config error"

    

Exit codes

The contract is stable across every renderer: 0 under threshold, 1 findings at/above failThreshold (or new findings with --baseline; an incomplete run always gates),2 usage/config error.