CodeQL ran on every pull_request push, and PR CI's security / codeql-gate
job polled up to 150 min for that run before ci-ok could pass. With ~30 PRs
pushed at once, the gate jobs held runners while the CodeQL runs they waited
for queued behind them, and PR CI starved for hours.
- codeql.yml: triggers are push to main, a weekly schedule, workflow_call
and workflow_dispatch; pull_request is gone. The open-alert check moves
here, unchanged and still fail-closed, as the `alerts` job (needs
analyze), so every main push and every weekly run fails while any
code-scanning alert is open. Push runs keep cancel-in-progress; called and
scheduled runs get a group of their own. The analysis key is pinned to the
push configuration so dry-run/release uploads do not open configurations
of their own on main.
- _security.yml: codeql-gate removed; callers grant contents: read only.
- dry-run.yml, release.yml: a `codeql` job calls codeql.yml on the
dispatched commit; release verify needs it and requires success.
- select-lanes.sh, require-all-green.sh: the codeql-gate lane is gone from
the selector universe and from ci-ok's job map; no other lane changes.
- tests: the fail-closed contract follows the check to codeql.yml and now
also pins the triggers, the derived callers' grants and release verify;
lane fixtures drop codeql-gate.
- SECURITY.md, MAINTAINERS.md: say where CodeQL runs now.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The license gate installed `scancode-toolkit` unpinned. pluggy 1.7.0
(uploaded to PyPI 2026-10-15 09:50 UTC) no longer finds the hookspecs that
plugincode 32.0.0 declares on a class (`@pre_scan_spec class
PreScanPlugin`), so scancode crashes at import with "ValueError: did not
find any 'pre_scan' hooks" and `security / license-gate` fails on every
run, whatever the tree. The last green gate started at 09:50:14 UTC;
every run since is red. `ci-ok` and the release `verify` job both need the
security workflow, so this blocks every PR and the release.
Install exactly scancode-toolkit 32.5.0 (the version every green run
used) with pluggy constrained to 1.6.0 through PIP_CONSTRAINT, which the
pip that pipx runs reads. The local hint in license-gate.sh names the
same command.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
pr.yml's `changes` job now lists the changed files (renames with their old
path too), runs scripts/ci/select-lanes.sh in a credential-less step and
outputs tier, full, lanes and the pr-smoke matrix. security, lint and test
pass the lanes to their reusable workflows, which take a `lanes` input
defaulting to "all": dry-run.yml and release.yml pass none and run exactly
as before (setup-matrix output for every broad/shard combination is
byte-identical; the TSan matrix moved into setup-matrix with the same legs).
Under a selection, setup-matrix keeps only the tagged legs of the selected
lanes (an untagged leg is an error, never a silent drop) and each lane job
has an `if:` on its lane. pr-smoke and memwaste run on their lanes instead of
the old product regex. Docs-only PRs (T0a) get a `contracts` job running the
new `scripts/test.sh --contracts-only` (Step 0 contracts, no build). ci-ok
needs contracts, lists the run's jobs (actions: read) and passes LANES/JOBS
to require-all-green.sh; shard-completeness passes --lanes.
tests/test_lane_wiring_contract.sh (Step 0z4) pins it: dry run and release
pass no lanes and the inputs default to all, pr.yml wires the selection
through, and every lane is served by a tagged leg or an `if:` naming it.
The smoke-fixture contract now checks the selector's decisions for the
smoke-harness paths instead of the removed regex; select-lanes.sh joins the
venue-parity interface probes.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The codeql-gate has never checked anything. It declared no permissions block,
so it inherited the workflow's contents:read and the code-scanning alert API
answered 403. gh writes the API error BODY to stdout, so
ALERTS=$(gh api '.../code-scanning/alerts?state=open' --jq 'length' 2>/dev/null || echo "0")
left ALERTS holding
{"message":"Resource not accessible by integration",...,"status":"403"}0
every [ ... -gt ... ] then failed as a non-integer comparison, the if took its
false branch, and the step printed "CodeQL gate passed (0 alerts)" and exited 0.
Observed in the log of a GREEN run (34700514102, job 103571322660) while the
repository had an open high-severity alert. The `|| echo "0"` reads as defensive
and is the exact opposite: it converts "I cannot see the alerts" into "there are
no alerts", which is the one direction a security gate must never fail in.
Grant the job security-events:read (and actions:read, which the CodeQL-run poll
needs for the same reason), and replace the fallback with a helper that treats a
non-zero gh exit or a non-numeric body as a hard failure. The helper returns
rather than exits because it runs inside a command substitution, where an exit
would end only the subshell and let the caller continue with an empty count --
the same silent pass in a new costume; both call sites check the status.
tests/test_security_gate_fail_closed.sh pins both halves and fails with six
assertions against the previous workflow.
Also bumps graph-ui's vitest to ^4.1.11 (GHSA-82fw-gwwq-j7x9, path traversal via
@vitest/mocker, CVSS 5.9). Development scope, and graph-ui ships in no release
artifact, so nothing released was ever exposed -- but it was the sole open alert
and the gate above is worthless while it stands unresolved. Raising the floor
past the vulnerable range also stops a fresh install resolving back into it.
graph-ui: npm ci clean, 47 tests in 12 files pass on 4.1.11.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The gate waited 90 x 30s = 45 min for CodeQL to finish on the PR head. That
is shorter than CodeQL actually takes on this repository, so the gate has
been failing runs that had not failed.
Measured on PR #1426, head 7b72652a: the CodeQL SAST workflow completed with
conclusion=success at 17:46:05, having started at 15:41:44 -- 124 minutes.
The gate step ran 16:52:58 to 17:38:44 and reported "BLOCKED: CodeQL timeout"
7 minutes and 21 seconds before the scan it was waiting for succeeded.
Two open contributor pull requests are red from exactly this: #1426 and
#1769, both with CodeQL completed=success on their head and every other
check green.
Three further PRs (#1703, #1741, #1742) are also red on codeql-gate alone,
but from a different cause: the CodeQL run on their head is
completed=cancelled, so the gate saw a non-success conclusion and correctly
exited 1 without waiting. This change does not help those and is not
intended to; they need a fresh scan, most likely having been superseded by
concurrency cancel-in-progress in codeql.yml.
300 x 30s = 150 min covers the measured 124 min with margin. The job already
declares timeout-minutes: 240, so the wait still cannot outlive its own job.
No trigger, permission or gating change: codeql-gate blocks exactly what it
blocked before, and a genuine CodeQL failure still exits 1 immediately rather
than waiting out the budget. Only the absence of a verdict waits longer.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The ubuntu-24.04-arm test leg (native ARM64 Linux running the full suite under
AddressSanitizer + the FastAPI incremental index) exceeds the 60-minute job
timeout and was killed, failing ci-ok even though the suite was on track to pass.
ARM + ASan is legitimately 2-3x slower than x86-64.
Raise the substantial compute jobs (test, build, bug-repro board, soak's short
legs, security/codeql, cross-platform smoke, fast-repro) to a generous 240-minute
(4h) cap so a slow-but-correct runner can't false-timeout. Trivial aggregator
jobs (5/10/15m: setup-matrix, ci-ok, dco, lint, license-gate, quick smokes) and
the intentional soak caps (300/320m) are unchanged.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Pull requests run the security island only — static audit, license
gates, and the CodeQL gate plus the ci-ok summary; the full dry-run
chain (lint/test/build/smoke) stays maintainer-driven via
workflow_dispatch. The CodeQL gate now resolves the PR head SHA instead
of the synthetic merge commit so it can find the analysis run.
Signed-off-by: Martin Vogel <martin.vogel@datadice.io>
The license gate now proves itself before running: a --selftest mode
plants an unlicensed vendored file and asserts the structural layer
detects it, so a silently broken gate can no longer pass. The
byte-identity provenance audit gains exit-code semantics (any verdict
outside the accepted set fails) and runs as a blocking step in the
security workflow for both dry runs and releases.
Release archives now carry THIRD_PARTY_NOTICES.md, generated by
scripts/gen-third-party-notices.sh from THIRD_PARTY.md, the grammar
manifest, and the per-component license texts; the Homebrew formula
and AUR PKGBUILD install it alongside the binary. The SBOM gains
per-component license metadata, corrected versions, and the previously
missing vendored libraries. The security workflow gains a
vendored-license scan with an explicit allow-list policy, and the
release workflow exposes a skip_perf input for releases that do not
touch pipeline logic.