Skip to content

[codex] add platform flag for images and runs#54

Merged
rgarcia merged 4 commits into
mainfrom
codex/add-platform-flag
Jun 9, 2026
Merged

[codex] add platform flag for images and runs#54
rgarcia merged 4 commits into
mainfrom
codex/add-platform-flag

Conversation

@rgarcia

@rgarcia rgarcia commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

What this does

Adds a Docker-style --platform flag to the Hypeman CLI so local (Apple-Silicon) users can drive the Rosetta / multi-platform support from hypeman #279 directly:

hypeman run --platform linux/amd64 --hypervisor vz docker.io/library/alpine:3.19

Pairs with server PR kernel/hypeman#279 (merge/deploy that first — the server does the actual platform resolution + validation).

Changes

  • --platform on hypeman pull, hypeman image create, and hypeman run (os/arch[/variant]). Threaded through auto-pull during run and onto the final instance-create call.
  • hypeman inspect now renders the server's raw response (RawJSON()) instead of marshaling the typed SDK struct, so newly-added fields like platform aren't dropped. Env values are still redacted (now via sjson on the raw JSON).
  • hypeman image list gains a PLATFORM column.
  • run cold-pull UX: a transient 404 while an image is still being pulled is treated as "still pulling" (via errors.As) instead of a misleading not-found.
  • snapshot restore --help documents the not-Running precondition.

Reviewer notes

  • The option.WithJSONSet("platform", …) calls and the RawJSON() rendering are deliberate temporary workarounds: the pinned hypeman-go SDK (v0.20.0) predates the platform field, so it isn't typed yet. Both should be replaced with typed fields after an SDK regen/bump — they're commented as such. This is the main thing to be aware of while reading run.go / inspect.go / imagecmd.go.
  • Suggested read order: run.go (flag + auto-pull threading) → imagecmd.go/pull.go (shared flag + list column) → inspect.go (RawJSON + env redaction) → tests.
  • New unit tests cover platform-option plumbing, env redaction (incl. odd key escaping), and the not-found detection.

Validation

go test ./pkg/cmd ./cmd/hypeman
go build -o bin/hypeman ./cmd/hypeman

CI lint + scan green. Exercised end-to-end against a local server across the #279 QA rounds (pull/run/inspect/list at both arches, cold-pull, error paths).


Note

Medium Risk
Changes instance/image API request shaping and inspect output path (raw JSON + env redaction); behavior depends on server platform support and temporary WithJSONSet workarounds until an SDK bump.

Overview
Adds Docker-style --platform (os/arch[/variant]) on pull, image create, and run, threading it through image pulls (including auto-pull in run) and instance create via option.WithJSONSet("platform", …) until the pinned SDK exposes a typed field.

image list shows a PLATFORM column read from each image’s RawJSON() (with - when missing). inspect outputs the server RawJSON() instead of marshaling the SDK struct so fields like platform are not dropped; env values are still redacted to [hidden] on the raw payload using sjson, with path escaping for odd env key names.

run treats transient 404s while polling an in-flight cold pull as “still pulling” (isNotFoundError now uses errors.As). snapshot restore --help notes the instance must not be Running.

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

@rgarcia rgarcia force-pushed the codex/add-platform-flag branch from ec08ca3 to f1a9bea Compare June 8, 2026 02:36
@rgarcia rgarcia force-pushed the codex/add-platform-flag branch from f1a9bea to 4a26c20 Compare June 8, 2026 02:44
@rgarcia rgarcia marked this pull request as ready for review June 8, 2026 20:27

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Platform flag ignored on create
    • I appended imageCreateRequestOptions in handleImageCreateLike so hypeman image create now forwards --platform to Images.New requests.

Create PR

Or push these changes by commenting:

@cursor push 30a6463dd8
Preview (30a6463dd8)
diff --git a/pkg/cmd/imagecmd.go b/pkg/cmd/imagecmd.go
--- a/pkg/cmd/imagecmd.go
+++ b/pkg/cmd/imagecmd.go
@@ -166,6 +166,7 @@
 	if cmd.Root().Bool("debug") {
 		opts = append(opts, debugMiddlewareOption)
 	}
+	opts = append(opts, imageCreateRequestOptions(cmd)...)
 
 	format := cmd.Root().String("format")
 	transform := cmd.Root().String("transform")

You can send follow-ups to the cloud agent here.

Comment thread pkg/cmd/imagecmd.go
@firetiger-agent

Copy link
Copy Markdown

Created a monitoring plan for this PR.

What this PR does: Adds a --platform os/arch[/variant] flag to hypeman run, hypeman pull, and hypeman image list, enabling users to run x86 images on Apple Silicon via Rosetta (e.g., --platform linux/amd64 --hypervisor vz).

Intended effect:

  • Platform API field acceptance: baseline 0 platform-related errors/hr; confirmed if no invalid_platform or unknown field rejections appear in API responses after users exercise the flag
  • Instance creation rate: baseline ~5 "failed to create instance" errors/hr (Jun 7-8, calm period); confirmed if this remains stable and no new error class emerges

Risks:

  • API rejects platform field — Railway stdout logs (hypeman has no OTel), alert if any 400/422 error referencing platform or unknown field appears after the first user invocation
  • image list unintended injectionhandleImageList now appends platform request options; alert if any user reports unexpected errors on hypeman image list after this release

Status updates will be posted automatically on this PR as monitoring progresses.

View monitor

rgarcia and others added 3 commits June 8, 2026 21:07
The server now returns a platform field on instance and image responses,
but the SDK v0.20.0 structs predate it. Render `hypeman inspect` from the
raw server payload (instance.RawJSON()) so the platform shows, and add a
PLATFORM column to `image list` via a shared platformFromRaw helper.
Long-term this is better fixed by an SDK regen/bump.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…hot restore precondition

- During a cold `run` the image-resolve poll loop now treats a transient
  404 as still-pulling and keeps waiting (via errors.As), instead of
  surfacing a misleading not-found.
- Document on `snapshot restore --help` that the target must not be
  Running (returns 409 invalid_state).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n helper

Reviewer-cleanup pass:
- Fix: `hypeman image create --platform` was silently dropped — handleImageCreateLike
  never forwarded the platform option. It now does. (Cursor Bugbot: "Platform flag
  ignored on create".)
- Remove the misplaced platform-option append on `image list` (no --platform flag
  there, so it was always a no-op).
- Collapse the three identical platform request-option helpers
  (imageCreateRequestOptions / imageCreateOptionsForPlatform /
  instanceCreateOptionsForPlatform) into one platformRequestOptions(platform).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Colon in env keys breaks redaction
    • Updated escapeSJSONKey to escape : and extended redaction tests to cover colon-containing env keys so redaction no longer falls back to unmodified JSON.

Create PR

Or push these changes by commenting:

@cursor push e7c5384733
Preview (e7c5384733)
diff --git a/pkg/cmd/inspect.go b/pkg/cmd/inspect.go
--- a/pkg/cmd/inspect.go
+++ b/pkg/cmd/inspect.go
@@ -95,10 +95,10 @@
 }
 
 // escapeSJSONKey escapes characters sjson treats specially in a path (the '.'
-// separator plus the '*', '?', '|', '#', and '@' wildcards/modifiers) so env var
-// names containing them address the intended key.
+// and ':' separators plus the '*', '?', '|', '#', and '@' wildcards/modifiers)
+// so env var names containing them address the intended key.
 func escapeSJSONKey(key string) string {
-	for _, special := range []string{".", "*", "?", "|", "#", "@"} {
+	for _, special := range []string{".", ":", "*", "?", "|", "#", "@"} {
 		key = strings.ReplaceAll(key, special, "\\"+special)
 	}
 	return key

diff --git a/pkg/cmd/inspect_test.go b/pkg/cmd/inspect_test.go
--- a/pkg/cmd/inspect_test.go
+++ b/pkg/cmd/inspect_test.go
@@ -35,12 +35,12 @@
 	})
 
 	t.Run("handles env keys containing sjson special chars", func(t *testing.T) {
-		// '*', '?', '|', '#', '@' are all special to sjson path parsing.
-		raw := `{"env":{"A*B":"s1","C?D":"s2","E|F":"s3","G#H":"s4","I@J":"s5"}}`
+		// ':', '*', '?', '|', '#', '@' are all special to sjson path parsing.
+		raw := `{"env":{"A:B":"s0","A*B":"s1","C?D":"s2","E|F":"s3","G#H":"s4","I@J":"s5"}}`
 
 		redacted := redactEnvValues(raw)
 
-		for _, key := range []string{`env.A\*B`, `env.C\?D`, `env.E\|F`, `env.G\#H`, `env.I\@J`} {
+		for _, key := range []string{`env.A\:B`, `env.A\*B`, `env.C\?D`, `env.E\|F`, `env.G\#H`, `env.I\@J`} {
 			assert.Equal(t, "[hidden]", gjson.Get(redacted, key).String(), "key %s", key)
 		}
 	})

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit de21b5d. Configure here.

Comment thread pkg/cmd/inspect.go
for _, special := range []string{".", "*", "?", "|", "#", "@"} {
key = strings.ReplaceAll(key, special, "\\"+special)
}
return key

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Colon in env keys breaks redaction

Medium Severity

escapeSJSONKey does not escape : in env var names, but sjson path syntax treats colons specially. Keys containing : can make sjson.Set fail or target the wrong path; redactEnvValues then returns the original JSON, exposing secret env values on default inspect without --show-env.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit de21b5d. Configure here.

@rgarcia

rgarcia commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Addressed Cursor Bugbot finding + cleanup

Bugbot "Platform flag ignored on create" — fixed in de21b5d. hypeman image create --platform … was silently dropped: the platform request-option was wired onto image list (which has no --platform flag, so it was a no-op) instead of image create. Now image create forwards it and the dead image list append is gone.

Also unified the three identical platform request-option helpers (imageCreateRequestOptions / imageCreateOptionsForPlatform / instanceCreateOptionsForPlatform) into one platformRequestOptions(platform), so the temporary WithJSONSet workaround (SDK v0.20.0 has no typed platform field yet) lives in one place.

go build ./... + go test ./pkg/cmd/ green; CI re-running. Requesting review 🙏

@rgarcia rgarcia merged commit 8c811c0 into main Jun 9, 2026
8 checks passed
@rgarcia rgarcia deleted the codex/add-platform-flag branch June 9, 2026 15:00
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