Skip to content

PR26.3: DirectAdmin adapter under panelfw#530

Merged
itcmsgr merged 2 commits intomainfrom
feat/pr26.3-directadmin-adapter
Apr 29, 2026
Merged

PR26.3: DirectAdmin adapter under panelfw#530
itcmsgr merged 2 commits intomainfrom
feat/pr26.3-directadmin-adapter

Conversation

@itcmsgr
Copy link
Copy Markdown
Owner

@itcmsgr itcmsgr commented Apr 29, 2026

Summary

DirectAdmin adapter — the first specimen registered under the PR26.2 panelfw.PanelAdapter contract. Read-only adapter implementation. No real-host destructive testing in this PR.

Scope

Hard exclusions preserved:

  • No cPanel / Plesk / cyberpanel / hestia adapter
  • No authority residue classifier
  • No restore semantics change
  • No firewall mutation
  • No runtime nft surgery
  • No destructive host testing

What landed

File Purpose
internal/installer/panelfw/adapters/directadmin/directadmin.go Adapter implementation (251 lines)
internal/installer/panelfw/adapters/directadmin/directadmin_test.go Detect / RequiredPorts / ValidateReachability + framework integration tests (414 lines)
cmd/nftban-installer/main.go Blank import so the adapter's init() fires during process startup

Detect (4 signals)

Signal Source
install-dir-present /usr/local/directadmin/
binary-present /usr/local/directadmin/directadmin
service-active directadmin.service (via ServiceActive)
listener-tcp <port> in LISTEN state via ss -lnt parse

Confidence: 3+ → strong; 1–2 → weak (with warning); 0 → Detected=false.

RequiredPorts

  • Default: TCP [2222]
  • Override: parses port=N from /usr/local/directadmin/conf/directadmin.conf (tolerates inline comments, falls back to default on malformed/missing config)
  • UDP always empty

ValidateReachability

  • Verifies the required TCP port is in LISTEN state via ss -lnt
  • Returns structured error on miss (port not listening, ss failed, or prefix collision like :22222:2222)
  • Read-only — no nft, no service writes, no file writes

Tests

22 tests in ./internal/installer/panelfw/adapters/directadmin/..., all green on lab4:

  • TestDetect_AllSignals_Strong / _Absent_NotDetected / _PartialInstall_Weak / _ServiceOnly_Weak
  • TestRequiredPorts_Default / _ConfigOverride / _MalformedConfig_FallsBackToDefault (5 sub-tests) / _ConfigInlineComment
  • TestValidateReachability_Listening_OK / _NotListening_ReturnsError / _PortPrefixCollision / _SsErrorsOut_NotListening / _OverridePortHonored
  • TestID
  • TestFrameworkIntegration_DA_Detected_Reachable_Passes / _NotReachable_Blocks / _Absent_Passes / _NotReachable_OperatorDisabled_Passes (proves --no-panel still works for DA)
  • TestInitRegistration_AdapterPresent (proves init() populates the global registry)
  • TestReadOnly_NoWrites_NoMutationCommands (structural mutation audit)

Lab proof (lab4, RHEL/cPanel, go1.25.8)

Branch base: fdbebe8c (origin/main, post-PR26.2 merge).

go vet ./internal/installer/panelfw/... ./internal/installer/validate/... ./cmd/nftban-installer/...
  → VET_EXIT=0 (clean)

go test -v ./internal/installer/panelfw/...
  → PASS — 14 panelfw + 22 directadmin tests, all green

go test ./...
  → 66 packages PASS, 0 FAIL
  (was 65 pre-PR26.3; +1 = new internal/installer/panelfw/adapters/directadmin)

TMPDIR=/root/build-tmp (lab4: both /tmp and /var/tmp are noexec under cPanel /usr/tmpDSK).

Behavior on a real DirectAdmin host (post-merge)

When the installer runs on a host where /usr/local/directadmin/ exists, directadmin binary is present, directadmin.service is active, and TCP 2222 is listening:

  1. panelfw.RegisteredAdapters() returns [directadmin] (init() fires on startup).
  2. phaseValidate calls RunAssertionsWithOpts with the operator-derived policy.
  3. assertPanelSurvival calls panelfw.EvaluateAdapters([directadmin], policy):
    • Detect → strong, 4 evidence rows, RequiredTCP=[2222]
    • RequiredPorts → [2222], [], nil
    • ValidateReachability → nil (port 2222 in LISTEN)
    • PanelResult: Fatal=false, PortsApplied=true, ReachableAfter=true
  4. Assertion passes; install proceeds to StateCommitted.

If TCP 2222 is NOT listening (DirectAdmin stopped, panel-enable failed, or another bug): Fatal=true, the assertion fails, AllPassed=false, install drops to StateDegraded. dns2's silent panel-enable failure is now caught at install time — unless the operator passes --no-panel.

Test plan

  • go test ./internal/installer/panelfw/... green on lab4
  • go vet ./internal/installer/panelfw/... ./internal/installer/validate/... ./cmd/nftban-installer/... clean on lab4
  • go test ./... green on lab4 (66 packages, 0 fail)
  • CI green on this PR
  • Auditor on-PR final review

🤖 Generated with Claude Code

PR26.3 — DirectAdmin adapter, the first specimen under the PR26.2
panelfw.PanelAdapter contract. Read-only by interface contract; no
firewall mutation, no service writes, no host destructive testing.

internal/installer/panelfw/adapters/directadmin/:
  - Detect: 4-signal evidence (install dir / binary / service active /
    TCP listener) → strong (3+) or weak (1-2) confidence
  - RequiredPorts: default TCP 2222, override via
    /usr/local/directadmin/conf/directadmin.conf `port=N`
  - ValidateReachability: ss -lnt parse for the required port
  - init() registers the adapter via panelfw.Register

cmd/nftban-installer/main.go:
  - blank import to fire the adapter's init() during process startup,
    so phaseValidate sees DirectAdmin in panelfw.RegisteredAdapters()
    on a real DA host

Hard exclusions:
  - no cPanel / Plesk / cyberpanel adapter
  - no authority residue classifier
  - no restore semantics change
  - no firewall mutation
  - no destructive host testing

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

github-actions Bot commented Apr 29, 2026

Dependency Review

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

Scanned Files

None

Clarifies PR26.3 scope after auditor disposition:

  - Top-level doc-comment: "control-plane only"; full DirectAdmin
    service-port surface (16+ public-facing ports) is NOT validated
    here — that lands in PR26.4 via
    internal/ports/panel_loader.LoadPanelConfig("directadmin") and
    /etc/nftban/conf.d/panels/directadmin/main.conf.
  - PR26.4 follow-up note inline at the top of directadmin.go.
  - ValidateReachability error message: explicitly says
    "control-plane port N not in LISTEN state — control-plane
    unreachable" so the user-facing AssertionResult.Detail (and
    log lines) cannot be misread as a full panel-survival claim.
  - New test: ErrorMentionsControlPlane (positive: "control-plane"
    is in the message; negative: no affirmative full-surface claim).
  - New test: Reason_DoesNotImplyFullPortSurvival at the framework
    integration layer.
  - Tightened existing TestFrameworkIntegration_DA_Detected_NotReachable_Blocks
    to assert the surfaced Reason mentions "control-plane".

No internal/ports import in this PR (deliberately deferred to
PR26.4). No new mutation surface; adapter remains read-only. No
cPanel/Plesk/classifier/restore code added.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@itcmsgr
Copy link
Copy Markdown
Owner Author

itcmsgr commented Apr 29, 2026

Path A applied — control-plane scope clarification

Per the auditor disposition, scope of this adapter is now explicitly bounded to DirectAdmin control-plane reachability only. Full DirectAdmin service-port surface validation is deferred to PR26.4.

Changes in 44d98a1a:

  1. Top-level doc-comment in directadmin.go adds a "SCOPE — CONTROL PLANE ONLY (PR26.3)" section and an inline "PR26.4 follow-up" note specifying the next step:

    Full port-surface validation MUST reuse internal/ports/panel_loader.LoadPanelConfig("directadmin") and the canonical conf.d panel config in PR26.4.

  2. ValidateReachability error message now explicitly says "control-plane port N not in LISTEN state — control-plane unreachable" (and includes a parenthetical noting full-surface validation lands in PR26.4). This is the string that surfaces in AssertionResult.Detail and the installer log; operators can no longer misread it as a full panel-survival claim.

  3. New tests:

    • TestValidateReachability_NotListening_ErrorMentionsControlPlane — positive: error contains "control-plane"; negative: no affirmative full-surface claim verbs.
    • TestFrameworkIntegration_DA_Reason_DoesNotImplyFullPortSurvival — same negative check at the framework integration layer.
  4. Tightened TestFrameworkIntegration_DA_Detected_NotReachable_Blocks to also assert the surfaced PanelResult.Reason contains "control-plane".

Hard exclusions preserved: PR26.3 does NOT import internal/ports. PR26.3 does NOT implement 16-port reuse. No cPanel/Plesk. No shell decommission. No authority residue classifier. No restore changes.

Lab4 re-proof (post-Path-A, base fdbebe8c):

  • go vet ./internal/installer/panelfw/... ./cmd/nftban-installer/... → clean (exit 0)
  • go test -count=1 ./internal/installer/panelfw/... → PASS
  • go test ./... → 0 failures across the full repo

🤖 Generated with Claude Code

@itcmsgr itcmsgr merged commit 5366caf into main Apr 29, 2026
63 checks passed
@itcmsgr itcmsgr deleted the feat/pr26.3-directadmin-adapter branch April 29, 2026 21:18
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