Commit 48b9e50
fix(v1.100 Amendment 2): code-B — preflight accepts /usr/sbin/csf.disabled for restore-to-CSF (#520)
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>1 parent 433f53c commit 48b9e50
2 files changed
Lines changed: 187 additions & 4 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
187 | 187 | | |
188 | 188 | | |
189 | 189 | | |
190 | | - | |
191 | | - | |
192 | | - | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
193 | 214 | | |
194 | | - | |
195 | 215 | | |
196 | 216 | | |
197 | 217 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
899 | 899 | | |
900 | 900 | | |
901 | 901 | | |
| 902 | + | |
| 903 | + | |
| 904 | + | |
| 905 | + | |
| 906 | + | |
| 907 | + | |
| 908 | + | |
| 909 | + | |
| 910 | + | |
| 911 | + | |
| 912 | + | |
| 913 | + | |
| 914 | + | |
| 915 | + | |
| 916 | + | |
| 917 | + | |
| 918 | + | |
| 919 | + | |
| 920 | + | |
| 921 | + | |
| 922 | + | |
| 923 | + | |
| 924 | + | |
| 925 | + | |
| 926 | + | |
| 927 | + | |
| 928 | + | |
| 929 | + | |
| 930 | + | |
| 931 | + | |
| 932 | + | |
| 933 | + | |
| 934 | + | |
| 935 | + | |
| 936 | + | |
| 937 | + | |
| 938 | + | |
| 939 | + | |
| 940 | + | |
| 941 | + | |
| 942 | + | |
| 943 | + | |
| 944 | + | |
| 945 | + | |
| 946 | + | |
| 947 | + | |
| 948 | + | |
| 949 | + | |
| 950 | + | |
| 951 | + | |
| 952 | + | |
| 953 | + | |
| 954 | + | |
| 955 | + | |
| 956 | + | |
| 957 | + | |
| 958 | + | |
| 959 | + | |
| 960 | + | |
| 961 | + | |
| 962 | + | |
| 963 | + | |
| 964 | + | |
| 965 | + | |
| 966 | + | |
| 967 | + | |
| 968 | + | |
| 969 | + | |
| 970 | + | |
| 971 | + | |
| 972 | + | |
| 973 | + | |
| 974 | + | |
| 975 | + | |
| 976 | + | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
| 982 | + | |
| 983 | + | |
| 984 | + | |
| 985 | + | |
| 986 | + | |
| 987 | + | |
| 988 | + | |
| 989 | + | |
| 990 | + | |
| 991 | + | |
| 992 | + | |
| 993 | + | |
| 994 | + | |
| 995 | + | |
| 996 | + | |
| 997 | + | |
| 998 | + | |
| 999 | + | |
| 1000 | + | |
| 1001 | + | |
| 1002 | + | |
| 1003 | + | |
| 1004 | + | |
| 1005 | + | |
| 1006 | + | |
| 1007 | + | |
| 1008 | + | |
| 1009 | + | |
| 1010 | + | |
| 1011 | + | |
| 1012 | + | |
| 1013 | + | |
| 1014 | + | |
| 1015 | + | |
| 1016 | + | |
| 1017 | + | |
| 1018 | + | |
| 1019 | + | |
| 1020 | + | |
| 1021 | + | |
| 1022 | + | |
| 1023 | + | |
| 1024 | + | |
| 1025 | + | |
| 1026 | + | |
| 1027 | + | |
| 1028 | + | |
| 1029 | + | |
| 1030 | + | |
| 1031 | + | |
| 1032 | + | |
| 1033 | + | |
| 1034 | + | |
| 1035 | + | |
| 1036 | + | |
| 1037 | + | |
| 1038 | + | |
| 1039 | + | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
| 1044 | + | |
| 1045 | + | |
| 1046 | + | |
| 1047 | + | |
| 1048 | + | |
| 1049 | + | |
| 1050 | + | |
| 1051 | + | |
| 1052 | + | |
| 1053 | + | |
| 1054 | + | |
| 1055 | + | |
| 1056 | + | |
| 1057 | + | |
| 1058 | + | |
| 1059 | + | |
| 1060 | + | |
| 1061 | + | |
| 1062 | + | |
| 1063 | + | |
| 1064 | + | |
0 commit comments