Commit cd76842
v1.100 PR-26-doc: restore verification / evidence hardening contract seed (#512)
* docs(v1.100 PR-26): contract seed — Part IV §§37-50 (restore verification / evidence hardening)
PR-26 contract seed. Doc-only commit. No production code, no CI changes.
Appends Part IV (§§37-50) to internal/installer/restore/contract.md
with Q1-Q5 proposed locks for the restore verification / evidence
hardening lane. Mirrors PR-24 / PR-25 / Amendment-1 contract-first
discipline: this seed must be reviewed and locked before any code
phase opens.
Pinned sentence (§37):
PR-25 answered: "can restore execute safely?"
PR-26 answers: "can we prove the restore outcome is correct
after execution?"
Sections added:
§37 Pinned sentence
§38 Scope (permitted / forbidden / scope-bounding invariants)
§39 Q1 — Verification authority (proposed lock):
- kernel evidence (NftTableExists, ServiceActive) BLOCKING
- target-specific safety predicate BLOCKING
- authority class via uninstall.Classify BLOCKING
- update-history.json unchanged (sha256 pre/post) BLOCKING
- terminal == StateRestoreExecuted BLOCKING
- external SSH continuity (out-of-band session) ADVISORY
- validator full sweep NOT REQUIRED
- CLI ruleset parsing NOT REQUIRED
§40 Q2 — Real-host destructive soak scope:
- staged DirectAdmin VM merge-blocker
- lab2/lab4 fixture coverage acceptable for code-A/B/C
- srv3 supplemental, operator-approved per run only
- evidence private by default; redaction rules locked
§41 Q3 — Safety-net-safe predicate tightening:
- resolved target's specific unit (csf.service for csf restore)
- sshd via running listener only (Source 1)
- target firewall has loaded SSH-allow rule (kernel evidence)
- non-csf still typed-unsupported (Amendment 1 §30.2 unchanged)
§42 Q4 — Cron backup / A.4 restore:
- install-time: switchop.disarmCSFArtifacts writes manifest
- manifest schema_version + sha256 per file
- A.4 preconditions: manifest present + valid + integrity ok +
target paths absent + E.1/E.7
- corrupt-manifest → typed sentinel ErrCSFRestoreCronManifestCorrupt
- existing installs without manifest → soft-skip (graceful migration)
§43 Q5 — Executor hardening:
- add typed ServiceUnmask(unit) + Rename(old, new)
- migrate restore_deps_csf.go off raw Run("systemctl",unmask,…) +
Run("mv",…)
- tighten G4-RESTORE-EXEC-NO-OUT-OF-TARGET to forbid mutating
Run("systemctl",…) verbs + Run("mv",…)
- per-call unit allow-list pinned to {csf.service, nftband.service}
§44 Proposed invariants (6 named):
INV-PR26-VERIFICATION-IS-PROOF-NOT-DECISION
INV-PR26-NO-NEW-MUTATION-PRIMITIVES
INV-PR25-HISTORY-GATE (carry-forward)
INV-PR26-EVIDENCE-PRIVATE-BY-DEFAULT
INV-PR26-TARGET-SPECIFIC-PREDICATE
INV-PR26-RAW-RUN-FORBIDDEN-FOR-MUTATION
§45 Merge-blocking evidence requirements (8 rows)
§46 CI gate requirements:
- tighten G4-RESTORE-EXEC-NO-OUT-OF-TARGET (forbid + per-call)
- new G4-RESTORE-EVIDENCE-RECORD
- new G4-RESTORE-CRON-MANIFEST-INTEGRITY
§47 Reviewer checklist (PR-26 code-phase merge-blocking)
§48 Open questions (7 explicitly marked):
§48.1 target-firewall SSH-rule kernel-evidence mechanism
§48.2 firewallType vs targetUnit plumbing
§48.3 cron-backup directory path
§48.4 cron-backup manifest schema details
§48.5 unmask/rename helper inline-vs-keep
§48.6 evidence-record file path + schema
§48.7 staging VM source
§49 Non-goals (explicit):
no ufw/firewalld/iptables authorization
no panels other than DirectAdmin
no §22/§19.4 changes
no validator full sweep / module-health
no repo hygiene / UX / GOTH / metrics / module cleanup
no PR-24 lattice changes
no read-only systemctl probe promotion
§50 Sequencing recommendation:
PR-26-doc → contract seed (this commit)
PR-26-code-A → target-specific safety predicate (Q3)
PR-26-code-B → typed executor methods + migration (Q5)
PR-26-code-C → cron backup manifest at install + A.4 (Q4)
PR-26-code-D → evidence-record file + new CI gates (Q1)
PR-26-code-E → destructive staged DA soak evidence
PR-26-final → CHANGELOG + release prep
Hard fence honored:
- §§1-36 untouched (PR-24 + PR-25 + Amendment 1)
- No production code in this commit
- No CI workflow changes in this commit
- No installer/update/uninstall/service lifecycle code touched
- Cron-backup amendment to switchop/takeover.go is contracted in §42
but NOT implemented here — that lands in PR-26-code-C after seed lock
Verified locally:
- contract.md section ladder: §§1-50 + Amendment history (1182 lines)
- doc compiles cleanly; no production-code diff
Awaiting auditor + operator pass over Q1-Q5 proposed locks before any
code-phase commit opens. The seven §48 open questions are explicitly
flagged for lock decisions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs(v1.100 PR-26): contract seed amendment — auditor P0/P1 fixes
Self-audit pass on b509f63 surfaced 1 P0 + 4 P1 issues. This commit
amends the seed in place (still doc-only, still no production code,
still no CI workflow change).
Edits:
1) P0-A — INV invariant rename + rewrite
- Renamed: INV-PR26-NO-NEW-MUTATION-PRIMITIVES
to: INV-PR26-NEW-MUTATION-SURFACES-BOUNDED
- Old wording was self-contradictory ("no new" but listed three
exceptions) and contained an arithmetic error ("four executor
additions" — only two exist).
- New wording enumerates exactly three new mutation surfaces:
(1) typed executor.ServiceUnmask
(2) typed executor.Rename
(3) install-time CSF/LFD cron-backup manifest write under
/var/lib/nftban/state/csf-cron-backup/
- "No fourth mutation surface is permitted without a new contract
amendment."
- §38.3 + §44 row 2 updated in lockstep.
2) P1-B / P1-C — §46 CI gate wording hardened
- New §46.1 "Locked discipline for text-grep gates":
- production-code gates exclude *_test.go files
- grep gates ignore line-leading comments
(grep -vE '^[[:space:]]*//' or equivalent)
- future complex write-path gates use Go AST or structural
runtime tests, not raw grep
- §46 gate table renamed §46.2 and references §46.1 discipline
in the gate-rationale column.
- G4-RESTORE-EVIDENCE-RECORD rewritten as a STRUCTURAL requirement:
"All evidence-record writes must route through a single helper
using a named constant evidenceRecordDir. Tests must assert
every WriteFileAtomic call in restore_evidence.go uses that
helper/constant. CI may grep for forbidden direct WriteFileAtomic
calls outside the helper."
- G4-RESTORE-CRON-MANIFEST-INTEGRITY similarly tightened to
structural requirement (sha256 helper symbols present in writer
+ reader; behavior tests assert refusal on mismatch).
- Goal: prevent the same false-positive class that hit Policy
Gates / Suppression-comment audit on PR #511.
3) P1-A / P1-D — §39.1 row 11 + §48.1
- §39.1 row 11 rationale rephrased from nft-only wording to
typed-evidence wording:
"CLI ruleset parsing is not required and must not be used as
truth. Kernel/service truth must come from typed executor methods,
such as NftTableExists, ServiceActive, and any additional typed
introspection method explicitly authorized by Q5/§48.1."
- §48.1 marked HARD BLOCKER for PR-26-code-A. Decision fork made
explicit:
- Option A: add typed IptablesRuleExists(table, chain, port);
keep row 6 BLOCKING. Q5's bounded-3-MUTATION-method invariant
is unaffected (the new method is READ-ONLY introspection;
mutation count remains 2).
- Option B: do not add iptables introspection; downgrade row 6
to ADVISORY.
- "No PR-26-code-A may start until operator/auditor chooses
Option A or Option B."
4) §50 sequencing — internal ordering note for code-C
- Added: install-time manifest creation in switchop/takeover.go
MUST land in the same commit as — and BEFORE — the A.4
restore-from-manifest enablement in restore_deps_csf.go.
- A.4 must remain skip/refuse-only on hosts where the manifest
is absent (existing pre-PR-26 installs). The two changes are
co-required: enabling A.4 without the writer would break on
first run; writing the manifest without consuming it leaves
dead state.
Self-audit re-check (fixed sections only):
- P0-A: INV-PR26-NEW-MUTATION-SURFACES-BOUNDED appears in §38.3
AND §44 row 2 verbatim; old name returns 0 grep hits — PASS.
- P1-B: §46.1 discipline section present with all three locked
rules; gate table references it — PASS.
- P1-C: G4-RESTORE-EVIDENCE-RECORD now specifies the named
helper / named constant pattern + the structural test
requirement — PASS.
- P1-A/D: §39.1 row 11 rationale rewritten to allow future typed
introspection without lying about current scope — PASS.
- §48.1: HARD BLOCKER tag present + Option A/B fork explicit +
Q5-invariant interaction documented — PASS.
- §50: code-C row carries the internal-ordering paragraph — PASS.
Stats: +30 / -9 lines, all in internal/installer/restore/contract.md.
§§1-36 still byte-identical to main.
Awaiting independent auditor pass + operator Q1-Q5 lock signal
before push. Code phase is gated on §48.1 Option-A-or-B decision.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 6a0ab67 commit cd76842
1 file changed
Lines changed: 364 additions & 0 deletions
0 commit comments