1- # trusted-workload -launcher
1+ # git -launcher
22
3- A minimal, auditable launcher image for dstack. Given a config file that
3+ A minimal, auditable Git launcher image for dstack. Given a config file that
44names an upstream Git repo and a full commit SHA, the launcher fetches that
55exact commit, verifies ` HEAD ` after checkout, and runs the workload's own
66entry point script — with no fallback to branches, tags, or short SHAs.
77
8- "Trusted" in the name refers to what a dstack deployment using this image
9- can produce — a * trusted workload deployment* — not to any intrinsic
10- property of the workload code. The launcher's job is to make the identity
11- of what runs in the TEE checkable: it combines TEE attestation with an
12- auditable image digest and an attested config that names the workload
13- commit. Whether the workload at that commit is itself trustworthy is up to
14- the auditor.
8+ The name is literal: this image launches arbitrary Git input, but only at an
9+ explicit commit selected by attested config. It does not make the workload
10+ trustworthy by itself. Its job is to make the identity of what runs in the TEE
11+ checkable by combining TEE attestation, an auditable launcher image digest, and
12+ an attested config that names the workload commit. Whether the workload at that
13+ commit is itself trustworthy is up to the auditor.
1514
1615By convention, ** the workload repo provides its own bash entry point at
1716` entrypoint.sh ` ** (default mode). This keeps install/build/run logic inside
@@ -109,10 +108,10 @@ given (launcher image digest, attested config) pair.
109108## CLI
110109
111110```
112- trusted-workload -launcher <config-file>
111+ git -launcher <config-file>
113112```
114113
115- The launcher is a single bash script (` bin/trusted-workload -launcher ` ). It
114+ The launcher is a single bash script (` bin/git -launcher ` ). It
116115depends only on ` bash ` , ` git ` , and POSIX coreutils. It is ** not** sourced
117116and ** does not source** the config. In default mode, the only bytes it
118117executes are those of the workload repo's ` entrypoint.sh ` at the pinned
@@ -191,14 +190,28 @@ audited alongside `COMMIT_SHA`.
191190 mode it executes ` INSTALL_CMD ` / ` RUN_CMD ` via ` bash -c ` . Nothing else
192191 from the config reaches a shell.
193192
193+ ### Persistent volume and reboot behavior
194+
195+ ` WORK_DIR ` should normally live on a persistent Docker volume, for example
196+ ` /var/lib/git-launcher/<workload> ` . On first boot, ` git-launcher ` creates the
197+ directory and clones ` REPO_URL ` there. On reboot or container restart, the same
198+ directory is reused only if it is already a git checkout whose ` origin ` exactly
199+ matches ` REPO_URL ` .
200+
201+ Every boot still runs the same verification path: fetch from ` origin ` , detach
202+ checkout to ` COMMIT_SHA ` , then assert ` git rev-parse HEAD == COMMIT_SHA ` .
203+ Persistent state is therefore only a cache. It does not decide what runs. If
204+ the volume is empty, the launcher reclones. If the volume is non-empty but not a
205+ git checkout, or if it points at a different origin, startup fails.
206+
194207## Example
195208
196209See [ ` examples/web-app.conf ` ] ( ./examples/web-app.conf ) . Adapt ` REPO_URL ` ,
197210` COMMIT_SHA ` , and (if you need it) ` REPO_SUBDIR ` for your workload, and
198211make sure the workload repo has a ` entrypoint.sh ` at the pinned commit.
199212
200213``` sh
201- ./bin/trusted-workload -launcher ./examples/web-app.conf
214+ ./bin/git -launcher ./examples/web-app.conf
202215```
203216
204217The launcher logs the resolved repo, commit, workdir, and selected mode at
@@ -235,11 +248,11 @@ reflected in the dstack attestation.
235248``` yaml
236249services :
237250 workload :
238- image : docker.io/<org>/trusted-workload -launcher@sha256:<launcher-digest>
239- command : ["/etc/trusted-workload -launcher/config.conf"]
251+ image : docker.io/<org>/git -launcher@sha256:<launcher-digest>
252+ command : ["/etc/git -launcher/config.conf"]
240253 volumes :
241- - ./web-app.conf:/etc/trusted-workload -launcher/config.conf:ro
242- - workload-checkout:/var/lib/trusted-workload -launcher
254+ - ./web-app.conf:/etc/git -launcher/config.conf:ro
255+ - workload-checkout:/var/lib/git -launcher
243256 - /var/run/dstack.sock:/var/run/dstack.sock
244257 restart : unless-stopped
245258
@@ -257,13 +270,13 @@ against the one they audited:
257270` ` ` yaml
258271services :
259272 workload :
260- image : docker.io/<org>/trusted-workload -launcher@sha256:<launcher-digest>
261- command : ["/etc/trusted-workload -launcher/config.conf"]
273+ image : docker.io/<org>/git -launcher@sha256:<launcher-digest>
274+ command : ["/etc/git -launcher/config.conf"]
262275 configs :
263276 - source : pin
264- target : /etc/trusted-workload -launcher/config.conf
277+ target : /etc/git -launcher/config.conf
265278 volumes :
266- - workload-checkout:/var/lib/trusted-workload -launcher
279+ - workload-checkout:/var/lib/git -launcher
267280 - /var/run/dstack.sock:/var/run/dstack.sock
268281 restart : unless-stopped
269282
@@ -272,7 +285,7 @@ configs:
272285 content : |
273286 REPO_URL=https://github.com/example-org/example-web-app.git
274287 COMMIT_SHA=<full-40-or-64-hex-sha>
275- WORK_DIR=/var/lib/trusted-workload -launcher/example-web-app
288+ WORK_DIR=/var/lib/git -launcher/example-web-app
276289
277290volumes :
278291 workload-checkout :
@@ -288,9 +301,9 @@ If you want a single digest to fully determine the workload, build a small
288301downstream image that copies the config in :
289302
290303` ` ` dockerfile
291- FROM docker.io/<org>/trusted-workload -launcher@sha256:<launcher-digest>
292- COPY web-app.conf /etc/trusted-workload -launcher/config.conf
293- CMD ["/etc/trusted-workload -launcher/config.conf"]
304+ FROM docker.io/<org>/git -launcher@sha256:<launcher-digest>
305+ COPY web-app.conf /etc/git -launcher/config.conf
306+ CMD ["/etc/git -launcher/config.conf"]
294307` ` `
295308
296309Deploy that derived image (pinned by its own `@sha256:…`). The derived
@@ -331,11 +344,11 @@ unprivileged in CI or on a developer laptop.
331344
332345# # Release image provenance
333346
334- The release workflow (`.github/workflows/trusted-workload -launcher-release.yml`
347+ The release workflow (`.github/workflows/git -launcher-release.yml`
335348in this repository's root `.github/`) follows the dstack-examples pattern :
336349
3373501. run `./tests/run-tests.sh`;
338- 2. build and push `docker.io/${DOCKERHUB_ORG}/trusted-workload -launcher:<tag>`;
351+ 2. build and push `docker.io/${DOCKERHUB_ORG}/git -launcher:<tag>`;
3393523. call `actions/attest-build-provenance@v1` with the Docker build digest;
3403534. write the digest and a Sigstore search link into both the GitHub Actions
341354 step summary and the GitHub release body.
@@ -349,7 +362,7 @@ compare that digest before trusting the launcher image.
349362If you are reviewing this directory at commit `L` before signing off on a
350363launcher image, the relevant audit surface is :
351364
352- 1. `bin/trusted-workload -launcher` — every line. Confirm :
365+ 1. `bin/git -launcher` — every line. Confirm :
353366 * No `eval`, no `source`/`.`, no command substitution applied to config
354367 values during parsing.
355368 * `git checkout` always uses the verbatim `COMMIT_SHA` and the result is
0 commit comments