Skip to content

macOS guests 2/6: OCI machine-image integration - #499

Draft
chruffins wants to merge 8 commits into
spike/macos-guestsfrom
feat/macos-oci-images
Draft

chruffins wants to merge 8 commits into
spike/macos-guestsfrom
feat/macos-oci-images

Conversation

@chruffins

@chruffins chruffins commented Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Stack

PR 2/6 of the macOS guest integration stack. Depends on #498; kept draft while the machine-image schema and Windows integration are reconciled.

Summary

  • Accept complete darwin/arm64 machine bundles through the existing OCI image manager, rather than treating them as Linux root filesystems.
  • Validate version/kind/disk format, confined payload paths, matching auxiliary storage and platform configuration before marking an image ready.
  • Materialize the boot disk and auxiliary storage, preserve platform/identity metadata, and enforce requested-platform matching on cached reuse.
  • Support additional tags within the same repository; reject cross-repository promotion until all machine components are handled safely.
  • Add synthetic loopback registry round-trip/negative tests and document the experimental schema.

No Geranos dependency, new runtime transport, image delta format, or concurrent clone/rekey guarantee.

Validation

Passed focused tests:

  • TestMacOSMachineValidation and TestMacOSMachineOCIRoundTrip: reconstructed disk/aux hashes, manifest digest, config identity, cache reuse, same-repository tag and wrong-platform rejection.
  • Platform-resolution and existing TestTagImage* regressions.
  • Formatting and diff checks.

The test registry's PATCH path buffers uploads in memory, even with disk storage. The test seeds blobs through its streaming disk handler, publishes a manifest, then pulls through the normal HTTP image manager. This tests pull/materialization, not streaming OCI push.

Remaining draft gates

  • Real stopped-bundle round-trip and normal HTTP API pull-to-boot. The first real test was killed during the test registry upload, before Hypeman pull; no real round-trip or boot success is claimed.
  • Shared machine-image schema alignment with Windows work (Add OCI Windows machine images #429).
  • Broader auth/cancellation/failure/GC and Linux regression coverage; sparse storage measurements and cross-repository promotion.
  • Independent automated review is blocked by reviewer authentication (401), not reported as clean.

No live VM/API changes or committed VM images, credentials, benchmark tasks, traces, or private planning notes.


Note

Medium Risk
Changes image pull, conversion, and on-disk layout for darwin/arm64 artifacts and path validation for bundled files; Linux rootfs export is unchanged when labels do not denote a machine image.

Overview
Registry pulls for darwin/arm64 complete machine bundles now go through the normal image manager instead of being rejected as “local import only.” Manifests are recognized via experimental io.hypeman.machine-image.* labels; the build path validates confined disk/aux/platform paths, copies the raw boot disk (no Linux rootfs export), installs aux.img, and stores MacOS platform metadata on finalize.

Platform and tagging behavior loosens: resolveManifestPlatform accepts darwin/arm64 manifests, CreateImage checks cached ready images against an explicit --platform, and same-repository tags work for macOS bundles while cross-repository promotion stays blocked.

New parseMacOSMachine logic and OCI round-trip tests (synthetic loopback registry) cover validation and pull/materialization; docs describe the experimental OCI bundle schema and updated import vs registry capabilities.

Reviewed by Cursor Bugbot for commit fdc003f. Configure here.

@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 using default effort and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit fdc003f. Configure here.

Comment thread lib/images/manager.go Outdated
if err != nil || !platform.Matches(actual) {
return nil, fmt.Errorf("%w: requested %s but cached manifest is %s", ErrInvalidPlatform, platform, cached.Platform)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Empty platform fails cache reuse

Medium Severity

The new cached-reuse check calls ParsePlatform on stored cached.Platform and treats any parse error as a mismatch. Ready images from before platform tracking store an empty platform and are otherwise treated as the host. An explicit platform on CreateImage or instance create now fails reuse of those images with ErrInvalidPlatform instead of matching them as host-native.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit fdc003f. Configure here.

@chruffins

Copy link
Copy Markdown
Contributor Author

QA update on reviewed head 66b5a59: real stopped installed macOS bundle OCI pull/materialization passed (test exit 0 plus the required roundtrip.json).

  • 64-GiB raw disk; compressed OCI layer ~26.22 GiB; total test ~373 seconds.
  • Normal image manager pulled through a loopback registry, reached ready on darwin/arm64, and verified disk/aux SHA256, complete platform metadata, manifest digest, canonical modes, cache reuse, same-repository aliasing, cross-repository rejection and wrong-platform rejection.
  • Follow-up cached artifact list/get through authenticated generated HTTP image handlers also passes with race detector; unauthenticated requests rejected.
  • Allowlisted environment with empty Docker config, nice=10, GOMAXPROCS=1, GOMEMLIMIT=256MiB. Sampled job-process-group RSS peak ~62 MiB; kernel file cache is not included. Free disk remained ~523 GiB, above the 60-GiB floor.

Important scope: the registry blobs were seeded via the disk-streaming handler, so this validates large real HTTP pull/materialization, not large-layer PATCH upload. It also does not prove cold boot or live GuestService provisioning/lifecycle. No existing instance was started, stopped or reprovisioned by these tests. Keep draft pending the remaining gates.

@chruffins

Copy link
Copy Markdown
Contributor Author

Follow-up live QA: the artifact from the earlier real HTTP materialization run now passed normal authenticated API create/cold boot on Apple silicon with the source registry offline, actual macOS27.0.1/26A434 SSH readiness, template CPU/RAM inheritance, duplicate-identity409, live API restart recovery without guest reboot, and HTTP stop/start with persistent guest marker. Full immutable materialized base disk+aux SHA256 stayed identical after testing. Original instance/API/storage untouched; isolated QA VM/API ended stopped and QA slot released. Stop used system-agent-disabled fallback, not verified root-agent graceful shutdown. Combined reviewed PR1–3 + PR4 patches tested; reviewer branches not rewritten. See runtime issue/result detail: #498 (comment). Separately, actual26.22GiB streaming monolithic POST upload to empty production-registry-handler destination plus independent blob/manifest validation passed; default PATCH is still buffered/unproven, and that destination was not freshly pulled/booted: #503 (comment).

@chruffins
chruffins force-pushed the feat/macos-oci-images branch 3 times, most recently from 5fcd8c9 to 4d9bc18 Compare October 9, 2026 19:49
chruffins and others added 8 commits October 9, 2026 16:47
- Give the boot disk private permissions regardless of registry modes.
- Stage auxiliary storage before taking the manager lock; finalization
  only renames it into place.
- Count auxiliary storage in the image size used for accounting.
- Require a 6-byte Ethernet machine MAC.
- Reject bundle files that are hardlinks of one another.
Compare the machine platform after the same normalization used for manifest
matching, so aarch64 and case variants such as Darwin select the machine
path instead of falling through to the rootfs path.
Copy and validate the boot disk and auxiliary storage in a single helper, and
hand finalization one staged-files value (paths, payload, size) instead of
separately correlated paths and a variadic payload. Finalization still only
renames staged files and commits metadata under the manager lock.
- Compare the requested platform with cached records only for macOS images.
  Linux records from before platform tracking have no platform, and the check
  rejected every explicit-platform create that reached one.
- Track everything finalization installs (aux, disk, manifest model) in one
  list, removed together if finalization fails before the metadata commit.
- Use MacOSImage.Validate for the OCI machine parser, sharing the import rules.
- Drop the env-gated real-bundle branch from the unit test. It shelled to lsof
  and wrote a report file; the synthetic round trip covers the same pull path.
finalize reads just the platform from the machine payload, so stagedImageFiles
holds that platform rather than the whole payload. The payload's source paths
are only needed while staging.
…es whole

- Check an explicit platform against a ready macOS record inside
  reuseExistingImage, which already reads that record under the create lock,
  instead of reading it a second time in CreateImage.
- Resolve an explicit platform against the manifest through
  validateDigestPlatform, which already holds the same check and message.
- stageMacOSMachine returns the staged files value, so buildImage assigns one
  value instead of assembling the aux path, platform and size separately.
@chruffins
chruffins force-pushed the feat/macos-oci-images branch from 4d9bc18 to 4888603 Compare October 9, 2026 21:53
@chruffins

Copy link
Copy Markdown
Contributor Author

Simplification update at 4888603: OCI uses the shared bounded bundle decoder; permanent TestFinalizationRollbackPreservesUninstalledManifest fixes the reproduced regression where rollback deleted an existing manifest that had never been installed. Focused image regressions passed 3 race runs; no new real upload/pull/boot claim.

All PRs remain draft. This is source-level/synthetic validation, not a new live boot or production build proof. Default Codex independent review was attempted but is still blocked by authentication (HTTP401). Published atomically after checking reviewer heads with explicit per-ref force-with-lease; prior heads preserved locally.

This branch has not been deployed

No deployments
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.

1 participant