feat(ci): CT-04 CodeQL with honest ruby/python/actions matrix (TIN-3398) - #126
Jess Sullivan (Jesssullivan) wants to merge 3 commits into
Conversation
…N-3398) Adds .github/workflows/codeql.yml: CodeQL analysis over the three languages actually present (ruby, python, actions) with the security-extended query pack, on pull_request + push:main + weekly schedule. Runs on ubuntu-latest (rationale recorded in-file) rather than tinyland-nix, since none of the three languages need the Nix devShell/Bazel cache the ARC pool exists to provide, and the pool is under documented capacity pressure. CodeQL has no shell analyzer, so a shellcheck job over scripts/*.sh is added in the same workflow as the required substitute coverage. The file also states explicitly, per the issue's acceptance criteria, what CodeQL does NOT cover here (inline run: blocks, vendored JSON, dependency CVEs) and what covers each instead.
Verification pass (read-only) — FLAG, 4 defectsVerified against #110's COMPLETION METRIC and acceptance criteria verbatim, on a clean detached worktree of What holds up
D1 (blocker) — the shellcheck job is red on arrival
shellcheck's default severity floor is Note this is also a hole in the claimed static-proof set: shellcheck is already in this repo's D2 — floating action tags violate this repo's own pinning doctrineFour unpinned third-party refs:
Separately, D3 — no
|
…tions, add timeout (TIN-3398) Addresses the opus-verify FLAG on PR #126: - Drop the shellcheck job entirely (was red on arrival: shellcheck's default severity floor treats the 3 pre-existing SC2016 infos in scripts/cache-attachment-contract*.sh as fatal, unrelated to this PR's CodeQL deliverable). Deferred to a follow-up PR wired into the Justfile check chain instead of invoking apt-get directly on a hosted runner. "What CodeQL does not cover" footer updated to match. - Pin all four floating third-party action refs to full commit SHAs per .greptile/rules.md:7: actions/checkout pinned to d23441a48e516b6c34aea4fa41551a30e30af803 (v6.1.0, matching every other pin in this repo; also fixes the v4->v6 two-major drift from the rest of the fleet), github/codeql-action/init and github/codeql-action/analyze pinned to c4dd10e44af883a891fe31ced449bcb4a6728b9b (v3.37.6, resolved live from the v3 tag). - Add timeout-minutes: 20 to the analyze job (.greptile/rules.md). - Narrow concurrency.cancel-in-progress to pull_request only, so a rapid second push:main can't cancel the scan the completion metric's zero-open-alerts clauses read from. - CHANGELOG [Unreleased] entry (golden rule 4; missing from the original commit). Verified: ruby YAML.load_file + actionlint clean; ruby scripts/lint-runs-on.rb --root . gives 40 checked, 0 FAIL, 22 WARN (unchanged from baseline); full just check chain runs clean through every target except the pre-existing restricted-workflow-contract-check failure (spoke-lane-env pin drift, TIN-489/#122 -- tracked and fixed separately on branch fix/spoke-lane-env-pin-drift-20260806 / draft PR #129, not this PR's defect).
|
Fixed in 068af20 (see the review-fix changelog section of the updated PR body for full detail):
|
Re-verification of the review-fix commit (068af20) — FLAG (1 substantive + 1 minor)Read-only re-run of every reproduction step from the original FLAG (comment), in a clean throwaway clone of Original defects: all four resolved, confirmed
No regressions introduced
New: the first run will actually runChecked because D1 was exactly this class of defect: D5 (substantive) —
|
|
Re-cutting, same reason as CT-01.
The premise holds: The re-cut's actual work is the runner-class decision -- where the CodeQL bundle downloads and the analysis runs on a GF cache-fronted capability class. That is the PR, not a detail of it. |
CT-04 — CodeQL with an honest language matrix
Wave 1 "Enforcement spine" milestone (2026-08-06). Linear project: ci-templates — Strict Governance & Org Interface Contract · Linear issue: TIN-3398. Closes #110.
Revised 2026-08-06 after opus-verify FLAG (see PR comment for the full defect list this addresses). Summary of what changed and why is in the "Review-fix changelog" section near the bottom — read that first if you reviewed the original version of this PR.
Completion metric (verbatim, from #110)
Honest metric status: 0/3 clauses provable pre-merge, all 3 structurally satisfiable
None of the three clauses can be true yet — no CodeQL run has ever executed against this repo, so
code-scanning/analysesis empty and there is nothing for the alert-severity queries to return but[](a vacuous, not yet meaningful, pass). This is not a deferral of scope; it's an inherent property of a code-scanning completion metric: it can only be evaluated after the workflow lands onmainand runs once. This PR's job is to make the workflow structurally correct and its first run trustworthy, not to fake a pre-merge alert query..github/workflows/codeql.ymladds a matrixedanalyzejob over[ruby, python, actions]— the actual code surface in this repo (scripts/*.rb,scripts/*.py, and the workflow/action YAML itself). All three usebuild-mode: noneandqueries: security-extended. Triggers:pull_request(branches: main),push(branches: main), and a weeklyschedule. After merge, the firstpush:mainrun populates all three languages intocode-scanning/analyses, satisfying clause 1.tinyland-inc/ci-templatesitself right now:code-scanning/analysesreturns[null]and both alert-count queries return0, confirming no CodeQL has ever run and the calls authenticate/parse correctly; re-run after this PR merges and the firstpush:mainCodeQL run completes, typically visible within ~10 minutes post-merge):gh api -X PATCH repos/tinyland-inc/ci-templates/code-scanning/alerts/{number} -f state=dismissed -f dismissed_reason=<reason>) before the metric is truly met. This PR cannot pre-verify that outcome.Scope note (per #110's own acceptance criterion #4 — "state plainly what CodeQL does not cover")
CodeQL has no shell analyzer. This repo's largest realized risk class is inline
run:shell with${{ }}expression interpolation (see PR #99 / TIN-3270 cited in #110) andscripts/*.sh. Neither is covered by this PR. The workflow file states this explicitly at the bottom (# What CodeQL does NOT cover here...):run:blocks embedded in workflow/action YAML: not extracted or analyzed. Tracked as a real, un-solved gap.scripts/*.sh: not covered. A shellcheck job was in the original version of this PR but was dropped during review-fix — see "Review-fix changelog" below. Follow-up is tracked, not silently dropped.schemas/*.json,tinyland.repo.json): out of scope by construction, not code in any CodeQL-supported sense.security_and_analysis.dependabot_security_updates=enabled, confirmed live).Runner-class decision (explicit, does not inherit CT-01's tinyland-nix)
runs-on: ubuntu-latest. None of ruby/python/actions need the Nix devShell or Bazel cache tinyland-nix exists to provide (build-mode: none— nothing to build); the CodeQL bundle download is a hosted-runner-native path; and the ARC pool is under documented capacity pressure, so a scan job with zero cluster-native requirement should not consume sharedtinyland-nixslots. Rationale is recorded in-file as a comment so it isn't silently assumed to carry over from CT-01.Dependency note
#110 lists this as depending on CT-01 (#107, in-flight at the time of this PR). This workflow does not structurally depend on
validate.ymlexisting — it's a standalone trigger surface — so it's implementable and provable independently. Sequencing onto branch protection (CT-02, #108) still correctly waits on this PR's check name landing, per CT-02's own completion metric.Review-fix changelog (2026-08-06, addressing opus-verify FLAG)
The original version of this PR (975e25c) was flagged with 4 defects + minors. All are fixed in 068af20:
shellcheck scripts/*.shexits 1 on unmodifiedmaintoday (3× pre-existing SC2016 info findings inscripts/cache-attachment-contract*.sh; shellcheck's default severity floor treatsinfoas fatal). Per the reviewer's own recommended options, the shellcheck job is dropped entirely — CodeQL is this PR's actual deliverable, and landing an enforcement job that fails on its own first run (including gating this PR's ownpull_requesttrigger) is worse than shipping CodeQL alone with the gap stated honestly. Shell coverage is deferred to its own follow-up PR that also wires it into the Justfilecheckchain (doctrine: Justfile is the single validation entrypoint), rather thanapt-get install-ing an unpinned shellcheck directly on a hosted runner outside that entrypoint (which was D4 in the same review, resolved for free by dropping the job)..greptile/rules.md:7:actions/checkout@v4→actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6.1.0— also fixes a two-major regression (@v4was the only@v4checkout in the repo; every other workflow is on@v6/v6.1.0's pinned SHA). Verified live:git ls-remote --tags https://github.com/actions/checkout.git→refs/tags/v6.1.0=d23441a48e516b6c34aea4fa41551a30e30af803, byte-identical to the pin already used inspoke-ci-restricted.yml/spoke-lane-env-restricted.yml.github/codeql-action/init@v3andgithub/codeql-action/analyze@v3→ both pinned toc4dd10e44af883a891fe31ced449bcb4a6728b9b # v3.37.6. Verified live:git ls-remote --tags https://github.com/github/codeql-action.git→refs/tags/v3^{}(dereferenced annotated tag) =c4dd10e44af883a891fe31ced449bcb4a6728b9b; confirmed viagh api repos/github/codeql-action/tagsthat this commit is taggedv3.37.6.timeout-minutes. Addedtimeout-minutes: 20to theanalyzejob (.greptile/rules.md: "Usetimeout-minuteson all jobs"). Theshellcheckjob's timeout is moot — the job no longer exists.concurrency.cancel-in-progresscould cancel apush:mainrun. Narrowed tocancel-in-progress: ${{ github.event_name == 'pull_request' }}— redundant PR re-runs still get cancelled, but a rapid second push tomaincan no longer clobber the scan the zero-open-alerts metric clauses read from.[Unreleased]entry per golden rule 4 (missing from the original commit).shell: bashon inlinerun:blocks, missing job-levelpermissionson the shellcheck job, fail-open empty-globexit 0branch.Static proofs run locally (no workflow dispatches, per lane discipline)
Re-run on the fixed tree (068af20), in a clean isolated worktree:
ruby -e 'require "yaml"; YAML.load_file(...)'over all.github/**/*.{yml,yaml}— parses clean (just yaml-parse).actionlint .github/workflows/codeql.yml— 0 errors.ruby scripts/lint-runs-on.rb --root .— 40 runs-on checked, 0 FAIL, 22 WARN across 11 workflow files (unchanged from the pre-existing baseline; dropping the shellcheck job removed one previously-checked literal, net zero new WARN/FAIL).ruby scripts/restricted-workflow-contract.rb— the only failure is the pre-existing, unrelatedspoke-lane-envlegacy-bytes drift (TIN-489/docs(tin-489): stop teaching Blahaj-dispatch PR-env routing — owner overlay is the producer #122, tracked and already fixed on branchfix/spoke-lane-env-pin-drift-20260806/ draft PR fix(ci): re-cut spoke-lane-env legacy byte pin after TIN-489 docs drift #129) — confirmed by diffing this branch's output against a cleanorigin/maincheckout: identical single failure, nothing new introduced by this PR.just check(PATHadjusted sopython3resolves an interpreter withjsonschemainstalled — the nix devShell isn't buildable on this darwin sandbox due to a remote-builder machine mismatch unrelated to the repo; no repo files changed for that workaround): every target throughrestricted-workflow-contract-checkpasses; that target fails for the pre-existing reason above; every target after it (endpoint-free-check,ci-cached-endpoint-free-check,cache-backed-optin-contract-check,cache-contract-selftest,secrets-scan-dir,lint-runs-on-selftest,lint-runs-on-check) was run individually and passes clean.No AI attribution in this commit/PR.