<!-- nornir:class: design -->
# OCI image-build + path-extract — killing the last `podman build`/`cp` twin
Additive extension of the OCI backend (`backend-oci`) so a build-in-a-container job
(**Skidbladnir `pack.rs`**: `podman build` a Containerfile → image, then `podman
create` + `podman cp <container>:/out <host>` to capture artifacts) routes through
draupnir's **one** OCI engine instead of a `Command::new("podman")` shell twin.
Companion to [`oci-bind-mounts.md`](oci-bind-mounts.md) (which killed the `podman -v`
twin for `msi.rs`).
## What was added (additive — `BootSpec` and every existing call site UNCHANGED)
Two `ContainerBoot` methods (feature `backend-oci`; honest `Error::Unsupported`
without it, `Error::Backend` when the socket is unreachable — never a fake):
| method | maps the podman twin | over bollard |
|---|---|---|
| `build_image(context_dir, containerfile, tag) -> tag` | `podman build -f <containerfile> -t <tag> <context>` | tar the context (`context_tar`) → `body_full` → `Docker::build_image` (stream; an `error_detail` fails the call) |
| `extract_path(image, container_path, host_dest)` | `podman create <image>` + `podman cp <c>:<path> <host>` + `rm` | `create_container` (un-started) → `download_from_container` (tar stream) → unpack into `host_dest` → force-`remove_container` (even on error) |
- **tar** rides the new `tar` optional dep (in `backend-oci`) — used to *pack* the
build context and *unpack* the downloaded archive. Lean default pulls nothing.
- `context_tar(dir)` is a **pure** fn (daemon-free tested): every file under the
context, nested included, lands at its relative path (archive root `.`).
- The extracted tree is rooted at the basename of `container_path` — the same
layout `podman cp` yields, so the consumer's path handling is unchanged.
- Zero-shell: every step is a bollard REST call, never a `podman`/`docker` subprocess.
## Flow

## Now routed (Skidbladnir side)
`Skidbladnir/src/pack.rs`'s `PodmanBuild::build_into` now drops `Command::new("podman")
build/create/cp` for `ContainerBoot::build_image` + `extract_path` behind the
`pack-oci` feature (default-off, honest podman fallback kept), closing the last of
the two `pack`/`msi` podman twins the dup-audit flagged. The Skidbladnir side
flattens `extract_path`'s basename-rooted (`out/…`) tar to the `podman cp {cid}:/out/.`
contents-in-`into` layout so the manifest stays byte-identical across engines.
Reuse-first: no second engine, no shell.
## Tests
`context_tar_packs_the_build_context` (pure — temp context → tar → read back, asserts
Containerfile + nested file present) · `build_and_extract_are_unsupported_without_the_engine`
(lean build → honest `Unsupported`). backend-oci 37 pass, lean 34 pass.