Skip to content

Structured image builds and images.json - #17

Merged
KA-ROM merged 2 commits into
mainfrom
platform-image-builds
Sep 23, 2026
Merged

KA-ROM merged 2 commits into
mainfrom
platform-image-builds

Conversation

@KA-ROM

@KA-ROM KA-ROM commented Sep 22, 2026

Copy link
Copy Markdown
Collaborator

A container that pins a source repo used to describe its build as a shell line. That string is only useful to a local docker or podman run: nothing else can tell the repo from the Dockerfile from the secrets, so anything that builds decker's images elsewhere ends up keeping a second copy of the pins, and the two drift.

ImageBuildSpec now carries the build in fields — repo, ref, name, variant, version, dockerfile or assetDockerfile, assets, target, buildArgs, secrets — and the build command is derived from them. cmd stays as an escape hatch for a build no combination of fields expresses.

decker build writes every spec to manifests/<recipe>/images.json, keyed by the tag the manifests actually reference. A builder in CI or in a cluster reads that one file and builds exactly what the run will pull. With DECKER_IMAGE_MODE=pull decker builds nothing itself and only references the tags.

Build inputs that are not in the source repo — a Dockerfile that patches it, the patches it applies — can sit with the recipe that needs them. assetsDir points a spec at the directory that owns them, so a recipe living in its own repo ships its own build inputs instead of adding them here. Those bytes hash into the image tag, so a patched image can never collide with a pristine one, and they are copied next to images.json for whoever does the building.

The rest is in support of running a mainnet-shaped L1:

  • MAINNET_SYSTEM_CONTRACTS predeploys the EIP-4788, 2935, 7002 and 7251 contracts the EL system-calls every block. With no code at those addresses the block's state diff takes a shape mainnet never produces.
  • L1 artifacts take withdrawals: "none" for BLS credentials, so a devnet can run without per-block withdrawal sweeps.
  • scripts/trie-padding.ts creates N fresh accounts before load. decker's genesis is a dozen accounts, and a builder whose root hasher is only ever exercised on mainnet-deep tries can compute wrong roots against a trie that shallow.
  • lighthouse takes config.feeRecipient, because a builder that proves the proposer payment against state needs a recipient that exists in genesis.

Tested with deno lint, deno check over all tracked TypeScript, 14 unit tests and the e2e suite against the compiled binary. New coverage: the derived build command, the images.json payload, assets owned by an out-of-tree recipe, and an e2e test asserting that every tag in images.json is referenced by the rendered manifests.

A container that pins a source repo described its build as a shell line. That
string is opaque to anything but a local docker/podman run: an external builder
cannot tell the repo from the Dockerfile from the secrets, so it ends up keeping
its own copy of the pins, which then drift.

ImageBuildSpec now carries the build in fields (repo, ref, name, variant,
version, dockerfile/assetDockerfile, assets, target, buildArgs, secrets) and
derives the command from them; `cmd` stays as an escape hatch. `decker build`
writes every spec to manifests/<recipe>/images.json, keyed by the tag the
manifests reference, so a builder in CI or in a cluster builds exactly what the
run will pull.

Build inputs that are not in the source repo — a Dockerfile that patches it, the
patches — can sit with the recipe that needs them: assetsDir points a spec at
the directory that owns them, so a recipe in its own repo ships its own. Those
bytes hash into the image tag (a patched build cannot collide with a pristine
one) and are copied next to images.json for whoever builds.

Also here, all in support of running a mainnet-shaped L1:

- MAINNET_SYSTEM_CONTRACTS predeploys the EIP-4788/2935/7002/7251 contracts the
  EL system-calls every block; without code there the state diff takes a shape
  mainnet never produces.
- l1 artifacts take withdrawals: "none" for BLS (0x00) credentials, so a devnet
  can run without per-block withdrawal sweeps.
- scripts/trie-padding.ts creates N fresh accounts before load: decker's genesis
  is 12 accounts, and a builder whose root hasher is only exercised on
  mainnet-deep tries can compute wrong roots against a dozen leaves.
- lighthouse takes config.feeRecipient: a builder that proves the proposer
  payment against state needs a recipient that exists in genesis.
Comment thread README.md Outdated
- **Renderers:** Run your recipe on any target (podman, docker, process-compose and anything you want)
- **CLI:** Hack on the clone, run immediately with preinstalled binary

## Images

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we move this to notes/images.md?

Per review: the README keeps a one-line pointer, and notes/images.md has room
to show the shapes — a spec, an images.json entry, an out-of-tree asset dir —
instead of describing them in prose.
@KA-ROM
KA-ROM merged commit 33dcd0e into main Sep 23, 2026
2 checks passed
@KA-ROM
KA-ROM deleted the platform-image-builds branch September 23, 2026 07:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants