Skip to content

refactor(onboard): extract dockerfile patch helpers - #3300

Merged
ericksoa merged 65 commits into
mainfrom
refactor/onboard-dockerfile-patch
May 13, 2026
Merged

refactor(onboard): extract dockerfile patch helpers#3300
ericksoa merged 65 commits into
mainfrom
refactor/onboard-dockerfile-patch

Conversation

@cv

@cv cv commented May 9, 2026

Copy link
Copy Markdown
Collaborator

Summary

Extract Dockerfile patching helpers out of the large onboarding module. This continues the onboarding cleanup stack by moving sandbox image ARG rewriting, proxy validation, and Docker JSON ARG encoding into a focused helper module.

Changes

  • Add src/lib/onboard/dockerfile-patch.ts for Dockerfile ARG rewriting, proxy host/port validation, and base64 JSON ARG encoding.
  • Update src/lib/onboard.ts to import Dockerfile patch helpers while preserving the existing patchStagedDockerfile export and call sites.
  • Add unit tests covering JSON ARG encoding, proxy validation, base image/inference ARG patching, proxy ARG patching, and messaging ARG patching.

Type of Change

  • Code change (feature, bug fix, or refactor)
  • Code change with doc updates
  • Doc only (prose changes, no code sample modifications)
  • Doc only (includes code sample changes)

Verification

  • npx prek run --all-files passes
  • npm test passes
  • Tests added or updated for new or changed behavior
  • No secrets, API keys, or credentials committed
  • Docs updated for user-facing behavior changes
  • make docs builds without warnings (doc changes only)
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: Carlos Villela cvillela@nvidia.com

Summary by CodeRabbit

  • Refactor

    • Dockerfile patching moved out of the onboarding core into a dedicated module for clearer separation and maintainability.
  • New Features

    • Added proxy host/port validation, stable base64 encoding for build-time JSON args, and a Darwin VM compatibility flag used during onboarding image builds.
    • Ensures selected build-time flags and sanitization of interpolated ARG values.
  • Tests

    • Added tests covering ARG encoding, proxy validation and CR/LF sanitization of patched Dockerfile values.

Review Change Stack

@cv cv self-assigned this May 9, 2026
@coderabbitai

coderabbitai Bot commented May 9, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 28bd025a-d914-4900-9564-eba5c784af10

📥 Commits

Reviewing files that changed from the base of the PR and between b0347b1 and cd70819.

📒 Files selected for processing (3)
  • src/lib/onboard.ts
  • src/lib/onboard/dockerfile-patch.test.ts
  • src/lib/onboard/dockerfile-patch.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/lib/onboard/dockerfile-patch.test.ts
  • src/lib/onboard.ts
  • src/lib/onboard/dockerfile-patch.ts

📝 Walkthrough

Walkthrough

This PR extracts Dockerfile ARG patching, proxy validators, and JSON-encoding helpers from src/lib/onboard.ts into src/lib/onboard/dockerfile-patch.ts, updates onboard.ts to import them, and adds Vitest tests under src/lib/onboard/dockerfile-patch.test.ts.

Changes

Dockerfile Patch Module Extraction

Layer / File(s) Summary
Update onboard.ts imports
src/lib/onboard.ts
Removes inline Dockerfile patching, proxy validation, and JSON encoding implementations and imports isValidProxyHost, isValidProxyPort, and patchStagedDockerfile from the new module.
Dockerfile patch module helpers and encoding
src/lib/onboard/dockerfile-patch.ts
Adds Dockerfile-safe JSON base64 encoding and CR/LF sanitization, and exports isValidProxyHost/isValidProxyPort.
Main Dockerfile patching implementation
src/lib/onboard/dockerfile-patch.ts
Adds patchStagedDockerfile(...) to compute sandbox inference config, optionally pin BASE_IMAGE, rewrite many ARGs (model/provider/inference/chat/build id, darwin VM compat), apply env-driven overrides, validate proxy/ports, force device-auth disable, base64-encode messaging JSON ARGs, and write the patched Dockerfile.
Test coverage for Dockerfile patching module
src/lib/onboard/dockerfile-patch.test.ts
Vitest suite creating temp Dockerfiles, clearing env, and testing encodeDockerJsonArg, proxy validators, ARG rewriting (including sandbox inference compat decoding), and CR/LF sanitization of interpolated ARG values.

Sequence Diagram

sequenceDiagram
  participant Test
  participant patchStagedDockerfile
  participant Filesystem
  Test->>Filesystem: Create temp Dockerfile with baseline ARGs
  Test->>Test: Set NEMOCLAW_PROXY_HOST/PORT env vars
  Test->>patchStagedDockerfile: Call with provider/model/chat/inference/messaging/compat args
  patchStagedDockerfile->>Filesystem: Read Dockerfile
  patchStagedDockerfile->>patchStagedDockerfile: Compute sandbox inference config & validate proxy/ports
  patchStagedDockerfile->>patchStagedDockerfile: Rewrite ARGs (model/provider/inference/build id/overrides) and sanitize CR/LF
  patchStagedDockerfile->>patchStagedDockerfile: Base64-encode messaging/telegram/discord configs as needed
  patchStagedDockerfile->>Filesystem: Write patched Dockerfile
  Test->>Filesystem: Read and assert ARG values updated / certain ARGs removed
  Test->>Filesystem: Cleanup temp directory and clear env vars
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

I hop through lines of code with cheer,
I tuck patch logic tidy and near.
Helpers split out, tests that sing,
ARGs now neat — no stray newline string.
🐰 Encode, validate, and write with cheer.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% 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 'refactor(onboard): extract dockerfile patch helpers' directly and clearly describes the main change: extracting Dockerfile patching logic into a separate module.
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 refactor/onboard-dockerfile-patch

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

@cv
cv marked this pull request as draft May 9, 2026 01:23
@copy-pr-bot

copy-pr-bot Bot commented May 9, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@copy-pr-bot

copy-pr-bot Bot commented May 9, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@cv cv added v0.0.40 and removed v0.0.39 labels May 12, 2026
@github-actions

github-actions Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: None
Optional E2E: None

Workflow run

Full advisor summary

Pi Semantic E2E Advisor

Failed: pi exited with status 1; see /home/runner/work/NemoClaw/NemoClaw/artifacts/e2e-advisor/e2e-advisor-pi-raw-output.txt

@cv
cv changed the base branch from refactor/onboard-config-sync to main May 12, 2026 23:09
@cv
cv marked this pull request as ready for review May 12, 2026 23:09

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
src/lib/onboard/dockerfile-patch.ts (2)

79-249: 🏗️ Heavy lift

patchStagedDockerfile is too complex; split patch rules into small helpers.

The function has many repeated replace blocks and branching paths, which makes behavior harder to audit and extend safely.

Refactor direction (pattern)
+type ArgPatch = {
+  key: string;
+  value: string | null;
+};
+
+function applyArgPatch(dockerfile: string, { key, value }: ArgPatch): string {
+  if (value === null) return dockerfile;
+  return dockerfile.replace(new RegExp(`^ARG ${key}=.*$`, "m"), `ARG ${key}=${value}`);
+}
- dockerfile = dockerfile.replace(/^ARG NEMOCLAW_MODEL=.*$/m, `ARG NEMOCLAW_MODEL=${model}`);
- dockerfile = dockerfile.replace(
-   /^ARG NEMOCLAW_PROVIDER_KEY=.*$/m,
-   `ARG NEMOCLAW_PROVIDER_KEY=${providerKey}`,
- );
+dockerfile = applyArgPatch(dockerfile, { key: "NEMOCLAW_MODEL", value: model });
+dockerfile = applyArgPatch(dockerfile, { key: "NEMOCLAW_PROVIDER_KEY", value: providerKey });

As per coding guidelines, "**/*.{js,ts,tsx}: Keep function complexity low; prefix unused variables with underscore (_)".

🤖 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 `@src/lib/onboard/dockerfile-patch.ts` around lines 79 - 249,
patchStagedDockerfile is too large and duplicates many dockerfile.replace
patterns; extract small helpers and move branching logic into them to reduce
complexity. Create helpers such as applyArgReplacement(dockerfile, argName,
value), applyEnvValidatedReplacement(dockerfile, envName, argName, validator),
applyJsonArgReplacement(dockerfile, argName, obj, encoder = encodeDockerJsonArg)
and pinBaseImageIfSandbox(dockerfile, baseImageRef, SANDBOX_BASE_IMAGE) and use
those from patchStagedDockerfile (keeping calls to
getDockerfileSandboxInferenceConfig, POSITIVE_INT_RE, isValidProxyHost,
isValidProxyPort unchanged); replace each repeated regex/replace block with the
appropriate helper call so validation and encoding live in one place and the
main function reads as a sequence of small steps.

65-67: ⚡ Quick win

Use nullish coalescing operator for JSON arg default.

value || {} applies boolean coercion; use value ?? {} to more precisely handle only null and undefined. While the test confirms this behavior is intentional (line 40 in dockerfile-patch.test.ts expects encodeDockerJsonArg(null) to yield "{}"), the semantic intent is clearer with the nullish coalescing operator and guards against accidental falsy-value corruption.

Suggested fix
 export function encodeDockerJsonArg(value: unknown): string {
-  return Buffer.from(JSON.stringify(value || {}), "utf8").toString("base64");
+  return Buffer.from(JSON.stringify(value ?? {}), "utf8").toString("base64");
 }
🤖 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 `@src/lib/onboard/dockerfile-patch.ts` around lines 65 - 67, The
encodeDockerJsonArg function currently uses boolean coercion (value || {}) which
incorrectly treats other falsy values like 0, "" or false as null; update the
function to use the nullish coalescing operator (value ?? {}) so only
null/undefined fall back to an empty object, i.e., change the defaulting logic
inside encodeDockerJsonArg to use ?? and keep the rest of the
JSON.stringify/base64 behavior unchanged.
🤖 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.

Nitpick comments:
In `@src/lib/onboard/dockerfile-patch.ts`:
- Around line 79-249: patchStagedDockerfile is too large and duplicates many
dockerfile.replace patterns; extract small helpers and move branching logic into
them to reduce complexity. Create helpers such as
applyArgReplacement(dockerfile, argName, value),
applyEnvValidatedReplacement(dockerfile, envName, argName, validator),
applyJsonArgReplacement(dockerfile, argName, obj, encoder = encodeDockerJsonArg)
and pinBaseImageIfSandbox(dockerfile, baseImageRef, SANDBOX_BASE_IMAGE) and use
those from patchStagedDockerfile (keeping calls to
getDockerfileSandboxInferenceConfig, POSITIVE_INT_RE, isValidProxyHost,
isValidProxyPort unchanged); replace each repeated regex/replace block with the
appropriate helper call so validation and encoding live in one place and the
main function reads as a sequence of small steps.
- Around line 65-67: The encodeDockerJsonArg function currently uses boolean
coercion (value || {}) which incorrectly treats other falsy values like 0, "" or
false as null; update the function to use the nullish coalescing operator (value
?? {}) so only null/undefined fall back to an empty object, i.e., change the
defaulting logic inside encodeDockerJsonArg to use ?? and keep the rest of the
JSON.stringify/base64 behavior unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: c8b3af31-db82-4619-ba3a-ea635ef8987b

📥 Commits

Reviewing files that changed from the base of the PR and between ef8b231 and 7203165.

📒 Files selected for processing (3)
  • src/lib/onboard.ts
  • src/lib/onboard/dockerfile-patch.test.ts
  • src/lib/onboard/dockerfile-patch.ts

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/lib/onboard/dockerfile-patch.ts (1)

79-254: 🏗️ Heavy lift

patchStagedDockerfile has grown beyond the project’s complexity guideline.

This function is now heavily branchy and repetitive. Consider extracting table-driven ARG rewrites plus small feature-specific patch helpers (base image, inference, env overrides, messaging) to reduce regression risk and simplify tests.

As per coding guidelines, **/*.{js,ts,tsx}: Keep function complexity low.

🤖 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 `@src/lib/onboard/dockerfile-patch.ts` around lines 79 - 254,
patchStagedDockerfile is too large and repetitive; refactor it by extracting
smaller, testable helpers and a table-driven ARG-rewrite mechanism. Create
helpers like patchBaseImageArg(dockerfile, baseImageRef, SANDBOX_BASE_IMAGE),
applyArgRewrite(dockerfile, argName, value), applyEncodedArg(dockerfile,
argName, value, encoder=encodeDockerJsonArg), and feature-specific small
functions for inference config, env overrides (use POSITIVE_INT_RE,
isValidProxyHost, isValidProxyPort), and messaging/telegram patches; then have
patchStagedDockerfile call getDockerfileSandboxInferenceConfig once and
sequentially apply those helpers to produce the final dockerfile before
fs.writeFileSync. Ensure all existing symbols
(getDockerfileSandboxInferenceConfig, encodeDockerJsonArg, POSITIVE_INT_RE,
isValidProxyHost, isValidProxyPort, SANDBOX_BASE_IMAGE) are used so behavior is
unchanged and unit tests can target the small helpers.
🤖 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 `@src/lib/onboard/dockerfile-patch.ts`:
- Around line 79-146: The patchStagedDockerfile function interpolates untrusted
values into Dockerfile ARG lines which can allow line-injection via newlines;
create a small sanitizer (e.g., sanitizeDockerArg) that strips or encodes
newline and carriage-return characters (at minimum remove \n and \r) and use it
for all non-constant interpolations in patchStagedDockerfile — specifically
apply it to model, chatUiUrl, buildId, providerKey, primaryModelRef,
inferenceBaseUrl, inferenceApi, darwinVmCompat (converted to sanitized "1"/"0"),
baseImageRef handling, telegramConfig/messagingAllowedIds/discordGuilds values,
and any other places later in the function (lines ~149-217) where inputs/env
values are injected into ARG or Dockerfile lines so that every replacement call
uses the sanitized value instead of the raw input.

---

Nitpick comments:
In `@src/lib/onboard/dockerfile-patch.ts`:
- Around line 79-254: patchStagedDockerfile is too large and repetitive;
refactor it by extracting smaller, testable helpers and a table-driven
ARG-rewrite mechanism. Create helpers like patchBaseImageArg(dockerfile,
baseImageRef, SANDBOX_BASE_IMAGE), applyArgRewrite(dockerfile, argName, value),
applyEncodedArg(dockerfile, argName, value, encoder=encodeDockerJsonArg), and
feature-specific small functions for inference config, env overrides (use
POSITIVE_INT_RE, isValidProxyHost, isValidProxyPort), and messaging/telegram
patches; then have patchStagedDockerfile call
getDockerfileSandboxInferenceConfig once and sequentially apply those helpers to
produce the final dockerfile before fs.writeFileSync. Ensure all existing
symbols (getDockerfileSandboxInferenceConfig, encodeDockerJsonArg,
POSITIVE_INT_RE, isValidProxyHost, isValidProxyPort, SANDBOX_BASE_IMAGE) are
used so behavior is unchanged and unit tests can target the small helpers.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: be517081-ebba-415d-a7dc-340bfc39b418

📥 Commits

Reviewing files that changed from the base of the PR and between 7203165 and 0d41699.

📒 Files selected for processing (3)
  • src/lib/onboard.ts
  • src/lib/onboard/dockerfile-patch.test.ts
  • src/lib/onboard/dockerfile-patch.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/onboard/dockerfile-patch.test.ts
  • src/lib/onboard.ts

Comment thread src/lib/onboard/dockerfile-patch.ts
@ericksoa
ericksoa merged commit ba65d49 into main May 13, 2026
60 of 62 checks passed
@cv
cv deleted the refactor/onboard-dockerfile-patch branch May 27, 2026 21:18
@wscurran wscurran added area: packaging Packages, images, registries, installers, or distribution platform: container Affects Docker, containerd, Podman, or images and removed Docker labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: packaging Packages, images, registries, installers, or distribution platform: container Affects Docker, containerd, Podman, or images refactor PR restructures code without intended behavior change

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants