Skip to content

fix(v1.100 Amendment 2): code-B — preflight accepts /usr/sbin/csf.disabled for restore-to-CSF#520

Merged
itcmsgr merged 1 commit intomainfrom
amendment-2-code-B-preflight-csf-disabled
Apr 28, 2026
Merged

fix(v1.100 Amendment 2): code-B — preflight accepts /usr/sbin/csf.disabled for restore-to-CSF#520
itcmsgr merged 1 commit intomainfrom
amendment-2-code-B-preflight-csf-disabled

Conversation

@itcmsgr
Copy link
Copy Markdown
Owner

@itcmsgr itcmsgr commented Apr 28, 2026

Summary

Fixes the preflight contract bug surfaced by the Amendment-2-code-E srv3 destructive run (2026-04-28T21:06:03Z).

The dispatcher reached G1/AuthorityNFTBan/OrphanProceed PROCEED correctly, but failed at RESTORE_FAILED_EXECUTION (stage=preflight, exit=8) because the existing PR-25 §23.1 preflight requires the canonical csf binary in PATH. The Amendment-2 orphan-restore scenario specifically has /usr/sbin/csf ABSENT and /usr/sbin/csf.disabled PRESENT (the install-time-disabled state from switchop.DisableConflicts step 4), which the dispatcher restores via §32 A.3 rename later.

This is a contract gap in PR-25 preflight, not in Amendment 2's decision layer. Code-A (#519) and Amendment 2 §53 + §54 work as designed.

Surgical patch

In productionPreflightDep.PreflightTarget:

  • For firewallType == "csf": if no canonical csf binary in PATH, accept /usr/sbin/csf.disabled as a restorable candidate.
  • For non-CSF firewalls (ufw / firewalld / iptables): existing strict in-PATH check unchanged. No .disabled relaxation. Per Amendment 1 §30.2 (CSF-only inverse-of-install scope).
  • Existing unit-file presence check unchanged.
  • Preflight remains read-only — uses existing exec.FileExists.

A.3 (Amendment 1 §31) remains the authoritative rename and detects the ambiguous-both-present state for refusal at §32 step 1.

Tests added (10 new test functions)

Test Scenario Expected
AMD2_CSF_InPath_DisabledAbsent_Pass csf in PATH, .disabled absent PASS
AMD2_CSF_Absent_DisabledPresent_Pass csf absent, .disabled present PASS (§54 case)
AMD2_CSF_BothAbsent_Refuse both absent REFUSE ErrPreflightBinaryMissing
AMD2_CSF_BothPresent_Pass_AmbiguityIsA3 both present PASS (ambiguity is A.3's job)
AMD2_CSF_InPath_UnitAbsent_Refuse csf in PATH, unit absent REFUSE ErrPreflightUnitMissing
AMD2_NonCSF_NoDisabledRelaxation ufw/firewalld/iptables .disabled present REFUSE (CSF-only scope)
AMD2_UnknownFirewall_StillRefuse unknown firewallType REFUSE ErrPreflightUnknownFirewall
AMD2_CSF_DisabledBranch_NoMutationCalls §54 branch zero mutation commands

Test results (lab4 build host)

  • go test ./cmd/nftban-installer/... -run 'Preflight|RestoreDeps'PASS
  • go test ./cmd/nftban-installer/...PASS
  • go test ./internal/installer/restore/...PASS
  • go test ./...64 packages PASS, 0 FAIL

Files changed

File Change
cmd/nftban-installer/restore_deps.go +24 / -4 (CSF-only .disabled branch in PreflightTarget)
cmd/nftban-installer/restore_deps_test.go +163 (10 new test functions)

Files NOT touched

  • internal/installer/restore/contract.md
  • internal/installer/restore/engine.go
  • internal/installer/restore/execute.go
  • internal/installer/state/machine.go
  • cmd/nftban-installer/flags.go
  • cmd/nftban-installer/main.go
  • .github/workflows/*
  • All other files ✅

Invariants preserved

  • §23.1 preflight read-only: unchanged.
  • INV-PR26-NEW-MUTATION-SURFACES-BOUNDED: zero new surfaces.
  • §32 ordering: unchanged. A.3 still authoritative rename.
  • §22 / §19.4 terminals + exit codes: unchanged.
  • Amendment 1 §30.2 CSF-only scope: preserved (non-CSF .disabled files explicitly refuse — pinned in tests).
  • §19.2 layer 4 / main.go:132 history gate: untouched.
  • Existing 4B-1 fixture matrix: unchanged behavior, all pass.

Out of scope

  • No new lattice rule.
  • No new state terminal.
  • No new exit code.
  • No new mutation surface.
  • No CI workflow edit.
  • No host action.

Test plan

  • CI passes
  • Auditor verifies CSF-only scope (non-CSF .disabled paths still REFUSE)
  • Auditor verifies preflight remains read-only (zero Run/Service*/Nft* calls in changed branch)
  • Auditor verifies A.3 ambiguity-detection at §32 step 1 unchanged

After merge

Fresh Tier 1 binary build → fresh srv3 H2/H3 attestation → fresh auditor CONDITIONAL PRE-EXECUTION GO → one new srv3 destructive attempt.

🤖 Generated with Claude Code

…abled for restore-to-CSF

Surfaced by Amendment-2-code-E srv3 destructive run (2026-04-28T21:06:03Z):
the dispatcher reached G1/AuthorityNFTBan/OrphanProceed PROCEED but
RESTORE_FAILED_EXECUTION at preflight stage with exit=8 because the
existing PR-25 §23.1 preflight required the canonical csf binary to be
present in PATH. The Amendment-2 orphan-restore scenario specifically
has /usr/sbin/csf ABSENT and /usr/sbin/csf.disabled PRESENT (the
install-time-disabled state from switchop.DisableConflicts step 4),
which the dispatcher then restores via §32 A.3 rename.

This is a contract gap in PR-25 preflight, NOT in Amendment 2's
decision layer. Code-A (#519) and Amendment 2 §53 + §54 work as
designed.

Surgical patch
==============

In productionPreflightDep.PreflightTarget:
- For firewallType=="csf": if no canonical csf binary in PATH, accept
  /usr/sbin/csf.disabled as a restorable candidate.
- For non-CSF firewalls (ufw / firewalld / iptables): existing strict
  in-PATH check unchanged. No .disabled relaxation. Per Amendment 1
  §30.2 (CSF-only inverse-of-install scope).
- Existing unit-file presence check unchanged.
- Preflight remains read-only — uses existing exec.FileExists.

A.3 (Amendment 1 §31) remains the authoritative rename and detects
the ambiguous-both-present state for refusal at §32 step 1.

Tests added (9 cases per operator scope)
========================================

1. AMD2-1: csf in PATH, .disabled absent, unit present → PASS
2. AMD2-2: csf absent, .disabled present, unit present → PASS (§54 case)
3. AMD2-3: csf absent, .disabled absent, unit present → REFUSE
   ErrPreflightBinaryMissing
4. AMD2-4: csf in PATH AND .disabled present, unit present → PASS at
   preflight; ambiguity is A.3's responsibility
5. AMD2-5: csf in PATH, unit absent → REFUSE ErrPreflightUnitMissing
6. AMD2-6: ufw absent + ufw.disabled present → REFUSE (no relaxation)
7. AMD2-7: firewalld absent + firewall-cmd.disabled present → REFUSE
8. AMD2-8: iptables absent + iptables.disabled present → REFUSE
9. AMD2-9: unknown firewallType → REFUSE ErrPreflightUnknownFirewall
10. AMD2-10: §54 branch records ZERO mutation commands (read-only
    contract preserved)

Test results (lab4 build host)
==============================

- go test ./cmd/nftban-installer/... -run 'Preflight|RestoreDeps' → PASS
- go test ./cmd/nftban-installer/...                              → PASS
- go test ./internal/installer/restore/...                        → PASS
- go test ./...                                                    → 64 pkgs PASS, 0 FAIL

Files changed
=============

cmd/nftban-installer/restore_deps.go          | +24 / -4   (28 lines)
cmd/nftban-installer/restore_deps_test.go     | +163       (10 new tests)

No files outside the operator-allowed two.

Invariants preserved
====================

- §23.1 preflight read-only: unchanged. New branch uses FileExists only.
- INV-PR26-NEW-MUTATION-SURFACES-BOUNDED: zero new surfaces.
- §32 ordering: unchanged. A.3 still authoritative rename.
- §22 / §19.4 terminals + exit codes: unchanged.
- Amendment 1 §30.2 CSF-only scope: preserved (non-CSF .disabled
  files explicitly refuse — tests AMD2-6/7/8 pin this).
- §19.2 layer 4 / main.go:132 history gate: untouched.
- Existing 4B-1 fixture matrix: unchanged behavior, all pass.

No CI workflow edit. No state machine change. No flag change. No
contract change. No execute.go change. No engine.go change. No
main.go change.

No srv3 action.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@itcmsgr itcmsgr merged commit 48b9e50 into main Apr 28, 2026
63 checks passed
@itcmsgr itcmsgr deleted the amendment-2-code-B-preflight-csf-disabled branch April 28, 2026 21:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant