@serve.zone/workloadinit
@serve.zone/workloadinit is the static serve.zone workload launcher that injects file-delivered secrets into a process environment immediately before replacing itself with that process. The npm package exposes two TypeScript surfaces: the root diagnostic binary-path resolver and the Node-only @serve.zone/workloadinit/verifier release and approval-artifact verifier. Neither surface installs or executes the binary.
Issue Reporting and Security
For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.
Launch Protocol
The only workload invocation is:
workloadinit run --map /run/serve.zone/workloadinit-map.json -- <command> [args...]
The map must be a canonical IWorkloadInitEnvironmentMap from @serve.zone/interfaces 32. It contains exactly manifestId, manifestDigest, and one to 256 sorted entries, in that property order. Each entry contains exactly variableName, resource, and source, also in that order. Duplicate JSON keys, unknown or reordered fields, malformed scalar types, noncanonical identifiers, duplicate variables/resources/sources, unsorted entries, and any source outside /run/serve.zone/secrets/<resource> are rejected. A pre-32 map — one carrying schemaVersion, or delivered at /run/serve.zone/workloadinit-map-v1.json — is refused rather than read; no compatibility path exists.
The fixed exit status contract is:
| Status | Meaning |
|---|---|
0 |
help, version, or successful install; successful run transfers control and preserves the workload's eventual status |
64 |
CLI usage |
65 |
map open, metadata, read, or validation failure |
66 |
secret source metadata, read, UTF-8, or NUL failure |
69 |
installation failure |
70 |
executable resolution or execve failure |
Failure output contains only a stable error class and code. It never includes paths, argv, map content, environment content, or secret values.
Security Boundary
run is Linux-only and fails closed if openat2 with RESOLVE_BENEATH | RESOLVE_NO_SYMLINKS | RESOLVE_NO_MAGICLINKS is unavailable. It opens / once, resolves the fixed map and every declared secret beneath that descriptor, uses O_NOFOLLOW, reads each already-open descriptor exactly once, and compares pre/post fstat identity and mutation metadata.
The map must be a root-owned regular file with exact mode 0444 and is bounded to 1 MiB. Secret sources must be regular files with exact mode 0400 or 0440, can have any owner, and are bounded to 500 KiB. Secret bytes must be strict UTF-8 without NUL. Newlines and every other byte are preserved; values are never trimmed.
The launcher snapshots raw inherited environ entries without Unicode conversion, preserving unaffected bytes, duplicates, and order. It removes every inherited occurrence of a mapped variable and appends exactly one replacement per map order. Executable resolution uses the original inherited PATH before overrides: slash-containing argv[0] is used exactly; slash-free names use the first inherited PATH, /bin:/usr/bin when absent, and current directory for empty components. execve receives the original argv bytes and the rebuilt environment directly, without a shell. A successful handoff preserves PID and signal semantics.
Controlled secret, source, and rebuilt-environment buffers use zeroize on failure paths. This cannot guarantee erasure of copies held by the kernel, the executed process, allocator internals, prior reallocations, crash dumps, swap, or compiler/runtime machinery. Successful execve replaces the process image instead of running cleanup code.
Install Lifecycle
The helper image has one installation command:
workloadinit install
It installs its authenticated running executable at:
/opt/serve.zone/runtime-assets/workloadinit/workloadinit
A runtime-asset tree written by a pre-32 launcher carries the executable at /opt/serve.zone/runtime-assets/workloadinit/v1/workloadinit, which no 32 workload invocation reaches, so that tree is rebuilt with this major.
The installer must run as root with root group. It traverses and creates only those fixed parent components through held directory descriptors, and rejects any component that is not root-owned/root-group or is group/world writable. It removes only canonical stale temporary names from an earlier interrupted install, writes a cryptographically random same-directory temporary file, synchronizes it, sets exact mode 0555, verifies root ownership, one link, bytes, SHA-256, and metadata, atomically renames it over the target, and synchronizes the parent directory. An identical root-owned single-link target is left unchanged. A different, symlinked, hardlinked, or wrongly owned target is atomically replaced so a consumer can deploy protocol-compatible security patches. The consumer's digest-pinned OCI image controls downgrade and version policy; no sidecar or symlink supplies trust.
Run one install job per node-local runtime-assets volume before workloads start. Mount that volume read-write only into the install job and read-only into workloads. Starting with 1.2.2, the released image is FROM scratch, supports linux/amd64 and linux/arm64, and contains exactly /workloadinit, /license.md, and /third-party-notices.md in one filesystem layer. Earlier signed releases retain their historical executable-only filesystem.
Coreflow and Onebox integration is future consumer work. This package release does not claim an end-to-end secret-delivery deployment.
Signed Image Release
WorkloadInit images use only immutable v<package-version> tags. latest, rebuild-on-push, and automatic Docker publication are intentionally disabled, which is why .smartconfig.json keeps the docker release target off. The Git and npm release happens first through the configured gitzone release -y workflow. Docker publication is a separate, signature-gated continuation that runs on TSDocker 3.5's release publication protocol: release-qualify builds and journals exactly one immutable candidate, and release-promote later publishes only that journaled digest graph. Every step between them is either an operator decision or an independent verification.
Every step below is started by the release operator; no step runs automatically:
| Step | Command | Operator involvement |
|---|---|---|
| Git and npm release | gitzone release -y |
operator-run |
| Candidate qualification | pnpm run release:prepare |
operator-run, automated end to end |
| Interrupted-candidate recovery | pnpm run release:cleanup-candidate |
operator decision, never automatic |
| Statement signing | cosign attest-blob with the encrypted operator key |
operator only — the key never enters this repository |
| Signer key ID | pnpm run release:key-id |
operator-run |
| Digest-fenced publication | pnpm run release:docker |
operator-run, requires the signed bundle and expected key ID |
| Release approval | Cloudly/Onebox policy | operator, outside this repository |
The release statement and validators come from @serve.zone/interfaces/runtime/workloadinit 32. The statement has exactly one subject: the SHA-256 digest of the candidate root OCI index, which publication later requires and re-verifies remotely. That digest transitively binds both runnable platform manifests, their configs and layers, and the exact /workloadinit bytes. For 1.2.2 and later it also binds both legal files; earlier releases retain their historical one-file policy. The release verifier independently checks that graph for linux/amd64 and linux/arm64, including TSDocker source/version/revision labels and paired BuildKit provenance descriptors. It accepts the historical BuildKit image-config attestation and the current OCI artifact form; the latter must bind the exact runnable descriptor as its subject and use BuildKit's artifact type and the canonical OCI empty JSON config. Both forms must retain the paired root-index annotation and the in-toto statement's runnable digest and source provenance. The build type is https://serve.zone/buildtypes/workloadinit-gitzone-tsdocker and the builder is https://serve.zone/builders/workloadinit-manual-release; statements signed under the pre-32 /v1 identifiers no longer validate, and every approval built on them is re-issued rather than migrated.
Release binaries use the pinned Rust 1.95.0 toolchain and the x86_64-unknown-linux-musl and aarch64-unknown-linux-musl targets. TSRust 1.13.0 runs Cargo with --locked, verifies static ELF output, and writes each binary next to its hash-bound <binary>.tsrust-build.json provenance sidecar. The build wrapper admits exactly that binary and sidecar per built target, moves both to the public workloadinit_linux_amd64 and workloadinit_linux_arm64 filenames, and re-reads the moved sidecar, so a complete dist_rust/ holds the two binaries plus their two sidecars and pnpm exec tsrust inspect dist_rust/workloadinit_linux_amd64 still answers what a binary was built from. The sidecar is a local build artifact rather than release evidence — the signed statement already binds the source revision, the build-tool versions and the exact /workloadinit bytes — so package.json files excludes dist_rust/*.tsrust-build.json and the npm tarball ships only the two binaries. The npm package and helper image include the deterministic third-party notices for the locked crate graph and pinned Rust musl runtime.
Candidate Preparation
After the clean source release commit and v<version> Git tag exist, the operator starts one qualification:
export VERSION="<release-version>"
export RELEASE_DIR=".nogit/workloadinit-release/v${VERSION}"
pnpm run release:prepare -- --version "$VERSION"
export CANDIDATE_DIGEST="$(jq -r '.workloadInitImageIndexDigest' "$RELEASE_DIR/workloadinit-v${VERSION}.candidate-evidence.json")"
test -n "$CANDIDATE_DIGEST"
release:prepare first requires the exact branch and annotated tag on Git origin, plus identical package integrity from Verdaccio and npmjs. It then derives one canonical TSDocker qualification request from the release version and revision alone — patterns Dockerfile_v##version##, no registry restriction, no pre-build registry login, and container tests disabled — and its SHA-256 is the candidate ID. No TSDOCKER_SESSION_ID or other ambient state takes part in that identity.
Preparation runs release-capabilities, release-validate, and release-qualify through pnpm exec tsdocker, each with a private canonical request file and a single canonical JSON response. TSDocker verifies the clean worktree at that exact revision, stamps the release version and revision into the OCI provenance labels, builds into candidate-isolated registry storage under .nogit/docker-registry/releases/<candidateId>/, verifies the nested OCI graph, pre-probes the destination digest and alias, and journals the completed candidate atomically. Repeating the identical request returns the exact recorded result instead of building again.
Container tests stay disabled because TSDocker runs image tests through bash inside the image, while the released image is FROM scratch. The ceremony qualifies the binaries itself: it re-opens the candidate registry storage, verifies the whole candidate graph without extracting any filesystem, and executes each platform-manifest digest's /workloadinit --version entrypoint in a read-only, networkless, capability-free container. It records build-tool versions on both sides of the build, writes a candidate checkpoint holding the qualification evidence, and finally writes a canonical no-newline statement plus candidate evidence beneath .nogit/. It rejects version 1.0.0 permanently and refuses to build over completed ceremony artifacts.
If qualification is interrupted before it completes, TSDocker keeps a preparing candidate record and fails closed on every later attempt; it never resumes or rebuilds by itself. The operator inspects the situation and then explicitly releases that candidate:
pnpm run release:cleanup-candidate -- --version "$VERSION"
Cleanup removes only that candidate's own storage, and it refuses to run once a checkpoint, statement, or evidence file exists, because publication still needs the qualified candidate.
Signing Ceremony
Signing requires a separately authorized encrypted ECDSA P-256 operator key. Never place a private key in this repository, .nogit/, a release asset, a command argument, or an environment variable. The public key, statement, bundle, and factual receipts contain no secret material. This is the human step: nothing in this repository signs or publishes unattended, and publication cannot start without the operator-supplied bundle, public key, and expected key ID.
Use the pinned official Cosign v3.1.2 Linux amd64 binary:
mkdir -p .nogit/tools
curl -fL 'https://github.com/sigstore/cosign/releases/download/v3.1.2/cosign-linux-amd64' -o .nogit/tools/cosign-v3.1.2-linux-amd64
printf '%s %s\n' 'f7622ed3cf22e55e1ae6377c080979ff77a22da9981c11df222a2e444991e7cf' '.nogit/tools/cosign-v3.1.2-linux-amd64' | sha256sum -c -
chmod 0755 .nogit/tools/cosign-v3.1.2-linux-amd64
With operator-controlled paths for the encrypted key and its public key:
export COSIGN=".nogit/tools/cosign-v3.1.2-linux-amd64"
export STATEMENT="$RELEASE_DIR/workloadinit-v${VERSION}.statement.json"
export BUNDLE="$RELEASE_DIR/workloadinit-v${VERSION}.sigstore.json"
export PUBLIC_KEY="/operator-controlled/path/workloadinit-release.pub"
export ENCRYPTED_KEY="/operator-controlled/path/workloadinit-release.key"
"$COSIGN" attest-blob \
--statement "$STATEMENT" \
--bundle "$BUNDLE" \
--key "$ENCRYPTED_KEY" \
--tlog-upload=false \
--use-signing-config=false \
--yes
pnpm run release:key-id -- --public-key "$PUBLIC_KEY"
Record the printed sha256:<SPKI DER digest> as KEY_ID. The --tlog-upload=false deprecation warning is expected; --use-signing-config=false and the explicit encrypted key keep the ceremony independent of OIDC, Fulcio, Rekor, ambient Sigstore trust, and network signing services.
Digest-Fenced Publication
Publication repeats local graph, per-platform executable, and signature verification before it publishes. It re-derives the same candidate request, reopens the prepared checkpoint, requires the signed statement to report the recorded build tooling, and only then promotes the journaled candidate:
export KEY_ID="sha256:<operator-verified-spki-digest>"
pnpm run release:docker -- \
--version "$VERSION" \
--candidate-digest "$CANDIDATE_DIGEST" \
--statement "$STATEMENT" \
--bundle "$BUNDLE" \
--public-key "$PUBLIC_KEY" \
--expected-key-id "$KEY_ID" \
--cosign "$COSIGN"
The command never builds. Its only TSDocker publication operation is release-promote, once per configured destination: TSDocker copies the journaled graph by digest, children before parents, verifies the destination root digest, and attempts at most one alias PUT with single-writer semantics — a lost acknowledgement is reconciled by a probe rather than retried. Publication requires an exact digest and alias result, then re-verifies the complete remote graph itself and writes a factual receipt. Candidate execution uses each exact local platform-manifest digest rather than a mutable tag. If Git/npm publication succeeded but Docker publication did not, retry the same command with the same candidate digest; never rebuild under the existing version.
The detached bundle and release assets are untrusted transport. WorkloadInit verifies cryptographic consistency and reports the signer SPKI ID, but it does not authorize that signer. The transported public key's canonical SPKI DER SHA-256 must equal the caller-trusted key ID; PEM byte equality is not the trust comparison. Cloudly's private policy exclusively owns trusted-key pinning, rotation, revocation, policy generation, and release approval. A publication receipt is factual evidence only and is never a Cloudly approval.
TypeScript API
Install with pnpm:
pnpm add @serve.zone/workloadinit
Resolve the packaged binary for diagnostics or tests:
import { getWorkloadInitBinaryPath } from '@serve.zone/workloadinit';
const binaryPath = getWorkloadInitBinaryPath();
getWorkloadInitBinaryPath() supports Linux x64 and arm64, verifies that the selected packaged file exists, and performs no installation.
Cloudly approval policy can consume the runtime-safe verifier subpath:
import { verifyWorkloadInitRelease } from '@serve.zone/workloadinit/verifier';
const result = await verifyWorkloadInitRelease({
statementBytes,
bundleBytes,
publicKeyPem: transportedPublicKeyPem,
registry: {
baseUrl: 'https://code.foss.global',
repository: 'serve.zone/workloadinit',
tokenUrl: 'https://code.foss.global/v2/token',
tokenService: 'container_registry',
},
trustPolicy: {
policyGeneration: trustedPolicy.generation,
policyDigest: trustedPolicy.digest,
verifiedAt: trustedVerificationTime,
trustedSigner: {
keyId: trustedPolicy.signerKeyId,
publicKeyPem: trustedPolicy.signerPublicKeyPem,
},
revokedSignerKeyIds: trustedPolicy.revokedSignerKeyIds,
},
expected: {
version: expectedVersion,
imageIndexDigest: expectedImageIndexDigest,
platforms: ['linux/amd64', 'linux/arm64'],
},
});
if (!result.success) throw new Error(result.errorCode);
const verifiedEvidence = result.evidence;
verifyWorkloadInitRelease() validates canonical statement bytes, the detached P-256 DSSE signature, the transported public key's SPKI SHA-256 against the caller-trusted key ID and revocations, exact version/digest/platform expectations, and the complete bounded remote OCI graph. Images before 1.2.2 retain their authenticated historical one-file filesystem policy; 1.2.2 and later must contain exactly the executable and both legal files described above. Success returns canonical authenticated statement evidence, digest-verified registry evidence, and copied caller-supplied policy metadata. Failure returns only one finite TWorkloadInitVerifierErrorCode and echoes no input.
Cloudly and Onebox can share the strict approval artifact boundary without sharing file ingress code:
import {
verifyWorkloadInitApprovalArtifact,
type TWorkloadInitApprovalArtifactResult,
} from '@serve.zone/workloadinit/verifier';
const approvalResult: TWorkloadInitApprovalArtifactResult =
await verifyWorkloadInitApprovalArtifact(parsedJson, { now });
if (approvalResult.status === 'active') {
persistAuthority(approvalResult.authority, approvalResult.approvalDigest);
}
parseWorkloadInitApprovalArtifact() accepts only the exact bounded active or revoked artifact JSON shape, rejects present undefined, noncanonical SHA-256 digests, and noncanonical base64url values such as padded encodings, and returns a detached snapshot. verifyWorkloadInitApprovalArtifact() requires caller-supplied now, applies approval timeline and signer-revocation fences, delegates release proof to verifyWorkloadInitRelease(), constructs the canonical Interfaces 32 IWorkloadInitActiveApprovalAuthority, and returns its approval digest for persistence and fencing. Every result uses a finite status; invalid and unconfigured results also contain only a finite error code, while revoked contains no transported value. Decoded statement, bundle, transported-key, and trusted-key copies are zeroized in finally.
The approval API does not read files, environment variables, credentials, or source trust, policy, or time from ambient state. Consumers explicitly supply the artifact policy and now, own JSON/file ingress, and decide whether a missing path maps to an undefined unconfigured input. Passing undefined or null returns APPROVAL_ARTIFACT_UNCONFIGURED; malformed configured content returns an invalid result rather than being silently treated as absent.
The verifier shape-validates and copies policyGeneration, policyDigest, and verifiedAt; it does not authenticate or recompute them, check their freshness, or establish the policy that supplied them. The caller must obtain those values, the trusted signer key and key ID, current revocations, and exact expected release values from an authenticated authority. No release trust, policy, key, expectation, or time comes from ambient state. The transported statement, bundle, public key, registry responses, tags, and headers remain untrusted. Verifier success is factual evidence for policy code to use; it is not by itself a Cloudly approval.
The @serve.zone/workloadinit/verifier graph does not load WorkloadInit release tooling, TSDocker, child_process, or fs. It performs no signing and accepts only public SPKI PEM, never a private key.
Audited Unsafe Boundaries
Rust unsafe is confined to small Linux ABI boundaries: openat2 and descriptor syscalls, raw inherited environ traversal, execve, and test-only fork/wait helpers. Every pointer passed to the kernel is backed by a live NUL-terminated buffer, every inherited environment pointer is copied before use, and every returned descriptor is immediately placed under owned RAII management.
License and Legal Information
This repository contains open-source code licensed under the MIT License. A copy of the license can be found in license.md. Notices and license terms for components linked into the packaged Rust binaries are reproduced in third-party-notices.md.
Please note: The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.
Trademarks
This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.
Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.
Company Information
Task Venture Capital GmbH
Registered at District Court Bremen HRB 35230 HB, Germany
For any legal inquiries or further information, please contact us via email at hello@task.vc.
By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.