diff --git a/.github/DEPENDENCY_SECURITY.md b/.github/DEPENDENCY_SECURITY.md new file mode 100644 index 00000000..de5c53ad --- /dev/null +++ b/.github/DEPENDENCY_SECURITY.md @@ -0,0 +1,71 @@ +# Dependency update and vulnerability audit policy + +The root `bun.lock` is the source of truth for resolved dependencies. GitHub +Dependabot checks Bun workspaces weekly and groups compatible production +and development updates separately. GitHub Actions updates are tracked +in a separate weekly group. + +The **Dependency audit (high and critical)** CI job runs +`bun audit --audit-level=high` on the committed Bun lockfile. A high- or +critical-severity finding fails the job; an unavailable or malformed npm +advisory response also fails closed. This deliberately does not use +`--prod`, since development and build tools can expose contributors +and CI systems to attack. + +## When an advisory is reported + +1. Open the advisory (GHSA ID) and identify the installed package, dependency + path, affected versions, available patched release, and reachable impact. +2. Prefer a compatible direct dependency update; otherwise propose an + appropriate transitive upgrade or reviewed override. Update `bun.lock` + with Bun and validate `bun install --frozen-lockfile` in a clean checkout. +3. Run the repository's full commit gate, plus the relevant web/indexer + integration checks described in `AGENTS.md`. Do not disable tests or lower + audit thresholds to make the change appear successful. +4. If no published fix exists, document the risk in a tracked issue and + propose a mitigation or replacement. A temporary ignore requires explicit + maintainer security review. + +## Narrowly-scoped exceptions + +A temporary exception must identify: + +- **GHSA ID** (use GHSA or numeric npm advisory IDs, not CVE IDs for Bun's + `--ignore` flag) +- affected package and exact installed version +- whether the vulnerable code can be reached in production, development or CI +- why an update, override, isolation or replacement is not currently possible +- compensating controls and the issue tracking a permanent fix +- maintainer approval, approval date and a removal/review deadline + +Only after approval may the CI command add the specific +`--ignore GHSA-xxxx-yyyy-zzzz` option. Never ignore a whole severity class +or an unaudited vulnerability just to turn CI green. Keep each approved +exception documented beside the audit command and in the tracking issue. + +**Review every exception at least quarterly**, and immediately when a fix +is released, the affected dependency changes or an incident changes its +impact. Remove ignores as soon as they are no longer justified. + +No exceptions are pre-approved by this document. Current audit failures +must be investigated, not automatically bypassed. + +## Observed baseline: October 18, 2026 + +The first implementation run of `bun audit --audit-level=high` reported +three **high** advisories in the unmodified upstream lockfile: + +| Advisory | Resolved dependency path | Status on review date | +| --- | --- | --- | +| [GHSA-vfj7-8cjw-p6xm](https://github.com/advisories/GHSA-vfj7-8cjw-p6xm) | `@workspace/ui` → `shadcn` → `braces` | No patched published version | +| [GHSA-jmr9-qjv8-65gv](https://github.com/advisories/GHSA-jmr9-qjv8-65gv) | `docs` → `@lhci/cli` → `extract-zip` | No patched published version | +| [GHSA-7pqw-9j4j-h8q3](https://github.com/advisories/GHSA-7pqw-9j4j-h8q3) | `docs` → `@lhci/cli` → `extract-zip` | No patched published version | + +These are **unresolved**; the audit job intentionally fails until an +effective dependency replacement/remediation ships or maintainers approve +time-bound, reachability-reviewed exceptions using the process above. +A detected vulnerability is not evidence that this product's code path is +exploitable. Before an exception, assess whether untrusted brace patterns +or untrusted ZIP files can reach the cited tools in production or CI. +The next quarterly checkpoint is **January 18, 2027**, or sooner when +patches become available. diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..ddb0f21a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,35 @@ +version: 2 +updates: + # Bun owns the text bun.lock. The npm ecosystem would update the wrong lockfile. + - package-ecosystem: "bun" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "06:00" + timezone: "Etc/UTC" + open-pull-requests-limit: 8 + groups: + runtime-minor-patch: + dependency-type: "production" + update-types: + - "minor" + - "patch" + developer-tooling-minor-patch: + dependency-type: "development" + update-types: + - "minor" + - "patch" + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "06:30" + timezone: "Etc/UTC" + open-pull-requests-limit: 4 + groups: + actions: + patterns: + - "*" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 84273646..33ae8fb0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,6 +12,21 @@ concurrency: cancel-in-progress: true jobs: + dependency-audit: + name: Dependency audit (high and critical) + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Setup Bun + uses: oven-sh/setup-bun@v2 + + - name: Audit locked dependencies + run: bun audit --audit-level=high + ci: name: Lint · Typecheck · Build runs-on: ubuntu-latest @@ -27,8 +42,6 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@v2 - with: - bun-version: latest - name: Cache Bun dependencies uses: actions/cache@v4 @@ -39,7 +52,7 @@ jobs: ${{ runner.os }}-bun- - name: Install dependencies - run: bun install + run: bun install --frozen-lockfile - name: Lint run: bun lint @@ -89,8 +102,6 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@v2 - with: - bun-version: latest - name: Cache Bun dependencies uses: actions/cache@v4 @@ -101,7 +112,7 @@ jobs: ${{ runner.os }}-bun- - name: Install dependencies - run: bun install + run: bun install --frozen-lockfile - name: Install Playwright browsers run: bunx playwright install --with-deps chromium