From 73a1a3f9e6f63dcf6a68c92748bf66886676379a Mon Sep 17 00:00:00 2001 From: Ryan <10638626+ryancee@users.noreply.github.com> Date: Sat, 18 Apr 2026 21:40:42 -0400 Subject: [PATCH 1/2] fix(runtime): bind-mount file secrets to target paths in Apple container runtime The Apple runtime was staging file secrets on the host but only mounting the entire secrets directory at /run/scion-secrets:ro, instead of bind-mounting each secret to its intended container target path. This mirrors how the Docker runtime handles file secrets: capture the mount specs returned by writeFileSecrets() and pass them to insertVolumeFlags(), so each secret (e.g. OPENCODE_AUTH) lands at its correct path inside the container (e.g. ~/.local/share/opencode/auth.json). Also disables MetadataInterception for Apple runtime since it does not support --cap-add NET_ADMIN required by the iptables-based GCE metadata blocking approach. --- pkg/runtime/apple_container.go | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/pkg/runtime/apple_container.go b/pkg/runtime/apple_container.go index cb312c953..d35435da9 100644 --- a/pkg/runtime/apple_container.go +++ b/pkg/runtime/apple_container.go @@ -18,9 +18,7 @@ import ( "context" "encoding/json" "fmt" - "os" "os/exec" - "path/filepath" "strings" "time" @@ -48,11 +46,14 @@ func (r *AppleContainerRuntime) ExecUser() string { func (r *AppleContainerRuntime) Run(ctx context.Context, config RunConfig) (string, error) { // Stage file, variable, and secret-map secrets before building args + var secretMountSpecs []string if config.HomeDir != "" && len(config.ResolvedSecrets) > 0 { containerHome := util.GetHomeDir(config.UnixUsername) - if _, err := writeFileSecrets(config.HomeDir, containerHome, config.ResolvedSecrets); err != nil { + mounts, err := writeFileSecrets(config.HomeDir, containerHome, config.ResolvedSecrets) + if err != nil { return "", fmt.Errorf("failed to stage file secrets: %w", err) } + secretMountSpecs = mounts if err := writeVariableSecrets(config.HomeDir, config.ResolvedSecrets); err != nil { return "", fmt.Errorf("failed to write variable secrets: %w", err) } @@ -66,6 +67,10 @@ func (r *AppleContainerRuntime) Run(ctx context.Context, config RunConfig) (stri config.Env = append(config.Env, telemetryGCPCredentialsEnvVar+"="+credPath) } + // Apple container runtime does not support Linux capabilities (--cap-add). + // Metadata interception relies on GCE_METADATA_HOST env var instead of iptables. + config.MetadataInterception = false + args, err := buildCommonRunArgs(config) if err != nil { return "", err @@ -109,13 +114,10 @@ func (r *AppleContainerRuntime) Run(ctx context.Context, config RunConfig) (stri // Skip the original 'run', '-d', and '-i' from buildCommonRunArgs (indices 0, 1, 2) newArgs = append(newArgs, args[3:]...) - // Insert secrets staging directory volume before the image so it is treated - // as a container flag rather than an argument to the container command. - if config.HomeDir != "" && len(config.ResolvedSecrets) > 0 { - secretsDir := filepath.Join(filepath.Dir(config.HomeDir), "secrets") - if _, err := os.Stat(secretsDir); err == nil { - newArgs = insertVolumeFlags(newArgs, config.Image, []string{secretsDir + ":/run/scion-secrets:ro"}) - } + // Insert file secret bind-mounts before the image so they are treated as + // container flags rather than arguments to the container command. + if len(secretMountSpecs) > 0 { + newArgs = insertVolumeFlags(newArgs, config.Image, secretMountSpecs) } WriteRuntimeDebugFile(config, r.Command, newArgs) From 68a1bfc38dd0a8e8e5eb2941c0b4d8305b7d4340 Mon Sep 17 00:00:00 2001 From: Ryan <10638626+ryancee@users.noreply.github.com> Date: Sat, 18 Apr 2026 21:49:50 -0400 Subject: [PATCH 2/2] fix(runtime): clarify MetadataInterception comment for Apple runtime The original comment incorrectly implied that GCE_METADATA_HOST was being set here as an alternative to iptables interception. In fact GCE_METADATA_HOST and GCE_METADATA_ROOT are already injected into the agent env by the broker (start_context.go) for assign/block metadata modes. The comment now accurately describes the trade-off: iptables interception is unavailable on Apple, so only apps that honour the standard env vars will reach the scion metadata server. --- pkg/runtime/apple_container.go | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pkg/runtime/apple_container.go b/pkg/runtime/apple_container.go index d35435da9..ca36b38e5 100644 --- a/pkg/runtime/apple_container.go +++ b/pkg/runtime/apple_container.go @@ -67,8 +67,13 @@ func (r *AppleContainerRuntime) Run(ctx context.Context, config RunConfig) (stri config.Env = append(config.Env, telemetryGCPCredentialsEnvVar+"="+credPath) } - // Apple container runtime does not support Linux capabilities (--cap-add). - // Metadata interception relies on GCE_METADATA_HOST env var instead of iptables. + // Apple container runtime does not support Linux capabilities (--cap-add NET_ADMIN), + // so iptables-based metadata traffic interception is not available. Disable it here + // to avoid a fatal unsupported-flag error at container startup. Apps that honour the + // GCE_METADATA_HOST / GCE_METADATA_ROOT environment variables (already injected by + // the broker for assign/block modes) will still reach the scion metadata server; + // only apps that bypass those variables and hardcode metadata.google.internal will + // not be intercepted. config.MetadataInterception = false args, err := buildCommonRunArgs(config)