Skip to content

chore(tooling): switch linting to biome - #2862

Merged
cv merged 4 commits into
mainfrom
chore/switch-to-biome
May 1, 2026
Merged

cv merged 4 commits into
mainfrom
chore/switch-to-biome

Conversation

@cv

@cv cv commented May 1, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Switches JavaScript and TypeScript linting/formatting from ESLint and Prettier to Biome. Keeps the credential environment-variable security check by replacing the custom ESLint rule with a standalone TypeScript guard wired into npm scripts and prek.

Changes

  • Add biome.json and update root/plugin npm scripts plus Makefile targets to use Biome.
  • Replace prek Prettier/ESLint hooks with Biome format/lint hooks.
  • Remove ESLint/Prettier configs and dependencies from root and plugin projects.
  • Add scripts/check-direct-credential-env.ts and update tests to preserve the direct credential env guard.
  • Remove stale ESLint suppression comments from source and tests.

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)

AI Disclosure

  • AI-assisted — tool: pi coding agent

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

Summary by CodeRabbit

  • Chores
    • Migrated formatting/linting from ESLint/Prettier to Biome and removed legacy formatter configs and many inline lint suppressions.
  • New Features
    • Added an automated CLI check that scans source files for direct reads of credential environment variables.
  • Documentation
    • Updated linting guidance to reflect Biome-based configuration and project linting behavior.
  • Bug Fixes
    • Interactive consent now prints " Installation cancelled" on prompt errors and returns false.
  • Tests
    • Added/updated tests for credential-guarding logic and the interactive consent error path.

Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@cv cv self-assigned this May 1, 2026
@coderabbitai

coderabbitai Bot commented May 1, 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: 5e4e5e0a-f393-4dc7-8650-f11f7e42e6c2

📥 Commits

Reviewing files that changed from the base of the PR and between 2cc8d50 and 8f9d61f.

📒 Files selected for processing (3)
  • src/lib/onboard-session.ts
  • src/lib/onboard.ts
  • test/onboard.test.ts
💤 Files with no reviewable changes (2)
  • src/lib/onboard-session.ts
  • test/onboard.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/lib/onboard.ts

📝 Walkthrough

Walkthrough

Migrate repository tooling from Prettier/ESLint to Biome, remove ESLint flat configs and custom rule, add a TypeScript AST checker for direct credential env reads, update pre-commit hooks/Makefile/package scripts, remove many inline ESLint suppressions, and adjust/add tests accordingly.

Changes

Cohort / File(s) Summary
Pre-commit & repo tooling
\.pre-commit-config.yaml, biome.json, Makefile, commitlint.config.js, AGENTS.md
Replace Prettier/ESLint hooks with Biome hooks; add a priority local guard hook to run the TS credential checker when src/lib/onboard.ts changes; add repo-level biome.json; update Makefile format targets and commitlint formatting.
Package manifests
package.json, nemoclaw/package.json
Switch npm scripts from ESLint/Prettier to Biome; add check:credential-env script using tsx and the new checker; add @biomejs/biome and remove ESLint/Prettier devDeps.
Credential guard: new script & tests
scripts/check-direct-credential-env.ts, test/no-direct-credential-env.test.ts
Add AST-based TypeScript checker with exported types/functions (DirectCredentialEnvViolation, findDirectCredentialEnvReads, checkFiles, formatViolations); update tests to validate the checker instead of the removed ESLint rule.
ESLint & Prettier config removal
eslint.config.mjs, eslint-rules/no-direct-credential-env.js, .prettierrc, nemoclaw/eslint.config.mjs, nemoclaw/.prettierrc
Remove ESLint flat configs, custom eslint rule module, and Prettier config files (replaced by Biome configuration).
Source: lint directive removals & minor logic
src/... (multiple files; e.g., src/lib/*, src/nemoclaw.ts, src/lib/onboard.ts)
Remove many inline eslint-disable comments; small behavior change in src/lib/onboard.ts to normalize credential env values before conditionally overwriting.
Tests: formatting, suppression removals & additions
nemoclaw/src/..., test/... (various test files)
Remove inline ESLint suppression comments, reformat some tests, add a test for prompt-exception path, and change onboarding integration to run the TS checker.
Miscellaneous small edits
src/lib/usage-notice.ts, other single-line edits
Add error handling in ensureUsageNoticeConsent for prompt failures; other single-line comment/format edits without functional change.

Sequence Diagram(s)

sequenceDiagram
  participant Dev as Developer
  participant Git as Git / Commit
  participant Pre as pre-commit hooks
  participant Biome as Biome (format & lint)
  participant Guard as TS Checker (check-direct-credential-env)
  participant FS as File System

  Dev->>Git: git commit (staged files)
  Git->>Pre: run pre-commit hooks
  Pre->>Biome: npx biome format --write (formatter)
  Pre->>Biome: npx biome lint (linter)
  Pre->>Guard: run local guard if matched files changed
  Guard->>FS: read matched files (e.g. src/lib/onboard.ts)
  Guard->>Guard: parse TS/JS AST and locate direct env reads
  Guard-->>Pre: return violations or success
  Pre->>Dev: allow commit or abort with errors
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

enhancement: testing

Suggested reviewers

  • ericksoa
  • jyaunches

Poem

🐇 I hopped through configs, swapped linting's tune,
Biome now sings where Prettier left soon.
I sniffed the env for secrets in the grass,
Flagged the direct reads, then hopped off to pass.
Carrots for commits — tidy code en masse!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 22.22% 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 'chore(tooling): switch linting to biome' directly and accurately describes the main change: replacing ESLint and Prettier with Biome as the linter and formatter across the codebase.
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 chore/switch-to-biome

Review rate limit: 7/10 reviews remaining, refill in 12 minutes and 33 seconds.

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

@cv cv added the v0.0.33 label May 1, 2026

@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: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
AGENTS.md (1)

1-1: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add the required SPDX header to this Markdown file.

This modified Markdown file is missing the required SPDX HTML comment header.

Suggested patch
+<!-- SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. -->
+<!-- SPDX-License-Identifier: Apache-2.0 -->
+
 # Agent Instructions

As per coding guidelines: **/*.{js,ts,tsx,sh,md} must include SPDX headers, and “Markdown uses HTML comments.”

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

In `@AGENTS.md` at line 1, Add the required SPDX HTML comment header to the top of
AGENTS.md: open the file and insert an HTML comment containing the SPDX license
identifier (e.g., the project’s SPDX short-tag) as the very first line so the
Markdown file complies with the `**/*.{js,ts,tsx,sh,md}` header rule; ensure it
uses an HTML comment format (not plain text) so the Markdown parser ignores it
and commit the change.
src/lib/onboard.ts (1)

4995-5000: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Fix credential “missing” detection for dynamic env keys to treat whitespace-only env vars as unset.

Same issue as above: !process.env[credentialEnv] won’t treat whitespace-only strings as missing. Since this block is responsible for applying NEMOCLAW_PROVIDER_KEY to provider-specific credential env vars, whitespace-only values should be normalized and treated as unset.

🔧 Proposed change
           const _providerKeyHint = (process.env.NEMOCLAW_PROVIDER_KEY || "").trim();
           // check-direct-credential-env-ignore -- intentional: checking if env is already set before applying NEMOCLAW_PROVIDER_KEY override
-          if (_providerKeyHint && credentialEnv && !process.env[credentialEnv]) {
-            process.env[credentialEnv] = _providerKeyHint;
-          }
+          if (_providerKeyHint && credentialEnv) {
+            const existingCredentialKey = normalizeCredentialValue(
+              process.env[credentialEnv] ?? "",
+            );
+            if (!existingCredentialKey) {
+              process.env[credentialEnv] = _providerKeyHint;
+            }
+          }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/onboard.ts` around lines 4995 - 5000, The check that decides whether
to apply NEMOCLAW_PROVIDER_KEY uses !process.env[credentialEnv], which treats
whitespace-only values as present; change the condition to treat whitespace-only
env vars as unset by trimming the existing env value before testing (e.g.
compute existing = (process.env[credentialEnv] || "").trim() and use !existing
in the if). Update the if that references _providerKeyHint, credentialEnv and
process.env[credentialEnv] so it checks trimmed existing value instead of raw
process.env to ensure whitespace-only values are overridden by _providerKeyHint.
🧹 Nitpick comments (3)
src/lib/usage-notice.ts (2)

214-226: ⚡ Quick win

Type require("./credentials").prompt explicitly to make the CJS boundary safe.

Right now ask is inferred from promptFn || require("./credentials").prompt, which can be “any-ish” across the CJS/TS boundary. Even if it works today, this makes the contract fragile. Consider explicitly casting the required prompt to PromptFn and using ?? to express the null-default intent.

Suggested change
   // credentials is still CJS
-  const ask = promptFn || require("./credentials").prompt;
+  const ask: PromptFn =
+    promptFn ??
+    (require("./credentials") as { prompt: PromptFn }).prompt;

   const answer = String(await ask(`  ${config.interactivePrompt}`))
     .trim()
     .toLowerCase();

This keeps the runtime behavior identical while making the type contract explicit at compile time.

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

In `@src/lib/usage-notice.ts` around lines 214 - 226, The binding for ask is
currently inferred from promptFn || require("./credentials").prompt which
crosses a CJS/TS boundary; explicitly cast the required prompt to the expected
PromptFn type and use the nullish-coalescing operator to express the default
intent. Locate the ask assignment in usage-notice.ts (the ask variable,
promptFn, and require("./credentials").prompt) and change it so the CJS import
is asserted/typed as PromptFn and use "promptFn ?? (require(...).prompt as
PromptFn)" so the type contract is explicit while keeping runtime behavior
identical.

214-222: ⚡ Quick win

Preserve UX on prompt failures (add try/catch around ask).

If require("./credentials").prompt (or the provided promptFn) rejects/throws, ensureUsageNoticeConsent will throw and skip the normal “Installation cancelled” messaging + boolean return path. Wrapping the prompt call lets you fail closed with a consistent false outcome.

Suggested change
-  const answer = String(await ask(`  ${config.interactivePrompt}`))
-    .trim()
-    .toLowerCase();
+  let answer: string;
+  try {
+    answer = String(await ask(`  ${config.interactivePrompt}`))
+      .trim()
+      .toLowerCase();
+  } catch {
+    writeLine("  Installation cancelled");
+    return false;
+  }
   if (answer !== "yes") {
     writeLine("  Installation cancelled");
     return false;
   }

This is especially relevant since this is an onboarding/consent flow where reliability matters.

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

In `@src/lib/usage-notice.ts` around lines 214 - 222, The prompt call (ask) can
throw/reject and currently would bubble out, skipping the normal cancellation
flow; wrap the await ask(...) invocation in a try/catch inside
ensureUsageNoticeConsent (or the function containing this snippet) so any thrown
error is caught, call writeLine("  Installation cancelled") and return false on
catch, preserving the same UX path for failures; reference the promptFn /
require("./credentials").prompt and the local variable ask and ensure you still
trim().toLowerCase() only when the call succeeds.
test/no-direct-credential-env.test.ts (1)

56-80: ⚡ Quick win

Add a regression case where suppression token appears in a string literal.

Right now there’s no test proving that only actual comments can suppress. Adding this prevents future bypass regressions in the guard logic.

✅ Suggested test addition
   it.each([
@@
     // Dynamic read with credential-containing variable name
     ["if (!process.env[credentialEnv]) {}", "[credentialEnv]"],
     ["const x = process.env[resolvedCredentialEnv];", "[resolvedCredentialEnv]"],
+    // Suppression token inside non-comment text must NOT suppress
+    [
+      "const marker = 'no-direct-credential-env';\nconst key = process.env.NVIDIA_API_KEY;",
+      "NVIDIA_API_KEY",
+    ],
   ])("flags %s", (code, key) => {
     expect(findDirectCredentialEnvReads(code)).toMatchObject([{ key }]);
   });

Based on learnings: Security-sensitive code paths (credential sanitization, SSRF validation, Docker capability drops, process limits) require extra test coverage.

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

In `@test/no-direct-credential-env.test.ts` around lines 56 - 80, Add a regression
test in test/no-direct-credential-env.test.ts within the existing it.each cases
for findDirectCredentialEnvReads that ensures a suppression token appearing
inside a string literal does NOT suppress detection; specifically add a case
where a string containing the suppression marker is present alongside a direct
process.env read and assert findDirectCredentialEnvReads still reports the
credential key (e.g., OPENAI_API_KEY), referencing the existing test harness
(the it.each block and the findDirectCredentialEnvReads helper) so only actual
comment tokens (not string literals) suppress the rule.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.pre-commit-config.yaml:
- Around line 99-115: The Biome pre-commit hooks (ids: biome-format and
biome-lint-fix) currently only match TypeScript under nemoclaw/src and skip
root-level CLI TypeScript files; update the hooks' files regex to also include
root CLI TS (e.g., add ^src/.*\.ts$ or include src/.*\.ts in the existing
alternations) so that root-level src/**/*.ts files are covered by both
biome-format and biome-lint-fix; ensure both the "files" entries for
biome-format and biome-lint-fix are changed consistently to include the root src
pattern.

In `@biome.json`:
- Around line 10-23: The Biome include list currently misses root CLI TypeScript
files (e.g., src/lib/onboard.ts), so files under src/**/*.ts are not
linted/formatted; update the "includes" array in biome.json to add the pattern
"src/**/*.ts" (or a similar root-src glob) alongside existing entries so Biome
will pick up and process those CLI TypeScript files such as src/lib/onboard.ts.

In `@scripts/check-direct-credential-env.ts`:
- Around line 197-203: The suppression detection in hasSuppressionComment
currently tests raw line text (using sourceFile.getFullText().split...) which
allows suppression tokens inside strings; change it to only inspect actual
comment text by using TypeScript's comment APIs (e.g.,
ts.forEachLeadingCommentRange or ts.getLeadingCommentRanges) on the node (and
optionally the previous token/node) and test SUPPRESSION_PATTERN against the
comment text; update hasSuppressionComment to obtain the node start
(node.getStart(sourceFile)) and scan leading comment ranges for that position
(and the preceding token's trailing comments if you want to support
previous-line comments), returning true only if a comment's text matches
SUPPRESSION_PATTERN.

In `@src/lib/onboard.ts`:
- Around line 4956-4960: The guard currently checks !process.env.NVIDIA_API_KEY
which treats an all-whitespace value as present; change the condition to treat
whitespace-only as unset by trimming the existing env var before checking (e.g.,
use !( (process.env.NVIDIA_API_KEY || "").trim() ) ). Keep using the
already-trimmed _nvProviderKey and only assign it when the trimmed
NVIDIA_API_KEY is empty, updating the block that sets process.env.NVIDIA_API_KEY
from _nvProviderKey.

---

Outside diff comments:
In `@AGENTS.md`:
- Line 1: Add the required SPDX HTML comment header to the top of AGENTS.md:
open the file and insert an HTML comment containing the SPDX license identifier
(e.g., the project’s SPDX short-tag) as the very first line so the Markdown file
complies with the `**/*.{js,ts,tsx,sh,md}` header rule; ensure it uses an HTML
comment format (not plain text) so the Markdown parser ignores it and commit the
change.

In `@src/lib/onboard.ts`:
- Around line 4995-5000: The check that decides whether to apply
NEMOCLAW_PROVIDER_KEY uses !process.env[credentialEnv], which treats
whitespace-only values as present; change the condition to treat whitespace-only
env vars as unset by trimming the existing env value before testing (e.g.
compute existing = (process.env[credentialEnv] || "").trim() and use !existing
in the if). Update the if that references _providerKeyHint, credentialEnv and
process.env[credentialEnv] so it checks trimmed existing value instead of raw
process.env to ensure whitespace-only values are overridden by _providerKeyHint.

---

Nitpick comments:
In `@src/lib/usage-notice.ts`:
- Around line 214-226: The binding for ask is currently inferred from promptFn
|| require("./credentials").prompt which crosses a CJS/TS boundary; explicitly
cast the required prompt to the expected PromptFn type and use the
nullish-coalescing operator to express the default intent. Locate the ask
assignment in usage-notice.ts (the ask variable, promptFn, and
require("./credentials").prompt) and change it so the CJS import is
asserted/typed as PromptFn and use "promptFn ?? (require(...).prompt as
PromptFn)" so the type contract is explicit while keeping runtime behavior
identical.
- Around line 214-222: The prompt call (ask) can throw/reject and currently
would bubble out, skipping the normal cancellation flow; wrap the await ask(...)
invocation in a try/catch inside ensureUsageNoticeConsent (or the function
containing this snippet) so any thrown error is caught, call writeLine(" 
Installation cancelled") and return false on catch, preserving the same UX path
for failures; reference the promptFn / require("./credentials").prompt and the
local variable ask and ensure you still trim().toLowerCase() only when the call
succeeds.

In `@test/no-direct-credential-env.test.ts`:
- Around line 56-80: Add a regression test in
test/no-direct-credential-env.test.ts within the existing it.each cases for
findDirectCredentialEnvReads that ensures a suppression token appearing inside a
string literal does NOT suppress detection; specifically add a case where a
string containing the suppression marker is present alongside a direct
process.env read and assert findDirectCredentialEnvReads still reports the
credential key (e.g., OPENAI_API_KEY), referencing the existing test harness
(the it.each block and the findDirectCredentialEnvReads helper) so only actual
comment tokens (not string literals) suppress the rule.
🪄 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: c94c99ed-5033-4f18-b3ef-36804943aa53

📥 Commits

Reviewing files that changed from the base of the PR and between fd240ff and 7a60946.

⛔ Files ignored due to path filters (2)
  • nemoclaw/package-lock.json is excluded by !**/package-lock.json
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (41)
  • .pre-commit-config.yaml
  • .prettierrc
  • AGENTS.md
  • Makefile
  • biome.json
  • commitlint.config.js
  • eslint-rules/no-direct-credential-env.js
  • eslint.config.mjs
  • nemoclaw/.prettierrc
  • nemoclaw/eslint.config.mjs
  • nemoclaw/package.json
  • nemoclaw/src/blueprint/private-networks.test.ts
  • nemoclaw/src/blueprint/runner.test.ts
  • nemoclaw/src/commands/migration-state.test.ts
  • nemoclaw/src/lib/ports.test.ts
  • nemoclaw/src/register.test.ts
  • package.json
  • scripts/check-direct-credential-env.ts
  • src/lib/agent-defs.ts
  • src/lib/credentials.ts
  • src/lib/gateway-state.ts
  • src/lib/http-probe.ts
  • src/lib/inference-config.ts
  • src/lib/local-inference.ts
  • src/lib/model-prompts.ts
  • src/lib/nim.ts
  • src/lib/onboard-inference-probes.ts
  • src/lib/onboard-session.ts
  • src/lib/onboard.ts
  • src/lib/openshell.ts
  • src/lib/preflight.ts
  • src/lib/provider-models.ts
  • src/lib/runtime-recovery.ts
  • src/lib/skill-install.ts
  • src/lib/usage-notice.ts
  • src/nemoclaw.ts
  • test/http-proxy-fix-e2e.test.ts
  • test/http-proxy-fix-rewrite.test.ts
  • test/no-direct-credential-env.test.ts
  • test/onboard.test.ts
  • test/validate-configs-dangerous-hosts.test.ts
💤 Files with no reviewable changes (27)
  • src/lib/onboard-session.ts
  • .prettierrc
  • src/lib/gateway-state.ts
  • src/lib/onboard-inference-probes.ts
  • nemoclaw/.prettierrc
  • src/lib/credentials.ts
  • src/lib/runtime-recovery.ts
  • nemoclaw/src/register.test.ts
  • src/lib/agent-defs.ts
  • src/lib/model-prompts.ts
  • src/lib/provider-models.ts
  • nemoclaw/src/lib/ports.test.ts
  • src/lib/http-probe.ts
  • src/lib/local-inference.ts
  • src/lib/preflight.ts
  • test/validate-configs-dangerous-hosts.test.ts
  • test/http-proxy-fix-e2e.test.ts
  • src/lib/inference-config.ts
  • src/nemoclaw.ts
  • nemoclaw/eslint.config.mjs
  • test/onboard.test.ts
  • eslint.config.mjs
  • eslint-rules/no-direct-credential-env.js
  • test/http-proxy-fix-rewrite.test.ts
  • src/lib/openshell.ts
  • src/lib/skill-install.ts
  • src/lib/nim.ts

Comment thread .pre-commit-config.yaml Resolved
Comment thread biome.json Resolved
Comment thread scripts/check-direct-credential-env.ts Resolved
Comment thread src/lib/onboard.ts Resolved
Signed-off-by: Carlos Villela <cvillela@nvidia.com>

@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)
AGENTS.md (2)

108-115: ⚡ Quick win

Clarify Biome config scope in the JavaScript style bullets.

The TS section says “root Biome config”, but the JS bullet just says “Biome config in biome.json”. Consider making it explicit that this is the repo-root config (and that it applies to formatting/linting as described elsewhere), e.g.:

🛠️ Suggested tweak
- - Biome config in `biome.json`
+ - Biome config at repo root (`./biome.json`)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@AGENTS.md` around lines 108 - 115, Update the JavaScript style bullet about
Biome to explicitly state it's the repo-root Biome config and that it governs
formatting/linting as referenced elsewhere; specifically change the "Biome
config in `biome.json`" bullet to something like "Repo-root Biome config in
`biome.json` (applies to formatting and linting as described elsewhere)" so it
matches the TS section's "root Biome config" wording and clarifies scope for
readers.

169-175: 💤 Low value

Use inline-code formatting consistently for node_modules.

In the “Gotchas” bullet, node_modules is currently not wrapped in backticks; wrapping it improves scanability and matches the rest of the conventions in this doc:

🛠️ Suggested tweak
-- - The `nemoclaw/` subdirectory has its own `package.json` and `node_modules`, while sharing the root Biome config — it's a separate npm project
+- - The `nemoclaw/` subdirectory has its own `package.json` and `node_modules`, while sharing the root Biome config — it's a separate npm project

(If the intent is that both package.json and node_modules should be backticked, ensure both are consistently formatted in the actual file.)

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

In `@AGENTS.md` around lines 169 - 175, The "Gotchas" bullet is inconsistent:
`node_modules` is not inline-code formatted like the other terms; update the
text in the bullet about the `nemoclaw/` subdirectory so both `package.json` and
`node_modules` are wrapped in backticks (e.g., `package.json` and
`node_modules`) to match the document's convention and improve scanability—edit
the line containing "nemoclaw/ subdirectory has its own package.json and
node_modules" accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@AGENTS.md`:
- Around line 108-115: Update the JavaScript style bullet about Biome to
explicitly state it's the repo-root Biome config and that it governs
formatting/linting as referenced elsewhere; specifically change the "Biome
config in `biome.json`" bullet to something like "Repo-root Biome config in
`biome.json` (applies to formatting and linting as described elsewhere)" so it
matches the TS section's "root Biome config" wording and clarifies scope for
readers.
- Around line 169-175: The "Gotchas" bullet is inconsistent: `node_modules` is
not inline-code formatted like the other terms; update the text in the bullet
about the `nemoclaw/` subdirectory so both `package.json` and `node_modules` are
wrapped in backticks (e.g., `package.json` and `node_modules`) to match the
document's convention and improve scanability—edit the line containing
"nemoclaw/ subdirectory has its own package.json and node_modules" accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: ba1f18b8-f794-48af-b307-e7abb6649174

📥 Commits

Reviewing files that changed from the base of the PR and between 7a60946 and 8438c30.

📒 Files selected for processing (8)
  • .pre-commit-config.yaml
  • AGENTS.md
  • biome.json
  • scripts/check-direct-credential-env.ts
  • src/lib/onboard.ts
  • src/lib/usage-notice.ts
  • test/no-direct-credential-env.test.ts
  • test/usage-notice.test.ts
✅ Files skipped from review due to trivial changes (2)
  • biome.json
  • scripts/check-direct-credential-env.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/lib/usage-notice.ts
  • test/no-direct-credential-env.test.ts
  • .pre-commit-config.yaml
  • src/lib/onboard.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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/lib/onboard.ts (1)

5199-5209: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Apply NEMOCLAW_PROVIDER_KEY before hydrating saved credentials.

Line 5199 hydrates the provider-specific credential into process.env before the new fallback checks on Lines 5207 and 5248 run. So when a key is already saved locally, existingNvidiaKey / existingCredentialKey is never empty and the explicit NEMOCLAW_PROVIDER_KEY override is ignored. That still lets stored credentials win over an explicit env override.

🔧 Suggested fix
-        hydrateCredentialEnv(credentialEnv);
+        const providerKeyOverride = normalizeCredentialValue(
+          process.env.NEMOCLAW_PROVIDER_KEY ?? "",
+        );
+        if (providerKeyOverride && credentialEnv) {
+          // check-direct-credential-env-ignore -- intentional: explicit alias should win
+          // unless the provider-specific env var was already exported.
+          const existingCredentialKey = normalizeCredentialValue(process.env[credentialEnv] ?? "");
+          if (!existingCredentialKey) {
+            process.env[credentialEnv] = providerKeyOverride;
+          }
+        }
+        hydrateCredentialEnv(credentialEnv);

         if (selected.key === "build") {
-          // Allow NEMOCLAW_PROVIDER_KEY as a fallback for NVIDIA_API_KEY.
-          // Check raw process.env first — NEMOCLAW_PROVIDER_KEY is a user-facing
-          // override that should take precedence before resolving from credentials.json.
-          const _nvProviderKey = (process.env.NEMOCLAW_PROVIDER_KEY || "").trim();
-          // check-direct-credential-env-ignore -- intentional: checking if env is already set before applying NEMOCLAW_PROVIDER_KEY override
-          const existingNvidiaKey = normalizeCredentialValue(process.env.NVIDIA_API_KEY ?? "");
-          if (_nvProviderKey && !existingNvidiaKey) {
-            process.env.NVIDIA_API_KEY = _nvProviderKey;
-          }
           if (isNonInteractive()) {
             const resolvedNvidiaKey = resolveProviderCredential("NVIDIA_API_KEY");
             if (!resolvedNvidiaKey) {
               console.error(
                 "  NVIDIA_API_KEY (or NEMOCLAW_PROVIDER_KEY) is required for NVIDIA Endpoints in non-interactive mode.",
@@
         } else {
-          // NEMOCLAW_PROVIDER_KEY is a universal alias: if the specific credential env
-          // isn't already set, use NEMOCLAW_PROVIDER_KEY as the API key for this provider.
-          // Check raw process.env — the override must apply before resolving from credentials.json.
-          const _providerKeyHint = (process.env.NEMOCLAW_PROVIDER_KEY || "").trim();
-          if (_providerKeyHint && credentialEnv) {
-            // check-direct-credential-env-ignore -- intentional: checking if env is already set before applying NEMOCLAW_PROVIDER_KEY override
-            const existingCredentialKey = normalizeCredentialValue(process.env[credentialEnv] ?? "");
-            if (!existingCredentialKey) {
-              process.env[credentialEnv] = _providerKeyHint;
-            }
-          }
-
           if (isNonInteractive()) {
             if (!resolveProviderCredential(credentialEnv)) {
               console.error(
                 `  ${credentialEnv} (or NEMOCLAW_PROVIDER_KEY) is required for ${remoteConfig.label} in non-interactive mode.`,

Based on learnings: credential hydration here must preserve fill-only-if-missing semantics so explicitly provided environment credentials are not shadowed by saved credentials.

Also applies to: 5246-5250

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

In `@src/lib/onboard.ts` around lines 5199 - 5209, The saved-credentials hydration
currently runs before honoring the explicit NEMOCLAW_PROVIDER_KEY override, so
hydrateCredentialEnv(...) can shadow an explicit env value; fix by applying the
NEMOCLAW_PROVIDER_KEY check and setting process.env.NVIDIA_API_KEY (using
normalizeCredentialValue logic) before calling hydrateCredentialEnv, or
alternatively change hydrateCredentialEnv to be strictly fill-only-if-missing so
it never overwrites an already-set process.env variable; apply the same
ordering/guard for the other provider check that uses existingCredentialKey (the
block around lines referencing existingCredentialKey /
normalizeCredentialValue).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/lib/onboard.ts`:
- Around line 5199-5209: The saved-credentials hydration currently runs before
honoring the explicit NEMOCLAW_PROVIDER_KEY override, so
hydrateCredentialEnv(...) can shadow an explicit env value; fix by applying the
NEMOCLAW_PROVIDER_KEY check and setting process.env.NVIDIA_API_KEY (using
normalizeCredentialValue logic) before calling hydrateCredentialEnv, or
alternatively change hydrateCredentialEnv to be strictly fill-only-if-missing so
it never overwrites an already-set process.env variable; apply the same
ordering/guard for the other provider check that uses existingCredentialKey (the
block around lines referencing existingCredentialKey /
normalizeCredentialValue).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: e7964960-22e2-4022-b534-78f1a8319603

📥 Commits

Reviewing files that changed from the base of the PR and between 8438c30 and 2cc8d50.

📒 Files selected for processing (6)
  • .pre-commit-config.yaml
  • nemoclaw/src/blueprint/runner.test.ts
  • package.json
  • src/lib/onboard.ts
  • src/nemoclaw.ts
  • test/onboard.test.ts
💤 Files with no reviewable changes (2)
  • test/onboard.test.ts
  • src/nemoclaw.ts
✅ Files skipped from review due to trivial changes (1)
  • nemoclaw/src/blueprint/runner.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • package.json
  • .pre-commit-config.yaml

@cv
cv requested a review from brandonpelfrey May 1, 2026 23:13
@cv
cv merged commit defeffc into main May 1, 2026
18 of 19 checks passed
@cv
cv deleted the chore/switch-to-biome branch May 27, 2026 21:16
@wscurran wscurran added the chore Build, CI, dependency, or tooling maintenance label Jun 8, 2026
cjagwani added a commit that referenced this pull request Aug 21, 2026
<!-- markdownlint-disable MD041 -->
## Summary

Restore the PR exact OpenClaw MCP qualification path end to end. The job
now onboards the exact managed image, preserves a classified MCP
credential environment alongside gateway-only inference credentials, and
performs authenticated discovery with the live revision-scoped OpenShell
placeholder.

## Root cause

The same two five-phase qualification jobs were genuinely green before
the dependency upgrade. The last clean pre-upgrade pair, [run
32332905722](https://github.com/NVIDIA/NemoClaw/actions/runs/32332905722)
at `ab5db717b`, installed OpenShell 0.0.101 and passed without a waiver.
[NemoClaw PR #9192](#9192) then
merged at 2026-08-19 22:29 PDT and upgraded OpenShell directly from
0.0.101 to 0.0.106. The first exact pair based on 0.0.106, [run
32338412376](https://github.com/NVIDIA/NemoClaw/actions/runs/32338412376),
failed phase 3 in both passes with no successful MCP request.

The causal OpenShell change is [OpenShell PR
#2510](NVIDIA/OpenShell#2510), merged as
`0120535ef`, which introduced endpoint-bound static credential
snapshots. A profileless inference provider contributes a static
environment key without binding or non-secret classification; the
binding-capable supervisor rejects that snapshot as `provider
environment contains an unclassified credential key` and revokes the
otherwise correctly bound MCP credential too.

The failures occurred at five successive boundaries:

1. The PR MCP child environment dropped the managed-image catalog and
activation inputs. Onboarding therefore built a Dockerfile image instead
of qualifying the candidate image.
2. With the exact image active, OpenShell 0.0.106 emitted the legacy
`openai` provider credential without selected-profile binding metadata.
The supervisor rejected the provider environment as containing an
unclassified credential and atomically withheld the MCP static
credential too.
3. After classifying the inference provider with an endpointless
profile, the discovery runtime still synthesized
`openshell:resolve:env:<KEY>`. OpenShell's bound resolver requires the
current live revision-scoped value
(`openshell:resolve:env:v<revision>_<KEY>`), so discovery received HTTP
500 before any request reached the fake MCP server.
4. Once diagnostic discovery used the live revision and successfully
listed `fake_echo` and `fake_status`, the managed mcporter config still
persisted the canonical unversioned placeholder. The direct
agent-adapter proof therefore received HTTP 500 even though the
diagnostic path was green.
5. After both diagnostic discovery and direct mcporter discovery passed,
the test entered a separate trusted-private DNS-rebinding fixture. That
fixture rewrote `/etc/hosts` on the runner and sandbox, but OpenShell
resolves egress in the Docker supervisor namespace. The supervisor never
observed the fake hostname mapping, rejected the connection before it
reached the server, and the negative-only raw probe had previously
passed for the same wrong reason.
6. Once both passes reached the rebuild lifecycle, the 0.0.106
migration's pre-delete `removeGeneratedPolicy()` correctly removed
`mcp-bridge-fake`, but the captured policy selection still handed that
generated name to inner onboarding and generic policy replay. The first
correction normalized the rebuild session, but resumed sandbox creation
then overwrote it from the intentionally preserved crash-recovery
registry row. Recreate therefore still failed deterministically with
`Preset not found: mcp-bridge-fake` before the dedicated MCP restore
phase could reattach the provider, generated policy, and adapter.

This is the normal host-gateway / one-container-per-sandbox topology. No
custom MCP sidecar is involved.

## Changes

- Preserve the workflow-owned managed-image catalog, candidate SHA, live
qualification flag, and supervisor image across the MCP child-process
boundary.
- Activate onboarding through `--temp-managed-runtime` and
`--temp-managed-runtime-catalog`, then require the sandbox receipt to
identify the exact candidate revision.
- Import an endpointless, inference-capable `openai` profile before the
endpointless MCP profile so OpenShell can classify gateway-only
inference credentials without injecting them into workloads.
- When `openai` already exists, export it and require the exact
gateway-only boundary: `id: openai`, empty
credentials/endpoints/binaries, and `inference_capable: true`. Fail
closed before MCP policy or provider mutation on export failure,
malformed output, or a mismatch.
- Make MCP discovery read the fresh process environment and accept only
a canonical or revision-scoped OpenShell placeholder for the declared
key. Raw, wrong-key, malformed, missing, and injected values fail closed
and never enter argv, output, or a request.
- Return the bounded live credential revision from the
attachment-readiness proof and project that exact revision into managed
mcporter configuration. Post-write registration inspection now requires
the same readiness-proven revision (`v12` cannot verify as `v11`);
canonical status/removal matching remains available only when readiness
was canonical.
- Qualify every `mcp-bridge-*.ts` change through the PR and main
managed-image workflow boundaries so adapter projection changes cannot
bypass this live proof.
- Scope exact managed-image CI to the topology it actually owns:
exact-image onboarding, authenticated public MCP discovery, direct
adapter use, endpoint boundaries, credential rotation, restart, and
removal. The evidence records `managed-image-discovery`; the job no
longer claims trusted-private DNS-rebinding coverage from a
runner/sandbox hosts fixture that cannot control the supervisor
resolver. Full MCP E2E retains that proof for supervisor-authoritative
DNS topologies.
- Exclude only the generated policy names already preserved by the MCP
rebuild transaction from inner-onboard and generic policy replay. The
outer rebuild now carries that normalized selection through an explicit
authoritative create intent, so sandbox recreation cannot replace it
from the stale source registry row or ambient policy variables.
Matching-journal recovery remains a fallback, a journal for another
sandbox cannot supply policy state, the crash-recovery registry remains
untouched, built-in and operator policy selections remain unchanged, and
the dedicated post-rebuild MCP phase remains the sole owner of restoring
the provider-bound generated policy and adapter.
- Rebuild and pin the reviewed MCP discovery runtime bundle.

The `openai` profile is a provisional compatibility path for the pinned
0.0.106 binary, not the intended ownership model. The ownership-free fix
is [OpenShell PR #2862](NVIDIA/OpenShell#2862):
at the gateway response boundary, remove each static key that lacks
binding metadata before sending the snapshot to a binding-capable
supervisor. Bound static credentials and valid dynamic credentials
remain active, provider resolution stays unchanged, and legacy
supervisors retain their existing strip-all behavior. The full
1,415-test server suite passes (1,408 passed, 7 ignored), as do
formatting and warning-as-error clippy. After that fix is released and
NemoClaw updates its pin, this PR should remove the provisional shared
profile and its lifecycle code.

## Type of Change

- [x] 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)

## Quality Gates

- [x] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [ ] Tests not applicable — justification:
- [x] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — Senthil explicitly accepted the provisional `openai` profile
ownership boundary and approved at `52b2db132`; Ryan's rebuild and
exact-revision findings on `75aefaf3b` are addressed by signed commits
`a51adb149` and `6c05be2d9`, and the current head awaits re-review.
OpenShell PR #2862 remains the ownership-free follow-up.
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## DGX Station Hardware Evidence

- [ ] Tested on DGX Station
- Tested commit:
- Station profile/scenario:
- Result:
- Supporting evidence:

## Verification

- [x] PR description includes a `Signed-off-by:` line and every pushed
commit is signed and DCO-compliant
- [x] Normal pre-commit, commit-msg, and pre-push hooks passed
- [x] Targeted behavior tests pass for the current change set — the
371-test MCP bridge suite, 217 publication/risk-boundary tests, the
current 179-test affected workflow/scope suite, the earlier 149 focused
provider, discovery, onboarding, image, build-context, and publication
tests, the current 126-test policy/rebuild suite, and the current
98-test adapter/status/crash/restart suite pass; the isolated discovery
runtime wire test and typecheck also pass
- [x] `npm run typecheck:cli`, `npm run build:cli`, focused Oxlint,
formatting, `npm run checks:repository`, and the 32-test growth guard
pass
- [ ] Applicable broad gate passed — current replacement managed-image
run
[32468003695](https://github.com/NVIDIA/NemoClaw/actions/runs/32468003695)
is pending for signed commit `6c05be2d9`; run
[32463784345](https://github.com/NVIDIA/NemoClaw/actions/runs/32463784345)
passed the exact-image build and phases 1–3 in both discovery passes,
including authenticated `fake_echo`/`fake_status` discovery with
`credentialRewriteMatched: true`, then proved that inner sandbox
creation still reloaded the stale generated-policy name from the
preserved registry; attempt 3 of run
[32457422244](https://github.com/NVIDIA/NemoClaw/actions/runs/32457422244)
first reproduced that same phase-4 boundary in both passes, run
[32454193518](https://github.com/NVIDIA/NemoClaw/actions/runs/32454193518)
first exposed rebuild failure, and run
[32452343170](https://github.com/NVIDIA/NemoClaw/actions/runs/32452343170)
reached live discovery in both passes but was cancelled by a newer push
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings (doc changes only)
- [ ] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

---
Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>

---------

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Signed-off-by: Senthil Ravichandran <senthilr@nvidia.com>
Signed-off-by: Charan Jagwani <cjagwani@nvidia.com>
Signed-off-by: Julie Yaunches <jyaunches@nvidia.com>
Co-authored-by: Senthil Ravichandran <senthilr@nvidia.com>
Co-authored-by: Charan Jagwani <cjagwani@nvidia.com>
Co-authored-by: Julie Yaunches <jyaunches@nvidia.com>
prekshivyas added a commit that referenced this pull request Sep 11, 2026
## Outcome

NemoClaw now performs a focused, full cutover from OpenShell `0.0.106`
to exactly `0.0.116`. Active selectors, installers, runtime images, the
TypeScript SDK, credential-boundary evidence, and directly affected
tests agree on `0.0.116`; static credential consumers accept its stable
`s<64 lowercase hex>` handles. The obsolete NemoClaw OpenAI
endpointless-profile workaround is removed because NVIDIA/OpenShell#2862
is an ancestor of the exact `0.0.116` tag, while ordinary OpenAI
provider support remains intact.

## Reason

The earlier dependency upgrade pretrusted OpenShell `0.0.116` artifacts
but did not activate them across NemoClaw. OpenShell `0.0.116`
introduces stable credential handles and a main-process spec and already
includes the upstream static-credential classification repair from
NVIDIA/OpenShell#2862. Retaining `0.0.106` selectors or NemoClaw's
pre-#2862 OpenAI profile shim would leave the cutover internally
inconsistent.

### Related issues

Fixes #11229

## Changes

- Pin the supported OpenShell window, installers, workflows, managed
runtimes, and SDK dependency to exactly `0.0.116`, using the reviewed
release hashes and manifests.
- Replace the `0.0.106` child-visible credential evidence with the
`0.0.116` manifest and bind it to the current NemoClaw credential
consumers.
- Accept legacy revision handles where backward parsing remains
required, while requiring stable `s[a-f0-9]{64}` handles in
exact-`0.0.116` static-credential runtime proofs.
- Preserve a stable handle across same-authorization token refreshes and
require a new handle after key removal, provider detach/re-add, or
another authorization-epoch change. The credential-generation-window and
MCP provider readiness tests protect this behavior.
- Remove the obsolete automatic OpenAI compatibility-profile import,
validation, checked-in profile, and profile-specific fixtures now that
`0.0.116` contains NVIDIA/OpenShell#2862. Keep the ordinary OpenAI
provider type and the separate endpointless `nemoclaw-mcp-v1` profile.
- Fail closed on any recovery or omitted-blueprint path that would
select a release other than exactly `0.0.116`; legacy `0.0.106`
supervisor selection is removed.
- Honor the `0.0.116` main-process spec and perform managed Docker
replacement while the OpenShell sandbox is deliberately stopped, then
restart through OpenShell authority only after protected bootstrap
completion and durable shared-state commit.
- Require a post-update wire-level authorization proof before
registering an MCP adapter when OpenShell retains the same stable
credential handle.
- Compare the external gateway's complete release token exactly, keep
child supervision below the enclosing sandbox timeout, and preserve
credential redaction in messaging diagnostics.
- Rebuild the reviewed MCP tool-discovery bundles and update directly
affected documentation and test fixtures.

## Verification

- Post-review OpenAI-removal and merged-main focused matrix — 360 tests
across 20 files passed.
- `npm run typecheck:cli` — passed.
- Live E2E assertion census regenerated from the merged tree; `npm run
e2e:assertions:check` passed with 1,795 direct expect calls across 86
files.
- Managed-bootstrap and provider-profile suite — 314 tests across 18
files passed.
- Earlier full `npm run validate:pr` — passed, including the strict
source build, plugin/JS/CLI typechecks, formatting, lint, schemas,
repository checks, E2E semantic phases, source-shape budget, growth
guardrails, and commit validation. Final exact-head validation will run
after the required Pi receipt refresh.
- Focused OpenShell/MCP/stable-credential Vitest suite — 206 tests
passed.
- Review-focused activation suite — 97 tests across 7 files passed.
- Base-trust transition and installer suite — 111 tests across 4 files
passed.
- `npm run docs` — passed with 0 errors.
- `npm --prefix tools/mcp-tool-discovery-runtime run
bundle:reviewed:check` — passed.
- `npm --prefix tools/mcp-tool-discovery-runtime test` — passed.
- `npm --prefix tools/mcp-tool-discovery-runtime run typecheck` —
passed.
- `npx vitest run --project installer-integration
test/installer-integration/install-hermes-portable-active.test.ts
--testTimeout=120000` — 3 tests passed against the committed manifest.
- Base-controlled SDK and installer authorization landed in #11253. The
final exact supervisor template authority landed separately in #11292
after independent maintainer approval and exact candidate verification.
- The diff contains no secrets, API keys, or raw credentials.

## Review notes

This PR changes contributor-sensitive workflow, installer,
agent-runtime, sandbox, credential, messaging, and E2E enforcement
paths. Review covered the full cutover diff, current-main conflict
resolution, base-trust separation, and the focused checks listed above.

Removing the obsolete checked-in OpenAI profile changes a Pi
managed-image input. Exact-head CI must publish the AMD64 and ARM64 Pi
candidates from one cohort; the checked-in qualification receipts will
then be refreshed from those authoritative contracts before merge. No
receipt is synthesized locally.

---

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added support for stable credential handles that persist across
refreshes and provider updates.
* Improved sandbox lifecycle recovery, restart, rollback, and
process-command handling.
  * Managed images now default to the non-root `sandbox` user.

* **Security & Reliability**
* OpenShell installations now require the exact stable `0.0.116` release
with verified artifacts.
  * Development builds and channels are rejected.
* Credential authorization is revalidated before preserving unchanged
handles.

* **Documentation**
* Updated setup, troubleshooting, security, and lifecycle guidance for
OpenShell `0.0.116`.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Prekshi Vyas <prekshiv@nvidia.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

chore Build, CI, dependency, or tooling maintenance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants