Kubernetes and CRI release conformance

The stackie-kubernetes-conformance binary is the release-only proof that the pinned upstream K3s kubelet uses Stackie’s CRI v1 plugin without a container-runtime fallback. It first proves one catalog-mapped image and one ordinary OCI image through a real Kubernetes node, then stops K3s, requires a clean dedicated CRI endpoint, and runs the unmodified version-matched upstream critest suite.

The runner has no focus, skip, retry, flake-attempt, label, or source-patch option. Its only critest behavior inputs are the runtime and image endpoints. Fixed JSON and JUnit destinations are added solely to collect evidence. The compact public summary binds exact artifact and traceability hashes; raw process logs and upstream reports remain private.

Supported release profile

ComponentRequired value
HostLinux amd64 or Linux arm64
Kubernetes distributionReal upstream K3s v1.36.2+k3s1 / Kubernetes v1.36.2
CRI endpointOne dedicated absolute Unix socket, used for runtime and image services
CRI validationUnmodified upstream critest v1.36.0
OCI runtimeUpstream runc v1.4.2
CNI toolsUpstream CNI plugins v1.9.1
Mapped smoke imagenginx:1.28.3, authorized only by its mocker.images catalog entry
Unmatched smoke imageregistry.k8s.io/e2e-test-images/busybox:1.36.1-1

Every upstream artifact comes from the exact HTTPS URL in the plugin’s checked-in lock. Stackie enforces the byte ceiling while downloading, verifies SHA-256 before use, and re-verifies cached bytes. A concurrent run cannot replace an existing cache entry.

What the release proof does

Pinned upstream artifact lock

Agentless real K3s server

Separate K3s agent and upstream kubelet

Dedicated Stackie CRI v1 socket

One Ready node reports Stackie runtime

Mocker-mapped nginx block answers HTTP

Unmatched busybox emits OCI marker

Delete smoke pods and stop K3s

Require zero CRI sandboxes and containers

Complete unmodified critest v1.36.0

100% applicable pass and compact evidence

Stackie flowchart: #stackie-mermaid-0{font-family:Inter Variable,Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-size:16px;fill:#f8fafc;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#stackie-mermaid-0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#stackie-mermaid-0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#stackie-mermaid-0 .error-icon{fill:#111827;}#stackie-mermaid-0 .error-text{fill:#f8fafc;stroke:#f8fafc;}#stackie-mermaid-0 .edge-thickness-normal{stroke-width:1px;}#stackie-mermaid-0 .edge-thickness-thick{stroke-width:3.5px;}#stackie-mermaid-0 .edge-pattern-solid{stroke-dasharray:0;}#stackie-mermaid-0 .edge-thickness-invisible{stroke-width:0;fill:none;}#stackie-mermaid-0 .edge-pattern-dashed{stroke-dasharray:3;}#stackie-mermaid-0 .edge-pattern-dotted{stroke-dasharray:2;}#stackie-mermaid-0 .marker{fill:#facc15;stroke:#facc15;}#stackie-mermaid-0 .marker.cross{stroke:#facc15;}#stackie-mermaid-0 svg{font-family:Inter Variable,Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-size:16px;}#stackie-mermaid-0 p{margin:0;}#stackie-mermaid-0 .label{font-family:Inter Variable,Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;color:#f8fafc;}#stackie-mermaid-0 .cluster-label text{fill:#f8fafc;}#stackie-mermaid-0 .cluster-label span{color:#f8fafc;}#stackie-mermaid-0 .cluster-label span p{background-color:transparent;}#stackie-mermaid-0 .label text,#stackie-mermaid-0 span{fill:#f8fafc;color:#f8fafc;}#stackie-mermaid-0 .node rect,#stackie-mermaid-0 .node circle,#stackie-mermaid-0 .node ellipse,#stackie-mermaid-0 .node polygon,#stackie-mermaid-0 .node path{fill:#1f2937;stroke:#facc15;stroke-width:1px;}#stackie-mermaid-0 .rough-node .label text,#stackie-mermaid-0 .node .label text,#stackie-mermaid-0 .image-shape .label,#stackie-mermaid-0 .icon-shape .label{text-anchor:middle;}#stackie-mermaid-0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#stackie-mermaid-0 .rough-node .label,#stackie-mermaid-0 .node .label,#stackie-mermaid-0 .image-shape .label,#stackie-mermaid-0 .icon-shape .label{text-align:center;}#stackie-mermaid-0 .node.clickable{cursor:pointer;}#stackie-mermaid-0 .root .anchor path{fill:#facc15!important;stroke-width:0;stroke:#facc15;}#stackie-mermaid-0 .arrowheadPath{fill:rgba(255, 255, 255, 0);}#stackie-mermaid-0 .edgePath .path{stroke:#facc15;stroke-width:1px;}#stackie-mermaid-0 .flowchart-link{stroke:#facc15;fill:none;}#stackie-mermaid-0 .edgeLabel{background-color:#171717;text-align:center;}#stackie-mermaid-0 .edgeLabel p{background-color:#171717;}#stackie-mermaid-0 .edgeLabel rect{opacity:0.5;background-color:#171717;fill:#171717;}#stackie-mermaid-0 .labelBkg{background-color:rgba(23, 23, 23, 0.5);}#stackie-mermaid-0 .cluster rect{fill:#111827;stroke:#2dd4bf;stroke-width:1px;}#stackie-mermaid-0 .cluster text{fill:#f8fafc;}#stackie-mermaid-0 .cluster span{color:#f8fafc;}#stackie-mermaid-0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:Inter Variable,Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-size:12px;background:#111827;border:1px solid #2dd4bf;border-radius:2px;pointer-events:none;z-index:100;}#stackie-mermaid-0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#f8fafc;}#stackie-mermaid-0 rect.text{fill:none;stroke-width:0;}#stackie-mermaid-0 .icon-shape,#stackie-mermaid-0 .image-shape{background-color:#171717;text-align:center;}#stackie-mermaid-0 .icon-shape p,#stackie-mermaid-0 .image-shape p{background-color:#171717;padding:2px;}#stackie-mermaid-0 .icon-shape .label rect,#stackie-mermaid-0 .image-shape .label rect{opacity:0.5;background-color:#171717;fill:#171717;}#stackie-mermaid-0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#stackie-mermaid-0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#stackie-mermaid-0 .node .neo-node{stroke:#facc15;}#stackie-mermaid-0 [data-look="neo"].node rect,#stackie-mermaid-0 [data-look="neo"].cluster rect,#stackie-mermaid-0 [data-look="neo"].node polygon{stroke:url(#stackie-mermaid-0-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#stackie-mermaid-0 [data-look="neo"].swimlane.cluster rect{filter:none;}#stackie-mermaid-0 [data-look="neo"].node path{stroke:url(#stackie-mermaid-0-gradient);stroke-width:1px;}#stackie-mermaid-0 [data-look="neo"].node .outer-path{filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#stackie-mermaid-0 [data-look="neo"].node .neo-line path{stroke:#facc15;filter:none;}#stackie-mermaid-0 [data-look="neo"].node circle{stroke:url(#stackie-mermaid-0-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#stackie-mermaid-0 [data-look="neo"].node circle .state-start{fill:#000000;}#stackie-mermaid-0 [data-look="neo"].icon-shape .icon{fill:url(#stackie-mermaid-0-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#stackie-mermaid-0 [data-look="neo"].icon-shape .icon-neo path{stroke:url(#stackie-mermaid-0-gradient);filter:drop-shadow( 1px 2px 2px rgba(185,185,185,1));}#stackie-mermaid-0 :root{--mermaid-font-family:Inter Variable,Inter,ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;}, Pinned upstream artifact lock, Agentless real K3s server, Separate K3s agent and upstream kubelet, Dedicated Stackie CRI v1 socket. Use horizontal scrolling when the full diagram is wider than the visible frame. Generated from Stackie public documentation source.

In text: Stackie verifies the artifacts, starts an agentless K3s server on a reserved loopback port, and then starts a separate K3s agent. That agent’s upstream kubelet receives the same explicit Stackie endpoint for both CRI services. The runner requires exactly one Ready node, a Stackie runtime identity, and no embedded containerd socket. It then observes the catalog annotation and HTTP behavior of mapped nginx plus the digest and log marker of unmatched busybox. After deleting both pods, it stops agent then server, proves that the endpoint is empty, and gives that dedicated endpoint to the complete upstream suite.

K3s supplies the API server, controllers, scheduler, kubelet, and client behavior. Stackie does not reimplement Kubernetes. Managed EKS, GKE, and AKS support is a separate Spaceport follow-up.

Run the release proof

Build the separately selectable conformance package from the exact release commit:

cargo build --locked --release -p stackie-plugin-kubernetes --features conformance --bin stackie-kubernetes-conformance

Start the release CRI plugin with real Mocker compatibility and Stackied workload dependencies on a new dedicated socket. Then choose a reusable artifact cache and two new absolute directories. The run and evidence directories must not already exist or contain each other.

target/release/stackie-kubernetes-conformance run \
  --artifact-dir /var/cache/stackie/kubernetes-conformance \
  --evidence-dir /var/lib/stackie/conformance/evidence-000120 \
  --runtime-endpoint unix:///run/stackie/conformance-000120/cri-v1.sock \
  --image-endpoint unix:///run/stackie/conformance-000120/cri-v1.sock \
  --run-root /var/lib/stackie/conformance/run-000120 \
  --traceability /src/stackie/crates/stackie-plugin-cri/cri-traceability.yaml \
  --release-commit 0123456789abcdef0123456789abcdef01234567

Replace the example object ID with the exact lowercase 40-character parent release commit. The host needs the privileges required by real K3s and the pinned OCI runtime. The endpoint must not be shared with another kubelet, suite, or user workload.

The upstream suite receives exactly the two configurable endpoint arguments plus fixed report destinations:

--runtime-endpoint <dedicated endpoint>
--image-endpoint <same dedicated endpoint>
--report-dir <private fixed directory>
--ginkgo.json-report critest.json
--ginkgo.junit-report critest.xml

The runner exposes no focus, skip, label, fail-fast, retry, flake-attempt, repeat, alternate-test, or source-patch option.

Release decision table

ObservationDecision
Artifact URL, platform, digest, size, or archive layout differsBlock
K3s server is not agentless, endpoints differ, or another runtime socket existsBlock
Node is absent, duplicated, not Ready, or reports a non-Stackie runtimeBlock
Nginx lacks dev.stackie.catalog.block=nginx or its unique host port failsBlock
Busybox is catalog-pinned, lacks an OCI digest, or lacks its log markerBlock
A sandbox or container remains before the suiteBlock
JSON/JUnit is missing, malformed, or disagreesBlock
A failed, panicked, pending, interrupted, aborted, timed-out, or unknown spec appearsBlock
Any skip is not an exact sourced upstream automatic skip in traceabilityBlock
Applicable denominator is empty or passage is below 100%Block
Every applicable spec passes and both reports agreeEligible for release review

Stackie-selected skips are never accepted. A newly legitimate upstream platform, capability, or NRI automatic skip must first be sourced in the canonical CRI applicability overlay, regenerated into traceability, and reviewed before another unmodified run.

Interruption and private evidence

The runner stores its random server token, K3s logs, and upstream reports in owner-only files. It reserves unique server, agent load-balancer, and mapped host ports until the corresponding owner binds them. On interruption it deletes smoke pods when possible, stops agent before server, reaps owned children, and force-cleans suite-owned CRI state after kubelet stops.

If the foreground process or host is lost, do not kill K3s by name and do not delete the run directory. Recover the exact marker-owned run:

target/release/stackie-kubernetes-conformance recover \
  --run-root /var/lib/stackie/conformance/run-000120

Recovery requires each live PID’s verified executable, role, complete argument hash, and owned run-root argument to match /proc. It refuses PID reuse or marker tampering before sending a signal. It cleans only the recorded endpoint and removes only the exact marker-owned directory.

Raw files under evidence/private/ are controlled release-attempt evidence; do not attach them to ordinary tickets or publish them. The owner-only release-evidence.json is the compact review input: it binds the release commit, platform, artifact and traceability hashes, redacted endpoint identity, topology facts, both smoke outcomes, report hashes, sourced skips, denominator counts, and the required 100% applicable passage.