ship-artifact · git:20260806.146d8e8 · 2026-08-06 · sha256 da9fceccceefd8f1
ship-artifact git:20260806.146d8e8A
Immutable. This exact content never changes and is served at /api/v1/blob/da9fceccceefd8f1.
---
name: ship-artifact
description: "Package immutable release artifacts with provenance evidence."
---
## OBJECTIVE
**IMMUTABLE REALITY.**
Turn code into a portable artifact that can be traced, verified, and rejected automatically if the supply chain is wrong.
**The Law**:
1. **Traceable**: Every artifact points to an exact repo, full Git commit, builder, and build time.
2. **Portable**: Ship the smallest practical runtime; public CLI releases should prefer self-contained/static binaries when the stack supports it.
3. **Verifiable**: Publish digests, checksums, signatures, SBOM, and provenance that a consumer can verify independently.
4. **Policy-Enforced**: Unsigned, unscanned, or unverifiable artifacts do not get promoted.
5. **Reproducible by Proof**: If you claim "same source, same artifact", pin inputs and prove it with repeated-build verification.
## PROTOCOL
### Phase 1: Release Identity (Naming)
*No "v1.0". Use specifics.*
1. **Primary Identity**: The image digest or binary checksum. Tags are pointers, not truth.
2. **Commit Tag**: `sha-a1b2c3d` for operator convenience.
3. **Semantic Tag**: `v1.2.3` only for an intentional release.
4. **Latest Tag**: **DANGER**. Only update `latest` after successful verification and deployment.
5. **Release Bundle**: For non-OCI artifacts, publish `SHA256SUMS`, signatures, SBOM, and provenance together.
6. **Release Manifest**: Publish one machine-readable record that binds Git SHA, artifact digest/checksum, bundle hash, version, SBOM path, and provenance path.
### Phase 2: Build for Portability
*The world is not just Intel.*
1. **Setup**: Use `docker buildx` for OCI artifacts and an isolated builder for non-container releases.
2. **Canonical Builder**:
- Build through one checked-in entrypoint such as `scripts/build_artifact.sh` or `make artifact`.
- No ad-hoc builder hosts with hidden state.
3. **Platforms**: `linux/amd64` (Server), `linux/arm64` (Apple Silicon/AWS Graviton).
4. **Minimize Runtime**:
- **Multi-Stage**: The final image MUST NOT contain a compiler, package manager, or source tree.
- **Minimal Final Layer**: Use distroless or another minimal base pinned by digest.
- **Language-Neutral Caching**: Copy dependency manifests before application source so cache reuse works across rebuilds.
5. **Static / Self-Contained CLI Builds**:
- Prefer self-contained binaries for public CLI releases. They reduce install friction and improve accessibility on clean hosts.
- Go: prefer `CGO_ENABLED=0`, `-trimpath`, and verify the result with `file` / `ldd`.
- Rust: prefer a `*-unknown-linux-musl` target when Linux portability matters and dependencies allow it.
- Treat `upx` as optional. It can trigger AV heuristics and make debugging harder.
6. **Reproducibility Controls**:
- Set `SOURCE_DATE_EPOCH` from the commit timestamp.
- Pin base images, dependencies, and lockfiles by digest or checksum.
- Strip non-deterministic metadata and absolute paths where the toolchain supports it.
- If you claim reproducibility, build twice and compare digests or artifact hashes.
### Phase 3: Registry / Supply-Chain Handshake
1. **Auth**:
- Local: `docker login`.
- CI: OIDC or short-lived creds from a secret manager. No long-lived static tokens.
2. **Metadata Injection (OCI Labels)**:
- `org.opencontainers.image.source` = Repo URL.
- `org.opencontainers.image.revision` = full Git SHA.
- `org.opencontainers.image.version` = SemVer (if any).
- `org.opencontainers.image.created` = build timestamp.
3. **SBOM & Provenance**:
- Emit SBOM and build provenance during the build when the toolchain supports it.
- `docker buildx`: `--sbom=true` and `--provenance=mode=max`.
- Capture the pushed digest from build metadata and use that digest for every downstream step.
4. **Security Gates**:
- Scan the image, dependencies, and SBOM before publish; fail above policy threshold.
- Sign by digest, not mutable tag.
- Verify signatures and attestations with pinned identity / OIDC issuer or equivalent admission policy.
- Only promote `latest` or production channels after verification passes.
### Phase 4: Platform Packaging & Customer Bundle
1. **Bundle Generation Is the Single Source of Truth**:
- Generate customer-facing archives, installers, manifests, docs, and checksum files from one packaging step.
- Do not hand-assemble release zips on a builder host.
2. **Desktop (Tauri/Electron)**:
- Build: `tauri build` / `electron-builder`
- Output: `.msi` (Win), `.dmg` (Mac), `.AppImage` (Linux)
- **Security**: Codesign (Cert) + Notarize (Apple).
3. **Mobile (iOS/Android)**:
- Build: Gradle (Android) / Xcode (iOS)
- Output: `.aab` / `.ipa`
- **Security**: Keystores in CI Secrets. Never commit `.jks` or `.p12`.
4. **CLI (Binary)**:
- Build: `cargo build --release --target x86_64-unknown-linux-musl` / `CGO_ENABLED=0 go build -trimpath -ldflags="-s -w"`
- **Verification**: Check linkage with `file` / `ldd`; smoke test on a clean host or container.
- **Distribution**: Publish binaries, `SHA256SUMS`, signatures, SBOM, and install instructions together.
5. **IoT (Firmware/Edge)**:
- Build: Cross-compile (`GOARCH=arm` / `armv7-unknown-linux-gnueabihf`)
- Output: Static Binary or Multi-arch Docker Image (`linux/arm/v7`)
- **Constraint**: Check binary size, startup memory, and read-only filesystem limits.
### Phase 5: Verification & Enforcement
*Did we ship something users can trust, or just something that happened to compile?*
1. **Run It**: `docker run --rm [image@digest] --version` (or healthcheck).
2. **Check Size**: If > 1GB, flag for review (unless ML model).
3. **Check Layers**: `docker history`. Ensure no secrets, package-manager caches, or source dumps.
4. **Check Signature**: `cosign verify` (or equivalent) with expected identity and issuer.
5. **Check Attestations**: Confirm provenance and SBOM exist and are inspectable.
6. **Check Runtime**: Confirm non-root execution and expected entrypoint / linkage.
7. **Check the Bundle in a Clean Room**:
- Install or unpack the exact shipped bundle on a fresh host or container.
- Verify required files exist and forbidden files are absent.
8. **Check for Internal Leaks**:
- No source tree, test fixtures, internal prompts, debug endpoints, or private config should ship unless explicitly intended.
## OUTPUT FORMAT
**The Build Script (`scripts/build_artifact.sh`)**
```bash
#!/usr/bin/env bash
set -euo pipefail
IMAGE_NAME="${IMAGE_NAME:-ghcr.io/OWNER/IMAGE}"
REPO_URL="${REPO_URL:-https://github.com/OWNER/REPO}"
RELEASE_MANIFEST="${RELEASE_MANIFEST:-release-manifest.json}"
COMMIT_SHA="$(git rev-parse HEAD)"
COMMIT_SHORT="$(git rev-parse --short HEAD)"
VERSION="${VERSION:-}"
BUNDLE_SHA256="${BUNDLE_SHA256:-}"
SOURCE_DATE_EPOCH="$(git log -1 --pretty=%ct)"
BUILD_METADATA="$(mktemp)"
BUILD_DATE="$(
SOURCE_DATE_EPOCH="$SOURCE_DATE_EPOCH" python3 - <<'PY'
from datetime import datetime, timezone
import os
print(datetime.fromtimestamp(int(os.environ["SOURCE_DATE_EPOCH"]), timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"))
PY
)"
docker buildx create --name artifact-builder --use >/dev/null 2>&1 || docker buildx use artifact-builder
docker buildx build \
--platform linux/amd64,linux/arm64 \
--tag "${IMAGE_NAME}:sha-${COMMIT_SHORT}" \
--label "org.opencontainers.image.source=${REPO_URL}" \
--label "org.opencontainers.image.revision=${COMMIT_SHA}" \
--label "org.opencontainers.image.created=${BUILD_DATE}" \
--provenance=mode=max \
--sbom=true \
--metadata-file "${BUILD_METADATA}" \
--push \
.
IMAGE_DIGEST="$(
python3 - "${BUILD_METADATA}" <<'PY'
import json, sys
with open(sys.argv[1], "r", encoding="utf-8") as f:
data = json.load(f)
print(data["containerimage.digest"])
PY
)"
IMAGE_REF="${IMAGE_NAME}@${IMAGE_DIGEST}"
syft "${IMAGE_REF}" -o cyclonedx-json > sbom.cdx.json
cosign sign --yes "${IMAGE_REF}"
cosign attest --yes --predicate sbom.cdx.json --type cyclonedx "${IMAGE_REF}"
cosign verify \
--certificate-identity "https://github.com/OWNER/REPO/.github/workflows/release.yml@refs/heads/main" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com" \
"${IMAGE_REF}" >/dev/null
COMMIT_SHA="${COMMIT_SHA}" IMAGE_REF="${IMAGE_REF}" IMAGE_DIGEST="${IMAGE_DIGEST}" REPO_URL="${REPO_URL}" BUILD_DATE="${BUILD_DATE}" VERSION="${VERSION}" BUNDLE_SHA256="${BUNDLE_SHA256}" python3 - <<'PY' > "${RELEASE_MANIFEST}"
import json
import os
print(json.dumps({
"repo": os.environ["REPO_URL"],
"git_sha": os.environ["COMMIT_SHA"],
"version": os.environ["VERSION"] or None,
"image_ref": os.environ["IMAGE_REF"],
"image_digest": os.environ["IMAGE_DIGEST"],
"bundle_sha256": os.environ["BUNDLE_SHA256"] or None,
"built_at": os.environ["BUILD_DATE"],
"sbom": "sbom.cdx.json",
"provenance": "oci-attestation",
}, indent=2))
PY
docker buildx imagetools inspect "${IMAGE_REF}" --format '{{json .Provenance}}' >/dev/null
docker buildx imagetools inspect "${IMAGE_REF}" --format '{{json .SBOM}}' >/dev/null
docker run --rm "${IMAGE_REF}" --version
```
## EXECUTION RULES
1. **NO DIRTY BUILDS**: If `git status` is not clean, **ABORT**. You cannot trace a dirty build.
2. **NO SECRETS IN IMAGE**: Never `COPY .env .`. Pass config at runtime.
3. **PIN THE SUPPLY CHAIN**: Pin base images, dependencies, and third-party CI actions by digest, checksum, or immutable version.
4. **CACHE BY MANIFEST**: Arrange Dockerfile layers so dependency manifests install before application source. Do not make this Node-only.
5. **DIGESTS ONLY**: Deploy by image digest, not mutable tags.
6. **SIGN, VERIFY, ENFORCE**: Verification is not optional. The pipeline or admission policy must reject unsigned or unverifiable artifacts.
7. **STATIC DOES NOT MEAN MAGIC**: Prefer self-contained binaries for CLI accessibility, but verify libc, TLS, CGO, and target-runtime reality before claiming portability.
8. **PROMOTE THE MANIFEST, NOT A MEMORY**: Every downstream step should consume the generated release manifest / bundle manifest, not hand-copied values.