Rulebearing Playground Coverage Schemas GitHub

ADR-0025: Continuous integration runs least-privileged, pinned and bounded, and the dependency supply chain is closed

Context

The project ships a binary that other people will run in their pipelines, built by workflows that run on every push. Three things were unhardened: the workflows themselves (default write token, floating action tags, no timeouts), the dependency sources (licences and advisories were checked, registries were not), and two promises that nothing verified, namely the declared minimum Rust version and the claim that a narrower build never links the other extractors.

Decision

1. Workflows are least-privileged, pinned and bounded.

Control Setting
Token permissions: contents: read at the top of every workflow; the release workflow raises it for the jobs that publish, and nowhere else
Actions Pinned to a commit SHA with the tag in a trailing comment; bumped by Dependabot, never by editing the tag
Time timeout-minutes on every job, sized to the job
Duplication A concurrency group per workflow and ref, cancelling superseded runs
Shell Workflows are linted by actionlint and every committed script by shellcheck

2. The dependency supply chain is closed. cargo deny check licenses advisories bans sources runs as a required check. [sources] denies unknown registries and all git dependencies, allowing only crates.io. A git or private-registry dependency needs an ADR first. Dependabot watches Cargo, npm and the Actions themselves, weekly and grouped; conformance pins are deliberate and excluded, because the upstream version is the specification (ADR-0009).

3. Both untested promises are now tested. A msrv job builds the workspace on the exact toolchain named by rust-version, and fails if the two disagree. A features job runs cargo hack check --feature-powerset over rb-cli, so every combination of extract-ts, extract-dotnet and extract-python is built rather than one.

4. Spelling and prose mechanics are checked. typos runs over the repository, excluding the verbatim export in docs/artifacts/ and vendored fixtures, with project vocabulary in .typos.toml. This is deliberately narrow: it catches a misspelled identifier or heading, and it is not a prose linter (ADR-0023 explains why there is none).

5. Hooks are a convenience, never the gate. .githooks/pre-commit runs formatting and the link check; .githooks/pre-push runs cargo lint and the test suite. They are opt-in with git config core.hooksPath .githooks and skippable with --no-verify, which is exactly why every one of those checks is also required in CI.

Consequences

Alternatives considered