Skip to content
Merged
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
41 changes: 36 additions & 5 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,9 @@ jobs:
name: Bun audit
if: github.event.pull_request.draft != true
runs-on: ubuntu-latest
timeout-minutes: 5
# Budget for a degraded advisory registry: the report step is capped at 4
# minutes, the gate below retries hung or 5xx lookups up to three times.
timeout-minutes: 20
permissions:
contents: read

Expand All @@ -60,11 +62,21 @@ jobs:
- name: Setup Bun
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2
with:
bun-version: '1.3.12'
# Deliberately newer than the 1.3.12 the build jobs pin: before 1.4,
# `bun audit --prod` run from a workspace root reported workspace
# members' devDependencies as production (oven-sh/bun#26675, fixed
# in 1.4 by oven-sh/bun#38333). That made the gate below fail on
# @faker-js/faker 5.5.3, reachable only through the dev-only
# @stoplight/prism-http mock server (postman-collection pins it and
# no upstream release lifts the pin). 1.4.0 keeps reporting real
# production findings (verified against the fast-uri/mysql2 lock).
bun-version: '1.4.0'

- name: Run bun audit (report)
# Full advisory list for visibility; does not fail the build itself.
# Bounded so a hung registry request cannot eat the gate's time.
continue-on-error: true
timeout-minutes: 4
run: bun audit --prod | tee bun-audit.txt

- name: Summary
Expand All @@ -77,10 +89,29 @@ jobs:

- name: Gate on high/critical advisories
# The blocking gate: fail on HIGH or CRITICAL production advisories.
# pipefail so tee does not mask a non-zero exit.
# pipefail so tee does not mask a non-zero exit. The advisory lookup is
# one POST to registry.npmjs.org's bulk endpoint, which on 2026-09-04
# alternated between 503s and minute-long hangs; a registry outage must
# not read as a finding, so a hung (exit 124) or transport-error attempt
# is retried up to three times, 30 s apart. A run that lists advisories
# exits 1 with no transport error line and keeps the red on the first
# pass, exactly as before.
run: |
set -o pipefail
bun audit --prod --audit-level=high | tee bun-audit-gate.txt
set +e -o pipefail
for attempt in 1 2 3; do
timeout 240 bun audit --prod --audit-level=high 2>&1 | tee bun-audit-gate.txt
status=${PIPESTATUS[0]}
if [ "$status" -eq 0 ]; then
exit 0
fi
if [ "$status" -ne 124 ] && ! grep -q -E '^error: (GET|POST) https?://' bun-audit-gate.txt; then
exit 1
fi
echo "advisory registry request failed or hung (attempt $attempt/3, exit $status); retrying in 30s"
sleep 30
done
echo "advisory registry unreachable after 3 attempts" >&2
exit 1

# ---------------------------------------------------------------------------
# Scan source tree for known CVEs in dependencies + misconfigurations + secrets.
Expand Down
Loading