Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -459,27 +459,34 @@ eliminated by the constraints listed under the decision.
## Action items

1. [x] **Ratify or reject.** Ratified by `@mbeacom` on 2026-08-26.
2. [ ] **Add the trusted contexts to the `main` ruleset — after merge.** This
cannot be done before merge and must not be faked: `pull_request_target`
executes the workflow from the default branch, so `trusted-dco` and
`gate-integrity` do not exist until this lands, and adding a required
context that never reports would block every pull request including this
one. The exact operation, and the verification that it took, are in
2. [x] **Add the trusted contexts to the `main` ruleset — after merge.** Done
2026-08-27, after the workflow landed in
[PR #179](https://github.com/mbeacom/adrkit/pull/179). The live ruleset
now carries 10 required contexts, including `trusted-dco` and
`gate-integrity`; the old pull-request-controlled `dco` context was
retired only after `trusted-dco` reported green on real pull requests.
The read-back and exact evidence are in
[`docs/repository-trust-operations.md`](../repository-trust-operations.md).
3. [ ] **Observe both trusted jobs on a real pull request after merge**, per
ADR-0016. The kernel of `gate-integrity` has been observed blocking on this
change's own real changed-path list and passing once the label is applied;
its three fail-quiet guards — empty list, truncated list, unreadable
payload — have each been observed firing; and a rename that carried a gate
path out of the protected prefix has been observed blocking after that
bypass was found and closed. The *deployed workflow* has not run, and
cannot until it is on the default branch. All of it is recorded in
`docs/repository-trust-operations.md` rather than asserted here.
3. [x] **Observe both trusted jobs on a real pull request after merge**, per
ADR-0016. `gate-integrity` failed without acknowledgment and passed after
labeling on PRs
[#175](https://github.com/mbeacom/adrkit/pull/175),
[#177](https://github.com/mbeacom/adrkit/pull/177), and
[#178](https://github.com/mbeacom/adrkit/pull/178). `trusted-dco` was
then deliberately observed rejecting an unsigned commit and accepting
its signed-off amendment on
[PR #180](https://github.com/mbeacom/adrkit/pull/180). This is real
deployed-workflow evidence on the repository's own pull requests and
remains **rung 1** under ADR-0014; no reference-repository or
external/community validation is claimed. Exact run and job URLs are
recorded in `docs/repository-trust-operations.md`.
4. [ ] **Decide on the fork-PR approval policy.** Currently
`first_time_contributors`. Tightening to `all_external_contributors` means
no fork's workflows run without a maintainer's explicit action, at the cost
of friction for repeat contributors. Left as a maintainer judgment rather
than changed silently; the command is in the operations document.
`first_time_contributors`, re-read unchanged on 2026-08-27. Tightening to
`all_external_contributors` means no fork's workflows run without a
maintainer's explicit action, at the cost of friction for repeat
contributors. It remains a separate open maintainer decision rather than
being changed as part of this evidence exercise; the command is in the
operations document.
5. [x] **Enable required SHA pinning for actions.** Done 2026-08-26 —
`sha_pinning_required` moved `false` → `true`, verified by re-reading
`/repos/mbeacom/adrkit/actions/permissions`.
Expand Down
213 changes: 110 additions & 103 deletions docs/repository-trust-operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ subject is checks that report success without having looked; a settings change
that is described but never applied has the same shape, and reads identically to
one that was.

Everything below was read from the live repository on **2026-08-26** with `gh`.
Re-read rather than trusted: each claim carries the command that produced it.
The initial configuration was read from the live repository on **2026-08-26**
with `gh`. The deployed state and evidence were re-read on **2026-08-27**.
Re-read rather than trusted: each claim carries either the command that produced
it or a link to the exact run.

---

Expand Down Expand Up @@ -76,87 +78,63 @@ file from becoming an unowned gate surface.

---

## 2. Must wait until merge
## 2. Deployed state and remaining decisions

### 2.1 Add `trusted-dco` and `gate-integrity` as required status checks
### 2.1 `trusted-dco` and `gate-integrity` are required status checks

**This cannot be done before merge, and doing it early would be actively
harmful.** `pull_request_target` executes the workflow from the repository's
default branch, so neither job exists until this change lands on `main`. A
required context that never reports leaves every pull request — including the one
introducing it — permanently "Expected — waiting for status".
The trusted workflow landed on `main` in
[PR #179](https://github.com/mbeacom/adrkit/pull/179), merge commit
[`4d70b8add63070f4ca1722e76634aabdb473555c`](https://github.com/mbeacom/adrkit/commit/4d70b8add63070f4ca1722e76634aabdb473555c).
Only after that merge were `trusted-dco` and `gate-integrity` added to the
required contexts. This ordering matters: `pull_request_target` executes the
workflow from the repository's default branch, so adding either context before
the workflow reached `main` would have left every pull request waiting for a
status that could not report.

The payload below was constructed and validated against the live ruleset on
2026-08-26 and deliberately **not** sent. Re-run the first command after merge and
confirm the two new contexts appear before sending anything.
After `trusted-dco` reported green on real pull requests (§3.2), the old
pull-request-controlled `dco` context was removed from the required set. Its job
remains in `ci.yml` as a faster advisory report; it is not an authority for
merge. The
[live ruleset API response](https://api.github.com/repos/mbeacom/adrkit/rulesets/19149458)
was re-read after that change:

```bash
# 1. Build the payload from the ruleset as it stands, appending the two contexts.
gh api repos/mbeacom/adrkit/rulesets/19149458 --jq '
{rules: (.rules | map(
if .type == "required_status_checks"
then .parameters.required_status_checks += [
{context: "trusted-dco"},
{context: "gate-integrity"}
]
else . end))}' > /tmp/ruleset-payload.json

# 2. Read it before sending it. The existing nine contexts must still be present.
python3 -m json.tool < /tmp/ruleset-payload.json

# 3. Apply.
gh api -X PUT repos/mbeacom/adrkit/rulesets/19149458 --input /tmp/ruleset-payload.json

# 4. Verify it took, by reading back rather than by trusting the response.
gh api repos/mbeacom/adrkit/rulesets/19149458 \
--jq '.rules[] | select(.type=="required_status_checks")
| .parameters.required_status_checks[].context'
```console
$ gh api repos/mbeacom/adrkit/rulesets/19149458 \
--jq '.rules[] | select(.type=="required_status_checks")
| .parameters.required_status_checks[].context'
clean-clone-builds
node-smoke-built-artifacts (22.x)
node-smoke-built-artifacts (24.x)
audit
self-dogfood
Analyze (actions)
Analyze (javascript-typescript)
action-dogfood
trusted-dco
gate-integrity
```

Step 4 must list eleven contexts, ending with `trusted-dco` and `gate-integrity`.
Note that step 1 appends rather than replaces: a payload that omits the existing
nine would silently drop every current gate, and the response to a successful
`PUT` looks the same either way.

Do not add `integration_id` to the two new entries. The existing `dco` and
`action-dogfood` contexts carry none, and pinning the integration is a separate
decision from adding the check.
That is **10** contexts. The response reports
`updated_at: 2026-08-26T21:07:04.618-04:00`; it contains both trusted contexts
and no `dco` entry. The two trusted entries intentionally carry no
`integration_id`, matching `action-dogfood`; pinning an integration is a
separate decision from requiring the check.

**Sequencing.** Add the contexts *before* removing anything. `dco` in `ci.yml` is
advisory under ADR-0035 but is still a required context; leave it required until
`trusted-dco` has been observed green on a real pull request (§3.2).

**Pull requests open at the moment you do this will be stuck, and it is not
obvious why.** A required context is satisfied by a check run against the head
SHA, and `pull_request_target` only produces one when an event fires. Every pull
request already open when the contexts are added has a head that no
`trusted-gates.yml` run has ever seen, so both new contexts sit at "Expected —
waiting for status" indefinitely. Nothing retroactively creates them, and
re-running an old workflow run does not either, because the workflow did not
exist for that run.

Each open pull request needs a **new event** — push a commit, or close and
reopen it, or edit its base. Note that all three of those now *dismiss* the
`gate-change-acknowledged` label, which is intended: each one moves the head or
the base, so an acknowledgment given before it no longer describes what would
merge. Re-apply the label afterwards if the pull request needs one.

Check what is open before you start, and expect to touch each one:
Read the contexts back rather than trusting a successful settings mutation:

```bash
gh api "repos/mbeacom/adrkit/pulls?state=open" --jq '.[] | "#\(.number) \(.head.ref)"'

# For each, confirm the two contexts actually reported against its current head:
gh api "repos/mbeacom/adrkit/commits/<head-sha>/check-runs" \
--jq '[.check_runs[].name] | map(select(. == "trusted-dco" or . == "gate-integrity"))'
gh api repos/mbeacom/adrkit/rulesets/19149458 \
--jq '.rules[] | select(.type=="required_status_checks")
| .parameters.required_status_checks[].context'
```

That listing must show both names. An empty result is the stuck state, not a
pass.
**Rollback:** add `dco` back before removing `trusted-dco`, then re-read the
complete list. A payload that names only the context being changed silently
drops every omitted gate.

### 2.2 Fork pull request approval policy — a maintainer decision, not a default

Currently:
Re-read on 2026-08-27, the policy remains:

```console
$ gh api repos/mbeacom/adrkit/actions/permissions/fork-pr-contributor-approval
Expand Down Expand Up @@ -376,40 +354,69 @@ between the event's changed-file count and the live file listing blocks. An olde
run can delete a newer acknowledgment and cause a conservative re-acknowledgment,
but it cannot turn an unseen current head green.

### 3.2 Not yet observed — say so plainly

**The deployed workflow has never run.** It cannot, before merge: GitHub takes
`pull_request_target` workflows from the default branch, so `trusted-gates.yml`
is inert until it is on `main`. Nothing in this repository should be read as
claiming otherwise.

After merge, the first pull request that touches a gate path exercises both
halves. To observe it deliberately rather than waiting:

```bash
# On a scratch branch, touch a gate path and open a pull request.
printf '\n' >> scripts/check-gate-integrity.ts
git commit -sam 'chore: observe gate-integrity blocking' && git push -u origin HEAD
gh pr create --fill

# Expect gate-integrity RED. Then acknowledge, and expect it to turn GREEN.
gh pr edit <number> --add-label gate-change-acknowledged

# Read the conclusions back rather than reading the checks tab.
gh api "repos/mbeacom/adrkit/commits/$(git rev-parse HEAD)/check-runs" \
--jq '.check_runs[] | select(.name|test("^(trusted-dco|gate-integrity)$"))
| {name, status, conclusion}'
```

`trusted-dco` should be green throughout — the commit above is signed off. To
observe *it* failing, add a commit with `--no-signoff` on the same branch and
confirm `trusted-dco` goes red while the advisory `dco` job's verdict is
irrelevant to the merge.

Until both have been seen red and then green on a real pull request, ADR-0035
action item 3 stays open and the workflow counts as implemented, not as verified.

### 3.3 An instance, recorded rather than tidied away
### 3.2 Deployed `gate-integrity` evidence on real pull requests

The deployed `pull_request_target` workflow ran from `main` on three ordinary
pull requests that changed gate-defining paths. In each case `gate-integrity`
failed before the acknowledgment existed, `@mbeacom` applied
`gate-change-acknowledged`, and a new run for the same head passed. `trusted-dco`
reported green on the pre-label run in every case:

| Pull request | Red before acknowledgment | Label applied | Green after acknowledgment | `trusted-dco` |
|---|---|---|---|---|
| [#175](https://github.com/mbeacom/adrkit/pull/175) | [run `33028271780`](https://github.com/mbeacom/adrkit/actions/runs/33028271780), [`gate-integrity` job](https://github.com/mbeacom/adrkit/actions/runs/33028271780/job/98374610838) | 2026-08-27 00:52:57Z | [run `33028295112`](https://github.com/mbeacom/adrkit/actions/runs/33028295112), [`gate-integrity` job](https://github.com/mbeacom/adrkit/actions/runs/33028295112/job/98374685670) | [green job](https://github.com/mbeacom/adrkit/actions/runs/33028271780/job/98374611131) |
| [#177](https://github.com/mbeacom/adrkit/pull/177) | [run `33028638073`](https://github.com/mbeacom/adrkit/actions/runs/33028638073), [`gate-integrity` job](https://github.com/mbeacom/adrkit/actions/runs/33028638073/job/98375753726) | 2026-08-27 00:59:54Z | [run `33028662626`](https://github.com/mbeacom/adrkit/actions/runs/33028662626), [`gate-integrity` job](https://github.com/mbeacom/adrkit/actions/runs/33028662626/job/98375832157) | [green job](https://github.com/mbeacom/adrkit/actions/runs/33028638073/job/98375753950) |
| [#178](https://github.com/mbeacom/adrkit/pull/178) | [run `33028809634`](https://github.com/mbeacom/adrkit/actions/runs/33028809634), [`gate-integrity` job](https://github.com/mbeacom/adrkit/actions/runs/33028809634/job/98376291916) | 2026-08-27 01:02:51Z | [run `33028831801`](https://github.com/mbeacom/adrkit/actions/runs/33028831801), [`gate-integrity` job](https://github.com/mbeacom/adrkit/actions/runs/33028831801/job/98376362040) | [green job](https://github.com/mbeacom/adrkit/actions/runs/33028809634/job/98376291846) |

The run creation times bracket each label event: the red runs began at
00:52:32Z, 00:59:26Z, and 01:02:29Z; the green runs began at 00:52:59Z,
00:59:56Z, and 01:02:53Z. This is deployed evidence of both directions, not a
fixture or a local invocation.

`trusted-dco` was green throughout these gate-integrity observations. Its
separate deliberate red-to-green exercise is recorded in §3.3.

### 3.3 Deployed `trusted-dco` observed failing

The negative half was exercised deliberately on
[PR #180](https://github.com/mbeacom/adrkit/pull/180). Its initial sole
documentation commit,
[`91a1184376b00bf394712377933e1c07a0558f00`](https://github.com/mbeacom/adrkit/commit/91a1184376b00bf394712377933e1c07a0558f00),
retained the required `Co-authored-by` trailer but intentionally omitted
`Signed-off-by`.

The deployed workflow's
[run `33030349682`](https://github.com/mbeacom/adrkit/actions/runs/33030349682)
failed in the
[`trusted-dco` job](https://github.com/mbeacom/adrkit/actions/runs/33030349682/job/98381187821).
The job reported that it examined exactly one commit in
`e9169e7e6d6a8519ebafff06f5217a98a632c21f..91a1184376b00bf394712377933e1c07a0558f00`
and rejected that one commit because `the sign-off is missing`. This is the
deployed negative observation required by ADR-0016, not a local simulation.

The sole commit was then amended to add `Signed-off-by` and this observation,
and force-pushed only with an explicit lease against the recorded remote tip
`91a1184376b00bf394712377933e1c07a0558f00`.

The amended head,
[`4cda89cf299799ba1758cf2475ca6f384ecc7667`](https://github.com/mbeacom/adrkit/commit/4cda89cf299799ba1758cf2475ca6f384ecc7667),
then passed the deployed workflow's
[run `33030491642`](https://github.com/mbeacom/adrkit/actions/runs/33030491642)
and
[`trusted-dco` job](https://github.com/mbeacom/adrkit/actions/runs/33030491642/job/98381634309).
The job examined exactly one commit in
`e9169e7e6d6a8519ebafff06f5217a98a632c21f..4cda89cf299799ba1758cf2475ca6f384ecc7667`
and reported `1 signed, 0 exempt, 0 unsigned`. `gate-integrity` also
[passed](https://github.com/mbeacom/adrkit/actions/runs/33030491642/job/98381634493)
without an acknowledgment label because the pull request changes only
governance documentation. All 10 required contexts were green on that head.

Together, the two runs observe the deployed `trusted-dco` gate rejecting the
missing sign-off and accepting the corrected commit. This evidence is local to
the repository's own real pull request: it satisfies ADR-0016 and remains rung 1
under ADR-0014, not reference-repository or external/community validation.

### 3.4 An instance, recorded rather than tidied away

While building this, its author read an absence as a fact — the exact failure
ADR-0016 exists to name — and committed the wrong conclusion before catching it.
Expand Down
Loading