Skip to content

applecontainer: Inspect + FindContainerByLabel (PR-B)#60

Merged
bilby91 merged 2 commits into
mainfrom
m6/pr-b-inspect-find
May 15, 2026
Merged

applecontainer: Inspect + FindContainerByLabel (PR-B)#60
bilby91 merged 2 commits into
mainfrom
m6/pr-b-inspect-find

Conversation

@bilby91
Copy link
Copy Markdown
Member

@bilby91 bilby91 commented May 15, 2026

Summary

Third PR of M6. Replaces the InspectContainer / InspectImage /
FindContainerByLabel stubs with real implementations driven through
the bridge. Also lands the ac_bridge.h header-comment style guide
queued for this PR.

What lands

Bridge (Swift)

  • Helpers.swift — shared runSync (Task + DispatchSemaphore + hard
    wait timeout), encodeOK / encodeOKNull / encodeErr envelope
    helpers. ISO8601 date encoding strategy so Apple's Date fields
    decode cleanly into Go time.Time.
  • inspect.swift — three new exports:
    • ac_inspect_container (wraps ContainerClient.get)
    • ac_inspect_image (wraps ClientImage.get + image.config()
      surfaces OCI Labels, the load-bearing devcontainer.metadata
      fast path)
    • ac_find_container_by_label (list + filter + most-recently-
      started wins)
  • bridge.swift — refactored to use the shared helpers; ac_ping
    keeps its pre-style-guide flat shape for PR-A stability.
  • ac_bridge.h — full header-comment style guide. Every export
    documents the five contracts: ownership, cancellation, threading,
    error encoding, blocking.

cgo shim (Go side)

  • shim.h / shim.c — three new function-pointer slots and wrappers,
    resolved via dlsym in ac_load. Partial-failure path resets all
    pointers and dlcloses the handle.

Runtime methods (inspect_darwin_arm64.go)

  • Generic decodeEnvelope[T] for the canonical {ok, err, data} shape
    with null-data tolerance for the find-by-label miss path.
  • containerSnapshot / imageInspectPayload mirror the Apple JSON
    shapes we consume; only fields we need are listed.
  • snapshotToContainer / snapshotToDetails / mapState project
    Apple types into runtime.Container / runtime.ContainerDetails.
    Created, FinishedAt, ExitCode are zero — not in Apple's
    ContainerSnapshot; later PRs can surface them via additional XPC
    calls if needed.
  • mapInspectErr / mapImageInspectErr translate Apple's notFound
    errors into runtime.ContainerNotFoundError /
    runtime.ImageNotFoundError so the engine's typed-error contracts
    hold across backends.

Tests

  • envelope_test.go — pure Go unit tests for success / failure /
    null-data / malformed-JSON / mapState. No daemon, no cgo at
    runtime.
  • inspect_darwin_arm64_test.go — smoke tests against a live daemon:
    • InspectContainer round-trip with a labeled container
    • InspectContainer not-found typed-error
    • InspectImage with a warmed alpine image
    • InspectImage not-found typed-error
    • FindContainerByLabel hit + miss

Test plan

  • make bridge && go test ./runtime/applecontainer/... — 11 tests
    pass (5 envelope + 6 smoke)
  • go test ./... — full repo green; no regression in any
    existing package
  • GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build ./runtime/applecontainer/...
    — stub still compiles
  • go vet ./... clean

Summary by CodeRabbit

  • New Features

    • Add container inspection, image inspection, and label-based container search with timeout-aware calls.
  • Documentation

    • Expanded bridge header with usage, ownership, and error/encoding guidance for exported calls.
  • Tests

    • Add unit tests for envelope decoding and state mapping, plus runtime smoke tests exercising the new inspect flows.
  • Chores

    • Runtime shim updated to load and forward new inspection entry points.

Review Change Stack

Third PR of M6. Replaces the InspectContainer / InspectImage /
FindContainerByLabel stubs with real implementations driven through
the bridge. Also lands the ac_bridge.h header-comment style guide
queued for this PR.

Bridge (Swift):
- Helpers.swift: shared runSync (Task + DispatchSemaphore + hard wait
  timeout), encodeOK / encodeOKNull / encodeErr envelope helpers,
  ISO8601 date encoding strategy on the JSONEncoder so Apple's Date
  fields decode cleanly into Go's time.Time.
- inspect.swift: ac_inspect_container (ContainerClient.get),
  ac_inspect_image (ClientImage.get + image.config().Labels — the
  load-bearing devcontainer.metadata fast path), and
  ac_find_container_by_label (list + filter + most-recently-started
  wins).
- bridge.swift: refactored to use the shared helpers; ac_ping keeps
  its predates-style-guide flat shape for PR-A stability.
- ac_bridge.h: full header-comment style guide describing the five
  contracts every export documents (ownership, cancellation,
  threading, error encoding, blocking). All exports — ac_version,
  ac_ping, ac_free, plus the three new ones — documented.

cgo shim (Go side):
- shim.h / shim.c: add ac_inspect_container_p, ac_inspect_image_p,
  ac_find_container_by_label_p function-pointer slots; dlsym them in
  ac_load; reset and dlclose on partial-failure paths.

Runtime methods (inspect_darwin_arm64.go):
- decodeEnvelope[T] generic decoder for the canonical {ok, err, data}
  shape with null-data tolerance for the find-by-label miss path.
- containerSnapshot / imageInspectPayload mirror the Apple JSON
  shapes we consume; only the fields we need are listed.
- snapshotToContainer / snapshotToDetails / mapState project Apple
  types into runtime.Container / runtime.ContainerDetails. Created,
  FinishedAt, ExitCode are zero — not in Apple's ContainerSnapshot;
  surfaced via additional XPC calls in later PRs.
- decodeUserString handles ProcessConfiguration.User's
  raw/id enum variants.
- mapInspectErr / mapImageInspectErr translate Apple's "notFound"
  errors into runtime.ContainerNotFoundError /
  runtime.ImageNotFoundError so the engine's typed-error contracts
  hold across backends.

Tests (darwin/arm64 only — no daemon needed for envelope tests):
- envelope_test.go: success / failure / null-data / malformed-JSON /
  mapState. Pure Go, no cgo at runtime.
- inspect_darwin_arm64_test.go: smoke tests against a live daemon.
  InspectContainer round-trip with a labeled container,
  InspectContainer not-found typed-error contract, InspectImage
  with a warmed alpine image, InspectImage not-found typed-error,
  FindContainerByLabel hit + miss paths.

Test plan:
- `make bridge && go test ./runtime/applecontainer/...` — 11 tests
  pass (5 envelope unit tests + 6 daemon smoke tests)
- `go test ./...` — full repo green
- `GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build ./runtime/applecontainer/...`
  — stub still compiles
- `go vet ./...` clean

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 15, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 2943c756-de9b-49dc-a539-d22d98e76144

📥 Commits

Reviewing files that changed from the base of the PR and between 836cd52 and 582fb44.

📒 Files selected for processing (2)
  • applecontainer-bridge/Sources/ACBridge/inspect.swift
  • runtime/applecontainer/inspect_darwin_arm64_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • runtime/applecontainer/inspect_darwin_arm64_test.go

📝 Walkthrough

Walkthrough

Adds three Swift C-exported inspection entrypoints (container, image, label lookup) that run async work synchronously via a shared runSync helper and return deterministic JSON envelopes. The C header documents semantics; the shim resolves the symbols and the Go runtime decodes envelopes and maps them to runtime types with tests.

Changes

Container/Image Inspection via Bridge

Layer / File(s) Summary
ac_inspect_container entrypoint
applecontainer-bridge/Sources/ACBridge/inspect.swift
ac_inspect_container validates the C id arg, calls ContainerClient().get(id:) inside runSync(timeoutSeconds:), and returns encodeOK(snapshot) or encodeErr.
ac_inspect_image entrypoint and payload projection
applecontainer-bridge/Sources/ACBridge/inspect.swift
ac_inspect_image validates the reference, fetches ClientImage.get(reference) + .config(.current), projects fields into ImageInspectPayload (digest/reference/arch/os/user/env/labels) with empty defaults, and returns encodeOK(payload) or encodeErr.
ac_find_container_by_label entrypoint
applecontainer-bridge/Sources/ACBridge/inspect.swift
ac_find_container_by_label validates key/value, lists containers, filters by configuration.labels[key] == value, selects most-recent startedDate (nil => distantPast), returns encodeOK(pick) or encodeOKNull() when no match, and encodes errors via encodeErr.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • crunchloop/devcontainer#58: Earlier PR introduces the initial Swift bridge runSync pattern and JSON envelope helpers that this PR extends for inspection APIs.
  • crunchloop/devcontainer#59: Related PR extends the C shim dlopen/dlsym loader to resolve and expose the newly added Swift inspection exports via function-pointer wrappers.

Poem

A rabbit stitched a bridge of JSON light,
From Swift's async hills to Go's tidy sight.
Containers whisper labels, images show their name,
In envelopes steady, each response the same.
Hop, hop—inspection done. 🐰

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'applecontainer: Inspect + FindContainerByLabel (PR-B)' accurately reflects the main changes: adding inspect container/image functionality and finding containers by label to the applecontainer bridge.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch m6/pr-b-inspect-find

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
applecontainer-bridge/Sources/ACBridge/Helpers.swift (1)

67-73: 💤 Low value

Consider escaping additional JSON control characters.

The escaping handles \, ", and \n, but other control characters (\r, \t, \b, \f) could also produce invalid JSON if they appear in error messages. While unlikely for typical Apple framework errors, adding them would make the encoder more robust.

♻️ More complete escaping
 func encodeErr(_ error: Error) -> String {
     let msg = String(describing: error)
         .replacingOccurrences(of: "\\", with: "\\\\")
         .replacingOccurrences(of: "\"", with: "\\\"")
         .replacingOccurrences(of: "\n", with: "\\n")
+        .replacingOccurrences(of: "\r", with: "\\r")
+        .replacingOccurrences(of: "\t", with: "\\t")
     return "{\"ok\":false,\"err\":\"\(msg)\"}"
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@applecontainer-bridge/Sources/ACBridge/Helpers.swift` around lines 67 - 73,
The encodeErr function only escapes backslashes, double quotes and newlines;
update it to also escape JSON control characters (\r, \t, \b, \f) so error
strings always produce valid JSON. In the encodeErr(_ error: Error) -> String
function add replacingOccurrences calls (or a single pass normalizer) to replace
"\r" with "\\r", "\t" with "\\t", "\u{08}" (backspace) with "\\b" and "\u{0C}"
(form feed) with "\\f" before embedding msg into the JSON payload, keeping the
existing escapes for "\\" and "\"" and "\n".
runtime/applecontainer/inspect_darwin_arm64.go (1)

319-336: 💤 Low value

Consider using strings.Contains instead of custom indexOf.

The custom indexOf implementation adds maintenance overhead to avoid a single import. The strings package is part of the standard library and commonly used. Unless there's a specific constraint (e.g., build size), using strings.Contains would be cleaner.

♻️ Use standard library
+import "strings"
+
 func containsAny(s string, subs ...string) bool {
 	for _, sub := range subs {
-		if indexOf(s, sub) >= 0 {
+		if strings.Contains(s, sub) {
 			return true
 		}
 	}
 	return false
 }
-
-// indexOf is strings.Contains/strings.Index minus the import — keeps
-// this file's deps narrow (and avoids re-importing strings for this
-// one use). Inline implementation, O(n*m), fine for our short error
-// strings.
-func indexOf(s, sub string) int {
-	if len(sub) == 0 {
-		return 0
-	}
-	if len(sub) > len(s) {
-		return -1
-	}
-	for i := 0; i+len(sub) <= len(s); i++ {
-		if s[i:i+len(sub)] == sub {
-			return i
-		}
-	}
-	return -1
-}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@runtime/applecontainer/inspect_darwin_arm64.go` around lines 319 - 336,
Replace the custom indexOf function with the standard library: add an import for
"strings", remove the indexOf(s, sub string) function, and update call sites—if
code only checks presence, change indexOf(s, sub) != -1 to strings.Contains(s,
sub); if the code needs the integer offset, use strings.Index(s, sub) which
returns -1 on no match. This keeps behavior identical while using the built-in
strings package.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@runtime/applecontainer/inspect_darwin_arm64_test.go`:
- Around line 98-128: The test TestInspectImage_LabelsRoundTrip promises a
non-nil Labels contract but only logs it; add an explicit assertion after
calling rt.InspectImage to fail the test if details.Labels is nil (e.g. if
details.Labels == nil { t.Errorf("Labels is nil") }), so the contract is
enforced; place the check near the existing inspections (after verifying
details.Tags/ID and before or after the t.Logf) and reference the details
variable returned by rt.InspectImage.
- Around line 41-50: The helper cliRunStrict currently calls t.Skipf on any
non-zero exit which masks real failures; update it so that after running
exec.Command("container", args...).CombinedOutput() it checks whether the error
indicates the CLI binary is missing (use errors.Is(err, exec.ErrNotFound) or
inspect exec.ExitError vs lookup error) and only then call t.Skipf, otherwise
call t.Fatalf (or t.Fatalf-like) including the args, error and trimmed output to
fail the test on real setup failures; refer to the cliRunStrict function and the
exec.Command(...).CombinedOutput() / t.Skipf usage to locate where to change the
behavior.

---

Nitpick comments:
In `@applecontainer-bridge/Sources/ACBridge/Helpers.swift`:
- Around line 67-73: The encodeErr function only escapes backslashes, double
quotes and newlines; update it to also escape JSON control characters (\r, \t,
\b, \f) so error strings always produce valid JSON. In the encodeErr(_ error:
Error) -> String function add replacingOccurrences calls (or a single pass
normalizer) to replace "\r" with "\\r", "\t" with "\\t", "\u{08}" (backspace)
with "\\b" and "\u{0C}" (form feed) with "\\f" before embedding msg into the
JSON payload, keeping the existing escapes for "\\" and "\"" and "\n".

In `@runtime/applecontainer/inspect_darwin_arm64.go`:
- Around line 319-336: Replace the custom indexOf function with the standard
library: add an import for "strings", remove the indexOf(s, sub string)
function, and update call sites—if code only checks presence, change indexOf(s,
sub) != -1 to strings.Contains(s, sub); if the code needs the integer offset,
use strings.Index(s, sub) which returns -1 on no match. This keeps behavior
identical while using the built-in strings package.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c337338b-6a11-48b7-96e8-85a9d7d851a2

📥 Commits

Reviewing files that changed from the base of the PR and between 1abbbdd and 836cd52.

📒 Files selected for processing (10)
  • applecontainer-bridge/Sources/ACBridge/Helpers.swift
  • applecontainer-bridge/Sources/ACBridge/bridge.swift
  • applecontainer-bridge/Sources/ACBridge/inspect.swift
  • applecontainer-bridge/include/ac_bridge.h
  • runtime/applecontainer/envelope_test.go
  • runtime/applecontainer/inspect_darwin_arm64.go
  • runtime/applecontainer/inspect_darwin_arm64_test.go
  • runtime/applecontainer/runtime_darwin_arm64.go
  • runtime/applecontainer/shim.c
  • runtime/applecontainer/shim.h

Comment thread runtime/applecontainer/inspect_darwin_arm64_test.go
Comment thread runtime/applecontainer/inspect_darwin_arm64_test.go
Two CodeRabbit comments on #60, both valid:

cliRunStrict was masking setup failures by t.Skipf-ing on any
non-zero exit. Switched to errors.Is(err, exec.ErrNotFound) to
detect a missing `container` CLI (legitimate env mismatch — skip)
and t.Fatalf otherwise. Real regressions now surface as test
failures instead of silent skips.

InspectImage's Labels-non-nil contract was described in comments
but not actually enforced — the bridge would emit `null` when the
underlying OCI config had no labels, leaving Go with a nil map.
Tightened the Swift ImageInspectPayload to non-optional `labels:
[String: String]` and `env: [String]` with empty-collection
defaults, then added the missing assertion in
TestInspectImage_LabelsRoundTrip. Callers (engine
devcontainer.metadata fast path) can now read keys without nil-
guarding.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@bilby91 bilby91 marked this pull request as ready for review May 15, 2026 03:01
@bilby91 bilby91 merged commit c212bc8 into main May 15, 2026
8 of 9 checks passed
@coderabbitai coderabbitai Bot mentioned this pull request May 15, 2026
4 tasks
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