Skip to content

[plugin] Fix: resolve the container CLI matching the cross-compile method (lambda-build & archive)#678

Merged
sebsto merged 3 commits into
mainfrom
fix/plugin_container
Jun 29, 2026
Merged

[plugin] Fix: resolve the container CLI matching the cross-compile method (lambda-build & archive)#678
sebsto merged 3 commits into
mainfrom
fix/plugin_container

Conversation

@sebsto

@sebsto sebsto commented Jun 29, 2026

Copy link
Copy Markdown
Collaborator

Problem

Cross-compiling with Apple's container CLI did not work — neither via the new lambda-build plugin nor the legacy archive plugin. The build failed with:

/usr/local/bin/docker image pull swift:amazonlinux2023
  failed to connect to the docker API at unix:///Users/.../docker.sock ...

Both plugins always resolved the Docker binary (context.tool(named: "docker")) and forwarded it as the container CLI path, regardless of the selected cross-compilation method. So when container was requested, the plugin generated correct container-style arguments (image pull …) but executed them with the docker binary, which then failed.

Tool resolution has to happen in the plugin (the SwiftPM sandbox can only run tools it resolves up front), so the fix belongs there rather than in the helper.

Fix

Both plugins now peek the cross-compilation flag and resolve the matching tool — container when container is requested, docker otherwise — before invoking the helper. The original arguments are still forwarded unchanged.

  • AWSLambdaBuilder (lambda-build): honours --cross-compile (and the deprecated --container-cli alias).
  • AWSLambdaPackager (archive, Swift 6.4 deprecation passthrough): same bug, same fix; honours both --cross-compile and the legacy --container-cli.

Testing

Verified end-to-end against a sample project for both commands:

  • Default (no flag): resolves /usr/local/bin/docker — unchanged behaviour.
  • --cross-compile container / --container-cli container: resolves /usr/local/bin/container; the plugin now runs /usr/local/bin/container image pull … and the Linux container starts and builds.

Note

There is a separate, pre-existing limitation: Apple's container CLI communicates with its daemon over XPC, which the SwiftPM plugin sandbox blocks (XPC connection error: Connection invalid). The same command succeeds with --disable-sandbox. That sandbox issue is out of scope for this PR (which fixes the tool-resolution bug) and should be tracked separately.

@sebsto sebsto added the 🆕 semver/minor Adds new public API. label Jun 29, 2026
@sebsto sebsto self-assigned this Jun 29, 2026
@sebsto sebsto force-pushed the fix/plugin_container branch from 05aa2e9 to b77604a Compare June 29, 2026 09:13
The Swift 6.4 'archive' deprecation passthrough always resolved the docker
binary and forwarded it as --docker-tool-path, ignoring the requested
cross-compile method. As a result `archive --cross-compile container`
(and the legacy --container-cli container alias) ran container-style
arguments against the docker binary and failed.

Resolve the container CLI matching the requested method, mirroring the
fix in AWSLambdaBuilder.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@sebsto sebsto changed the title Fix: lambda-build resolves the container CLI matching --cross-compile Fix: resolve the container CLI matching the cross-compile method (lambda-build & archive) Jun 29, 2026
@sebsto sebsto merged commit 7dd3bfe into main Jun 29, 2026
53 checks passed
@sebsto sebsto deleted the fix/plugin_container branch June 29, 2026 09:53
sebsto added a commit that referenced this pull request Jun 29, 2026
…in args (#679)

### Summary

Refactors the internals of the `lambda-build` build path into a
pluggable backend
architecture, and tidies the plugin→helper argument plumbing. This is an
internal
refactor: no user-facing flag, no `--cross-compile` value, no output ZIP
path, and
no public Swift API changes. Behaviour is identical; the goal is to make
adding new
cross-compilation backends (podman, finch, colima, swift-static-sdk,
custom-sdk, …)
a localised, additive change.

### 1. Pluggable build backends (`lambda-build`)

The build logic in `Builder.swift` was a hard-coded
native-vs-docker/container
branch with an enum (`CrossCompileMethod`) that carried both the parsed
user choice
*and* the argv-building logic. It's now split along two independent
axes:

- **`BuildBackend` protocol** — *how* a build runs: `NativeBuildBackend`
(on an
  Amazon Linux host) and `ContainerBuildBackend` (inside a container).
- **`ContainerCLI` protocol** — the *argument flavor* of a container
runtime:
`DockerCLI` and `AppleContainerCLI`. A single `ContainerBuildBackend`
serves both
(and future runtimes) since only the argv spelling differs, not the
build flow.

`CrossCompileMethod` keeps only the parsed value, `parse(...)`, and a
`makeBackend(configuration:)` factory; its
`pullArguments`/`runArguments` (and the
`fatalError` SDK stubs) are gone. `Builder.build(...)` is now
select-and-delegate
(~8 lines); `Builder.swift` shrinks from ~700 to ~460 lines.

**No shared argv helper between CLIs — by design.** Each `ContainerCLI`
builds its
complete argument vector independently (no base struct, no default
implementation,
no shared closure). docker and Apple `container` argv may diverge in
future CLI
versions, and future runtimes may not be compatible at all; a shared
helper is
exactly the coupling that caused the earlier docker/container mix-up
(#678). Each
CLI is covered by its own golden-argv tests with no shared fixtures.

Adding a backend later is now additive: a new `*CLI.swift` + a
`CrossCompileMethod`
case + one line in `makeBackend` (container runtimes), or a new
`BuildBackend` type
(SDK methods). No edits to `Builder` or existing CLIs.

File layout:

```
lambda-build/
  Builder.swift                 # build() select+delegate, package(), BuilderConfiguration, BuilderErrors
  CrossCompileMethod.swift      # enum + parse + makeBackend factory
  Backends/
    BuildBackend.swift          # protocol
    NativeBuildBackend.swift
    ContainerBuildBackend.swift
    ContainerCLI.swift          # protocol
    DockerCLI.swift
    AppleContainerCLI.swift
```

### 2. Thin-layer plugin argument plumbing

The plugins are meant to be the thinnest possible layer: resolve only
the values
that need `PluginContext` / the package graph, then forward everything
else to the
helper. `lambda-build` and the deprecated `archive` (Swift 6.4
passthrough) were
re-appending the *original* arguments after extracting some, so options
like
`--products` reached the helper twice (and, for `--products`, caused the
product to
be built twice). Both now forward
`argumentExtractor.remainingArguments`, so a
consumed option is never forwarded again.

The same one-line bug (`+ arguments` → `+
argumentExtractor.remainingArguments`) is
fixed in `lambda-deploy`, which had it too.

The internal plugin→helper flag `--docker-tool-path` is renamed to
`--cross-compile-tool-path` (and the config field `dockerToolPath` →
`crossCompileToolPath`) so it no longer implies docker — it can carry
any
cross-compile tool. This flag is internal (plugin→helper), not
user-facing.

> Note: the deprecated pre-6.4 `archive` implementation (`Plugin.swift`,
behind
> `#if swift(<6.4)`) is intentionally left untouched.

### Testing

- New `BuildBackendTests.swift`: separate golden-argv tests for
`DockerCLI` and
`AppleContainerCLI` (no shared fixtures), plus `makeBackend` factory
tests
(docker → DockerCLI, container → AppleContainerCLI, SDK methods throw).
- All `AWSLambdaPluginHelperTests` pass (84 tests); `swift build` and
  `swift format lint --strict` clean.
- End-to-end against a sample project: `lambda-build` default (docker)
and
`--cross-compile container` emit byte-for-byte identical argv to before
the
  refactor; `--products` is no longer doubled.
@sebsto sebsto changed the title Fix: resolve the container CLI matching the cross-compile method (lambda-build & archive) [plugin] Fix: resolve the container CLI matching the cross-compile method (lambda-build & archive) Jun 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🆕 semver/minor Adds new public API.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant