Skip to content

Commit 1510e36

Browse files
itcmsgrclaude
andauthored
PR26.5: source-install payload completeness (#532)
* installer: source-install payload completeness (PR26.5) Closes the dns2 evidence finding (2026-04-30) where the source-install path reached StateDegraded with three named assertion failures: systemd_execstart_paths_ok (8 missing destinations) systemd_payload_inventory_ok (6 unknown nftban-owned references) panel_survival_ok (LoadPanelConfig directadmin not found) Per the operator-locked PR26.5 scope (`project_pr26_5_locked.md`): - source-install payload completeness ONLY - no takeover/CSF binary handling (PR26.6) - no cPanel/Plesk adapters (PR26.7+) internal/installer/payload/payload.go (buildEntries): - new shell-payload entries: cli/lib/nftban/exporters/*.sh -> /usr/lib/nftban/exporters/ cli/lib/nftban/cron/*.sh -> /usr/lib/nftban/cron/ scripts/*.sh -> /usr/lib/nftban/scripts/ install/helpers/*.sh -> /usr/lib/nftban/helpers/ (joins the existing cli/lib/nftban/helpers/ source — both flatten into the same destination) - new `panels` category staging the canonical panel conf.d files: etc/nftban/conf.d/panels/<name>/main.conf -> /etc/nftban/conf.d/panels/<name>/main.conf for all 8 first-class panels (directadmin, cpanel, plesk, cyberpanel, cwp, interworx, vesta, generic). policyConfigNoReplace: operator edits preserved on upgrade. install/systemd/ (retired unit files removed): - nftban-api.service, nftban-ui.service, nftban-ui-auth.service, nftban-ui-auth.socket — all reference Go binaries the project no longer builds. Operator-confirmed retired in v1.100.1b.A (GOTH PR-D4 stage 1) and already removed by packaging on RPM/DEB upgrade. Source-install path now matches that contract: not shipped, not in source tree, not staged. internal/installer/validate/assertions.go (defaultInventoryPaths): - extended with shell-payload destinations referenced by remaining units, so systemd_payload_inventory_ok no longer false-flags legitimate staged shell payload as "unknown". internal/installer/payload/payload_test.go (3 new tests): - TestStageAll_AllUnitNftbanOwnedExecStartPathsStaged_PR26_5: walks every install/systemd/*.service, parses every ExecStart/Pre/Post path, asserts every nftban-owned destination is in mock.WrittenFiles after StageAll. - TestStageAll_AllPanelConfDStaged_PR26_5: asserts every shipped panel's main.conf is staged at /etc/nftban/conf.d/panels/<name>/main.conf. - TestStageAll_PR26_5_NewShellCategoriesStaged: regression guard pinning the four specific destinations that failed on dns2 (exporter, cron, scripts, helpers). Lab proof (lab2, Ubuntu 24.04, go1.22.2): go vet payload/... validate/... cmd/nftban-installer/... clean go test -v ./internal/installer/payload/... 3 new tests PASS, full file PASS go test ./... 66 packages, 0 FAIL Hard exclusions preserved: no takeover-side cleanup, no CSF binary handling, no cPanel/Plesk adapters, no shell decommission, no parser rewrite, no restore changes, no firewall mutation, no destructive dns2 retry from this branch. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * installer: PR26.5 — seed stub binaries in test mock for CI Auditor flagged: TestStageAll_AllUnitNftbanOwnedExecStartPathsStaged_PR26_5 fails on CI because the runner ships a clean source checkout with no prebuilt binaries. lab2 happened to have prebuilt binaries from prior builds, so the test passed there. The test's intent is correct (assert every shipped unit's nftban-owned ExecStart path is staged), but it needs the binary source files to exist for the staging step to succeed. Fix: per auditor option 1, add a `seedStubBuiltBinaries` helper that populates `bin/<name>` with a stub byte-string in the test mock before StageAll. Production payload.go is unchanged. Helper applied to all 3 PR26.5 tests for environment consistency: TestStageAll_AllUnitNftbanOwnedExecStartPathsStaged_PR26_5 (the failing one) TestStageAll_AllPanelConfDStaged_PR26_5 TestStageAll_PR26_5_NewShellCategoriesStaged Lab proof — confirmed reproducer: rm -rf /root/nftban-src/bin && go test -count=1 -v -run PR26_5 ./... → all 3 PR26.5 tests PASS (was: 1 FAIL pre-fix on empty bin/) go test ./... → 66 packages PASS, 0 FAIL Production code: unchanged. The fix is fixture-only — no payload.go edits, no validate/ edits, no buildEntries change. Hard exclusions still preserved: no takeover preservation, no CSF binary handling, no cPanel/Plesk adapters, no shell decommission, no parser rewrite, no restore changes, no firewall mutation, no destructive dns2 retry. 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 bfe6eac commit 1510e36

7 files changed

Lines changed: 341 additions & 333 deletions

File tree

install/systemd/nftban-api.service

Lines changed: 0 additions & 65 deletions
This file was deleted.

install/systemd/nftban-ui-auth.service

Lines changed: 0 additions & 109 deletions
This file was deleted.

install/systemd/nftban-ui-auth.socket

Lines changed: 0 additions & 44 deletions
This file was deleted.

install/systemd/nftban-ui.service

Lines changed: 0 additions & 106 deletions
This file was deleted.

internal/installer/payload/payload.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,20 @@ func buildEntries(distro *detect.DistroInfo) []entry {
396396
{category: "data", srcRel: "cli/lib/nftban/data", srcGlob: "*", dstGlob: "/usr/lib/nftban/data", mode: 0644, policy: policyAlways, isDir: true},
397397
{category: "shell", srcRel: "cli/lib/nftban/health", srcGlob: "*.sh", dstGlob: "/usr/lib/nftban/health", mode: 0755, policy: policyAlways, isDir: true},
398398

399+
// PR26.5: source-install payload completeness — close the gaps surfaced
400+
// by the dns2 evidence run (2026-04-30). systemd unit ExecStart paths
401+
// referenced these destinations; pre-PR26.5 source install did not stage
402+
// them, causing PR26.1 systemd_execstart_paths_ok to fail.
403+
// G-14-C continued: shell payload destinations referenced by units.
404+
{category: "shell", srcRel: "cli/lib/nftban/exporters", srcGlob: "*.sh", dstGlob: "/usr/lib/nftban/exporters", mode: 0755, policy: policyAlways, isDir: true},
405+
{category: "shell", srcRel: "cli/lib/nftban/cron", srcGlob: "*.sh", dstGlob: "/usr/lib/nftban/cron", mode: 0755, policy: policyAlways, isDir: true},
406+
// Top-level scripts/ — referenced by nftban-soak.service.
407+
{category: "shell", srcRel: "scripts", srcGlob: "*.sh", dstGlob: "/usr/lib/nftban/scripts", mode: 0755, policy: policyAlways, isDir: true},
408+
// install/helpers/ ships the firewall-init-with-delay.sh helper which is
409+
// distinct from the cli/lib/nftban/helpers/ tree above. Both flatten into
410+
// /usr/lib/nftban/helpers/.
411+
{category: "shell", srcRel: "install/helpers", srcGlob: "*.sh", dstGlob: "/usr/lib/nftban/helpers", mode: 0755, policy: policyAlways, isDir: true, optional: true},
412+
399413
// Shipped nftables template (always overwrite — installer-managed,
400414
// never operator-edited here).
401415
{category: "templates", srcRel: "cli/lib/nftban/templates/nftables.conf.tpl", dstGlob: "/usr/lib/nftban/templates/nftables.conf.tpl", mode: 0644, policy: policyAlways, optional: true},
@@ -424,6 +438,21 @@ func buildEntries(distro *detect.DistroInfo) []entry {
424438
// Distro-aware path registry (always overwrite — installer-owned).
425439
{category: "configs", srcRel: "etc/nftban/distros", srcGlob: "*.conf", dstGlob: "/etc/nftban/distros", mode: 0640, policy: policyAlways, isDir: true},
426440

441+
// PR26.5: panel canonical port-declaration configs. Source-of-truth for
442+
// PR26.4's DirectAdmin adapter (and future PR26.7 cPanel / PR26.8 Plesk
443+
// adapters) via internal/ports/panel_loader.LoadPanelConfig. Per the
444+
// V190_PANELS audit there are 8 first-class panels; staging is a static
445+
// set of 8 single-file entries (one per panel) so future panel removals
446+
// require an explicit edit to this list.
447+
{category: "panels", srcRel: "etc/nftban/conf.d/panels/directadmin/main.conf", dstGlob: "/etc/nftban/conf.d/panels/directadmin/main.conf", mode: 0640, policy: policyConfigNoReplace, optional: true},
448+
{category: "panels", srcRel: "etc/nftban/conf.d/panels/cpanel/main.conf", dstGlob: "/etc/nftban/conf.d/panels/cpanel/main.conf", mode: 0640, policy: policyConfigNoReplace, optional: true},
449+
{category: "panels", srcRel: "etc/nftban/conf.d/panels/plesk/main.conf", dstGlob: "/etc/nftban/conf.d/panels/plesk/main.conf", mode: 0640, policy: policyConfigNoReplace, optional: true},
450+
{category: "panels", srcRel: "etc/nftban/conf.d/panels/cyberpanel/main.conf", dstGlob: "/etc/nftban/conf.d/panels/cyberpanel/main.conf", mode: 0640, policy: policyConfigNoReplace, optional: true},
451+
{category: "panels", srcRel: "etc/nftban/conf.d/panels/cwp/main.conf", dstGlob: "/etc/nftban/conf.d/panels/cwp/main.conf", mode: 0640, policy: policyConfigNoReplace, optional: true},
452+
{category: "panels", srcRel: "etc/nftban/conf.d/panels/interworx/main.conf", dstGlob: "/etc/nftban/conf.d/panels/interworx/main.conf", mode: 0640, policy: policyConfigNoReplace, optional: true},
453+
{category: "panels", srcRel: "etc/nftban/conf.d/panels/vesta/main.conf", dstGlob: "/etc/nftban/conf.d/panels/vesta/main.conf", mode: 0640, policy: policyConfigNoReplace, optional: true},
454+
{category: "panels", srcRel: "etc/nftban/conf.d/panels/generic/main.conf", dstGlob: "/etc/nftban/conf.d/panels/generic/main.conf", mode: 0640, policy: policyConfigNoReplace, optional: true},
455+
427456
// Manual whitelist/blacklist templates (%config(noreplace)).
428457
// safety.SeedManualWhitelist runs in phaseConfigure after these land.
429458
{category: "configs", srcRel: "etc/nftban/whitelist.d/99-manual.conf", dstGlob: "/etc/nftban/whitelist.d/99-manual.conf", mode: 0640, policy: policyConfigNoReplace, optional: true},

0 commit comments

Comments
 (0)