image field of your tinfoil-config.yml.
If instead you have source code you want to deploy, you’ll need to build an image for it first. How you do this depends on the visibility of the repository:
- Public source code → use
tinfoil-public-containers-template. When deploying public code you can do it all in one repo. Thepublic-containerstemplate contains one workflow that builds the image, substitutes the real digest into the config at the tagged release commit, and publishes the release. It consolidates thetinfoil-containers-hello-worldrepo and thetinfoil-containers-templaterepo. - Private source code → keep your code in its own private repo and use
tinfoil-containers-hello-worldas the build-and-publish pattern (Dockerfile + workflow that pushes to GHCR). Then reference the published image from atinfoil-containers-templatefork like the quickstart.
If the published image is private (not just the source), Tinfoil needs registry credentials to pull it at deploy time. See Private images. Public images work without any configuration.
Image digests in the release workflow
Theimage field must pin a SHA256 digest because this is what the attestation commits to and what clients verify. How the digest gets into your config depends on your setup:
- Pre-built image (the quickstart template, or any external image you pull): put the real digest in your config directly.
- Build your own image (the public-containers template): use a placeholder digest on
main:tinfoil-config.yml
tinfoil-release.yml builds the image, substitutes the real digest into the config on the tagged release commit (not on main), then runs the measurement and publish workflow against that commit. main keeps the placeholder.
For example, here’s the release for v0.0.118 of confidential-model-router:

The release contains measurements and the bundled binary
d3aad2e) that doesn’t belong to any branch. If we click on it we can see the placeholder being replaced with the real digest:


