Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/advisory-inventory.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Advisory inventory

# Every open dependency advisory at moderate or above has a triage row in
# SECURITY-EXPOSURE.md (scripts/security/check-exposure-coverage.mjs). It
# runs on every push to main (ci.yml's security-exposure job) and here, once
# a day, because an advisory can be published with nothing merged. A
# failure is one alert about main, answered by one triage row or one bump;
# pull requests are gated only on what they themselves add.

on:
schedule:
- cron: '41 6 * * *'
workflow_dispatch:

permissions:
contents: read

jobs:
inventory:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 22
cache: npm
cache-dependency-path: package-lock.json
- run: npm ci
- name: Every open advisory has a triage row
run: node scripts/security/check-exposure-coverage.mjs
26 changes: 24 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -757,20 +757,42 @@ jobs:
# SECURITY-EXPOSURE.md. Forces every new alert to be triaged with a
# documented decision (override / dismiss / track / patch) instead of
# accumulating silently. See also SECURITY-EXPOSURE.md operational notes.
# Dependency advisories, in the place each can be acted on. On a pull
# request: fail only on a vulnerable dependency the pull request's own
# changes bring in (GitHub's dependency review), unless SECURITY-EXPOSURE.md
# already triages it. On main: every open advisory has a triage row (the
# inventory, also run daily by advisory-inventory.yml). Until 0.21.0 the
# inventory ran on every pull request, so each newly published advisory
# turned every open PR red at once, about changes none of them made.
security-exposure:
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Advisories already triaged in SECURITY-EXPOSURE.md
if: github.event_name == 'pull_request'
id: triaged
run: echo "ids=$(grep -oE 'GHSA(-[0-9a-z]{4}){3}' SECURITY-EXPOSURE.md | sort -u | paste -sd, -)" >> "$GITHUB_OUTPUT"
- name: No vulnerable dependency added by this pull request
if: github.event_name == 'pull_request'
uses: actions/dependency-review-action@a1d282b36b6f3519aa1f3fc636f609c47dddb294 # v5.0.0
with:
fail-on-severity: moderate
allow-ghsas: ${{ steps.triaged.outputs.ids }}
license-check: false
comment-summary-in-pr: never
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
if: github.event_name != 'pull_request'
with:
node-version: 22
cache: npm
cache-dependency-path: package-lock.json
- run: npm ci
- name: Check exposure coverage
- if: github.event_name != 'pull_request'
run: npm ci
- name: Every open advisory has a triage row
if: github.event_name != 'pull_request'
run: node scripts/security/check-exposure-coverage.mjs

# Smoke-build the Dockerfile on every PR. The host build (`build` job)
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ Match the formatting of the file you are editing. CI does not run Prettier, and
| `Real clients (ubuntu-latest)` | Claude Code and Gemini CLI connect to this commit through the config `iris-eval install` writes |
| `Real clients (macos-latest)` | The same, on macOS |
| `Real clients (windows-latest)` | The same, on Windows |
| `security-exposure` | Every open dependency advisory has an assessed row in `SECURITY-EXPOSURE.md` |
| `security-exposure` | On a pull request: no dependency it adds carries an advisory of moderate or above, unless `SECURITY-EXPOSURE.md` already triages it. On main: every open advisory has an assessed row there |
| `website-lint-and-typecheck` | Lint, typecheck and production build of `website/` |
| `Hardcoded-claim scanner` | No number/claim restated outside the truthbase |
| `Truthbase regen vs committed` | `.claims.json` and the rendered files regenerate identical to what you committed |
Expand Down
8 changes: 8 additions & 0 deletions scripts/security/check-exposure-coverage.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@
// not have permission to read Dependabot alerts, so an API-based gate
// would require a PAT secret per repo.
//
// Where it runs (0.21.0): on every push to main (ci.yml's security-exposure
// job) and daily (advisory-inventory.yml), not on pull requests. There it
// turned every open PR red whenever an advisory was published, about
// changes none of them made; a pull request is now gated by GitHub's
// dependency review on the dependencies it adds, with the GHSA ids triaged
// in SECURITY-EXPOSURE.md allowed. Both remain satisfiable inside the
// change they block.
//
// Run locally: node scripts/security/check-exposure-coverage.mjs
// Run in CI: same — no secrets needed
//
Expand Down
Loading