Skip to content

feat(runtime): add Podman as supported container runtime for macOS and Linux#1359

Open
BenediktSchackenberg wants to merge 12 commits intoNVIDIA:mainfrom
BenediktSchackenberg:fix/podman-819-rebase
Open

feat(runtime): add Podman as supported container runtime for macOS and Linux#1359
BenediktSchackenberg wants to merge 12 commits intoNVIDIA:mainfrom
BenediktSchackenberg:fix/podman-819-rebase

Conversation

@BenediktSchackenberg
Copy link
Copy Markdown
Contributor

@BenediktSchackenberg BenediktSchackenberg commented Apr 2, 2026

Rebase + cleanup of #819 for @nv-ddave (by request).

What changed from the original PR

  • Rebased onto current main (resolved conflicts in onboard.js, platform.js, fix-coredns.sh, test/platform.test.js, README.md)
  • Removed the commitlint-failing revert commit — squashed into one clean feat(runtime): commit with Signed-off-by
  • Removed isUnsupportedMacosRuntime entirely (Podman on macOS is now supported)

Summary of the feature (credit: @nv-ddave)

Adds first-class Podman support alongside Docker and Colima:

  • Socket detection via getPodmanSocketCandidates() (machine socket, XDG_RUNTIME_DIR, /run/podman) with platform guards
  • CoreDNS patching enabled for Colima + Podman (both use custom network bridges)
  • fix-coredns.sh updated to use container default-gateway IP instead of resolv.conf
  • Runtime detection, README platform matrix, and troubleshooting docs updated
  • Test coverage: unit tests for platform.js + runtime-shell integration tests

Co-authored-by: nv-ddave nv-ddave@users.noreply.github.com
Signed-off-by: Benedikt Schackenberg 6381261+BenediktSchackenberg@users.noreply.github.com

Summary by CodeRabbit

  • New Features

    • Podman is now recognized as a supported runtime on macOS and Linux; onboarding/install flows accept it.
  • Bug Fixes

    • Improved runtime detection and CoreDNS handling to prefer Colima/Podman and avoid premature unsupported-runtime exits; CoreDNS patching now fails if no valid upstream is found.
  • Documentation

    • Updated container runtimes matrix and added a Podman troubleshooting guide.
  • Tests

    • Expanded/adjusted tests for Podman detection and related flows.
  • Chores

    • Updated ShellCheck configuration to follow sourced files.

…d Linux

Adds first-class Podman support alongside Docker and Colima:

- Detect Podman socket (machine socket, XDG_RUNTIME_DIR, /run/podman)
  via getPodmanSocketCandidates() with platform guards
- Remove the macOS Podman block in preflight — Podman on macOS is now
  supported via socket detection
- CoreDNS patching now runs for both Colima and Podman (both use custom
  network bridges where the loopback DNS is unreachable from pods)
- fix-coredns.sh updated to use the container default-gateway IP
  (reachable from k3s pods) instead of resolv.conf entries
- Runtime detection, platform matrix in README, and troubleshooting
  docs updated to reflect Podman support
- Test coverage: platform.js unit tests + runtime-shell integration tests

Rebased onto current main and squashed commit-lint-failing revert commit.

Co-authored-by: nv-ddave <nv-ddave@users.noreply.github.com>
Signed-off-by: Benedikt Schackenberg <6381261+BenediktSchackenberg@users.noreply.github.com>
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 2, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Removed macOS Podman incompatibility guard; added Podman socket discovery and support across runtime detection, onboarding, CoreDNS patching, scripts, tests, and documentation; .shellcheckrc now enables external source resolution and uses SCRIPTDIR for sourced-paths.

Changes

Cohort / File(s) Summary
Configuration & Docs
\.shellcheckrc, README.md, docs/reference/troubleshooting.md
Enabled ShellCheck external-sources=true and source-path=SCRIPTDIR; updated container runtimes matrix to include Podman; added Podman-specific troubleshooting and remediation steps.
Onboarding & Platform logic
bin/lib/onboard.js, bin/lib/platform.js
Removed isUnsupportedMacosRuntime guard/export; added getPodmanSocketCandidates; narrowed shouldPatchCoredns to colima/podman; included Podman socket candidates in Docker socket discovery.
Runtime scripts & CoreDNS
scripts/lib/runtime.sh, scripts/fix-coredns.sh, scripts/smoke-macos-install.sh
Replaced is_unsupported_macos_runtime with find_podman_socket; added Podman socket discovery and mapping to DOCKER_HOST; fix-coredns.sh now explicitly detects Colima/Podman and fails if no non-loopback DNS upstream is found.
Tests
test/platform.test.js, test/runtime-shell.test.js, test/smoke-macos-install.test.js, test/dns-proxy.test.js, test/...
Updated/added tests for Podman socket discovery and runtime detection; removed unsupported-macOS-Podman assertions; adjusted expectations for CoreDNS upstream failure behavior and socket candidate ordering.
Misc runtime consumers
bin/lib/..., scripts/..., install.sh, test/e2e/...
Propagated podman runtime string through utilities and callers; added ShellCheck source annotations where needed; removed early-exit path for macOS+Podman and updated related logging/messages.
sequenceDiagram
    participant User
    participant Script as Runtime Script
    participant Detector as Socket Detector
    participant Runtime as Engine (Colima/Podman/Docker)
    participant Onboard as Onboard Logic
    participant CoreDNS as CoreDNS Patch

    User->>Script: run install or fix command
    Script->>Detector: probe sockets (Colima, Podman, Docker)
    Detector-->>Script: socket path or none
    alt socket found
      Script->>Runtime: set DOCKER_HOST to unix://socket
      Script->>Onboard: inferContainerRuntime()
      Onboard->>CoreDNS: shouldPatchCoredns(runtime)
      CoreDNS-->>Script: patch result
    else no socket
      Script-->>User: skip/exit (no socket found)
    end
Loading

🎯 4 (Complex) | ⏱️ ~45 minutes

🐰 I sniffed the sockets near and far,

Found Podman hiding like a star,
Colima, Podman, Docker in a row,
CoreDNS tuned where it should go,
The rabbit hopped, and now they show. 🐇

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title accurately summarizes the main objective: adding Podman as a supported container runtime for macOS and Linux. The title is concise, specific, and directly reflects the primary changes across the codebase.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds first-class Podman support alongside existing container runtimes, updating runtime/socket detection and CoreDNS patching behavior to work on macOS and Linux, with accompanying docs and test updates.

Changes:

  • Add Podman socket discovery and runtime classification (Node + shell helpers), and remove the prior macOS Podman “unsupported” guard.
  • Extend CoreDNS patching logic to run for Podman (in addition to Colima).
  • Update docs and tests to reflect Podman support and new runtime-selection behavior.

Reviewed changes

Copilot reviewed 9 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
bin/lib/platform.js Adds Podman socket candidates; updates socket candidate ordering and CoreDNS patch condition.
bin/lib/onboard.js Removes macOS Podman rejection; patches CoreDNS for Podman/Colima with updated logging.
scripts/lib/runtime.sh Adds Podman socket detection and runtime classification; adjusts socket test helper behavior.
scripts/fix-coredns.sh Detects Podman sockets in addition to Colima; passes detected runtime into upstream resolver.
scripts/setup.sh Removes Podman macOS block; applies CoreDNS patch for Podman and Colima.
scripts/smoke-macos-install.sh Adds podman runtime option and improves runtime error messaging.
test/platform.test.js Adds tests for Podman socket candidate discovery and CoreDNS patch eligibility.
test/runtime-shell.test.js Adds tests for Podman socket detection and DOCKER_HOST runtime classification.
test/smoke-macos-install.test.js Updates unsupported runtime coverage and adds Podman runtime-option test.
README.md Updates runtime compatibility matrix to include Podman on Linux/macOS (Apple Silicon).
docs/reference/troubleshooting.md Adds Podman-specific troubleshooting guidance.
.shellcheckrc Improves ShellCheck source following configuration (external sources + script-relative source-path).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 12 to 14
# Fix: forward CoreDNS to the container's default gateway IP, which
# is reachable from pods and routes DNS through Docker/Podman to the host.
#
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

The header comment says the patch forwards CoreDNS to the container's default gateway IP, but the implementation currently derives an upstream nameserver from resolv.conf via resolve_coredns_upstream(). Please either update the comment to match the current behavior or change the implementation to actually compute and use the container default gateway IP so docs and behavior stay aligned.

Suggested change
# Fix: forward CoreDNS to the container's default gateway IP, which
# is reachable from pods and routes DNS through Docker/Podman to the host.
#
# Fix: forward CoreDNS to a non-loopback upstream resolver derived from
# the container and host resolv.conf, which is reachable from pods and
# routes DNS through Docker/Podman to the host.

Copilot uses AI. Check for mistakes.
Comment on lines +125 to +129
printf '%s\n' "$socket_path"
return 0
fi
done
else
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

find_podman_socket() hardcodes /run/user/$uid for rootless Podman. Many setups expose the socket at "$XDG_RUNTIME_DIR/podman/podman.sock" (usually the same, but not always). Consider checking XDG_RUNTIME_DIR first when set, then falling back to /run/user/$uid, to match the intended detection priority and avoid missing sockets in nonstandard environments.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

@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.

🧹 Nitpick comments (3)
scripts/fix-coredns.sh (1)

63-66: Error handling is more strict but reasonable.

Changing from a fallback to 8.8.8.8 to an error exit is a conservative choice. If the DNS upstream cannot be determined, failing explicitly prevents silent misconfiguration. However, this could cause onboarding failures in edge cases where the previous fallback would have worked.

Consider if a fallback with a warning would be more user-friendly for environments with unusual DNS configurations.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/fix-coredns.sh` around lines 63 - 66, The script currently exits with
an error when UPSTREAM_DNS is empty (in the block checking UPSTREAM_DNS and
DETECTED_RUNTIME), which may be too strict; change the logic to emit a warning
including DETECTED_RUNTIME and the fact no non-loopback upstream was found, then
set UPSTREAM_DNS to a safe fallback (e.g., 8.8.8.8) so onboarding doesn’t fail
in odd environments, while still logging the issue for operators; update any
downstream uses of UPSTREAM_DNS to rely on this fallback and ensure the warning
is clear and actionable.
test/platform.test.js (1)

40-55: Inconsistent assertion style: uses assert.deepEqual while rest of file uses expect().toEqual().

These tests use assert.deepEqual while all other tests in this file use expect(...).toEqual(). For consistency, consider using the same assertion style throughout.

♻️ Suggested fix for consistency
   describe("getPodmanSocketCandidates", () => {
     it("returns macOS Podman socket paths", () => {
       const home = "/tmp/test-home";
-      assert.deepEqual(getPodmanSocketCandidates({ platform: "darwin", home }), [
+      expect(getPodmanSocketCandidates({ platform: "darwin", home })).toEqual([
         path.join(home, ".local/share/containers/podman/machine/podman.sock"),
         "/var/run/docker.sock",
       ]);
     });

     it("returns Linux Podman socket paths with uid", () => {
-      assert.deepEqual(
-        getPodmanSocketCandidates({ platform: "linux", home: "/tmp/test-home", uid: 1001 }),
-        ["/run/user/1001/podman/podman.sock", "/run/podman/podman.sock"],
-      );
+      expect(
+        getPodmanSocketCandidates({ platform: "linux", home: "/tmp/test-home", uid: 1001 }),
+      ).toEqual(["/run/user/1001/podman/podman.sock", "/run/podman/podman.sock"]);
     });
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/platform.test.js` around lines 40 - 55, Replace the inconsistent
assert.deepEqual usage in the getPodmanSocketCandidates tests with the project's
standard expect(...).toEqual() style: update both test cases that call
getPodmanSocketCandidates (referenced by the function name
getPodmanSocketCandidates in the describe block) to use
expect(actual).toEqual(expected) instead of assert.deepEqual(...), keeping the
same inputs (platform, home, uid) and expected arrays.
scripts/lib/runtime.sh (1)

129-141: Consider using XDG_RUNTIME_DIR for Linux socket discovery.

The PR description mentions XDG_RUNTIME_DIR-based discovery, but the implementation hardcodes /run/user/$uid. While this is typically correct, respecting XDG_RUNTIME_DIR when set would be more robust for non-standard configurations.

♻️ Suggested enhancement
   else
     local uid
     uid="$(id -u 2>/dev/null || echo 1000)"
+    local xdg_runtime="${XDG_RUNTIME_DIR:-/run/user/$uid}"
     for socket_path in \
-      "/run/user/$uid/podman/podman.sock" \
+      "$xdg_runtime/podman/podman.sock" \
       "/run/podman/podman.sock"
     do
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/lib/runtime.sh` around lines 129 - 141, The socket discovery block
currently hardcodes "/run/user/$uid" instead of respecting XDG_RUNTIME_DIR;
update the logic in the else branch that defines uid and iterates over
socket_path to first check if XDG_RUNTIME_DIR is set and use
"$XDG_RUNTIME_DIR/podman/podman.sock" (or "$XDG_RUNTIME_DIR/podman.sock" as
appropriate) before falling back to "/run/user/$uid/podman/podman.sock" and
"/run/podman/podman.sock"; ensure you still derive uid with uid="$(id -u
2>/dev/null || echo 1000)" and use the same socket_exists function to test each
candidate path.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@scripts/fix-coredns.sh`:
- Around line 63-66: The script currently exits with an error when UPSTREAM_DNS
is empty (in the block checking UPSTREAM_DNS and DETECTED_RUNTIME), which may be
too strict; change the logic to emit a warning including DETECTED_RUNTIME and
the fact no non-loopback upstream was found, then set UPSTREAM_DNS to a safe
fallback (e.g., 8.8.8.8) so onboarding doesn’t fail in odd environments, while
still logging the issue for operators; update any downstream uses of
UPSTREAM_DNS to rely on this fallback and ensure the warning is clear and
actionable.

In `@scripts/lib/runtime.sh`:
- Around line 129-141: The socket discovery block currently hardcodes
"/run/user/$uid" instead of respecting XDG_RUNTIME_DIR; update the logic in the
else branch that defines uid and iterates over socket_path to first check if
XDG_RUNTIME_DIR is set and use "$XDG_RUNTIME_DIR/podman/podman.sock" (or
"$XDG_RUNTIME_DIR/podman.sock" as appropriate) before falling back to
"/run/user/$uid/podman/podman.sock" and "/run/podman/podman.sock"; ensure you
still derive uid with uid="$(id -u 2>/dev/null || echo 1000)" and use the same
socket_exists function to test each candidate path.

In `@test/platform.test.js`:
- Around line 40-55: Replace the inconsistent assert.deepEqual usage in the
getPodmanSocketCandidates tests with the project's standard
expect(...).toEqual() style: update both test cases that call
getPodmanSocketCandidates (referenced by the function name
getPodmanSocketCandidates in the describe block) to use
expect(actual).toEqual(expected) instead of assert.deepEqual(...), keeping the
same inputs (platform, home, uid) and expected arrays.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 18e8a1e0-3cf6-45da-901a-4a14149adfdf

📥 Commits

Reviewing files that changed from the base of the PR and between db65da8 and 75de11a.

📒 Files selected for processing (11)
  • .shellcheckrc
  • README.md
  • bin/lib/onboard.js
  • bin/lib/platform.js
  • docs/reference/troubleshooting.md
  • scripts/fix-coredns.sh
  • scripts/lib/runtime.sh
  • scripts/smoke-macos-install.sh
  • test/platform.test.js
  • test/runtime-shell.test.js
  • test/smoke-macos-install.test.js

- fix-coredns.sh: update comment to accurately describe the upstream
  resolver strategy (resolv.conf-derived, not gateway IP)
- runtime.sh: check XDG_RUNTIME_DIR first in find_podman_socket(),
  falling back to /run/user/$uid for rootless Podman compatibility

Signed-off-by: Benedikt Schackenberg <6381261+BenediktSchackenberg@users.noreply.github.com>
@BenediktSchackenberg
Copy link
Copy Markdown
Contributor Author

Addressed both Copilot comments:

  • fix-coredns.sh: updated the header comment to accurately describe the resolv.conf-derived upstream strategy (not "default gateway IP")
  • runtime.sh: find_podman_socket() now checks $XDG_RUNTIME_DIR/podman/podman.sock first, falling back to /run/user/$uid when XDG_RUNTIME_DIR is not set or differs

Copy link
Copy Markdown
Contributor

@cv cv left a comment

Choose a reason for hiding this comment

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

Clean rebase of #819. Podman socket detection, priority ordering, and CoreDNS patching logic all look correct. Good test coverage. The shouldPatchCoredns narrowing from all-runtimes to colima+podman-only is the right call.

Once this lands, platform.js is unblocked for TS migration.

cv and others added 2 commits April 2, 2026 18:31
- Replace assert.deepEqual with expect().toEqual in Podman socket tests
  (assert import was removed but calls weren't updated)
- Update fix-coredns.sh tests to match new behavior: script now targets
  Colima/Podman specifically and exits with error instead of falling
  back to resolvectl/8.8.8.8

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

@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.

🧹 Nitpick comments (1)
test/dns-proxy.test.js (1)

109-115: Tighten the exit 1 assertion to the same error block.

expect(content).toContain("exit 1") is a bit broad. Consider asserting the error message and exit 1 as an ordered block so unrelated exit 1 lines do not satisfy this test.

Suggested assertion tweak
-    expect(content).toContain("exit 1");
+    expect(content).toMatch(
+      /Could not determine a non-loopback DNS upstream[\s\S]*exit 1/
+    );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@test/dns-proxy.test.js` around lines 109 - 115, The test currently checks for
"exit 1" loosely; tighten it so the "Could not determine a non-loopback DNS
upstream" error and the subsequent "exit 1" occur together. Modify the
assertions in the "exits with error when no upstream DNS can be resolved" test:
after reading FIX_COREDNS into content, locate the index of the error message
string and assert that "exit 1" appears at or after that index (or use a single
regex that matches the error message followed by an "exit 1" line). Use the
existing variables (content and FIX_COREDNS) and replace the broad
expect(content).toContain("exit 1") with this ordered-check approach.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@test/dns-proxy.test.js`:
- Around line 109-115: The test currently checks for "exit 1" loosely; tighten
it so the "Could not determine a non-loopback DNS upstream" error and the
subsequent "exit 1" occur together. Modify the assertions in the "exits with
error when no upstream DNS can be resolved" test: after reading FIX_COREDNS into
content, locate the index of the error message string and assert that "exit 1"
appears at or after that index (or use a single regex that matches the error
message followed by an "exit 1" line). Use the existing variables (content and
FIX_COREDNS) and replace the broad expect(content).toContain("exit 1") with this
ordered-check approach.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e8c0efb1-f6b5-441b-869b-28dd50656280

📥 Commits

Reviewing files that changed from the base of the PR and between f18f762 and ca3eb10.

📒 Files selected for processing (2)
  • test/dns-proxy.test.js
  • test/platform.test.js
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/platform.test.js

cv and others added 5 commits April 2, 2026 19:10
.bashrc and nvm.sh don't exist in CI — shellcheck with
external-sources=true tries to follow them and reports info-level
findings that the prek hook treats as failures.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The version line can have variable spacing between the name and
version tag (e.g. "nemoclaw-installer  v0.0.3-32-gde76d69").

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@wscurran wscurran added Platform: MacOS Support for MacOS Local Models Running NemoClaw with local models enhancement: platform Request for support on other platforms. labels Apr 3, 2026
@wscurran
Copy link
Copy Markdown
Contributor

wscurran commented Apr 3, 2026

✨ Thanks for submitting this pull request, which proposes a way to support Podman as an alternative runtime on macOS and Linux. This could give users more flexibility in how they run local models.

@wscurran wscurran added enhancement: feature Use this label to identify requests for new capabilities in NemoClaw. enhancement: provider Use this label to identify requests to add a new AI provider to NemoClaw. and removed enhancement: platform Request for support on other platforms. labels Apr 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement: feature Use this label to identify requests for new capabilities in NemoClaw. enhancement: provider Use this label to identify requests to add a new AI provider to NemoClaw. Local Models Running NemoClaw with local models Platform: MacOS Support for MacOS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants