4.3

`sbx kit pack`, `sbx kit push --sign`, and `sbx kit verify`

The sbx kit commands package, sign, push, verify, and show provenance for v1 and v2 artifacts, and kit add appends a mixin to a running sandbox.

You wrote a v2 mixin that installs tree and drops a HELLO.md into the workspace. A colleague wants it without cloning your repository, and your security team wants to know who signed it. The sbx kit commands cover both, as long as the kit is v1 or v2.

When you finish this section, you can validate and pack a v2 kit, and describe what push --sign attaches to the manifest. You can also verify a signature and add a mixin to a running sandbox.

spec.yaml and files/

Mixin (v2): a directory with a spec.yaml whose schemaVersion is "2" and kind is mixin, plus an optional files/ tree. The capture kit wrote one:

the v2 mixin the capture kit wroteyamlFull log
schemaVersion: "2"
kind: mixin
name: hello-mixin
description: Installs tree and adds a greeting file to the workspace.
setup:
  install:
    - command: apt-get update && apt-get install -y tree
      user: "0"
      description: Install tree
permissions:
  network:
    allow:
      - example.com

files/workspace/HELLO.md holds one line, and sbx kit inspect reports it as a workspace file with mode 420 (the capture). The v2 grammar is the one the built-in agents use, and its normative text lives in SPEC-v2.md of docker/sbx-kits-contrib.

validate and pack

sbx kit validate REFERENCE accepts a directory, a ZIP, or a git reference, and --json reports a verdict and warnings:

validate, then packjsonFull log
{
  "reference": "./fixtures/kits/hello-mixin",
  "kind": "directory",
  "valid": true,
  "warnings": []
}
the ZIP that pack wrotetextFull log
$ sbx kit pack ./fixtures/kits/hello-mixin -o $CAPTURE/work/hello-mixin.zip
Packed artifact to $CAPTURE/work/hello-mixin.zip
[exit 0]

$ zip listing of work/hello-mixin.zip (size, name)
       0  files/
       0  files/workspace/
      22  files/workspace/HELLO.md
     297  spec.yaml

For pack, the directory must hold a valid spec.yaml and can hold a files/ directory. The same ZIP validates with kind: "zip" (the capture). A v3 directory fails both commands, as the descriptor section showed. Figure 4.3 draws the whole path, with the steps the capture kit did not run in dashed boxes.

Fig. 4.3from spec.yaml to a signed artifact and into a sandboxflow
From spec.yaml to a signed artifact and into a sandbox Row one, captured: the hello-mixin directory with spec.yaml and files, validated by sbx kit validate and packed by sbx kit pack into hello-mixin.zip. Row two, from the help text and not run: sbx kit sign with a key writes kit.sig.bundle beside spec.yaml, and sbx kit push with the sign flag pushes the manifest to an HTTPS registry with a signature referrer and a provenance referrer. Row three, not run: sbx kit verify and sbx kit provenance read those referrers back, beside the four settings that admit a kit. Row four, captured: sbx create with the kit flag builds m101-kit with tree installed and HELLO.md copied, sbx kit add appends env-mixin to m101-demo in a swap container, and sbx kit add refuses hello-mixin because it declares files. AUTHOR AND PACKAGE (12-VALIDATE.TXT, 12-PACK.TXT) hello-mixin/ spec.yaml, files/ sbx kit validate VALID (directory) sbx kit pack -o Packed artifact to hello-mixin.zip spec.yaml and files/ SIGN AND PUBLISH (HELP-SBX, NOT RUN) sbx kit sign --key writes kit.sig.bundle beside spec.yaml sbx kit push --sign DIR REF, form chosen by schemaVersion 1 or 2 HTTPS registry manifest, config, one layer signature + provenance referrers push READ BACK (NOT RUN) sbx kit verify --key cosign.pub sbx kit provenance UNSIGNED or VERIFIED settings that admit a kit kit.allowedSources, kit.requireSignature, kit.trustedSigners, kit.allowLocalKits CONSUME (12-RUN-KIT.TXT, 12-KIT-ADD.TXT, 12-KIT-ADD-FILES.TXT) sbx create shell --kit m101-kit: tree installed, HELLO.md, allow example.com sbx kit add env-mixin m101-demo recreated in a swap container, variable set sbx kit add hello-mixin refused: the kit declares files Dashed boxes come from the help text and were not run. Every solid box was captured.
A v2 kit is validated and packed on the host, signed and pushed with two referrers, verified from the registry, and consumed by create or kit add. Read row by row. Solid boxes come from the validate, pack, run, and kit-add captures. Dashed boxes follow the help text of sbx kit sign, push, verify, and provenance, which were not run.

sign, push --sign, and pull

The capture kit ran none of these three, because it has no registry and no signing identity. The help text is the source. sbx kit sign is keyless by default, with an OIDC token from the CI provider or a browser login. It never reads a token from SIGSTORE_ID_TOKEN, so a process that can set an environment variable cannot choose the token. With --key it signs with an unencrypted PEM private key. For a local directory, it writes a detached signature bundle to kit.sig.bundle next to spec.yaml.

sbx kit push DIRECTORY REFERENCE chooses the artifact form from schemaVersion: a ZIP for "1", a tar+gzip layer with the spec in the config blob for "2". With --sign, the push signs the manifest and attaches the Sigstore bundle to the kit as an OCI referrer. Every push also attaches a SLSA provenance attestation as an OCI referrer, and that provenance is signed only with --sign. --tlog-upload=false keeps a private kit out of the Rekor log. For pull, the registry must support HTTPS.

The same command signs a published v3 image by reference. A v3 kit that you share as a source directory or a Git reference cannot be signed.

verify, provenance, and the settings that admit a kit

sbx kit verify takes --key PUB for a key, or --certificate-identity with --certificate-oidc-issuer for a keyless signature. --insecure-ignore-tlog accepts a private keyless signature, and the flag changes nothing for a key-based verification. sbx kit provenance REFERENCE prints the attestation, and it reports an attestation as VERIFIED only when it verifies and its subject matches the digest of the kit.

Six settings decide what a sandbox accepts, all at their defaults on the recording host:

the kit settings at their defaultstextFull log
kit.allowExtractedAgents             true                               bool     default             Admit the pinned kit references that replace fo…
kit.allowLocalKits                   true                               bool     default             Allow installing kits from local directories or…
kit.allowedSources                   ["docker.io/"]                     json     default             JSON array of allowed kit source prefixes (e.g.…
kit.ignoreTransparencyLog            false                              bool     default             Verify keyless kit signatures without requiring…
kit.requireSignature                 false                              bool     default             Require a valid signature from a trusted signer…
kit.trustedSigners                   [{"identityRegexp":"^.*@docker\…   json     default             JSON array of trusted signer policies (key-base…
The description column is cut.

When kit.requireSignature is true, sbx rejects unsigned kits, signatures that do not match kit.trustedSigners, and ZIP kits. The default kit.trustedSigners policy trusts Docker employee identities that end in @docker.com, attested by the Google issuer. The settings table lists the environment variable of each key.

kit add and the builder

sbx kit add SANDBOX REFERENCE recreates the container with the mixin added, and it keeps the volumes that kits own, such as agent session state, across the swap. The capture shows the accepted case and the refused one:

kit add accepts env-mixin and refuses hello-mixintextFull log
$ sbx kit add m101-demo ./fixtures/kits/env-mixin
Recreating sandbox "m101-demo" to apply augmented kit list...
  Swap container m101-demo-swap-<id> started (id=<sha256>).
Kit "env-mixin" added to sandbox "m101-demo"
[exit 0]

$ sbx exec m101-demo sh -c 'env | grep M101_FROM_KIT'
M101_FROM_KIT=yes
[exit 0]
a mixin with files is refusedtextFull log
$ sbx kit add m101-demo ./fixtures/kits/hello-mixin
error: kit "hello-mixin" declares files, which the kit-add recreate flow does not yet apply; recreate the sandbox from scratch via `sbx rm` + `sbx create --kit` to use this kit
[exit 1]

Sandboxes created before the recreate-aware label are refused with an error, and long-running@1 cannot be added this way. sbx create shell --kit ./fixtures/kits/hello-mixin applied the same mixin in full: one install command, one workspace file, and one allow rule (the captures).

Source-form builds of v3 kits run in a shared builder sandbox named sbx-kit-builder, which sbx creates on first use. sbx kit builder status reports it, and history passes through to docker buildx history:

the builder before any buildtextFull log
$ sbx kit builder status
Builder:      not created (the first source-form kit build creates it)
Builder kit:  docker.io/docker/sbx-kit-builder:1
Kit registry: 127.0.0.1:5411 — reachable
[exit 0]

Docker Sandboxes (sbx) and Docker Agent (docker-agent) sbx 0.47.0, docker-agent 1.149.0 · bf4169c · 2026-10-07 · Edition 2026.10