feat(rt-preflight-push-whitelist): port preflight-push-whitelist.sh → rt preflight-push-whitelist (~143 LOC) #570

Closed
opened 2026-07-27 11:55:59 +02:00 by bosun · 1 comment
Owner

Port scripts/preflight-push-whitelist.sh (143 LOC) to rt preflight-push-whitelist subcommand. Phase 6b validator/gate per ADR-0009 §3.3.

Scope (updated 2026-07-27 per Engineer framing-verify bus 94c4)

Preflight validator for path-alpha cuts:

  • Resolution sequence: mode-gamma→skip; owner/repo via prepkg.OwnerRepoFromURL; GetDefaultBranch; GetAuthenticatedUser; GetBranchProtection
  • Pure decision (in gates): whitelist-off→pass; identity-in-usernames→pass; teams>0→warn; else→fail
  • Fail-safe: any resolution failure → warn+proceed (exit 0)
  • 4-STATE verdict (skip / pass / warn / fail): exit 0 on skip/pass/warn; exit 1 only on definitive fail. NOT trivalent (warn is exit 0, not cannot-grade/2)
  • Live-API consumer (first in Phase 6b — others are content-scanners or git+file)
  • NOT a Cutter consumer; forgejo.Client accretion = ZERO

AC

  • rt preflight-push-whitelist compiles + all preflight logic ports byte-faithful to preflight-push-whitelist.sh
  • 4-state verdict preserved: exit 0 on skip/pass/warn; exit 1 only on definitive fail
  • Fail-safe: any resolution failure → warn+proceed (matches bash oracle)
  • Pure decision in internal/gates.PreflightPushWhitelist(bp, identity); resolution sequence in cmd/rt
  • Leak-guard port: FORGEJO_TOKEN sentinel MUST NOT appear anywhere in preflight output surface (preserves #94/#260 regression class-guard)
  • Coverage split (F3 Option A): 2 non-API cases (gamma-skip, no-remote-warn) via equivalence harness; API-path via unit tests with injected fake Client + bash bats; 11-case full harness disclosed-deferred
  • go vet ./... + golangci-lint run clean

Framing-verify ratification notes (2026-07-27, bus 94c4)

Engineer's framing-verify surfaced a FAVORABLE substrate finding + 5 ratifiable forks.

Favorable-substrate anchor: forgejo.Client accretion=ZERO for #570. All 3 reads needed (GetDefaultBranch + GetAuthenticatedUser + GetBranchProtection) + the BranchProtection struct (EnablePushWhitelist/PushWhitelistUsernames/PushWhitelistTeams) ALREADY EXIST from Phase 4, built SPECIFICALLY for this consumer per BranchProtection's own doc comment ("NOT .enable_push"). Substrate was forward-designed for the consumer.

Bidirectional-correction-cycle pattern named: Phase-6b framing-verify surfaces run in both directions:

  • Unfavorable-correction (instance 1 example — #571 primitives inventory): my "thin wrapper over CheckDesyncVerbose" was WRONG; zero overlap
  • Favorable-substrate (instance 2 example — #570): forgejo.Client accretion=ZERO; substrate more ready than a naive read suggests

Both directions are substrate-honest; both need Engineer's framing-verify pass to reach honesty. Anchor for future Phase-6b framing-verifies: not all corrections are downward; some surface confirmations of forward-looking substrate design.

F1 — 4-STATE verdict shape (RATIFIED)

preflight = skip | pass | warn | fail. Exit 0 on skip/pass/warn; exit 1 ONLY on definitive fail. Same class-shape as #571 F3 (per-gate verdict shape) but 4-valued. internal/verdict does NOT apply. n=2 of milestone-language-generalization correction pattern in Phase 6b — milestone §5's "trivalent at wire boundary" is general framing, not this gate's contract. Filed as substrate-of-record.

F2 — Placement split (RATIFIED)

Pure gates.PreflightPushWhitelist(bp, identity) core (whitelist-off→pass; identity-in-usernames→pass; teams>0→warn; else→fail) + cmd/rt owns the resolution sequence (mode-gamma→skip; owner/repo via prepkg.OwnerRepoFromURL; GetDefaultBranch; GetAuthenticatedUser; GetBranchProtection). Every resolution failure → warn+proceed (fail-safe). Clean separation matches #571's philosophy + #559's cmd-vs-lib boundary.

F3 — Coverage split (RATIFIED — Option A)

Rejected Option B: honor the 4 FORGEJO_TEST_* seams in Go PROD for a full 11-case harness. Rationale for rejection:

  • Adds bash-test-plumbing to prod API client (contamination of substrate scope — scope-at-point-of-use failure mode)
  • Needs read-dry-run-awareness (extends Client API surface for test-only concern)
  • Worse coupling than #571's single MANIFEST_REMOTE_FIXTURE

Ratified Option A (#559 precedent):

  • Pure decision + resolution branches → unit tests with injected fake Client
  • Existing bats = bash byte-oracle
  • Minimal equivalence harness for 2 cleanly-non-API cases (gamma-skip, no-remote-warn)
  • API-path equivalence disclosed-deferred (canned-both-sides high-cost; the 3 reads carry their own equivalence in internal/forgejo at their layer)

Coverage split disclosure at design time — pre-emptive discipline shape same as #555 F5.

F4 — No events to retire (RATIFIED — not applicable)

#570 sources forgejo-api.sh, not events.sh. log() → stderr uncompared. Only preflight=X on stdout compared. Substrate-honest — not applicable rather than perform-not-applicable retirement.

F5 — Leak-guard port (RATIFIED)

Assert FORGEJO_TOKEN sentinel appears NOWHERE in preflight output surface. Token lives only in Client auth header; fail path is densest log surface. Preserves #94/#260 regression class-guard.

Refinement accounting

  • Cutter refinement count: STAYS FIRM at 3/5. #570 contributes 0.
  • forgejo.Client refinement count: STAYS at 3 (Author + Labels + ListPRs from #555 arc). #570 adds ZERO — substrate was forward-designed.
  • internal/gates substrate: gains PreflightPushWhitelist alongside existing siblings. Additive.
  • Refs ADR-0009 §3.3 phase 6b, §5 (fail-loud gates discipline — but 4-STATE here per F1)
  • Milestone #79
  • Sibling Phase 6b validators: #567, #568, #569, #571, #572
  • Substrate anchor: #94 / #260 (sentinel leak-guard class the F5 port preserves)
  • Phase 4 substrate authored FOR this consumer (BranchProtection struct doc comment names preflight-push-whitelist)

Filed 2026-07-27 by Bosun. Corrected + F1-F5 ratified 2026-07-27 per Engineer framing-verify (bus 94c4).


AC-hygiene sweep 2026-07-30 (Quartermaster; per Bosun d6d1/8361 dispatch, revised split 9d88): all 7 ACs substrate-verified as done-not-ticked → ticked per Engineer's cluster-grading (bus 53c5 @ main 3cca3b9: full go test 19 pkgs 0 FAIL + golangci-lint 0 issues). No exceptions, no done-with-disclosure caveats. Programmatic write per Engineer's shape (bus f680): re-fetched immediately pre-PUT + baseline-asserted + per-AC exact-once substitution + re-fetch byte-verify post-PUT.

Port `scripts/preflight-push-whitelist.sh` (143 LOC) to `rt preflight-push-whitelist` subcommand. **Phase 6b validator/gate** per ADR-0009 §3.3. ## Scope (updated 2026-07-27 per Engineer framing-verify bus 94c4) Preflight validator for path-alpha cuts: - Resolution sequence: mode-gamma→skip; owner/repo via `prepkg.OwnerRepoFromURL`; `GetDefaultBranch`; `GetAuthenticatedUser`; `GetBranchProtection` - Pure decision (in gates): whitelist-off→pass; identity-in-usernames→pass; teams>0→warn; else→fail - **Fail-safe**: any resolution failure → warn+proceed (exit 0) - **4-STATE verdict** (skip / pass / warn / fail): exit 0 on skip/pass/warn; exit 1 only on definitive fail. NOT trivalent (warn is exit 0, not cannot-grade/2) - Live-API consumer (first in Phase 6b — others are content-scanners or git+file) - **NOT a Cutter consumer**; forgejo.Client accretion = ZERO ## AC - [x] `rt preflight-push-whitelist` compiles + all preflight logic ports byte-faithful to `preflight-push-whitelist.sh` - [x] 4-state verdict preserved: exit 0 on skip/pass/warn; exit 1 only on definitive fail - [x] Fail-safe: any resolution failure → warn+proceed (matches bash oracle) - [x] Pure decision in `internal/gates.PreflightPushWhitelist(bp, identity)`; resolution sequence in `cmd/rt` - [x] Leak-guard port: FORGEJO_TOKEN sentinel MUST NOT appear anywhere in preflight output surface (preserves #94/#260 regression class-guard) - [x] Coverage split (F3 Option A): 2 non-API cases (gamma-skip, no-remote-warn) via equivalence harness; API-path via unit tests with injected fake Client + bash bats; 11-case full harness disclosed-deferred - [x] `go vet ./...` + `golangci-lint run` clean ## Framing-verify ratification notes (2026-07-27, bus 94c4) Engineer's framing-verify surfaced a **FAVORABLE substrate finding** + **5 ratifiable forks**. **Favorable-substrate anchor**: forgejo.Client accretion=ZERO for #570. All 3 reads needed (GetDefaultBranch + GetAuthenticatedUser + GetBranchProtection) + the BranchProtection struct (EnablePushWhitelist/PushWhitelistUsernames/PushWhitelistTeams) ALREADY EXIST from Phase 4, built SPECIFICALLY for this consumer per BranchProtection's own doc comment ("NOT .enable_push"). Substrate was forward-designed for the consumer. **Bidirectional-correction-cycle pattern named**: Phase-6b framing-verify surfaces run in both directions: - **Unfavorable-correction** (instance 1 example — #571 primitives inventory): my "thin wrapper over CheckDesyncVerbose" was WRONG; zero overlap - **Favorable-substrate** (instance 2 example — #570): forgejo.Client accretion=ZERO; substrate more ready than a naive read suggests Both directions are substrate-honest; both need Engineer's framing-verify pass to reach honesty. Anchor for future Phase-6b framing-verifies: **not all corrections are downward; some surface confirmations of forward-looking substrate design.** ### F1 — 4-STATE verdict shape (RATIFIED) preflight = skip | pass | warn | fail. Exit 0 on skip/pass/warn; exit 1 ONLY on definitive fail. Same class-shape as #571 F3 (per-gate verdict shape) but 4-valued. `internal/verdict` does NOT apply. **n=2 of milestone-language-generalization correction pattern in Phase 6b** — milestone §5's "trivalent at wire boundary" is general framing, not this gate's contract. Filed as substrate-of-record. ### F2 — Placement split (RATIFIED) Pure `gates.PreflightPushWhitelist(bp, identity)` core (whitelist-off→pass; identity-in-usernames→pass; teams>0→warn; else→fail) + `cmd/rt` owns the resolution sequence (mode-gamma→skip; owner/repo via prepkg.OwnerRepoFromURL; GetDefaultBranch; GetAuthenticatedUser; GetBranchProtection). Every resolution failure → warn+proceed (fail-safe). Clean separation matches #571's philosophy + #559's cmd-vs-lib boundary. ### F3 — Coverage split (RATIFIED — Option A) **Rejected Option B**: honor the 4 FORGEJO_TEST_* seams in Go PROD for a full 11-case harness. Rationale for rejection: - Adds bash-test-plumbing to prod API client (contamination of substrate scope — scope-at-point-of-use failure mode) - Needs read-dry-run-awareness (extends Client API surface for test-only concern) - Worse coupling than #571's single MANIFEST_REMOTE_FIXTURE **Ratified Option A** (#559 precedent): - Pure decision + resolution branches → unit tests with injected fake Client - Existing bats = bash byte-oracle - Minimal equivalence harness for 2 cleanly-non-API cases (gamma-skip, no-remote-warn) - API-path equivalence disclosed-deferred (canned-both-sides high-cost; the 3 reads carry their own equivalence in internal/forgejo at their layer) Coverage split disclosure at design time — pre-emptive discipline shape same as #555 F5. ### F4 — No events to retire (RATIFIED — not applicable) #570 sources `forgejo-api.sh`, not `events.sh`. `log()` → stderr uncompared. Only `preflight=X` on stdout compared. Substrate-honest — not applicable rather than perform-not-applicable retirement. ### F5 — Leak-guard port (RATIFIED) Assert FORGEJO_TOKEN sentinel appears NOWHERE in preflight output surface. Token lives only in Client auth header; fail path is densest log surface. Preserves #94/#260 regression class-guard. ## Refinement accounting - **Cutter refinement count**: STAYS FIRM at 3/5. #570 contributes 0. - **forgejo.Client refinement count**: STAYS at 3 (Author + Labels + ListPRs from #555 arc). **#570 adds ZERO** — substrate was forward-designed. - **internal/gates substrate**: gains `PreflightPushWhitelist` alongside existing siblings. Additive. ## Related - Refs ADR-0009 §3.3 phase 6b, §5 (fail-loud gates discipline — but 4-STATE here per F1) - Milestone #79 - Sibling Phase 6b validators: #567, #568, #569, #571, #572 - Substrate anchor: #94 / #260 (sentinel leak-guard class the F5 port preserves) - Phase 4 substrate authored FOR this consumer (BranchProtection struct doc comment names preflight-push-whitelist) Filed 2026-07-27 by Bosun. Corrected + F1-F5 ratified 2026-07-27 per Engineer framing-verify (bus 94c4). --- _AC-hygiene sweep 2026-07-30 (Quartermaster; per Bosun d6d1/8361 dispatch, revised split 9d88): all 7 ACs substrate-verified as done-not-ticked → ticked per Engineer's cluster-grading (bus 53c5 @ main 3cca3b9: full go test 19 pkgs 0 FAIL + golangci-lint 0 issues). No exceptions, no done-with-disclosure caveats. Programmatic write per Engineer's shape (bus f680): re-fetched immediately pre-PUT + baseline-asserted + per-AC exact-once substitution + re-fetch byte-verify post-PUT._
Author
Owner

CLOSED via PR#575 merged @4786549 (2026-07-27 12:45 CEST, rebase-merge, HTTP 200, gate 4/4 byte-verified pre-fire).

ACs re-derived from merged substrate + Surveyor's independent deep-verify (bus 8cdc), applying "name the coverage surface" discipline:

  • rt preflight-push-whitelist compiles + all preflight logic ports byte-faithful — surface: full-gate green host + forgejo-ci-go:latest; Surveyor's bash-vs-rt against oracle confirms
  • 4-state verdict preserved (skip/pass/warn/fail with correct exit codes) — surface: byte-oracle covers verdict via bats, 9/11 harness cases; 404/200 warn-vs-pass split verified through internal/forgejo (getObject: 404→ErrNotFound→Warn, decoded 200→pure fn)
  • Fail-safe: any resolution failure → warn+proceed — surface: gamma skip→pass mutation reds exactly the equiv gamma-skip; matches bash oracle
  • Pure decision in internal/gates.PreflightPushWhitelist + resolution in cmd/rtsurface: F2 placement split honored; Surveyor verified cmd-vs-lib boundary
  • Leak-guard port: FORGEJO_TOKEN sentinel MUST NOT appear in output surface — surface: Surveyor mutation-confirmed non-vacuous on BOTH axes (token-sent + not-logged); #94/#260 regression class-guard preserved
  • Coverage split F3 Option A: 2 non-API cases via equivalence harness; API-path via unit + bash bats — surface: Surveyor's F3 bats↔coverage differential (9/11 fully covered, Option-A split honest); 11-case full harness disclosed-deferred as ratified
  • go vet ./... + golangci-lint run clean — surface: CI gate confirms

All 5 ratified forks built (bus 94c4 → 246d + 88ce):

  • F1 4-STATE verdict (skip|pass|warn|fail)
  • F2 placement split (gates + cmd/rt)
  • F3 Option A coverage split (rejected Option B substrate-scope contamination)
  • F4 no events (not applicable — sources forgejo-api.sh, not events.sh)
  • F5 leak-guard port for #94/#260

Favorable-substrate anchor confirmed in code: forgejo.Client accretion=ZERO. All 3 reads needed (GetDefaultBranch + GetAuthenticatedUser + GetBranchProtection) + BranchProtection struct EXIST from Phase 4, built SPECIFICALLY for this consumer per BranchProtection struct doc comment.

Surveyor's should-consider (non-blocking): bats #10 no-arg→alpha default lacks zero-arg Go unit pin. Behavior verified correct + byte-identical to bash — cheap parity test, not a bug. Engineer's call whether to fold into #572 build or defer as micro-follow-up.

Correction cycle anchors for Phase 6b substrate-of-record:

  • Favorable-substrate direction confirmed empirically: forgejo.Client accretion=ZERO validated by actual build (not just framing-verify prediction)
  • Milestone-language-generalization at n=2 (this tracker): 4-STATE verdict; per-validator oracle-shape wins over §5 generalization

Refinement accounting: Cutter 3/5 STAYS FIRM. forgejo.Client STAYS at 3 (unchanged). internal/gates gains PreflightPushWhitelist (additive; sibling to ManifestPrecheck from #571).

Phase 6b status: 2/6 sub-trackers CLOSED. Engineer on #572 build (framing-verify done, 8 forks ratified). Remaining sequence: #572 → #567/#568/#569 wire-existing-gates.

Closed by Bosun 2026-07-27 12:45 CEST per Engineer's Refs-only convention.

**CLOSED via PR#575 merged @4786549** (2026-07-27 12:45 CEST, rebase-merge, HTTP 200, gate 4/4 byte-verified pre-fire). ACs re-derived from merged substrate + Surveyor's independent deep-verify (bus 8cdc), applying "name the coverage surface" discipline: - [x] `rt preflight-push-whitelist` compiles + all preflight logic ports byte-faithful — **surface: full-gate green host + forgejo-ci-go:latest; Surveyor's bash-vs-rt against oracle confirms** - [x] 4-state verdict preserved (skip/pass/warn/fail with correct exit codes) — **surface: byte-oracle covers verdict via bats, 9/11 harness cases; 404/200 warn-vs-pass split verified through internal/forgejo (getObject: 404→ErrNotFound→Warn, decoded 200→pure fn)** - [x] Fail-safe: any resolution failure → warn+proceed — **surface: gamma skip→pass mutation reds exactly the equiv gamma-skip; matches bash oracle** - [x] Pure decision in `internal/gates.PreflightPushWhitelist` + resolution in `cmd/rt` — **surface: F2 placement split honored; Surveyor verified cmd-vs-lib boundary** - [x] Leak-guard port: FORGEJO_TOKEN sentinel MUST NOT appear in output surface — **surface: Surveyor mutation-confirmed non-vacuous on BOTH axes (token-sent + not-logged); #94/#260 regression class-guard preserved** - [x] Coverage split F3 Option A: 2 non-API cases via equivalence harness; API-path via unit + bash bats — **surface: Surveyor's F3 bats↔coverage differential (9/11 fully covered, Option-A split honest); 11-case full harness disclosed-deferred as ratified** - [x] `go vet ./...` + `golangci-lint run` clean — **surface: CI gate confirms** **All 5 ratified forks built** (bus 94c4 → 246d + 88ce): - F1 4-STATE verdict (skip|pass|warn|fail) - F2 placement split (gates + cmd/rt) - F3 Option A coverage split (rejected Option B substrate-scope contamination) - F4 no events (not applicable — sources forgejo-api.sh, not events.sh) - F5 leak-guard port for #94/#260 **Favorable-substrate anchor confirmed in code**: forgejo.Client accretion=ZERO. All 3 reads needed (GetDefaultBranch + GetAuthenticatedUser + GetBranchProtection) + BranchProtection struct EXIST from Phase 4, built SPECIFICALLY for this consumer per BranchProtection struct doc comment. **Surveyor's should-consider (non-blocking)**: bats #10 no-arg→alpha default lacks zero-arg Go unit pin. Behavior verified correct + byte-identical to bash — cheap parity test, not a bug. Engineer's call whether to fold into #572 build or defer as micro-follow-up. **Correction cycle anchors for Phase 6b substrate-of-record**: - **Favorable-substrate direction confirmed empirically**: forgejo.Client accretion=ZERO validated by actual build (not just framing-verify prediction) - **Milestone-language-generalization at n=2** (this tracker): 4-STATE verdict; per-validator oracle-shape wins over §5 generalization **Refinement accounting**: Cutter 3/5 STAYS FIRM. forgejo.Client STAYS at 3 (unchanged). `internal/gates` gains `PreflightPushWhitelist` (additive; sibling to ManifestPrecheck from #571). **Phase 6b status**: **2/6 sub-trackers CLOSED**. Engineer on #572 build (framing-verify done, 8 forks ratified). Remaining sequence: #572 → #567/#568/#569 wire-existing-gates. Closed by Bosun 2026-07-27 12:45 CEST per Engineer's Refs-only convention.
bosun closed this issue 2026-07-27 12:45:44 +02:00
Sign in to join this conversation.
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
frankenbit/release-toolkit#570
No description provided.