run
run
¶
Subprocess execution boundary for all external commands.
Every shell-out in terok-shield flows through the CommandRunner
protocol. Production code uses SubprocessRunner; tests inject
fakes. This keeps external dependencies auditable and mockable in one
place.
CommandRunner
¶
Bases: Protocol
Protocol for executing external commands.
Decouples all subprocess calls behind a testable interface.
SubprocessRunner()
¶
Default CommandRunner implementation using subprocess.run.
Resolves the nft binary path at construction time and raises
NftNotFoundError immediately if nft is not installed.
Resolve the nft binary path, raising NftNotFoundError if missing.
Source code in src/terok_shield/run.py
run(cmd, *, check=True, stdin=None, timeout=None)
¶
Run a command, return stdout. Raise ExecError on failure when check=True.
Source code in src/terok_shield/run.py
has(name)
¶
Return True if an executable is on PATH or a sbin dir (cached).
sbin-aware for the same reason as find_nft: Debian-family login
shells omit /usr/sbin, and a plain which() there would silently
downgrade the DNS tier by "missing" dnsmasq.
Source code in src/terok_shield/run.py
nft(*args, stdin=None, check=True)
¶
Run nft command directly (hook mode, inside container netns).
Source code in src/terok_shield/run.py
nft_via_nsenter(container, *args, pid=None, stdin=None, check=True)
¶
Run nft inside a running container's network namespace.
Source code in src/terok_shield/run.py
podman_inspect(container, fmt)
¶
dig_all(domain, *, timeout=10)
¶
Resolve domain to both IPv4 and IPv6 addresses in a single query.
Runs dig +short domain A domain AAAA and validates each line
with ipaddress. Returns empty list on lookup failure or
timeout.
Raises:
| Type | Description |
|---|---|
DigNotFoundError
|
If |
Source code in src/terok_shield/run.py
getent_hosts(domain)
¶
Resolve domain via NSS (fallback when dig is missing or broken).
Queries both address families explicitly: plain getent hosts
stops at the first family glibc resolves (AAAA for dual-stack
names), which left allow_v4 empty on the one host whose dig
crashes -- an allowed literal-IPv4 target then hit the terminal
reject as "Host is unreachable" (terok#1119).
Source code in src/terok_shield/run.py
ExecError(cmd, rc, stderr)
¶
Bases: Exception
Raised when a subprocess fails.
Store command details and format the error message.
Source code in src/terok_shield/run.py
NftNotFoundError
¶
Bases: RuntimeError
Raised when the nft binary is not found on the host.
DigNotFoundError
¶
Bases: RuntimeError
Raised when the dig binary is not found on the host.
DNS resolution requires dig (from bind-utils / dnsutils).
ShieldNeedsSetup
¶
Bases: RuntimeError
Raised when global OCI hooks are not installed.
Per-container --hooks-dir does not persist across container
restarts, so global hooks are required. The message includes
system-specific setup hints.
which_sbin_aware(name)
¶
Resolve name like shutil.which, falling back to the sbin dirs.
Login shells on the Debian family exclude /usr/sbin from PATH, so
a plain which() misses sbin-installed daemons (dnsmasq) — and the DNS
tier silently downgrades to dig. shutil.which with an explicit
path= keeps the executability check identical to PATH resolution.
Source code in src/terok_shield/run.py
find_nft()
¶
Locate the nft binary, checking PATH then common sbin directories.
sbin directories are checked explicitly because rootless users often lack them in PATH. Returns empty string if not found.