diff --git a/AGENTS.md b/AGENTS.md index df34220..cd4f1a1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,7 +9,7 @@ ## Build, Test, and Development Commands - `make build` builds `./banger` and `./bangerd`. -- `make runtime-bundle` bootstraps `./runtime/` from `runtime-bundle.toml`. +- `make runtime-bundle` bootstraps `./runtime/` from the archive referenced by `RUNTIME_MANIFEST`; the checked-in `runtime-bundle.toml` is only a template. - `banger` validates required host tools per command and reports actionable missing-tool errors; do not assume one workstation's package set. - `./banger vm create --name testbox` creates and starts a VM. - `./banger vm ssh testbox` connects to a running guest. diff --git a/Makefile b/Makefile index a0bc1b5..77e4e8e 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ help: @printf '%s\n' \ 'Targets:' \ ' make build Build ./banger and ./bangerd' \ - ' make runtime-bundle Download and unpack ./runtime from runtime-bundle.toml' \ + ' make runtime-bundle Fetch and unpack ./runtime from the archive referenced by $(RUNTIME_MANIFEST)' \ ' make runtime-package Package $(RUNTIME_SOURCE_DIR) into $(RUNTIME_ARCHIVE) and print its SHA256' \ ' make install Build and install binaries plus the runtime bundle into $(DESTDIR)$(BINDIR) and $(DESTDIR)$(RUNTIMEDIR)' \ ' make test Run go test ./...' \ diff --git a/README.md b/README.md index d346f66..1bb7efa 100644 --- a/README.md +++ b/README.md @@ -30,22 +30,43 @@ The bundle contains: - `id_ed25519` - the helper scripts used by image builds and installs -Bootstrap a source checkout explicitly: +Bootstrap a source checkout from a local or published runtime archive. The +checked-in [`runtime-bundle.toml`](/home/thales/projects/personal/banger/runtime-bundle.toml) +is a template and intentionally ships with empty `url` and `sha256`. + +If you need to create a local archive first, do that from a checkout or machine +that already has a populated `./runtime/` tree: ```bash -make runtime-bundle +make runtime-package +cp dist/banger-runtime.tar.gz /path/to/fresh-checkout/dist/ ``` -`make runtime-bundle` reads [`runtime-bundle.toml`](/home/thales/projects/personal/banger/runtime-bundle.toml), -downloads the published bundle, verifies its SHA256, and unpacks it into -`./runtime/`. `make install` will not fetch artifacts for you. The manifest -must point at a published or locally staged bundle before bootstrap can work. +In the fresh checkout: +```bash +cp runtime-bundle.toml runtime-bundle.local.toml +``` + +Edit `runtime-bundle.local.toml` to point at the staged archive and checksum: +```toml +url = "./dist/banger-runtime.tar.gz" +sha256 = "" +``` + +Then bootstrap `./runtime/` with the local manifest copy: +```bash +make runtime-bundle RUNTIME_MANIFEST=runtime-bundle.local.toml +``` + +`url` may be a relative path, absolute path, `file:///...` URL, or HTTP(S) +URL. `make install` will not fetch artifacts for you. ## Build ```bash -make runtime-bundle make build ``` +Run `make build` after `./runtime/` has been bootstrapped. + Install into `~/.local/bin` by default, with the runtime bundle under `~/.local/lib/banger`: ```bash @@ -206,16 +227,19 @@ make rootfs is not available, pass an explicit `--base-rootfs` to `./make-rootfs.sh`. ## Maintaining The Runtime Bundle -Maintain the checked-in manifest in [`runtime-bundle.toml`](/home/thales/projects/personal/banger/runtime-bundle.toml) -with the published bundle URL, SHA256, and `bundle_metadata` defaults. +The checked-in [`runtime-bundle.toml`](/home/thales/projects/personal/banger/runtime-bundle.toml) +is a template. Keep `bundle_metadata` accurate there, but use a separate local +manifest copy when you need concrete `url` and `sha256` values for bootstrap +testing or publication. -Package a local `./runtime/` tree for publication: +Package a local `./runtime/` tree into an archive: ```bash make runtime-package ``` That writes `dist/banger-runtime.tar.gz` and prints its SHA256 so you can update -the manifest before publishing or testing bootstrap changes. +a local manifest copy before testing bootstrap changes or publishing the +archive elsewhere. ## Remaining Shell Helpers The runtime VM lifecycle is managed through `banger`. The remaining shell scripts are not the primary user interface: diff --git a/internal/runtimebundle/bundle.go b/internal/runtimebundle/bundle.go index 1b2e906..02546b0 100644 --- a/internal/runtimebundle/bundle.go +++ b/internal/runtimebundle/bundle.go @@ -69,10 +69,10 @@ func LoadManifest(path string) (Manifest, error) { func Bootstrap(ctx context.Context, manifest Manifest, manifestPath, outDir string) error { if manifest.URL == "" { - return fmt.Errorf("runtime bundle manifest %s has no url; publish a runtime bundle and update the manifest", manifestPath) + return fmt.Errorf("runtime bundle manifest %s has no url; point a local manifest copy at a staged or published runtime bundle archive", manifestPath) } if manifest.SHA256 == "" { - return fmt.Errorf("runtime bundle manifest %s has no sha256", manifestPath) + return fmt.Errorf("runtime bundle manifest %s has no sha256; add the checksum for the staged or published runtime bundle archive", manifestPath) } manifestDir := filepath.Dir(manifestPath) parentDir := filepath.Dir(outDir) diff --git a/internal/runtimebundle/bundle_test.go b/internal/runtimebundle/bundle_test.go index cc8affc..32a26a1 100644 --- a/internal/runtimebundle/bundle_test.go +++ b/internal/runtimebundle/bundle_test.go @@ -71,6 +71,30 @@ func TestBootstrapRejectsChecksumMismatch(t *testing.T) { } } +func TestBootstrapRejectsMissingURLWithLocalManifestGuidance(t *testing.T) { + manifest := Manifest{ + SHA256: strings.Repeat("0", 64), + BundleRoot: "runtime", + RequiredPaths: []string{"firecracker"}, + } + err := Bootstrap(context.Background(), manifest, filepath.Join(t.TempDir(), "runtime-bundle.toml"), filepath.Join(t.TempDir(), "runtime")) + if err == nil || !strings.Contains(err.Error(), "local manifest copy") { + t.Fatalf("Bootstrap() error = %v, want local manifest guidance", err) + } +} + +func TestBootstrapRejectsMissingSHAWithArchiveGuidance(t *testing.T) { + manifest := Manifest{ + URL: "./bundle.tar.gz", + BundleRoot: "runtime", + RequiredPaths: []string{"firecracker"}, + } + err := Bootstrap(context.Background(), manifest, filepath.Join(t.TempDir(), "runtime-bundle.toml"), filepath.Join(t.TempDir(), "runtime")) + if err == nil || !strings.Contains(err.Error(), "staged or published runtime bundle archive") { + t.Fatalf("Bootstrap() error = %v, want archive guidance", err) + } +} + func TestPackageWritesArchive(t *testing.T) { runtimeDir := t.TempDir() for _, rel := range []string{ diff --git a/runtime-bundle.toml b/runtime-bundle.toml index 286404c..e393b27 100644 --- a/runtime-bundle.toml +++ b/runtime-bundle.toml @@ -1,5 +1,6 @@ -# Update `url` and `sha256` to the published runtime bundle before using -# `make runtime-bundle` in a fresh checkout. +# Template manifest for local or published runtime bundle archives. +# Keep this checked-in file empty by default; use a local manifest copy with +# concrete `url` and `sha256` values when bootstrapping `./runtime/`. version = "v0" url = "" sha256 = ""