executor

package
v1.129.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 24, 2026 License: MPL-2.0 Imports: 12 Imported by: 0

Documentation

Overview

============================================================================= NFTBan v1.73 - Installer Executor Interface ============================================================================= SPDX-License-Identifier: MPL-2.0 meta:name="installer-executor" meta:type="lib" meta:owner="Antonios Voulvoulis <contact@nftban.com>" meta:created_date="2026-04-04" meta:description="Executor interface abstracting system commands for testability" meta:inventory.files="internal/installer/executor/executor.go" meta:inventory.binaries="" meta:inventory.env_vars="" meta:inventory.config_files="" meta:inventory.systemd_units="" meta:inventory.network="" meta:inventory.privileges="none" =============================================================================

============================================================================= NFTBan v1.73 - Installer Mock Executor ============================================================================= SPDX-License-Identifier: MPL-2.0 meta:name="installer-executor-mock" meta:type="test" meta:owner="Antonios Voulvoulis <contact@nftban.com>" meta:created_date="2026-04-04" meta:description="In-memory mock executor for unit testing" meta:inventory.files="internal/installer/executor/mock.go" meta:inventory.binaries="" meta:inventory.env_vars="" meta:inventory.config_files="" meta:inventory.systemd_units="" meta:inventory.network="" meta:inventory.privileges="none" =============================================================================

============================================================================= NFTBan v1.73 - Installer Real Executor ============================================================================= SPDX-License-Identifier: MPL-2.0 meta:name="installer-executor-real" meta:type="lib" meta:owner="Antonios Voulvoulis <contact@nftban.com>" meta:created_date="2026-04-04" meta:description="Production executor using os/exec and syscalls" meta:inventory.files="internal/installer/executor/real.go" meta:inventory.binaries="" meta:inventory.env_vars="" meta:inventory.config_files="" meta:inventory.systemd_units="" meta:inventory.network="" meta:inventory.privileges="root" =============================================================================

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Executor

type Executor interface {
	// Run executes a command and returns the result. Timeout defaults to 30s.
	Run(name string, args ...string) Result

	// RunContext executes a command with the given context for cancellation/timeout.
	RunContext(ctx context.Context, name string, args ...string) Result

	// RunTimeout is a convenience wrapper: creates a context with the given timeout.
	RunTimeout(timeout time.Duration, name string, args ...string) Result

	// ReadFile reads the contents of a file.
	ReadFile(path string) ([]byte, error)

	// WriteFileAtomic writes data to a temp file then renames to path (atomic on same FS).
	WriteFileAtomic(path string, data []byte, perm os.FileMode) error

	// FileExists returns true if path exists (file or directory).
	FileExists(path string) bool

	// MkdirAll creates a directory tree (like os.MkdirAll).
	MkdirAll(path string, perm os.FileMode) error

	// Chown changes file ownership.
	Chown(path string, uid, gid int) error

	// Chmod changes file permissions.
	Chmod(path string, perm os.FileMode) error

	// Remove deletes a file or empty directory.
	Remove(path string) error

	// Symlink creates a symbolic link (newname -> oldname).
	Symlink(oldname, newname string) error

	// Rename atomically renames oldpath to newpath. Same-filesystem
	// semantics equivalent to syscall.Rename. Implementations route
	// through whatever primitive their host abstraction provides
	// (RealExecutor uses os.Rename; MockExecutor records the call and
	// updates its in-memory file map).
	//
	// Added in PR-26-code-B per §43.2 lock to replace the previous
	// Run("mv", ...) indirection used by restore_deps_csf.go's A.3
	// binary-restore step. Mutation surface is bounded by
	// INV-PR26-NEW-MUTATION-SURFACES-BOUNDED (§44 row 2).
	Rename(oldpath, newpath string) error

	// Stat returns the FileMeta (mode / uid / gid / size) for a path.
	// Read-only introspection. Added in PR-26-code-C for the CSF
	// cron-backup manifest writer + reader. Per §51.5-A2 invariant,
	// read-only typed introspection is OUTSIDE the bounded-3 mutation
	// cap; no new mutation surface is introduced.
	//
	// Returns an error if the path does not exist or cannot be
	// stat'd (per os.Stat semantics in the real implementation).
	Stat(path string) (FileMeta, error)

	// NftTableExists returns true if the given nft table exists in the kernel.
	// family: "ip", "ip6", or "inet". table: e.g. "nftban".
	NftTableExists(family, table string) bool

	// NftListSet returns the elements of an nft set as a raw string.
	// Returns ("", error) if the set does not exist.
	NftListSet(family, table, set string) (string, error)

	// NftAddElement adds an element to an nft set.
	NftAddElement(family, table, set string, element string) error

	// NftDeleteTable deletes an nft table. Ignores "not found" errors.
	NftDeleteTable(family, table string) error

	// NftCheck runs nft -c -f on the given config content (syntax validation).
	// Returns nil if valid, error with details if invalid.
	NftCheck(configContent string) error

	// ServiceActive returns true if the systemd unit is active.
	ServiceActive(unit string) bool

	// ServiceEnable enables a systemd unit.
	ServiceEnable(unit string) error

	// ServiceStart starts a systemd unit.
	ServiceStart(unit string) error

	// ServiceStop stops a systemd unit.
	ServiceStop(unit string) error

	// ServiceDisable disables a systemd unit.
	ServiceDisable(unit string) error

	// ServiceMask masks a systemd unit (prevents start by any means).
	ServiceMask(unit string) error

	// ServiceUnmask unmasks a systemd unit (inverse of ServiceMask).
	// Used by the CSF restore A.1 step. Added in PR-26-code-B per
	// §43.2 lock to replace the previous
	// Run("systemctl", "unmask", ...) indirection. Mutation surface
	// is bounded by INV-PR26-NEW-MUTATION-SURFACES-BOUNDED (§44 row 2).
	ServiceUnmask(unit string) error

	// ServiceResetFailed clears systemd's "failed" state for a unit
	// (the `Result: signal` / `Result: exit-code` cosmetic marker that
	// persists after stop/mask escalation paths). Used by takeover
	// after successful ServiceMask of conflicting firewalls (csf, lfd,
	// future ufw / firewalld) so `systemctl --failed` does not show
	// stale entries for units nftban intentionally tore down.
	// PR-P1 / closes #524.
	//
	// Mutation surface bounded: callers must only invoke for units
	// they have just successfully masked. The restore path does NOT
	// call ServiceResetFailed (re-arming the watchdog is restore-side
	// and out of scope per Amendment 1 §31).
	ServiceResetFailed(unit string) error

	// DaemonReload runs systemctl daemon-reload.
	DaemonReload() error

	// CommandExists returns true if the named command is in PATH.
	CommandExists(name string) bool

	// UserExists returns true if the named system user exists.
	UserExists(name string) bool

	// GroupExists returns true if the named system group exists.
	GroupExists(name string) bool

	// Getenv returns the value of an environment variable.
	Getenv(key string) string
}

Executor contract (frozen):

Command execution:

  • Run: execute a command, return exit code + output
  • RunContext: execute with context (for timeout/cancellation)

File operations:

  • ReadFile / WriteFileAtomic / FileExists / MkdirAll
  • Chown / Chmod / Remove / Symlink

nftables queries:

  • NftTableExists / NftListSet / NftAddElement / NftDeleteTable / NftCheck

systemd:

  • ServiceActive / ServiceEnable / ServiceStart / ServiceStop
  • ServiceDisable / ServiceMask / ServiceUnmask / DaemonReload

File operations (atomic):

  • Rename — atomic same-filesystem rename via os.Rename

File metadata (read-only introspection):

  • Stat — return mode/uid/gid/size for a path

System:

  • CommandExists / UserExists / GroupExists / Getenv

type FileMeta added in v1.100.4

type FileMeta struct {
	Mode os.FileMode
	UID  int
	GID  int
	Size int64
}

FileMeta carries the read-only metadata Stat returns. Added in PR-26-code-C for the CSF cron-backup manifest writer + reader, which need to record and verify mode / uid / gid / size of the backed-up files.

Per §51.5-A2 invariant, this is read-only introspection — it is OUTSIDE the bounded-3 mutation surface cap of INV-PR26-NEW-MUTATION-SURFACES-BOUNDED. No new mutation surface is introduced.

type MockExecutor

type MockExecutor struct {

	// Commands records every command executed (for assertion).
	Commands []RecordedCommand

	// RunResults maps "name:arg1:arg2" to a preset Result.
	// If a command is not in RunResults, it returns exit 0 with empty output.
	RunResults map[string]Result

	// Files maps path -> content for ReadFile/FileExists.
	Files map[string][]byte

	// FileStats maps path -> FileMeta for Stat. PR-26-code-C
	// addition. When a path is in Files but absent from FileStats,
	// Stat synthesizes a default-mode (0644 root:root) FileMeta with
	// Size derived from the in-memory content. Tests that need to
	// pin specific mode/uid/gid populate FileStats explicitly.
	FileStats map[string]FileMeta

	// WrittenFiles records what was written via WriteFileAtomic.
	WrittenFiles map[string][]byte

	// Dirs records directories created via MkdirAll.
	Dirs map[string]bool

	// NftTables maps "family:table" -> exists.
	NftTables map[string]bool

	// NftSets maps "family:table:set" -> element list as string.
	NftSets map[string]string

	// Services maps "unit" -> active.
	Services map[string]bool

	// Users maps "name" -> exists.
	Users map[string]bool

	// Groups maps "name" -> exists.
	Groups map[string]bool

	// Env maps "key" -> value.
	Env map[string]string

	// ExistingCommands maps "name" -> exists.
	ExistingCommands map[string]bool

	// PR-26-code-B: typed-method error injection. When set non-nil,
	// the corresponding typed method returns the assigned error
	// instead of nil. Mirrors the RunResults pattern that controls
	// Run() exit codes.
	ServiceMaskErr        error
	ServiceUnmaskErr      error
	ServiceResetFailedErr error
	RenameErr             error
	// contains filtered or unexported fields
}

MockExecutor implements Executor with in-memory state for testing.

func NewMockExecutor

func NewMockExecutor() *MockExecutor

NewMockExecutor creates a MockExecutor with all maps initialized.

func (*MockExecutor) Chmod

func (m *MockExecutor) Chmod(_ string, _ os.FileMode) error

func (*MockExecutor) Chown

func (m *MockExecutor) Chown(_ string, _, _ int) error

func (*MockExecutor) CommandCallCount added in v1.98.0

func (m *MockExecutor) CommandCallCount(nameAndArgs ...string) int

CommandCallCount returns how many times a command matching the given prefix was recorded.

func (*MockExecutor) CommandCalled added in v1.98.0

func (m *MockExecutor) CommandCalled(nameAndArgs ...string) bool

CommandCalled returns true if a command matching the given name and args prefix was recorded.

func (*MockExecutor) CommandExists

func (m *MockExecutor) CommandExists(name string) bool

func (*MockExecutor) DaemonReload

func (m *MockExecutor) DaemonReload() error

func (*MockExecutor) FileExists

func (m *MockExecutor) FileExists(path string) bool

func (*MockExecutor) Getenv

func (m *MockExecutor) Getenv(key string) string

func (*MockExecutor) GroupExists

func (m *MockExecutor) GroupExists(name string) bool

func (*MockExecutor) MkdirAll

func (m *MockExecutor) MkdirAll(path string, _ os.FileMode) error

func (*MockExecutor) NftAddElement

func (m *MockExecutor) NftAddElement(family, table, set string, element string) error

func (*MockExecutor) NftCheck

func (m *MockExecutor) NftCheck(_ string) error

func (*MockExecutor) NftDeleteTable

func (m *MockExecutor) NftDeleteTable(family, table string) error

func (*MockExecutor) NftListSet

func (m *MockExecutor) NftListSet(family, table, set string) (string, error)

func (*MockExecutor) NftTableExists

func (m *MockExecutor) NftTableExists(family, table string) bool

func (*MockExecutor) OnCommand added in v1.98.0

func (m *MockExecutor) OnCommand(fn func(), name string, args ...string)

OnCommand registers a callback that fires when a specific command is executed. Use for simulating side-effects (e.g., fixing a service state after permissions enforce).

func (*MockExecutor) ReadFile

func (m *MockExecutor) ReadFile(path string) ([]byte, error)

func (*MockExecutor) Remove

func (m *MockExecutor) Remove(path string) error

func (*MockExecutor) Rename added in v1.100.4

func (m *MockExecutor) Rename(oldpath, newpath string) error

Rename simulates atomic rename in the mock's in-memory file map and records a "rename" command for trace assertions. Returns m.RenameErr (nil by default); when non-nil, the file map is left unchanged (matching real-world atomic-rename failure semantics). PR-26-code-B addition.

func (*MockExecutor) Run

func (m *MockExecutor) Run(name string, args ...string) Result

func (*MockExecutor) RunContext

func (m *MockExecutor) RunContext(_ context.Context, name string, args ...string) Result

func (*MockExecutor) RunTimeout

func (m *MockExecutor) RunTimeout(_ time.Duration, name string, args ...string) Result

func (*MockExecutor) ServiceActive

func (m *MockExecutor) ServiceActive(unit string) bool

func (*MockExecutor) ServiceDisable

func (m *MockExecutor) ServiceDisable(unit string) error

func (*MockExecutor) ServiceEnable

func (m *MockExecutor) ServiceEnable(unit string) error

func (*MockExecutor) ServiceMask

func (m *MockExecutor) ServiceMask(unit string) error

func (*MockExecutor) ServiceResetFailed added in v1.102.0

func (m *MockExecutor) ServiceResetFailed(unit string) error

ServiceResetFailed records a systemctl reset-failed call and returns m.ServiceResetFailedErr (nil by default). Mirrors ServiceUnmask semantics for parity. PR-P1 addition (closes #524).

func (*MockExecutor) ServiceStart

func (m *MockExecutor) ServiceStart(unit string) error

func (*MockExecutor) ServiceStop

func (m *MockExecutor) ServiceStop(unit string) error

func (*MockExecutor) ServiceUnmask added in v1.100.4

func (m *MockExecutor) ServiceUnmask(unit string) error

ServiceUnmask records a systemctl unmask call and returns m.ServiceUnmaskErr (nil by default). Mirrors ServiceMask semantics for parity. PR-26-code-B addition.

func (*MockExecutor) Stat added in v1.100.4

func (m *MockExecutor) Stat(path string) (FileMeta, error)

Stat returns FileMeta from FileStats if explicitly set; otherwise synthesizes a default-mode (0644 root:root) entry with Size derived from the in-memory content. Returns os.ErrNotExist if neither FileStats nor Files contains the path. PR-26-code-C addition.

func (m *MockExecutor) Symlink(_, _ string) error

func (*MockExecutor) UserExists

func (m *MockExecutor) UserExists(name string) bool

func (*MockExecutor) WriteFileAtomic

func (m *MockExecutor) WriteFileAtomic(path string, data []byte, _ os.FileMode) error

type RealExecutor

type RealExecutor struct{}

RealExecutor implements Executor using real system calls.

func (*RealExecutor) Chmod

func (r *RealExecutor) Chmod(path string, perm os.FileMode) error

func (*RealExecutor) Chown

func (r *RealExecutor) Chown(path string, uid, gid int) error

func (*RealExecutor) CommandExists

func (r *RealExecutor) CommandExists(name string) bool

func (*RealExecutor) DaemonReload

func (r *RealExecutor) DaemonReload() error

func (*RealExecutor) FileExists

func (r *RealExecutor) FileExists(path string) bool

func (*RealExecutor) Getenv

func (r *RealExecutor) Getenv(key string) string

func (*RealExecutor) GroupExists

func (r *RealExecutor) GroupExists(name string) bool

func (*RealExecutor) MkdirAll

func (r *RealExecutor) MkdirAll(path string, perm os.FileMode) error

func (*RealExecutor) NftAddElement

func (r *RealExecutor) NftAddElement(family, table, set string, element string) error

func (*RealExecutor) NftCheck

func (r *RealExecutor) NftCheck(configContent string) error

func (*RealExecutor) NftDeleteTable

func (r *RealExecutor) NftDeleteTable(family, table string) error

func (*RealExecutor) NftListSet

func (r *RealExecutor) NftListSet(family, table, set string) (string, error)

func (*RealExecutor) NftTableExists

func (r *RealExecutor) NftTableExists(family, table string) bool

func (*RealExecutor) ReadFile

func (r *RealExecutor) ReadFile(path string) ([]byte, error)

func (*RealExecutor) Remove

func (r *RealExecutor) Remove(path string) error

func (*RealExecutor) Rename added in v1.100.4

func (r *RealExecutor) Rename(oldpath, newpath string) error

Rename atomically renames oldpath to newpath via os.Rename. Same- filesystem semantics; cross-filesystem renames will return an error per the os.Rename contract (the caller must ensure same-FS).

Added in PR-26-code-B per §43.2: replaces the prior Run("mv", ...) indirection used by restore_deps_csf.go's A.3 step. Routing through os.Rename (rather than shelling to mv) avoids a process spawn and gives a typed error path consistent with WriteFileAtomic.

func (*RealExecutor) Run

func (r *RealExecutor) Run(name string, args ...string) Result

func (*RealExecutor) RunContext

func (r *RealExecutor) RunContext(ctx context.Context, name string, args ...string) Result

func (*RealExecutor) RunTimeout

func (r *RealExecutor) RunTimeout(timeout time.Duration, name string, args ...string) Result

func (*RealExecutor) ServiceActive

func (r *RealExecutor) ServiceActive(unit string) bool

func (*RealExecutor) ServiceDisable

func (r *RealExecutor) ServiceDisable(unit string) error

func (*RealExecutor) ServiceEnable

func (r *RealExecutor) ServiceEnable(unit string) error

func (*RealExecutor) ServiceMask

func (r *RealExecutor) ServiceMask(unit string) error

func (*RealExecutor) ServiceResetFailed added in v1.102.0

func (r *RealExecutor) ServiceResetFailed(unit string) error

func (*RealExecutor) ServiceStart

func (r *RealExecutor) ServiceStart(unit string) error

func (*RealExecutor) ServiceStop

func (r *RealExecutor) ServiceStop(unit string) error

func (*RealExecutor) ServiceUnmask added in v1.100.4

func (r *RealExecutor) ServiceUnmask(unit string) error

func (*RealExecutor) Stat added in v1.100.4

func (r *RealExecutor) Stat(path string) (FileMeta, error)

Stat returns FileMeta (mode/uid/gid/size) via os.Stat + syscall.Stat_t. Read-only introspection. Added in PR-26-code-C for the CSF cron-backup manifest writer + reader.

On non-POSIX hosts (Windows), uid/gid extraction would not work as written; the production target is Linux only, so this is acceptable.

func (r *RealExecutor) Symlink(oldname, newname string) error

func (*RealExecutor) UserExists

func (r *RealExecutor) UserExists(name string) bool

func (*RealExecutor) WriteFileAtomic

func (r *RealExecutor) WriteFileAtomic(path string, data []byte, perm os.FileMode) error

type RecordedCommand

type RecordedCommand struct {
	Name string
	Args []string
}

RecordedCommand tracks a command that was executed.

type Result

type Result struct {
	ExitCode int
	Stdout   string
	Stderr   string
}

Result holds the output of an executed command.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL