Skip to content

Fix container machine setup script being dropped from artifact.#1891

Open
anxkhn wants to merge 1 commit into
apple:mainfrom
anxkhn:patch-2
Open

Fix container machine setup script being dropped from artifact.#1891
anxkhn wants to merge 1 commit into
apple:mainfrom
anxkhn:patch-2

Conversation

@anxkhn

@anxkhn anxkhn commented Jul 4, 2026

Copy link
Copy Markdown
## Type of Change
- [x] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update

## Motivation and Context
When a container machine image ships a custom setup script as an OCI artifact,
that script was silently dropped and the default `create-user.sh` was used
instead.

In `MachineClient.fetchMachineArtifact`, the config layer is decoded into
`resources: MachineResources?` and the separate setup-script layer into
`setupScript: String?`. The two were merged with:

    if var resources, let setupScript {
        resources.setupScript = setupScript
    }

`MachineResources` is a value type (a `struct`), so `if var resources` binds a
mutable copy. Assigning `setupScript` mutates that throwaway copy, which is
discarded at the end of the block. The function then returns the outer
`resources`, whose `setupScript` is still `nil`. Downstream,
`MachineBundle.create` sees `resources?.setupScript == nil` and falls back to
copying the default `userSetupFile`, so the per-image script fetched from the
registry is never applied.

The fix merges through the optional (`resources?.setupScript = setupScript`) so
the value survives on the returned `MachineResources`. The merge is extracted
into a small `merge(resources:setupScript:)` helper, both to make the value
semantics explicit and to give the logic a unit-testable seam
(`fetchMachineArtifact` itself needs a live registry client).

## Testing
- [x] Tested locally
- [x] Added/updated tests
- [ ] Added/updated docs

Added a `MachineAPIClientTests` target with three tests for the merge:
- a non-nil setup script is applied to the returned resources,
- a nil setup script leaves an existing script untouched,
- a nil `resources` stays nil.

`swift test --filter MachineAPIClientTests` passes (3/3). Reverting the helper to
the original `if var resources` body makes the first test fail
(`merged?.setupScript` is `nil`), confirming the test covers this bug. The full
tree builds with `swift build --build-tests`, and `swift format lint --strict`
is clean on the changed files.

Files changed (3 files, +56 -3)

  • Sources/Services/MachineAPIService/Client/MachineClient.swift
    Replace the inline if var resources, let setupScript { ... } merge with a call
    to a new static func merge(resources:setupScript:) -> MachineResources? that
    assigns through the optional. Doc comment notes the value-type pitfall.
  • Package.swift
    Add a MachineAPIClientTests test target depending on MachineAPIClient
    (this target had no unit tests before, only VM-dependent integration tests).
  • Tests/MachineAPIClientTests/MachineClientMergeTests.swift (new)
    Three Swift Testing (import Testing) regression tests. Carries the repo's
    canonical Apache-2.0 license header (byte-identical to existing tracked files).

When fetching container machine resources from an OCI artifact, the
setup script layer was decoded separately and then merged into the
config with `if var resources, let setupScript`. Because
MachineResources is a value type, that binding mutated a throwaway
copy, so the fetched setup script was silently discarded and the
returned resources kept a nil setupScript. As a result MachineBundle
fell back to the default create-user.sh instead of the per-image
script.

Merge through the optional so the script survives on the returned
value, and add unit tests for the merge behavior.
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