Your browser sucks, JavaScript disabled! Gunnar's console needs JavaScript and WebAssembly. Git over SSH on port 2222 does not.

nordisk/Skidbladnir

.nornir/msi-oci-routing.md

MSI build → draupnir's ONE OCI engine (killing a podman -v twin)

dup-audit P1. Skidbladnir shelled Command::new("podman") -v … in two places; the constellation law is ONE container engine (draupnir's backend-oci, pure-Rust bollard over the podman/Docker REST API), zero shell. draupnir landed run_to_completion_with_binds (host -v binds) for exactly this — so the run-an-image twin now routes through it.

What changed

src/msi.rs WixBuilder::build — the WiX v4 / Wine MSI build is a podman run --rm -v work:/work <image> wine wix.exe build, i.e. run-an-existing-image-to-completion with one bind. That maps 1:1 onto draupnir:

WXS render + harvest (staged workdir)          ── unchanged, always real
        │
        ▼
#[cfg(feature = "msi-oci")]                     ── zero-shell path
  BootSpec::container("skidbladnir-wix-msi", image)
     .with_cmd([wine, wix.exe, build, /work/Product.wxs, -o, /work/out.msi])
  ContainerBoot::run_to_completion_with_binds(spec, RunOptions::default(),
                                              ["<workdir>:/work"])   ← draupnir, ONE engine
     └─ exit_code != Some(0) → honest bail (never a fake MSI)
        │
#[cfg(not(feature = "msi-oci"))]                ── lean fallback (kept, honest)
  podman_available() ? Command::new("podman") run : bail("needs podman …")
        │
        ▼
/work/out.msi  ──(bind)──▶  work/out.msi  ──▶  copy to `out`

Also routed now: src/pack.rs (pack-oci)

PodmanBuild::build_into does podman **build** (image build from a rendered Containerfile) + podman create + podman cp (extract /out). draupnir since grew the missing surface — ContainerBoot::build_image (tars the context → daemon /build) and ContainerBoot::extract_path (the create+cp twin) — so the second half of this twin now routes too, behind the pack-oci feature (default-off, same lean posture as msi-oci).

render Containerfile → ctx  +  tag                 ── unchanged, shared
        │
        ▼
#[cfg(feature = "pack-oci")]                        ── zero-shell path
  ContainerBoot::build_image(ctx, "Containerfile", tag)      ← draupnir, ONE engine
  ContainerBoot::extract_path(tag, "/out", tmp)              ← create+cp twin
     └─ extract roots the tar at the basename → tmp/out/…
     └─ copy_tree_contents(tmp/out, into)  ── flatten to the `cp {cid}:/out/.` layout
        (both engines leave `into` BYTE-IDENTICAL → same `walk` manifest)
        │
#[cfg(not(feature = "pack-oci"))]                   ── lean fallback (kept, honest)
  runtime_available() ? podman build/create/cp : bail("needs podman … or --features pack-oci")
        │
        ▼
walk(into) → sorted relative paths (engine-agnostic manifest)

Reuse (Law #1)

Zero new container code here — the whole engine is draupnir's; this only swaps the call. Second engine? none. Shell? none (under the feature).