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
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,46 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

---

## [Unreleased] - v1.100 PR-22A + PR-22B repair cycle

### Changed

- **v1.100 lifecycle truth repair** (PRs #480, #481, #482). Observational
paths (install refused, update and uninstall dry-run) are now
structurally honest. `StateFile.DryRun` suppresses state-file writes;
`writeHistory` gated on `!cfg.dryRun && state.IsApplyTerminal(sf.State)`;
`authority.IsNftbanAuthoritative` is the canonical predicate used by
both `authority.Classify` and `update.Preflight`. New `Ambiguous`
authority decision for orphan-table / daemon-down hosts routes through
the emergency-SSH injection path. `--panel-auto-takeover` flag
(default off) replaces the previous implicit panel auto-approve.
Flag validation now rejects `--mode=install --dry-run`,
`--repair --dry-run`, `--takeover --dry-run`, `--rpm --deb`, and
`--force-delete-operator-config` without `--purge`.

### Data-integrity note

- **Lifecycle-bridge authority mapping (v1.98 — v1.99)** — the
`observePlan` and `mapAuthority` switches in
`cmd/nftban-installer/lifecycle_bridge.go` compared uppercase
`authority.Decision` values (e.g. `"TAKEOVER"`) against lowercase
string literals. The switches silently hit their `default` arms on
every real run, so lifecycle consumers saw `ActionPreserveAuthority`
and `AuthorityNone` regardless of the installer's actual decision.
Fixed in PR-22B (#482) — switches now pin to `authority.Decision`
constants; `Ambiguous` maps to a new `lifecycle.AuthorityUnknown`
owner.

**Impact on historical records**: any lifecycle telemetry,
dashboards, or audit-trail consumers that ingested
`lifecycle.RunResult` JSON between v1.98 and the merge of PR-22B
will show `PreserveAuthority` / `AuthorityNone` on every install and
update run regardless of what actually happened on the host. This
does NOT affect install_state, update-history.json, or kernel
behavior — only the lifecycle bridge's external reporting surface.
Forensic interpretation of pre-PR-22B lifecycle output should treat
the authority decision as "unknown" rather than "preserve."

## [1.98.2] - 2026-04-19

**Runtime correctness patch — exit-code truth, health resilience, installer payload truth.**
Expand Down
54 changes: 54 additions & 0 deletions internal/installer/uninstall/contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,3 +202,57 @@ If any PR-22 commit requires:
→ **STOP PR-22.** Push the work to PR-23 or later. PR-22's scope lock
is the point of the contract seed — bending it collapses the evidence
chain for the whole v1.100 track.

---

## Standing lifecycle-truth rule (from PR-22B merge)

**No new lifecycle code may bypass the shared authority predicate, the
history-write gate, or the dry-run contract.**

Concretely, every new or modified lifecycle code path must:

1. use `authority.IsNftbanAuthoritative(exec)` — not re-implement the
predicate or proxy it via `NftTableExists` alone
2. respect the `!cfg.dryRun && state.IsApplyTerminal(sf.State)` history
gate — no back-door direct writes to `update-history.json`
3. respect `StateFile.DryRun` — no direct writes to `install_state` or
any path under `/var/lib/nftban/` or `/etc/nftban/` during dry-run
4. route `authority.Ambiguous` through emergency-SSH injection before
any mutation — never silent-continue, never collapse to Fresh/None
5. surface `--panel-auto-takeover` explicitly if it needs panel consent
— no implicit panel auto-approve path

CI gates (PR-22A + PR-22B): `G3-UN-NO-MUTATION`, `G3-UN-PLAN-RENDERS`,
`G3-UN-HISTORY-PURITY`, `G3-U3` hard-assertions, `G3-U5..U10` extended
grep, `G3-IN-REFUSE-DRY-RUN`, `G3-IN-FLAG-COMBOS`. Any lifecycle PR
that bypasses the rule above is expected to fail at least one of
these gates; if it doesn't, the gate needs extension, not the rule.

---

## Pre-PR-23 blockers (tracked follow-up PRs)

PR-23 (uninstall mutation: Switch phase + authority release) must NOT
start until all six items below have landed and been verified by a
narrow-scope audit. Each is its own PR with an explicit micro-contract
and one falsifiable proof test per PR-22B merge discipline.

| # | PR | Purpose | Blocking because |
|---|---|---|---|
| 1 | Prior-authority record hardening | Add `recorded_at`, `installer_version`, explicit `active_at_install=false` handling to `prior.go` | PR-24 restore enforcement cannot trust under-defined `RecordUsable` |
| 2 | External-firewall detection unification | One shared function + one precedence order used by install/update/uninstall | Detection drift between modules will cause disagreement under takeover/restore |
| 3 | Kernel/service snapshot CI gate | `nft list tables` + `systemctl is-active` diff before/after every dry-run path | Filesystem snapshot alone cannot prove process-level purity |
| 4 | Exec-trace CI gate | `strace -f -e trace=execve` (or equivalent) around dry-run paths; assert no forbidden mutators spawned | Strictest purity guarantee; catches dynamically-constructed commands |
| 5 | Auto-elevate shim removal gate | CI rule: PR-23-class changes blocked while the shim block in `flags.go` still exists | Prevents scaffold-era UX semantics leaking into mutation-era behavior |
| 6 | Payload integrity minimum checks | Minimum-size / header-presence for `nftban.conf`, `nftables.conf` | Presence-only validation lets a truncated file pass |

Phase 3 gating: once items 1–6 are merged and CI green, a focused
verification audit runs with ONLY these questions:

1. Is dry-run still pure across install / update / uninstall?
2. Is there any history / state drift?
3. Is the authority predicate still consistent across callers?

No exploratory scope in that audit. PR-23 starts only after it returns
clean.
Loading