Description
The pre-commit hook that #733 ships (ts dev install-hooks → ts dev lint domains --staged) is the only enforcement mechanism today. The spec says so outright: "No CI gate in v1. The pre-commit hook is the only enforcement mechanism."
That leaves two holes:
- The hook is bypassable with
git commit --no-verify.
- The hook only runs for developers who have actually run
ts dev install-hooks. A fresh clone, a new contributor, or a commit made through the GitHub web UI has no protection at all.
So nothing prevents a disallowed host from reaching main. Trusted Server runs at the edge on behalf of publishers, which makes an unreviewed outbound host a supply-chain concern rather than a style issue — the same framing as #1160.
No CI job checks domains today: no workflow file references the linter, and #733 touches no files under .github/.
Proposed solution
Stage 2 of the design spec already pins the shape: a GitHub Actions job that runs
ts dev lint domains --changed-vs $GITHUB_BASE_REF
on every pull request. Same delta-only enforcement as the hook, but unbypassable.
Requirements the spec calls out:
actions/checkout@v4 with fetch-depth: 0, or an explicit fetch of $GITHUB_BASE_REF.
- Reuse the host-target CI lane, since the
ts binary is host-target only (the workspace default target is wasm32-wasip1, where the CLI crate is an empty shell).
Implementation note: the lane to reuse is the existing test-cli job in .github/workflows/test.yml (cargo test (ts CLI, native)), which already builds the CLI for the host triple via ./scripts/test-cli.sh. Its actions/checkout@v4 step does not set fetch-depth: 0 today, so that has to be added or the base ref fetched explicitly — otherwise --changed-vs has no base commit to resolve and the job cannot compute a delta.
Why a gate and not just the hook: during review of #733, reviewers found four separate cases where the linter silently exited 0 on a disallowed host — userinfo spans crossing string boundaries, IPv4-mapped IPv6 literals, URL-valid punctuation such as ! and ; truncating the host to an allowlisted prefix, and consecutive single-quoted URLs causing a skipped host. Those are exactly the class of bug a gate running against real PR diffs surfaces, instead of depending on a reviewer hand-crafting probes.
Follow-on: Stage 3
Stage 3 (the full-repo audit as a gate, rather than delta-only) stays deferred and is blocked on the pre-existing-violation cleanup in #1216. Per the spec, the choice between (a) cleaning every violation and gating the full audit and (b) snapshotting a baseline file and subtracting it is deferred until Stages 1 and 2 are stable. Tracking it here as a follow-on rather than as its own ticket.
Done when
Affected area
.github/workflows, crates/trusted-server-cli, CI / Tooling.
Design
Description
The pre-commit hook that #733 ships (
ts dev install-hooks→ts dev lint domains --staged) is the only enforcement mechanism today. The spec says so outright: "No CI gate in v1. The pre-commit hook is the only enforcement mechanism."That leaves two holes:
git commit --no-verify.ts dev install-hooks. A fresh clone, a new contributor, or a commit made through the GitHub web UI has no protection at all.So nothing prevents a disallowed host from reaching
main. Trusted Server runs at the edge on behalf of publishers, which makes an unreviewed outbound host a supply-chain concern rather than a style issue — the same framing as #1160.No CI job checks domains today: no workflow file references the linter, and #733 touches no files under
.github/.Proposed solution
Stage 2 of the design spec already pins the shape: a GitHub Actions job that runs
on every pull request. Same delta-only enforcement as the hook, but unbypassable.
Requirements the spec calls out:
actions/checkout@v4withfetch-depth: 0, or an explicit fetch of$GITHUB_BASE_REF.tsbinary is host-target only (the workspace default target iswasm32-wasip1, where the CLI crate is an empty shell).Implementation note: the lane to reuse is the existing
test-clijob in.github/workflows/test.yml(cargo test (ts CLI, native)), which already builds the CLI for the host triple via./scripts/test-cli.sh. Itsactions/checkout@v4step does not setfetch-depth: 0today, so that has to be added or the base ref fetched explicitly — otherwise--changed-vshas no base commit to resolve and the job cannot compute a delta.Why a gate and not just the hook: during review of #733, reviewers found four separate cases where the linter silently exited 0 on a disallowed host — userinfo spans crossing string boundaries, IPv4-mapped IPv6 literals, URL-valid punctuation such as
!and;truncating the host to an allowlisted prefix, and consecutive single-quoted URLs causing a skipped host. Those are exactly the class of bug a gate running against real PR diffs surfaces, instead of depending on a reviewer hand-crafting probes.Follow-on: Stage 3
Stage 3 (the full-repo audit as a gate, rather than delta-only) stays deferred and is blocked on the pre-existing-violation cleanup in #1216. Per the spec, the choice between (a) cleaning every violation and gating the full audit and (b) snapshotting a baseline file and subtracting it is deferred until Stages 1 and 2 are stable. Tracking it here as a follow-on rather than as its own ticket.
Done when
ts dev lint domains --changed-vs $GITHUB_BASE_REFagainst the PR base ref on every pull request.fetch-depth: 0or an explicit fetch) so--changed-vsresolves.Affected area
.github/workflows,crates/trusted-server-cli, CI / Tooling.Design
docs/superpowers/specs/2026-05-18-check-domains-design.md, section Migration to CI (Stage 2 / Stage 3).