Skip to content

refactor(orch): render the distro selection in provision.sh's own template - #3463

Draft
tomassrnka wants to merge 2 commits into
mainfrom
distro-selector-template
Draft

refactor(orch): render the distro selection in provision.sh's own template#3463
tomassrnka wants to merge 2 commits into
mainfrom
distro-selector-template

Conversation

@tomassrnka

@tomassrnka tomassrnka commented Jul 30, 2026

Copy link
Copy Markdown
Member

The follow-up promised in the #3411 review (@dobrac's three comments: Go templating for the selector, profiles-as-data with selection living in provision.sh, init blocks in separate files). #3459 has merged; this now sits directly on main.

What changed

  • Structure vs data split: the selection block (case arms, rejected-id guard, ID_LIKE loop, all error/warning text) moved verbatim from the ShellSelector() string-builder into provision.sh as inline text/template actions. The distro package now contributes data only — distro.NewTemplateData() — with all shell-quoting kept in Go where it's unit-testable. No FuncMap (repo precedent).
  • Init-setup blocks left their Go string literals for distro/init-{systemd,openrc,nixos}.sh, go:embed'd.
  • Cache key: the selection structure is now covered by the raw embedded provision.sh that Hash() already hashes; distro.Fingerprint() covers the spliced data (%#v of the view — new fields fingerprint automatically). Version 1 → 2. The dev/fallback provision version rotates once on deploy; production rollout stays gated by the BuildProvisionVersion LD flag.
  • Tests: selection-text assertions moved to base/provision_test.go against the fully rendered script (the render seam and tests are build-tag-free, so they run on darwin). Every prior assertion is preserved, including the errexit guard (no if e2b_select_profile) and guard-before-fallback ordering. New: per-field %q-vs-sh quoting pins, byte-exact customer-message pins, and a leftover-{{ render check.

Verification

  • Rendered output diffed against the old ShellSelector(): byte-identical for the whole selection function; only deliberate comment/blank-line additions in the tail.
  • Full e2e on an E2B Local dev slot (cold cache, orchestrator rebuilt from this branch): oraclelinux:9 rejected with byte-identical ERROR lines; kali builds with the byte-identical ID_LIKE WARNING and boots; alpine (OpenRC path) builds and boots with envd healthy; ubuntu and debian build and boot. sh -n clean on the rendered script.

Rebase onto current main (#3478, #3440)

Both landed after the last rebase and both touch the code this PR moves, so the merge was semantic, not textual:

Tree swept for orphans of the moved code — E2B_CHRONY_PHC, command_args="-F 0", e2b-chrony-source, E2B_TIMESYNC_UNIT, E2B_INIT_BIN, /sbin/e2b-nixos-init, ShellSelector, DistroSelector: every consumer has a definition, no definition is stranded.

New test pinning the restored invariant: TestProvisionScriptSplicesEveryProfileField asserts every ProfileView field — including the init-setup body now sourced from a file — reaches its rendered case arm. A dropped template action would otherwise leave the Go-side tests over Profiles/initSetup green while the guest hits an undefined variable under set -eu, on every distro. It subsumes the old TestProvisionScriptInitSetup, which is removed.

Re-verified after the rebase: rendered script byte-identical to main's ShellSelector() output apart from the comments; sh -n, bash -n and shellcheck -s sh clean on the three new files and on the rendered script.

🤖 Generated with Claude Code

@cla-bot cla-bot Bot added the cla-signed label Jul 30, 2026
@cursor

cursor Bot commented Jul 30, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes the contract for every template base build and rotates cache keys; intended behavior is unchanged but a template wiring or quoting mistake would break provisioning across distros.

Overview
Distro profile selection for base-image provisioning is no longer built as a Go string (ShellSelector); it is rendered inside provision.sh via text/template, fed by distro.NewTemplateData() with quoting and init-setup bodies prepared in Go (init blocks moved to embedded init-*.sh files). Base-layer cache fingerprinting now hashes that view data and bumps distro Version to 2, while script shape stays in the existing provision script hash. Tests that asserted on generated selector text now render the full script in provision_test.go (including on darwin).

Reviewed by Cursor Bugbot for commit 5b134af. Bugbot is set up for automated code reviews on this repo. Configure here.

@codecov

codecov Bot commented Jul 30, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.92683% with 7 lines in your changes missing coverage. Please review.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...chestrator/pkg/template/build/phases/base/files.go 0.00% 4 Missing ⚠️
...pkg/template/build/phases/base/provision_script.go 66.66% 2 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@tomassrnka
tomassrnka force-pushed the distro-selector-template branch from 9437ec6 to 4b6d895 Compare July 30, 2026 11:08
Base automatically changed from warn-unsupported to main July 30, 2026 11:31
@tomassrnka
tomassrnka force-pushed the distro-selector-template branch from 4b6d895 to 3f449f6 Compare July 30, 2026 12:10
The three initSetup bodies leave their Go string literals for
init-{systemd,openrc,nixos}.sh, go:embed'd with the trailing newline
trimmed so they splice exactly like the literals did. Selector output is
unchanged apart from the entry comments moving in as # lines.

Rebased over #3440, which added chrony-source wiring to both init blocks
after this was written: the systemd drop-in, OpenRC's e2b-chrony-source
install and the unconditional command_args="-F 0" move into the new
files verbatim, checked byte-for-byte against main's literals.

First half of the #3411 follow-up (dobrac: init.go:21).
…plate

The selection structure (case arms, rejected-id guard, ID_LIKE loop,
error/warning text) moves verbatim from the ShellSelector string-builder
into provision.sh as inline template actions; the distro package now
contributes data only — distro.NewTemplateData(), with all shell-quoting
kept in Go. Fingerprint hashes the view data (%#v, so new fields are
covered automatically); the structure is already hashed via the raw
embedded template. Version 1 -> 2.

The render seam and its tests live in ungated files so they keep running
on darwin. Selection-text assertions move to base/provision_test.go
against the rendered script, with the guard-ordering anchor rewritten to
the fallback loop line (E2B_ID_LIKE is assigned earlier in the full
script). New guards: %q-vs-sh quoting assumptions pinned per profile
field, a leftover-"{{" render check, and a test that every ProfileView
field — including the init-setup body now sourced from a file — reaches
the rendered case arm. A dropped template action would otherwise leave
the Go-side tests green while the guest hits an undefined variable under
set -u.

#3440's chrony-deferral test now asserts on the rendered script rather
than the raw template: the init blocks moved out, so only the rendered
form covers both halves.

Rendered output verified byte-identical to main's ShellSelector output
modulo the added comments; customer-visible messages pinned byte-exact.

Completes the #3411 follow-up (dobrac: distro.go:160, provision.sh:29).
@tomassrnka
tomassrnka force-pushed the distro-selector-template branch from 3f449f6 to 5b134af Compare August 1, 2026 07:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant