pin the base image to a digest, with TTL refresh and audit labels
A tag is a moving pointer, and three things conspired to make the base immutable-in-practice while mutable-in-theory: image_hash() hashed the string "ubuntu:24.04" rather than what it resolves to, ensure_image() returns early when the tag exists, and podman build's pull policy is "missing" -- so even 'build --rebuild' rebuilt on the cached base. A Canonical patch simply never arrived, and nothing said so. Now the tag is resolved to a registry digest (skopeo, falling back to a pull unless AISB_BASE_PULL_FALLBACK=0), recorded per-ref under $AISB_CACHE_DIR/base/ at 0600, and used in FROM *and* in image_hash(): refreshing the base produces a new image instead of mutating one a sandbox may be running. Freshness is a TTL (AISB_BASE_TTL_DAYS=7, 0 every build, -1 never) plus an explicit 'update' / 'update --check'. Two rules keep it usable rather than merely strict. A stale pin beats a mutable tag: offline or with AISB_BASE_AUTO_UPDATE=0 the recorded digest is still used, and only a build with no digest at all is allowed -- announced as UNPINNED, labelled that way, warned about by doctor. And preview modes stay deterministic: --print-* never reach the network, inspect is the surface that asks the machine now. Both images carry aisb.base-digest / .node / .pi-package / .pi-version labels plus /etc/aisb/manifest.txt of resolved apt versions, which answers "which squid was enforcing this?" after the build log is gone. Tags are named after the base instead of the hardcoded u24- prefix. Bug found on the way: POL[base_digest]="$(base_pin ...)" silently produced unpinned labels, because an assignment inside a command substitution is discarded with the subshell. Helpers return text; callers assign. Also fixed: the manifest step used jq on npm's dependency objects as if they were strings, and a missing Node checksum used to skip verification quietly -- it now warns. 311 assertions pass (unit + e2e), shellcheck clean. LLM-Generated: true
This commit is contained in:
@@ -33,9 +33,22 @@ net = allow
|
||||
# tmpfs_size = 1g
|
||||
|
||||
# --- image -----------------------------------------------------------------
|
||||
# One base for both images (the gate is squid from this distro's apt, not a
|
||||
# third-party image). base_image may itself be pinned: name@sha256:...
|
||||
# base_image = docker.io/library/ubuntu:24.04
|
||||
# node_version = 22.23.4
|
||||
# pi_version = 1.4.0
|
||||
#
|
||||
# The tag is resolved to a registry digest and that digest becomes part of the
|
||||
# image tag, so builds are reproducible and a base patch is visible instead of
|
||||
# quietly folding into an existing image. Every base_ttl_days the digest is
|
||||
# re-resolved -- a manifest read, not a download. 0 re-resolves on every build,
|
||||
# -1 never does.
|
||||
# base_ttl_days = 7
|
||||
#
|
||||
# 0 keeps the recorded digest even past its TTL: nothing reaches the registry
|
||||
# unless you say so. An explicit refresh is `ai-sandbox update [--check]`.
|
||||
# base_auto_update = 1
|
||||
|
||||
# --- behaviour -------------------------------------------------------------
|
||||
# SELinux bind-mount option: ':z' (shared), ':Z' (private) or empty to disable.
|
||||
|
||||
Reference in New Issue
Block a user