Main already moved upload-sarif to v4.39.1 (#2779). Move init and analyze to
the same commit, 9b3254085494b55a0f7c4c2b3d2d52cc712ce370 (the commit the
v4.39.1 tag points to), so all three CodeQL actions run one version again.
The pin comment follows the form Dependabot wrote for upload-sarif. The
codeql-action Dependabot group added earlier on this branch keeps the three
in lockstep from here on.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Conflict in .github/workflows/scorecard.yml resolved to the main version:
main already pins upload-sarif to 9b3254085494b55a0f7c4c2b3d2d52cc712ce370
(v4.39.1, #2779), which supersedes this branch's v4.39.0 pin.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The hosted Ubuntu x64 runners read the archive through
mirror+file:/etc/apt/apt-mirrors.txt. With Acquire::Retries above 0
(including the apt default of 3), a failover from a dead first entry
of that list (connection refused, DNS failure or a stalled host) to
the next entry goes idle: apt-get fetches a few InRelease files from
the second mirror and then waits until the step timeout. With
Acquire::Retries=0 the same failover completes. Seen on noble
(apt 2.8.3) and jammy (apt 2.4.14).
Every apt step this branch hardened now picks the retry count at
runtime, applied to both update and install: 0 when the runner has the
mirror list (moving to the next mirror is the retry), 3 otherwise
(arm64 runners and any host with plain sources keep their retries).
--error-on=any, the http and https timeouts and the step timeouts are
unchanged.
Proof: the step text extracted from the edited _build.yml (update plus
install of zlib1g-dev), run under bash -e in ubuntu:24.04 and
ubuntu:22.04 containers with runner-shaped mirror lists:
- first mirror refused: exit 0 in 8 s / 9 s, every index and deb
fetched from the second mirror
- first mirror stalled (192.0.2.1): exit 0 in 68 s / 69 s, one 30 s
timeout each for update and install, then the second mirror
- healthy first mirror: exit 0 in 7 s / 9 s
- no mirror list, plain sources: the prefix keeps Retries=3, exit 0
in 8 s / 7 s
- every mirror dead: update exits 100 in under 1 s, install skipped
- revert check, the previous step text with a dead first mirror
(refused or stalled): idle with no Packages index at the 180 s cap
on both releases
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
apt-get update exits 0 when index fetches fail: it only prints
"W: Some index files failed to download. They have been ignored, or
old ones used instead." and the job breaks later at install time with
a misleading "Unable to locate package", or installs from stale lists.
Add --error-on=any to every apt-get update this branch hardens, placed
after the -o options as in test-infrastructure/Dockerfile.msan, so the
update step itself fails when an index cannot be fetched.
Proof in ubuntu:24.04 (apt 2.8.3) and ubuntu:22.04 (apt 2.4.14)
containers with a runner-shaped mirror+file:/etc/apt/apt-mirrors.txt
source and the same -o options CI passes:
- every mirror unreachable: exit 100 with the flag (E: lines), exit 0
without it (W: lines, zero Packages lists), on both apt versions
- first mirror refused or stalled (30 s connect timeout) and the real
archive second: the Ign: failover lines do not trip the flag, exit 0
with every index fetched (measured with Acquire::Retries=0)
- the image sources with the flag: exit 0 and no Ign/W/E lines, so the
option is understood by apt 2.4 and 2.8
- green hosted-runner logs (ubuntu-24.04 and ubuntu-22.04 legs) show no
Ign/Err/W/E lines in the update step
With Acquire::Retries=3 a mirror failover leaves apt idle after the
InRelease failover, with or without the flag and also for a plain
apt-get update; that apt behaviour predates this change and is
unchanged by it.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
On 2026-11-01 two Linux jobs hung in `sudo apt-get update` right after
"Get:5 https://archive.ubuntu.com/ubuntu noble-security InRelease" until
their job limit; the build never started in either:
- PR 2641, test-tsan x86 (run 41251045506, job 124688326533): the
"Install deps (Ubuntu)" step ran 2 h until the 120-minute job limit.
- PR 2395, test-unix gcc x86 (run 41256855177, job 124705168264): the
same step ran 4 h until the 240-minute job limit.
Both logs show the azure mirror ignored after about 15 s, the fallback to
archive.ubuntu.com, and then no output until the cancel. The default apt
http timeout (120 s) did not end the stall.
Rule applied to every workflow step whose run block calls apt:
- A step-level timeout-minutes. 10 for steps that only provision packages
(green runs on 2026-11-01 and the last green dry run: 5 to 76 s); 20 for
the three pr.yml steps that also run scripts/build.sh (green: 246 to
331 s). A stalled mirror now fails the step in minutes instead of
holding the runner until the job limit.
- `-o Acquire::Retries=3 -o Acquire::http::Timeout=30
-o Acquire::https::Timeout=30` on every apt-get update and install,
with the -o options before the subcommand as in
test-infrastructure/Dockerfile.msan.
Nothing else changes: no action, runner, package or step-order changes.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Dependabot opened one PR per CodeQL action (#2504 init, #2505 analyze, #2506 upload-sarif), each moving to 4.38.2. Merging them one at a time would leave init and analyze on different versions in between. This moves all three to v4.39.0 (6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee, the commit the v4.39.0 tag points to) in one change, and adds a Dependabot group so future CodeQL Action updates arrive as a single PR.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Bring CodeQL back to pull requests as jobs of PR CI itself (needed by
ci-ok, no polling), narrowed to first-party code, while push to main,
the weekly run, the dry run and the release keep the full scan.
- codeql.yml: one leg per language (c-cpp, javascript-typescript,
python, actions), scope in .github/codeql/codeql-config.yml. The full
scan traces the whole build, vendored C included. The PR scan
(light: true) analyses each selected language's whole first-party
scope; c-cpp compiles the third-party objects before tracing
(scripts/build.sh --vendored-only) and then traces the first-party
build plus the vendored files the PR changes (--reuse-vendored
--retrace-from, make -W). Diff-informed analysis (codeql-action
v4.38.1, forced on for PR calls) only restricts reported alerts.
The alert check moves into each leg and reads the analysed ref.
Push and PR runs cancel superseded runs per language; dispatched
runs never cancel. Compiler cache off so every compile is traced.
- pr.yml: a codeql job runs the legs of the selected codeql-* lanes;
ci-ok needs it.
- select-lanes.sh: codeql-cpp/-js/-py/-actions lanes, selected by a
change in their scope (any C/C++ incl. vendored; JS/TS, Python and
workflows inside the config's paths minus paths-ignore) and by every
full run (undeterminable diff, workflows, build, CodeQL machinery).
--codeql-scope LANGUAGE prints a list's in-scope paths.
- codeql-retrace-vendored.sh: the vendored C files a PR changes (empty,
never narrowing, when the diff cannot be determined).
- Makefile.cbm: cbm-third-party builds the vendored prod objects only.
- tests: the gate contract pins the new layout; the selector contract
pins that a C change always selects the C scan, an undeterminable
diff selects every language, and a vendored-only change retraces
exactly the changed vendored files. Selector fixtures, ci-ok's job
map, the replay's codeql-action failures (lane codeql-cpp) and the
interface probes follow.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
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>
CodeQL SAST keyed its concurrency group by commit SHA on push events,
so every merge to main got its own group and nothing was ever
cancelled; OpenSSF Scorecard had no group at all. On 2026-10-04 a day
of 36 merges queued one CodeQL analysis (40-100 minutes each) and one
Scorecard run per merge, ahead of every pull request run: pull request
CI waited hours for a runner, and a main analysis waited 4 hours.
CodeQL now groups by event and by pull request number or ref, so pull
requests keep one analysis each as before, and a newer push to main
cancels the analysis of an older main commit. Scorecard groups by ref
with the same cancellation. Only the newest main commit matters for
both: code scanning tracks the default branch's latest analysis.
DCO keeps its per-commit group on purpose: its push run on main is the
check that catches a merge rewriting sign-offs, so a superseded push
must still be checked, and a DCO job takes seconds.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Dependabot opened one PR per sub-action (#2363 init, #2365 analyze, #2364
upload-sarif). CodeQL refuses a split pin: with init at 4.38.1 and analyze
at 4.38.0 the analyze post-step fails with "Loaded a configuration file for
version '4.38.1', but running version '4.38.0'", so neither PR can pass
the codeql gate alone and merging either one would break the gate on main.
This bumps all three to 1c5b675653bb5c22dbe9b12b556ec555138e09fd, which is
the commit the upstream v4.38.1 annotated tag points to.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Dependabot split one upgrade across three PRs -- init (#2185), analyze
(#2187) and upload-sarif (#2186) -- but init and analyze share a
configuration file and CodeQL refuses to read one written by a different
version:
Loaded a configuration file for version '4.38.0',
but running version '4.37.9'
So #2185 and #2187 each go red on their own and neither can reach a green
required check, which means they cannot be merged one after the other
either: whichever lands first leaves the pair mismatched. The action also
warns about it directly -- "Not all workflow steps that use
github/codeql-action actions use the same version".
Both refs in codeql.yml therefore move in one commit, to the same pinned
SHA b96794f015dfd88f77b49b1c93e0fa7110f94c63 that both bot PRs target.
scorecard.yml's upload-sarif is deliberately not touched here: it runs in
a separate workflow that shares no configuration with init/analyze, which
is why #2186 is green on its own and can land as its own PR.
Supersedes #2185 and #2187.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Dependabot split this bump across two PRs -- #1898 bumps init, #1900 bumps
analyze -- but codeql-action requires every step in a workflow to run the
same version. Either PR alone produces a mismatch and analyze fails with:
Loaded a configuration file for version '4.37.4', but running version '4.37.9'
so neither can be green on its own, and merging either would leave main's
CodeQL job broken for every subsequent PR. Bump both pins in one commit.
Pin verified: cdf488f595d80d6e07e03d4674febd5ab45fa938 is the commit that
the annotated tag v4.37.9 dereferences to in github/codeql-action.
Supersedes #1898 and #1900.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Same treatment as v4.37.3 (#1434): dependabot splits the codeql-action
bump into init-only and analyze-only PRs (#1398, #1399 after their
rebase to 4.37.4), but the two actions must run at the same version, so
each split PR fails its own analyze job. SHA verified against the
upstream v4.37.4 tag.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Dependabot split the codeql-action bump into two PRs (#1398 init,
#1399 analyze), but init and analyze must run the same action version:
each PR alone fails its own analyze job with "Loaded a configuration
file for version '4.37.3', but running version '4.36.2'". Bump both
pins in one change instead. SHA verified against the upstream v4.37.3
tag.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
- graph-ui: bump vite ^6.4.2 -> ^6.4.3 and add overrides pinning the transitive
form-data >=4.0.6 and @babel/core >=7.29.6 (all dev-scope build/test deps, not
shipped in the binary). Clears the 4 open Dependabot alerts and Scorecard's
VulnerabilitiesID. `npm audit` now reports 0 vulnerabilities.
- codeql.yml: move `security-events: write` from the workflow top level to the
`analyze` job (top level is now `contents: read`), resolving Scorecard's
TokenPermissionsID least-privilege finding. CodeQL still uploads results from the
job-scoped token.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A new push to a PR (or ref) now cancels the in-progress validation for
the previous commit instead of letting obsolete pipelines run to
completion. Drafts deliberately keep the full gate set — multi-platform
feedback matters most during iteration.
Signed-off-by: Martin Vogel <martin.vogel@datadice.io>
Pull requests now execute the dry-run chain (security including the
license gates, lint, full test suite, all build legs, smoke) plus a
single ci-ok summary job that fails unless every stage succeeded.
Branch protection requires dco + ci-ok, so nothing unverified can merge
— including from admins. CodeQL also runs on pull requests so the
security island completes on PR commits.
Signed-off-by: Martin Vogel <martin.vogel@datadice.io>
Reverts the CodeQL portion of 27e640b ('fix(mcp,ci): harden
get_architecture serialization + CodeQL gate'). Leaves the mcp.c +
test_mcp.c changes (NULL-coercion, clusters/services serialization,
extract_text_content fix, regression test) intact.
Restored to the pre-27e640b state:
- drop 'jq' from build-deps install line
- drop 'queries: +./codeql' from codeql-action/init (no ./codeql
custom-query directory exists in this repo)
- drop 'id: analyze' and 'output: codeql-results' on analyze step
- drop the SARIF-parsing 'Fail on CodeQL error-level findings' step
CI workflow changes need their own design discussion per CONTRIBUTING.md
('Project configuration / CI workflows' is in the explicit-approval list);
the gate hardening landed bundled with an unrelated bug fix. Splitting it
out so the upstream MCP fix stays clean and any future CodeQL gate work
can be its own focused PR.
Follow-up to #281 (handle_get_architecture) plus a CodeQL workflow
upgrade developed in parallel; bundling into one commit because the
test suite had to land alongside both.
mcp.c — handle_get_architecture
- NULL-coerce every const-char* field in the architecture sections
via `x ? x : ""`, matching the rest of mcp.c (search_graph, etc.).
Without this, a NULL field becomes a missing JSON key instead of
an empty string; yyjson_mut_obj_add_str returns false on NULL and
silently no-ops, so an inconsistent omission could surprise callers.
- Serialize two more architecture aspects that #281 left on the
floor: services (cbm_service_link_t: from/to/type/count) and
clusters (cbm_cluster_info_t: id/label/members/cohesion plus the
top_nodes / packages / edge_types string arrays). The store-side
computation populates these for aspects=["all"] / explicit names,
so dropping them in the serializer was data loss.
tests/test_mcp.c
- New tool_get_architecture_emits_populated_sections regression test.
Uses a minimal inline fixture (single Function node tagged with
"is_entry_point": true) since arch_entry_points reads that flag
out of properties_json. Asserts the response contains both an
"entry_points" array and the function name — neither would appear
before #281 because handle_get_architecture never called
cbm_store_get_architecture.
- extract_text_content drilled too shallow: it pulled "content" only
from the JSON root, so it worked for cbm_mcp_handle_tool but
silently fell through to the raw response for cbm_mcp_server_handle
(where content lives under .result.content). Added a fallback that
checks .result.content; both unwrappers tested by existing fixtures.
ci(codeql)
- Run on pull_request to main, not just push; surfaces findings on
the PR instead of after merge.
- Pull custom queries from ./codeql via `queries: +./codeql`.
- Capture SARIF output and fail the job on any error-level finding,
using jq to enumerate rule id, file:line, and message text in the
GitHub Actions error annotation. Warnings are still reported as
before; only errors block.
Full suite: 2842 passed, 0 failed.