Image preparation¶
This chapter covers trusted-host acquisition, preparation and the evidence retained with reusable images. Follow CLI-first arena workflow for the shorter create/SSH workflow, and AI-assisted work for trust roles and authority. Preparation is a current host-side operation, not an untrusted agent task: it does not install or start arena services. The environment operator selects permitted inputs under the accepted policy; a prepared image is not acceptance of agent-generated work.
Run from a trusted Shyft checkout on the rootless Linux provisioning host, outside execution containers and writable task mounts. Prerequisites: working rootless Buildah/Podman and subordinate IDs, Python 3.11+, jq, Git; public sources also require Skopeo and registry/distribution repository access. Keep package/signature failures intact and fix trusted inputs rather than disabling checks.
Image lifecycle at a glance¶
A named selection records a profile, reviewed inputs and an immutable local image ID. Its output tag is a convenient reference; the recorded ID identifies what arena deployment must validate. Source admission, byte identity and origin evidence are different decisions, not a single universal “verified” status.
---
config:
flowchart:
nodeSpacing: 20
rankSpacing: 28
subGraphTitleMargin:
bottom: 24
top: 8
---
flowchart TD
E["External inputs<br/>registries + distribution repositories"] --> H
A["Upstream agent inputs<br/>archives, metadata + signatures"] --> H
L["Operator-supplied local inputs<br/>images + retained bundles"] --> H
subgraph HOST["Trusted provisioning host"]
H["Human operator guard<br/>permitted sources + required acceptance"] --> P["Host preparation tools<br/>Buildah / Podman / Skopeo + artifact checks"]
P -->|"profile-specific checks; resolve / prepare"| I["Immutable local image ID"]
P --> N["Private named selection<br/>provenance + operation records"]
I --- N
end
N -->|"explicit create / add / refresh"| D["Separate deployment guard<br/>arena.py validates selected local IDs"]
D --> R["Execution member<br/>untrusted agent + task workspace"]
classDef record fill:#f8fafc,stroke:#777777,color:#333333
classDef untrusted fill:#fbe1dc,stroke:#a74432,color:#54251e
classDef guard fill:#e4effb,stroke:#35669a,color:#193d62
classDef external fill:#eeeeee,stroke:#666666,color:#333333
class R untrusted
class H,P,D guard
class E,A,L external
class I,N record
style HOST fill:#f8fafc,stroke:#777777
Inputs and host-side checks precede a separate deployment decision; preparation does not change running services.¶
Gray input labels do not imply trust; blue labels identify operator and tool controls, and red/orange identifies untrusted execution. These are conceptual gates, not a claim that every input has the same authentication mechanism:
A hash or image digest establishes byte identity, not origin.
Release metadata and checksums alone are not independent publisher authentication.
Operator acceptance permits a selected source; it is not cryptographic attestation. Codex’s signature checks and OpenCode’s unsigned-source caveat are described separately in Fedora agents: explicitly selected local bundles.
Select an acquisition branch¶
Branch |
Trusted-host connectivity |
Input and evidence requirements |
|---|---|---|
Public registry source |
Registry acquisition/resolution and recipe package repositories. |
Permitted reference resolved to an immutable identity; recorded provenance does not by itself authenticate the publisher. |
Pre-existing local source |
No registry access for that source; package installation can still need distribution repositories. |
Existing local image inspected by ID, with local provenance; not an invented public-registry origin. |
Offline preparation |
Local source required; recipe networking disabled with |
Required distribution packages already installed; agents already present or supplied through the supported local bundle path. Acquire and review bundles beforehand, including any online signature trust-root checks. |
Fedora agent bundles |
Downloads and Codex trust-root updates may need host access; prepared bundles can then be reused locally. |
Both pinned bundles required for development and scripting, with the distinct integrity, signature and acceptance checks below. |
Local or offline input is not inherently trustworthy. Download access during provisioning does not grant the execution member package/vendor access: the baseline runtime has no general external access, with brokered inference the permitted data-export exception. IDE acquisition, if needed, is a separate trusted-host procedure in Optional IDE provisioning and named members.
Prepare baseline images and gateways¶
Prepare the Arch development image and gateways:
bash tools/ai/build.sh prepare archlinux-dev \
--source registry.gitlab.com/shyft-os/shyft/archlinux-dev:latest
bash tools/ai/build.sh gateways
bash tools/ai/build.sh status
The outputs are localhost/ai-archlinux-dev:prepared,
localhost/ai-archlinux-squid:prepared, and localhost/ai-caddy:prepared.
Arch Squid is built; registry.access.redhat.com/hi/caddy:latest is acquired
unmodified. Fedora Squid is selectable with gateways --squid fedora44.
Use gateways --squid-source REF --caddy-source REF and
--squid-output localhost/REPO:TAG --caddy-output localhost/REPO:TAG for overrides.
Gateway operations are sequential: a successful Squid selection remains recorded
if Caddy fails; rerunning reuses Squid before retrying Caddy.
Local-source alternative, with a separate named selection:
bash tools/ai/build.sh prepare archlinux-dev \
--source localhost/archlinux-dev:next --name local-dev
Local sources are inspected and used by image ID without registry access.
Their provenance records their local reference and identity, never the configured
public default. --offline requires a local source, disables recipe networking
and requires the recipe distribution packages already installed. Agents must
already exist in that source or be supplied through the supported local bundle
path described below. Ordinary local preparation can still use the distribution
repositories for package installation.
Arch online recipes retain their existing explicit package update behavior.
Fedora agents: explicitly selected local bundles¶
Fedora development and scripting require both reviewed agent bundles. Existing bundles can be supplied directly; bundle integrity and recorded approval/evidence checks run before every preparation or reuse. To prepare new bundles, download fixed archives and official release API metadata to a dedicated host directory outside execution mounts. These commands save files; they do not execute downloaded scripts:
INPUTS="$HOME/.local/share/dev-environment/artifacts/agents"
mkdir -p "$INPUTS"
# Use a new input directory for downloads; no existing file is overwritten.
curl --fail --location --proto '=https' --proto-redir '=https' --no-clobber \
--output "$INPUTS/opencode.tar.gz" \
https://github.com/anomalyco/opencode/releases/download/v1.18.35/opencode-linux-x64.tar.gz
curl --fail --location --proto '=https' --proto-redir '=https' --no-clobber \
--output "$INPUTS/opencode-release.json" \
https://api.github.com/repos/anomalyco/opencode/releases/tags/v1.18.35
curl --fail --location --proto '=https' --proto-redir '=https' --no-clobber \
--output "$INPUTS/codex.tar.gz" \
https://github.com/openai/codex/releases/download/rust-v0.162.1/codex-package-x86_64-unknown-linux-musl.tar.gz
curl --fail --location --proto '=https' --proto-redir '=https' --no-clobber \
--output "$INPUTS/codex.sigstore" \
https://github.com/openai/codex/releases/download/rust-v0.162.1/codex-package-x86_64-unknown-linux-musl.tar.gz.sigstore
curl --fail --location --proto '=https' --proto-redir '=https' --no-clobber \
--output "$INPUTS/codex-release.json" \
https://api.github.com/repos/openai/codex/releases/tags/rust-v0.162.1
python3 -B tools/ai/agents/artifacts.py prepare --agent opencode \
--archive "$INPUTS/opencode.tar.gz" --release-metadata "$INPUTS/opencode-release.json" \
--output "$INPUTS/opencode-bundle" --accept-release --accept-unsigned-source
python3 -B tools/ai/agents/artifacts.py prepare --agent codex \
--archive "$INPUTS/codex.tar.gz" --release-metadata "$INPUTS/codex-release.json" \
--signature "$INPUTS/codex.sigstore" --output "$INPUTS/codex-bundle" --accept-release
bash tools/ai/build.sh prepare fedora44-dev \
--opencode-bundle "$INPUTS/opencode-bundle" --codex-bundle "$INPUTS/codex-bundle"
bash tools/ai/build.sh prepare fedora44-scripting \
--source registry.gitlab.com/shyft-os/shyft/fedora44-shyft-app:37.1.0-1.1 \
--opencode-bundle "$INPUTS/opencode-bundle" --codex-bundle "$INPUTS/codex-bundle"
An independently installed, trusted cosign is required for Codex import.
Alternatively supply --verifier-image sha256:FULL_LOCAL_IMAGE_ID for an
independently trusted local cosign image; the existing confined verification
helper is used. Codex requires its pinned sidecar, release workflow certificate
identity/issuer, and independent Sigstore roots. Verification may need network
access to authenticated trust-root updates; no ignore/bypass flags are provided.
Codex import performs Sigstore verification with that independently trusted verifier. Later bundle verification checks the pinned archive, runtime bytes, modes and retained approval/signature evidence; it does not repeat online Sigstore verification or establish fresh origin trust from bundle metadata. Existing-bundle artifact preparation also verifies and reuses the retained bundle. Protect that evidence and its trusted acquisition chain outside execution mounts.
--accept-release records operator acceptance of the selected pinned release and
runtime assurance limits. OpenCode additionally requires
--accept-unsigned-source: its pinned SHA256 and official HTTPS/API asset metadata
are checked, but it has no independent publisher signature. Acceptance is not
cryptographic authentication. The tool creates and retains approval JSON itself;
operators do not write it. Both bundles retain complete archives and manifests,
reject unsafe archive entries and validate runtime bytes/modes. Rerunning artifact
preparation verifies and reuses an identical existing bundle; mismatches require
a new output path. Versions remain OpenCode 1.18.35 and Codex 0.162.1 for Fedora.
The scripting source defaults to
registry.gitlab.com/shyft-os/shyft/fedora44-shyft-app:37.1.0-1.1; the existing
recipe compares Shyft RPM versions/import paths before and after extension.
Selection, details and refresh¶
--name NAME selects an independent stable preparation record and output tag;
--output localhost/REPO:TAG explicitly selects an output reference. Output
names must be local and unused. Identical reruns inspect and reuse recorded
outputs without resolving a floating registry tag again. A moved local source,
changed recipe/bundle, or changed/missing output is a conflict, not an automatic
upgrade. Refresh deliberately re-resolves public sources and runs the recipe,
using a new generated output tag; it retains previous images and operation records:
bash tools/ai/build.sh refresh archlinux-dev
bash tools/ai/build.sh refresh archlinux-dev --name local-dev
bash tools/ai/build.sh gateways --refresh
bash tools/ai/build.sh status
Refresh inherits the selected source, agent bundle paths and offline selection;
--source, bundle flags and --output override those inputs. For a named record,
repeat its --name. An immutable registry input already in storage is reused
only when its manifest digest matches; conflicts are refused without overwrite.
A failed build retains logs but publishes no successful selection. If a helper
has committed an image before a later recording failure, a rerun refuses that
existing output; choose a new --output or refresh rather than overwriting it.
Deployment, refresh and image rollback¶
Preparation refresh advances a selection to a new local identity; existing
members still use their deployed identity. arena.py create/add/refresh consumes
selection names, not arbitrary tags or JSON paths, and does not pull or build.
The managed refresh procedure and rollback commands are in CLI-first arena workflow
and Arena administration reference.
---
config:
flowchart:
nodeSpacing: 22
rankSpacing: 28
---
flowchart TD
I["Initial prepared selection<br/>immutable local ID"] --> C["Explicit arena create"]
C --> R["Running member<br/>untrusted task execution"]
I -.-> F["build.sh refresh<br/>new selected ID; prior image retained"]
F --> D["Explicit arena refresh<br/>authorize interruption with --stop-running"]
D --> R
D -.-> B["Explicit image rollback<br/>retained prior deployed ID only"]
B --> R
classDef record fill:#f8fafc,stroke:#777777,color:#333333
classDef untrusted fill:#fbe1dc,stroke:#a74432,color:#54251e
classDef guard fill:#e4effb,stroke:#35669a,color:#193d62
class R untrusted
class C,F,D,B guard
class I record
Image preparation and deployment are separate actions; rollback changes an image identity, never persistent data.¶
Solid deployment arrows require an explicit arena operation; dashed branches
are optional maintenance. An unchanged deployed image is a no-op. Refreshing
running affected services requires --stop-running; gateway refresh temporarily
interrupts all members’ inference. Neither operation expands runtime egress.
Saved workspace/data mounts, private runtime/cache state and SSH keys persist across image replacement. Processes stop and unsaved data may be lost. Stopping containers does not stop independent host writers. Image rollback restores a retained prior deployed image ID, not historical workspace, agent or cache contents, and cannot undo data migrations. Persistent state is not a backup: arrange data backups separately before changes that may affect it.
Evidence, conflicts and failure behavior¶
Private host state defaults to
$HOME/.local/share/dev-environment/image-preparation. Completion prints the
output, profile and selection-record path. selections/NAME.json is the
machine-readable current selection for arena creation;
operations/ID/ holds request/result or failure JSON, operation logs and helper
provenance/inspection. No evidence path, run identifier, digest extraction or jq
is needed. --state /absolute/private/path overrides host state for every command;
keep it outside every execution mount. The default sits inside the canonical
management root, which existing workspace/data validation excludes from mounts.
A host lock serializes preparation in that state root. Trusted host operators
must also avoid concurrent mutations through independent Buildah commands.
Treat operation records and logs as sensitive operational evidence. Do not expose
them through execution mounts or collect credentials, raw authorization headers
or private source material for documentation. Completion plus build.sh status
should identify the profile, output and current selection. Inspect failure records
when preparation fails; do not treat a partial gateway result as a complete
selection set or bypass a conflict to force reuse.
Image preparation preserves the existing least privilege, agent configuration, SSH and user-mapping contracts. It is not security verification or certification of inference/file tools, isolation, IDE, SELinux or deployment readiness.
Use prepared images in an arena¶
Follow CLI-first arena workflow for create/status/SSH, refresh,
add and remove. arena.py --images SELECTION consumes the preparation record,
not an output tag or JSON filename. build.sh refresh prepares a new image;
arena.py refresh deliberately deploys that already prepared identity.
For state/ownership and recovery, use Arena administration reference; for package, artifact or conflict failures, use Arena troubleshooting and known issues. Scoped checks belong in Bounded security verification, not this preparation step. Read Known issues and assurance limits before agent use: the Codex file-tool sandbox failure and incomplete bridge-gateway host-service isolation remain known limitations. Local mock OpenCode success is not real-provider acceptance or whole-boundary assurance.