ADR-0011: CodeQL on every change, and Scorecard every week¶
Status: Accepted Date: 2026-10-12 Deciders: Alex Nodeland
Context¶
RFC-0003 puts CodeQL (Python, TypeScript) and OpenSSF Scorecard, weekly, under supply chain, in their own workflows, codeql.yml and scorecard.yml, in phase 6. It doesn't say when CodeQL runs, or what happens to what either finds.
GitHub offers CodeQL two ways. Its default setup is a repository setting, with no workflow, and it can't run beside a workflow of lattice's own. An advanced setup is a workflow, hardened and linted as every other one is (architecture). portalr's TypeScript is in packages/portalr/web/. zizmor and actionlint already check the workflows, in the hooks and in CI.
Scorecard publishes its result to the OpenSSF only from the default branch, and only when its job uses the actions it allows, with no top-level env or defaults.
Decision¶
codeql.ymlanalyses the Python and the TypeScript (python,javascript-typescript) on every pull request, on every push tomain, and every Monday, so new queries reach code that hasn't changed. Neither needs a build (build-mode: none). A pull request's newer push cancels its older analysis;main's analyses all finish. CodeQL'sactionslanguage stays off, since zizmor covers the workflows.scorecard.ymlruns every Monday, and by hand, onmain. It publishes the result to the OpenSSF's API (publish_results), and uploads its findings to code scanning.- Both are advanced setups, in lattice's own workflows: pinned by commit with the version beside it,
permissions: {}at the top,contents: readandsecurity-events: writeper job (andid-token: writefor Scorecard's signed result), and no credentials kept by the checkout. GitHub's default CodeQL setup stays off. - Neither is part of
CI. CodeQL's alerts show on the pull request, through GitHub's code scanning check. An alert is fixed, or dismissed with its reason, asosv-scanner.tomlrecords an advisory that doesn't apply (ADR-0008). Scorecard's findings are read each week, and a finding worth acting on becomes an issue.
Options considered¶
CodeQL¶
| Option | Runs | Configuration |
|---|---|---|
An advanced setup, codeql.yml (chosen) |
Pull requests, main, weekly |
In the repository, reviewed and linted like every workflow |
| GitHub's default setup | Pull requests, main, weekly |
A repository setting; actions that zizmor and Renovate never see |
When Scorecard runs¶
| Option | What it costs |
|---|---|
| Weekly, and by hand (chosen) | One short job a week |
On every push to main too |
A score for every merge, when what it scores changes rarely |
Trade-off analysis¶
The default setup is less to keep, but it hides the analysis in a setting and can't be pinned, linted or changed in review, which every other check in lattice is. Scorecard measures practices that move with settings and workflows, not with each commit, so a weekly score says as much as one per merge.
Consequences¶
- Easier: an injection, a path traversal or an unsafe deserialisation that CodeQL knows shows on the pull request that adds it.
- Easier: Scorecard's public score says how lattice is run, and its findings name what would raise it.
- Harder: Scorecard runs only on
main, so this workflow is first run after it merges, by hand.