#!/usr/bin/env bash # tests/unit/06_entrypoint.sh -- the container-side enforcement script. source "$TESTS/lib.sh" PROJ="$WORK/proj"; mkdir -p "$PROJ"; cd "$PROJ" || exit 1 export AISB_CONFIG_DIR="$WORK/cfg-empty"; mkdir -p "$AISB_CONFIG_DIR" # Extract the entrypoint exactly as it is baked into the image. EP="$WORK/entrypoint.sh" "$AISB" --print-entrypoint > "$EP" 2>"$WORK/ep.err"; RC=$? assert_eq 0 "$RC" "the embedded entrypoint can be printed" bash -n "$EP" && _ok "entrypoint is syntactically valid bash" || _bad "entrypoint is syntactically valid bash" grep -q 'set -Eeuo pipefail' "$EP" && _ok "entrypoint is strict" || _bad "entrypoint is strict" t_name "the image is described by the script itself" sb --print-containerfile assert_contains "FROM docker.io/library/ubuntu:24.04" "ubuntu 24.04 base" assert_contains "nftables" "image ships nftables" assert_contains "util-linux" "image ships setpriv (util-linux)" assert_contains "sha256sum -c" "node tarball is checksum verified" assert_contains "useradd" "image creates the sandbox user" assert_contains 'ENTRYPOINT ["/usr/local/lib/aisb/entrypoint.sh"]' "entrypoint is baked in" assert_contains "WORKDIR /project" "project is the default workdir" t_name "generated ruleset shape" # Run the rule generator outside a container (nft is not needed to render it). POL="$WORK/mnt"; mkdir -p "$POL" cat > "$POL/policy.env" < "$POL/direct4.list" printf '::1 8080\n' > "$POL/direct6.list" RULES="$AISB_STATE_DIR/rules.f" # Render the ruleset by extracting the generator and feeding it the policy above. GEN="$WORK/gen.sh" awk '/^gen_rules\(\) \{/{f=1} f{print} f&&/^\}$/{exit}' "$EP" > "$GEN" { printf 'POLICY_DIR=%q\nAISB_PROXY_IPS="100.64.0.1"\nAISB_PROXY_PORTS="18081"\nAISB_ALLOW_ICMP=1\nAISB_ALLOW_DNS=0\n' "$POL" printf 'gen_rules\n'; } >> "$GEN" bash "$GEN" > "$RULES" 2>"$WORK/gen.err" && _ok "rules render" || _bad "rules render" "$(tail -3 "$WORK/gen.err")" grep -q 'table inet aisb' "$RULES" && _ok "inet table (covers v4 and v6)" || _bad "inet table" grep -q 'policy drop' "$RULES" && _ok "default policy is drop" || _bad "default policy drop" grep -q 'aisb-default-drop' "$RULES" && _ok "explicit default-drop rule exists" || _bad "default-drop rule" grep -q 'oifname "lo" accept' "$RULES" && _ok "loopback stays usable" || _bad "loopback accept" grep -q 'ip daddr 10.0.0.5 tcp dport { 5432 }' "$RULES" && _ok "per-entry host:port rule" || _bad "host:port rule: $(grep -c . "$RULES") lines" grep -q 'ip daddr 10.1.0.0/16 tcp dport { 80,443 }' "$RULES" && _ok "CIDR rule with default ports" || _bad "CIDR rule" grep -q 'ip6 daddr ::1 tcp dport { 8080 }' "$RULES" && _ok "ipv6 rule" || _bad "ipv6 rule" grep -q 'ip daddr 100.64.0.1 tcp dport 18081' "$RULES" && _ok "gate endpoint is allowed" || _bad "gate rule" grep -q 'aisb-est' "$RULES" && _ok "established traffic accepted" || _bad "established rule" grep -c 'accept comment "aisb-direct"' "$RULES" | grep -qx 3 && _ok "exactly 3 direct rules" || _bad "direct rule count: $(grep -c 'aisb-direct' "$RULES")" t_name "no DNS hole when the gate is in front" grep -E 'th dport 53' "$RULES" >/dev/null && _bad "DNS is closed in gate mode" || _ok "DNS is closed in gate mode" t_name "privilege drop is the last thing that happens" tail -5 "$EP" | grep -q 'setpriv' && _ok "exec setpriv at the end" || _bad "setpriv last: $(tail -3 "$EP" | tr '\n' ' ')" grep -q -- '--bounding-set=-all' "$EP" && _ok "bounding set cleared" || _bad "bounding set cleared" grep -q -- '--inh-caps=-all' "$EP" && _ok "inheritable caps cleared" || _bad "inheritable caps cleared" grep -q -- '--no-new-privs' "$EP" && _ok "no new privileges" || _bad "no-new-privs" grep -q -- '--reuid=' "$EP" && _ok "uid switched" || _bad "reuid" grep -q 'fail "policy file' "$EP" && _ok "missing policy = refuse to start" || _bad "fail closed on missing policy" grep -q 'refusing to start\|Refusing to run unenforced' "$EP" && _ok "missing NET_ADMIN = refuse to start" || _bad "fail closed without NET_ADMIN"