Skip to content

fix(onboard): fall back from managed gateway failures - #8106

Merged
sandl99 merged 9 commits into
mainfrom
agent/gateway-service-fallback
Aug 3, 2026
Merged

fix(onboard): fall back from managed gateway failures#8106
sandl99 merged 9 commits into
mainfrom
agent/gateway-service-fallback

Conversation

@sandl99

@sandl99 sandl99 commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

Managed OpenShell gateway failures previously stopped onboarding after the selected systemd or Homebrew service failed to start or become healthy. Onboarding now prints the platform-specific log command, attempts managed-service cleanup, and continues through the existing ownership-gated standalone gateway path.

Related Issue

Fixes #8104

Changes

  • Return platform-specific log commands with managed-service results and preserve a diagnostic command when service inspection fails before a result is available.
  • Route operational service inspection, startup, cleanup, and health failures to the existing standalone gateway consumer. The direct return-to-standalone change is insufficient by itself because the managed service can remain in an auto-restart loop, so onboarding first attempts trusted service cleanup. Tests cover systemd, Homebrew, cleanup failure, health failure, and unexpected inspection/startup failures.
  • Preserve managed-service trust and unsafe-environment failures as hard boundaries. A missing Homebrew formula falls back as an unavailable managed service, while an installed formula with unverifiable identity or the wrong tap fails hard. Tests also protect foreign or symlinked systemd units, untrusted systemd executables, invalid DOCKER_HOST, and symlinked service-environment rejection.
  • Document the fallback, port-ownership gate, hard-failure boundary, and exact Linux and Homebrew log commands.

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)

Quality Gates

  • Tests added or updated for changed behavior
  • Existing tests cover changed behavior — justification:
  • Tests not applicable — justification:
  • Docs updated for user-facing behavior changes
  • Docs not applicable — justification:
  • Sensitive paths changed (security, policy, credentials, preflight, onboarding, inference, runner, sandbox, or messaging)
  • Sensitive-path review completed or maintainer-approved waiver recorded — reviewer/approval link/justification: All nine security-review categories passed at 39304fd42; review report.
  • Non-success, skipped, or missing CI check accepted by maintainer — check name, approval link, and follow-up issue:

Documentation Writer Review

DGX Station Hardware Evidence

  • Tested on DGX Station
  • Tested commit:
  • Station profile/scenario:
  • Result:
  • Supporting evidence:

Verification

  • PR description includes a Signed-off-by: line and every commit appears as Verified in GitHub
  • Normal pre-commit, commit-msg, and pre-push hooks passed, or npm run validate:pr passed after refreshing origin/main when hooks were skipped or unavailable
  • Targeted behavior tests pass for the current change set, or tests are marked not applicable above — command/result or justification: the focused managed-service suite passed 59/59 and test/onboard-gateway-prelaunch-cutover.test.ts passed 12/12 at 39304fd42; the unrelated pinned prompt-asset test passed 18/18 locally after an external GitHub fetch timeout in CI.
  • Manual fresh-Ubuntu validation passed: the managed service reached its 60-second health deadline, onboarding printed the exact journalctl command, the standalone gateway became healthy, and onboarding continued to step 3/8 without logout/login (evidence).
  • Applicable broad gate passed — npm test for broad runtime/test-harness changes; npm run check for repo-wide validation/coverage changes — command/result: Not applicable; this is a focused onboarding behavior change covered by the targeted CLI tests and normal hooks.
  • Quality Gates section completed with required justifications or waivers
  • No secrets, API keys, or credentials committed
  • npm run docs builds without warnings (doc changes only) — the command passed, but Fern reported its general 2-warning summary.
  • Doc pages follow the style guide (doc changes only)
  • New doc pages include SPDX header and frontmatter (new pages only)

Signed-off-by: San Dang sdang@nvidia.com

Summary by CodeRabbit

  • New Features

    • Gateway startup now falls back to standalone mode when supported managed services fail inspection, startup, or health checks.
    • macOS systems without Homebrew or the required service setup can use standalone mode, subject to exclusive gateway-port ownership.
    • Recovery guidance now includes service log commands and installer recommendations.
  • Bug Fixes

    • Prevented fallback when Docker settings, service trust, identities, or environment files are unsafe or invalid.
    • Added cleanup and clearer warnings when managed startup fails.

Signed-off-by: San Dang <sdang@nvidia.com>
@sandl99 sandl99 added area: docs Documentation, examples, guides, or docs build area: onboarding Onboarding FSM, provider setup, sandbox launch, or first-run flow labels Aug 3, 2026
@sandl99 sandl99 self-assigned this Aug 3, 2026
@copy-pr-bot

copy-pr-bot Bot commented Aug 3, 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.

@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Managed gateway startup now reports platform-specific logs and falls back to standalone startup after operational service failures. Trust-validation, unsafe environment, invalid Docker settings, and occupied-port conditions remain blocking conditions. Tests and documentation cover the updated behavior.

Changes

Gateway fallback

Layer / File(s) Summary
Service contracts and trust resolution
src/lib/onboard/docker-driver-gateway-service.ts
Service results now expose log commands and trust-block status. Homebrew and systemd resolution validates service identity and reports platform-specific diagnostics.
Managed service failure handling
src/lib/onboard/docker-driver-gateway-service.ts, src/lib/onboard/docker-driver-gateway-env.ts
Inspection, startup, cleanup, and health failures can continue to standalone startup. Trust and environment errors remain fatal.
Onboarding cutover orchestration
src/lib/onboard.ts, src/lib/onboard/docker-driver-gateway-cutover.ts
Managed startup and standalone cutover now use runDockerDriverGatewayManagedFallback. Listener evidence is refreshed before fallback. Standalone launch occurs only when cutover returns "launch".
Fallback validation and documentation
src/lib/onboard/*.test.ts, test/onboard-gateway-prelaunch-cutover.test.ts, docs/reference/*.mdx
Tests cover service failures, cleanup, diagnostics, trust checks, environment failures, and port ownership. Documentation describes fallback commands and blocking conditions.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#251: Adds gateway-port listener scanning and occupied-port handling that complement this cutover flow.
  • NVIDIA/NemoClaw#8053: Modifies Linux systemd gateway-service handling and trust validation.
  • NVIDIA/NemoClaw#8098: Modifies gateway-service resolution in the same service module for a different compatibility condition.

Suggested labels: bug-fix, platform: macos

Suggested reviewers: cv, prekshivyas

Sequence Diagram(s)

sequenceDiagram
  participant Onboarding
  participant ManagedGatewayService
  participant GatewayCutover
  participant StandaloneGateway
  Onboarding->>ManagedGatewayService: start and check managed gateway
  ManagedGatewayService-->>Onboarding: success or operational failure
  Onboarding->>GatewayCutover: run managed fallback
  GatewayCutover->>ManagedGatewayService: stop failed service
  GatewayCutover->>StandaloneGateway: verify port and reuse or launch
  StandaloneGateway-->>Onboarding: reused or launched gateway
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% 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
Linked Issues check ✅ Passed The changes address issue #8104 by adding diagnostics, operational fallback, cleanup, trust checks, port ownership, tests, and documentation.
Out of Scope Changes check ✅ Passed All changes support managed gateway fallback, validation, testing, or documentation required by issue #8104.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: onboarding now falls back when managed gateway startup fails.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch agent/gateway-service-fallback

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

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

@github-code-quality

github-code-quality Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in commit 39304fd in the agent/gateway-servic... branch remains at 96%, unchanged from commit 4cd4d64 in the main branch.

TypeScript / code-coverage/cli

The overall coverage in commit 39304fd in the agent/gateway-servic... branch remains at 81%, unchanged from commit a931be4 in the main branch.

Show a code coverage summary of the most impacted files.
File main a931be4 agent/gateway-servic... 39304fd +/-
src/lib/onboard...eway-cutover.ts 90% 70% -20%
src/lib/onboard.ts 31% 31% 0%
src/lib/onboard...-gateway-env.ts 92% 92% 0%
src/lib/sandbox...rce-identity.ts 88% 88% 0%
src/lib/state/m...-acquisition.ts 75% 75% 0%
src/lib/tunnel/services.ts 76% 76% 0%
src/lib/onboard...eway-service.ts 82% 86% +4%

Updated August 03, 2026 11:18 UTC

sandl99 added 3 commits August 3, 2026 14:20
Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: San Dang <sdang@nvidia.com>
@sandl99

sandl99 commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator Author

Security Review: PR #8106

Overall Verdict: PASS

The final diff at 39304fd42 preserves the existing managed-service trust and environment boundaries while routing operational service-manager failures through the ownership-gated standalone gateway path. A missing Homebrew formula is explicitly covered as an unavailable managed service; an installed formula with unverifiable identity or the wrong tap remains a hard failure. Operational inspection failures attempt the same trusted cleanup used by later managed-service failures. Standalone cutover refreshes the port listener scan after managed cleanup, and cleanup trust failures still block fallback. No blocking or non-blocking security findings remain.

Findings

No findings.

Category Results

  1. Secrets and credentials — PASS. No secrets, credential values, or credential-handling paths were added. The new diagnostic output contains only static service log commands. Gitleaks and private-key hooks passed.
  2. Input validation — PASS. Log commands use fixed service names rather than user input. Existing absolute local unix:// validation for DOCKER_HOST remains a hard failure, and symlinked environment files remain rejected.
  3. Authentication and authorization — PASS. No endpoint, mTLS, JWT, session, or authorization behavior changed.
  4. Dependencies — PASS. No dependencies or package versions changed.
  5. Error handling and logging — PASS. Operational failures now surface platform-specific diagnostic commands without exposing log contents or credentials. Errors retain context, and trust/environment failures are not downgraded to fallback.
  6. Cryptography — PASS. No cryptographic code, certificates, algorithms, or key handling changed.
  7. Configuration and security posture — PASS. Foreign or symlinked systemd units, untrusted systemd executable identity, invalid Homebrew formula identity, invalid DOCKER_HOST, and symlinked service environment files remain hard failures.
  8. Security testing — PASS. Tests cover foreign units and executables, unsafe environment configuration, trust failures during inspection and cleanup, the missing-Homebrew-formula fallback, operational inspection/startup/cleanup failures, exact systemd/Homebrew diagnostics, and caller-level managed-success and refreshed-listener behavior. Focused tests passed 59/59 and caller/cutover tests passed 12/12.
  9. System security — PASS. Standalone fallback remains gated by a fresh exclusive gateway-port ownership scan after managed cleanup. Cleanup is best effort only after identity validation; a cleanup trust failure blocks fallback. No new privileged operation, shell execution, or external attack surface was introduced.

Files Reviewed

  • src/lib/onboard/docker-driver-gateway-service.ts
  • src/lib/onboard/docker-driver-gateway-env.ts
  • src/lib/onboard.ts
  • src/lib/onboard/docker-driver-gateway-cutover.ts
  • src/lib/onboard/docker-driver-gateway-service.test.ts
  • src/lib/onboard/docker-driver-gateway-env-service.test.ts
  • src/lib/onboard/docker-driver-gateway-env.test.ts
  • test/onboard-gateway-prelaunch-cutover.test.ts
  • docs/reference/architecture.mdx
  • docs/reference/troubleshooting.mdx

Reviewer: Codex CLI (nemoclaw-maintainer-security-code-review)

@sandl99

sandl99 commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator Author

Fresh Ubuntu validation

Manual validation passed on a fresh Ubuntu machine with Docker and OpenShell 0.0.85:

nemoclaw onboard --agent openclaw --fresh

The managed nemoclaw-openshell-gateway service reached the configured 60-second health deadline. Onboarding then:

  • printed journalctl --user --unit nemoclaw-openshell-gateway --no-pager --lines=200;
  • started the standalone Docker-driver gateway;
  • reported ✓ Docker-driver gateway is healthy; and
  • continued to inference-provider configuration at step 3/8.

No logout/login cycle was required.

@github-actions

github-actions Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — No blocking findings reported

Advisor assessment: No blocking advisor findings reported
Next action: No advisor follow-up needed.
Findings: 0 blockers · 0 warnings · 0 suggestions

Model lanes

  • GPT-5.6 Terra (primary): Completed · medium confidence · 0 blockers · 0 warnings · 0 suggestions
  • Nemotron 3 Ultra (second opinion): Completed · high confidence · 0 blockers · 0 warnings · 0 suggestions
  • Model comparison: normalized findings match; normalized terminology decisions differ; normalized E2E selections differ; severity counts match.
3 terminology differences from the second opinion

Advisory only. These are normalized differences from the primary terminology receipt.

  • standalone fallback at docs/reference/architecture.mdx:90: primary classified it as established; the second opinion classified it as justified.
  • trust validation at docs/reference/troubleshooting.mdx:974: selected only by the second-opinion lane as justified.
  • unsafe environment at docs/reference/architecture.mdx:97: selected only by the second-opinion lane as define.
2 additional E2E selections from the second opinion

Advisory only. The primary lane did not select these E2E jobs or targets.

  • concurrent-gateway-ports: The completed second-opinion lane identified E2E coverage that the primary lane omitted.
  • double-onboard: The completed second-opinion lane identified E2E coverage that the primary lane omitted.

Second-opinion terminology and E2E selections are advisory. They do not change the primary assessment or E2E / PR Gate.

3 semantic terminology decisions

Terminology decisions are advisory. They affect the assessment only when a separate finding identifies concrete semantic impact.

  • established — standalone fallback at docs/reference/architecture.mdx:90: Keep `standalone fallback`; the changed text uses the established term consistently.
  • established — managed service at docs/reference/troubleshooting.mdx:972: Keep `managed service` where the surrounding gateway context identifies the service type.
  • justified — exclusive ownership at docs/reference/architecture.mdx:96: Keep `exclusive ownership`; it names the port-safety precondition for standalone startup.

E2E guidance

Advisory only. E2E / PR Gate selects and runs jobs independently.

Recommended E2E: onboard-repair, onboard-resume, cloud-onboard

1 optional E2E recommendation
  • gateway-guard-recovery

Workflow run details

This automated review informs maintainers. Warnings and suggestions do not require a response. A maintainer decides whether to merge.

Signed-off-by: San Dang <sdang@nvidia.com>
@sandl99

sandl99 commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator Author

Addressed the current PRA-1 warning in 65828bfaa.

  • src/lib/onboard.ts:1953 now routes the production managed-start result through runDockerDriverGatewayManagedFallback; managed success returns without standalone work, while managed failure invokes the existing standalone cutover.
  • test/onboard-gateway-prelaunch-cutover.test.ts:186 connects a failed managed start to that real cutover harness and proves an unattributable occupied port still throws before any fresh process is launched.
  • test/onboard-gateway-prelaunch-cutover.test.ts:123 also proves managed success skips standalone cutover.

The focused managed-service suite passes 58/58, caller/cutover tests pass 11/11, CLI typechecking passes, and the normal pre-commit and pre-push hooks pass.

sandl99 added 2 commits August 3, 2026 15:39
Signed-off-by: San Dang <sdang@nvidia.com>
Signed-off-by: San Dang <sdang@nvidia.com>
@sandl99
sandl99 marked this pull request as ready for review August 3, 2026 10:19

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

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/docker-driver-gateway-service.ts (1)

316-329: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Classify the missing Homebrew formula as an unavailable service, not an error.

Line 319 still throws a generic Error when brew list reports that the formula is absent. The PR objective states that a missing Homebrew formula must fall back as an unavailable service. The generic Error reaches startPackageManagedDockerDriverGateway through hasService() at Line 825 and is caught at Line 826, so onboarding does fall back. However, the user sees the warning "managed service could not be inspected", which describes an inspection defect rather than an absent formula.

Return false for the absent formula so resolveOpenShellGatewayUserService reports the service as not installed. Keep the trust errors for unverifiable or incorrectly sourced formulas.

🐛 Proposed fix
   if (
     !runBrew(["list", "--formula", OPENSHELL_GATEWAY_HOMEBREW_SERVICE], { env, spawnSyncImpl }).ok
   ) {
-    throw new Error("The official OpenShell Homebrew formula is not installed");
+    return false;
   }
🤖 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/docker-driver-gateway-service.ts` around lines 316 - 329,
Update the Homebrew formula check in the service-availability helper around
runBrew and resolveOpenShellGatewayUserService so a failed brew list indicating
the formula is absent returns false instead of throwing a generic Error.
Preserve the existing OpenShellGatewayServiceTrustError for failed identity or
source verification, allowing unavailable-service handling while retaining trust
failures.
🧹 Nitpick comments (5)
docs/reference/troubleshooting.mdx (1)

935-936: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Use one term for the failure set and one actor for the fallback.

Three variants describe the same condition: "inspection, startup, or its health check" (Line 936), "inspection, start, or health failure" (Line 951 and Line 964), and "inspection, start, and health failures" (Line 972). docs/reference/architecture.mdx Line 90 uses the first form. Pick one form. Line 935 also makes the formula the actor; NemoClaw performs the fallback. Line 964 drops "this log command", which breaks parallelism with Line 951.

As per coding guidelines, "Use the same term for the same concept" and "Use a professional, active, conversational voice".

📝 Proposed wording alignment
-   During onboarding, a missing `openshell` formula uses the standalone fallback.
+   During onboarding, NemoClaw uses the standalone fallback when the `openshell` formula is missing.
    If the installed service fails inspection, startup, or its health check, NemoClaw prints this log command:
-   After an inspection, start, or health failure, NemoClaw prints this log command:
+   If the service fails inspection, startup, or its health check, NemoClaw prints this log command:
-   After an inspection, start, or health failure, NemoClaw prints:
+   If the service fails inspection, startup, or its health check, NemoClaw prints this log command:
-   Managed-service inspection, start, and health failures on either platform attempt the standalone fallback.
+   On either platform, NemoClaw attempts the standalone fallback after managed-service inspection, startup, and health check failures.

Also applies to: 951-951, 964-964, 972-972

🤖 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 `@docs/reference/troubleshooting.mdx` around lines 935 - 936, Align the
troubleshooting wording at the referenced fallback descriptions to consistently
use “inspection, startup, or its health check” for the failure set, make
NemoClaw the actor performing the standalone fallback, and retain “this log
command” wherever the log command is introduced or referenced, including the
parallel entries around lines 951, 964, and 972.

Source: Coding guidelines

src/lib/onboard/docker-driver-gateway-service.ts (3)

63-68: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Preserve the original error as cause.

OpenShellGatewayServiceEnvironmentError keeps only the formatted message. The original error object, including its stack and errno code, is discarded. Node.js 22 supports the cause option, so keeping it costs nothing and improves diagnosis of filesystem failures raised by writeDockerGatewayDebEnvOverrideFile.

♻️ Proposed change
 export class OpenShellGatewayServiceEnvironmentError extends Error {
   constructor(error: unknown) {
-    super(formatError(error));
+    super(formatError(error), { cause: error });
     this.name = "OpenShellGatewayServiceEnvironmentError";
   }
 }
🤖 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/docker-driver-gateway-service.ts` around lines 63 - 68,
Update the OpenShellGatewayServiceEnvironmentError constructor to preserve the
incoming error as the Error cause while retaining the formatted message and
existing name. Ensure errors raised by writeDockerGatewayDebEnvOverrideFile keep
their original stack and errno details.

820-896: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Extract the managed-start and fallback handling into helpers.

startPackageManagedDockerDriverGateway now spans about 140 lines. It contains the inspection guard, a nested stopBeforeStandaloneFallback closure, a nested reportLogs closure, the start try/catch, the not-started branch, the health poll, and the timeout branch. This exceeds the complexity target for the file type.

Extract stopBeforeStandaloneFallback and the managed-start-result handling into module-level functions that take stopService, managedServiceLogCommand, and exitOnFailure as parameters. The function then reads as inspect, start, wait, report.

As per coding guidelines: "Keep function complexity low and prefix intentionally unused variables with _."

🤖 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/docker-driver-gateway-service.ts` around lines 820 - 896,
Refactor startPackageManagedDockerDriverGateway by extracting the nested
stopBeforeStandaloneFallback and managed-start-result handling (including log
reporting) into module-level helpers that accept stopService,
managedServiceLogCommand, and exitOnFailure. Keep the main function’s flow
limited to inspect, start, wait, and report while preserving existing fallback,
trust-error, logging, and exit behavior; prefix any intentionally unused helper
parameters with _.

Source: Coding guidelines


330-351: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Narrow the try block to the JSON parse.

The try at Line 330 also wraps the tap check at Line 337. The OpenShellGatewayServiceTrustError thrown at Line 338 enters the catch, passes the SyntaxError test, and is rethrown at Line 348. The result is correct, but the control flow is indirect. Parse inside the try and validate the tap outside it.

♻️ Proposed refactor
-  try {
-    const parsed = JSON.parse(info.stdout ?? "") as {
-      formulae?: Array<{ name?: string; tap?: string }>;
-    };
-    const formula = parsed.formulae?.find(
-      (candidate) => candidate.name === OPENSHELL_GATEWAY_HOMEBREW_SERVICE,
-    );
-    if (formula?.tap !== OPENSHELL_GATEWAY_HOMEBREW_TAP) {
-      throw new OpenShellGatewayServiceTrustError(
-        `OpenShell Homebrew formula must come from ${OPENSHELL_GATEWAY_HOMEBREW_TAP}`,
-      );
-    }
-  } catch (error) {
-    if (error instanceof SyntaxError) {
-      throw new OpenShellGatewayServiceTrustError(
-        "OpenShell Homebrew formula identity check returned invalid JSON",
-      );
-    }
-    throw error;
-  }
+  let parsed: { formulae?: Array<{ name?: string; tap?: string }> };
+  try {
+    parsed = JSON.parse(info.stdout ?? "") as typeof parsed;
+  } catch {
+    throw new OpenShellGatewayServiceTrustError(
+      "OpenShell Homebrew formula identity check returned invalid JSON",
+    );
+  }
+  const formula = parsed.formulae?.find(
+    (candidate) => candidate.name === OPENSHELL_GATEWAY_HOMEBREW_SERVICE,
+  );
+  if (formula?.tap !== OPENSHELL_GATEWAY_HOMEBREW_TAP) {
+    throw new OpenShellGatewayServiceTrustError(
+      `OpenShell Homebrew formula must come from ${OPENSHELL_GATEWAY_HOMEBREW_TAP}`,
+    );
+  }
🤖 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/docker-driver-gateway-service.ts` around lines 330 - 351, In
the formula identity check, narrow the try/catch around JSON.parse so it only
converts SyntaxError into OpenShellGatewayServiceTrustError. Move the formula
lookup and tap validation using parsed and OPENSHELL_GATEWAY_HOMEBREW_TAP
outside the try block, preserving the existing validation behavior and error
message.
src/lib/onboard/docker-driver-gateway-env.ts (1)

354-355: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Thread the injected environment into the log-command helper.

Every other default in this call site receives the resolved env and effectiveHome. getOpenShellGatewayManagedServiceLogCommand() receives no options, so it reads process.platform and the real fs.existsSync. Tests that inject a temporary home still resolve the unit name from the host filesystem. The helper accepts platform and existsSync, so pass them for consistency and test determinism.

🤖 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/docker-driver-gateway-env.ts` around lines 354 - 355, Update
the managedServiceLogCommand default in the surrounding configuration to call
getOpenShellGatewayManagedServiceLogCommand with the resolved env and
effectiveHome dependencies, including the injected platform and existsSync
implementations. Preserve the explicit options.managedServiceLogCommand override
while ensuring the default uses the same injected environment as the other
defaults.
🤖 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.ts`:
- Around line 1974-1990: Refresh the listener scan after managed startup
fallback before invoking runDockerDriverGatewayCutover. Replace the stale
servicePortOwnership.portListenerScan used in the cutover arguments with a newly
obtained port probe and listener scan, preserving the existing scan fields and
using the refreshed pids and complete values for reuse and cleanup decisions.

In `@src/lib/onboard/docker-driver-gateway-service.ts`:
- Around line 882-895: Update startPackageManagedDockerDriverGateway so
OpenShellGatewayServiceTrustError from stopBeforeStandaloneFallback, including
health-timeout cleanup, follows the same exitOnFailure behavior as
standaloneFallbackBlocked: exit with status 1 when enabled, otherwise propagate
the error. Add coverage for both cleanup paths.

In `@test/onboard-gateway-prelaunch-cutover.test.ts`:
- Around line 123-136: Add a test that invokes the public
startDockerDriverGateway entry point from the onboard module, configuring
managed startup to succeed and observing the standalone cutover callback or
equivalent invocation. Assert the result reflects managed startup and verify
standalone startup is not called; keep the existing helper-level test unchanged.

---

Outside diff comments:
In `@src/lib/onboard/docker-driver-gateway-service.ts`:
- Around line 316-329: Update the Homebrew formula check in the
service-availability helper around runBrew and
resolveOpenShellGatewayUserService so a failed brew list indicating the formula
is absent returns false instead of throwing a generic Error. Preserve the
existing OpenShellGatewayServiceTrustError for failed identity or source
verification, allowing unavailable-service handling while retaining trust
failures.

---

Nitpick comments:
In `@docs/reference/troubleshooting.mdx`:
- Around line 935-936: Align the troubleshooting wording at the referenced
fallback descriptions to consistently use “inspection, startup, or its health
check” for the failure set, make NemoClaw the actor performing the standalone
fallback, and retain “this log command” wherever the log command is introduced
or referenced, including the parallel entries around lines 951, 964, and 972.

In `@src/lib/onboard/docker-driver-gateway-env.ts`:
- Around line 354-355: Update the managedServiceLogCommand default in the
surrounding configuration to call getOpenShellGatewayManagedServiceLogCommand
with the resolved env and effectiveHome dependencies, including the injected
platform and existsSync implementations. Preserve the explicit
options.managedServiceLogCommand override while ensuring the default uses the
same injected environment as the other defaults.

In `@src/lib/onboard/docker-driver-gateway-service.ts`:
- Around line 63-68: Update the OpenShellGatewayServiceEnvironmentError
constructor to preserve the incoming error as the Error cause while retaining
the formatted message and existing name. Ensure errors raised by
writeDockerGatewayDebEnvOverrideFile keep their original stack and errno
details.
- Around line 820-896: Refactor startPackageManagedDockerDriverGateway by
extracting the nested stopBeforeStandaloneFallback and managed-start-result
handling (including log reporting) into module-level helpers that accept
stopService, managedServiceLogCommand, and exitOnFailure. Keep the main
function’s flow limited to inspect, start, wait, and report while preserving
existing fallback, trust-error, logging, and exit behavior; prefix any
intentionally unused helper parameters with _.
- Around line 330-351: In the formula identity check, narrow the try/catch
around JSON.parse so it only converts SyntaxError into
OpenShellGatewayServiceTrustError. Move the formula lookup and tap validation
using parsed and OPENSHELL_GATEWAY_HOMEBREW_TAP outside the try block,
preserving the existing validation behavior and error message.
🪄 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: 7c97c1eb-af13-4aae-8311-58b2baadf32b

📥 Commits

Reviewing files that changed from the base of the PR and between 4cd4d64 and e3e1d89.

📒 Files selected for processing (10)
  • docs/reference/architecture.mdx
  • docs/reference/troubleshooting.mdx
  • src/lib/onboard.ts
  • src/lib/onboard/docker-driver-gateway-cutover.ts
  • src/lib/onboard/docker-driver-gateway-env-service.test.ts
  • src/lib/onboard/docker-driver-gateway-env.test.ts
  • src/lib/onboard/docker-driver-gateway-env.ts
  • src/lib/onboard/docker-driver-gateway-service.test.ts
  • src/lib/onboard/docker-driver-gateway-service.ts
  • test/onboard-gateway-prelaunch-cutover.test.ts

Comment thread src/lib/onboard.ts Outdated
Comment thread src/lib/onboard/docker-driver-gateway-service.ts
Comment thread test/onboard-gateway-prelaunch-cutover.test.ts

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Security review for commit e3e1d892cc0211237e1aaa05c688ce28e525ec85 — FAIL

Scope is established by maintainer-authored issue #8104. The fallback must preserve exclusive gateway-port ownership and treat trust failures as hard failures.

  1. Secrets and credentials — PASS. No secret values are added to source, tests, or diagnostics. Existing environment-file and gateway-identity checks remain fail closed.
  2. Input validation and data sanitization — PASS. Command execution uses argument arrays, diagnostic commands are static, and invalid DOCKER_HOST values remain rejected.
  3. Authentication and authorization — PASS. Symlinked environment files, foreign systemd services, and untrusted Homebrew identities remain rejected.
  4. Dependencies and third-party libraries — PASS. No dependency, package, image, or download changes.
  5. Error handling and logging — WARNING. Generic service-inspection failures return to fallback without attempting the issue-required best-effort trusted cleanup. Cleanup trust failures also do not follow the established exitOnFailure behavior. The latter matches unresolved review thread r3703117804.
  6. Cryptography and data protection — PASS. No cryptographic or persisted-secret behavior changes.
  7. Configuration and security headers — PASS. No browser security headers or supported policy boundary changes. Existing trusted service configuration checks remain in place.
  8. Security testing — FAIL. The tests retain a fixed listener snapshot and do not exercise caller wiring when listener ownership changes during the managed attempt. This matches unresolved thread r3703117812.
  9. System security — FAIL. src/lib/onboard.ts captures the gateway listener scan before managed startup or cleanup, then passes that stale snapshot into standalone cutover after the managed attempt may have changed listeners. Because scanGatewayPortListeners materializes a point-in-time result, a managed or auto-restarting listener can be omitted from scoped cleanup or reuse evidence. That violates the exclusive port-ownership requirement and matches unresolved CodeRabbit Major finding r3703117799.

Smallest safe next step: after managed fallback, refresh the port probe and listener scan, pass that refreshed evidence into standalone cutover, and add a caller-level regression in which the listener set changes during the managed attempt. Address the cleanup and failure-boundary findings as part of the same lifecycle fix. Then resolve the review threads and repeat security and documentation writer reviews for the final commit; the current receipts cover 65828bfaa, not this commit.

Signed-off-by: San Dang <sdang@nvidia.com>

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Security review for commit 41f139a87f2656fd2e3268afd77106d9d3745475 — FAIL

Scope is established by maintainer-authored issue #8104. The fallback must preserve exclusive gateway-port ownership and attempt best-effort managed-service cleanup after operational failures while treating identity and trust failures as hard failures.

  1. Secrets and credentials — PASS. No secret values are added to source, tests, or diagnostics.
  2. Input validation and data sanitization — PASS. Command execution uses argument arrays, and invalid gateway inputs remain rejected.
  3. Authentication and authorization — PASS. Untrusted service identities and service configuration remain rejected.
  4. Dependencies and third-party libraries — PASS. No dependency, package, image, or download changes.
  5. Error handling and logging — WARNING. startPackageManagedDockerDriverGateway logs a non-trust hasService() exception and returns false without calling the trusted stopService cleanup used by the later failure paths. Issue #8104 explicitly requires best-effort managed-service stop before standalone fallback after operational inspection failures. The corresponding test supplies a stop spy but never asserts cleanup.
  6. Cryptography and data protection — PASS. No cryptographic or persisted-secret behavior changes.
  7. Configuration and security headers — PASS. Existing trusted service configuration checks remain in place; browser security headers are outside this change.
  8. Security testing — FAIL. The new regression invokes only runDockerDriverGatewayManagedFallback with inline callbacks. It does not exercise startDockerDriverGateway or prove that the production caller refreshes listener evidence after the managed attempt. It would still pass if production reverted to the stale snapshot. This matches current unresolved thread r3703117812.
  9. System security — PASS for the prior stale-listener finding. The production fallback now obtains a fresh port probe and listener scan after managed startup returns false, so current listener evidence reaches standalone cutover.

Required before approval: attempt the same trusted cleanup after a non-trust service-inspection exception and assert it in the unit test; add a caller-level regression through startDockerDriverGateway that proves managed success skips standalone cutover and managed fallback uses listener evidence captured after the managed attempt. Then resolve the remaining review thread and repeat the security and documentation writer reviews for the new commit.

@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

🤖 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 `@test/onboard-gateway-prelaunch-cutover.test.ts`:
- Around line 4-6: Update the subprocess invocation in the onboarding prelaunch
test to run through the repository’s tsx loader instead of relying on bare Node
type stripping. Adjust the spawnSync command setup and retain the existing
script arguments and assertions so src/lib/onboard.ts and its runtime-boundary
dependency load successfully.
🪄 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: 0d568992-61dc-46a6-b439-5d0149f07cb7

📥 Commits

Reviewing files that changed from the base of the PR and between 41f139a and 39304fd.

📒 Files selected for processing (4)
  • src/lib/onboard.ts
  • src/lib/onboard/docker-driver-gateway-service.test.ts
  • src/lib/onboard/docker-driver-gateway-service.ts
  • test/onboard-gateway-prelaunch-cutover.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/lib/onboard.ts
  • src/lib/onboard/docker-driver-gateway-service.ts

Comment thread test/onboard-gateway-prelaunch-cutover.test.ts

@cv cv left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Approved for commit SHA 39304fd42e618015e6c27beb5aafcb4e3e633786 and base SHA 4cd4d64fe67143b57707f874afa0b9d269dfeff2.

Product scope passes. Issue #8104 repairs the existing managed-gateway onboarding fallback and does not create a new supported surface.

The current nine-category security review passes. Operational inspection, startup, cleanup, and health failures enter the existing ownership-gated standalone path. Service trust errors, unsafe environment state, foreign or symlinked units, and untrusted executables remain hard failures. Current regression tests cover the cleanup, trust, port-ownership, and public-caller paths.

The documentation writer review is current for this commit. Required GitHub checks for this commit pass. The repository gate checker reports allPass: true; GitHub reports MERGEABLE. The PR body contains the DCO declaration, all nine commits appear as GitHub Verified, and no unresolved major or critical CodeRabbit finding remains.

@sandl99
sandl99 merged commit d09b530 into main Aug 3, 2026
98 of 104 checks passed
@sandl99
sandl99 deleted the agent/gateway-service-fallback branch August 3, 2026 13:20
senthilr-nv added a commit that referenced this pull request Aug 4, 2026
<!-- markdownlint-disable MD041 -->
## Summary

Adds the canonical dated `v0.0.101` changelog entry that was missing
when the release tag was cut. This post-release recovery records the
shipped behavior on current `main` without changing or replacing the
existing tag.

## Changes

- Add `docs/changelog/2026-08-03.mdx` with the exact `## v0.0.101`
heading, release summary, detailed behavior changes, support boundaries,
and links to durable documentation.
- [#7317](#7317) ->
`docs/changelog/2026-08-03.mdx`: Records experimental OpenClaw Google
Chat support and its restricted credential and webhook boundary.
- [#7715](#7715) ->
`docs/changelog/2026-08-03.mdx`: Records strict onboarding recovery
state and authoritative resume identity.
- [#7749](#7749) ->
`docs/changelog/2026-08-03.mdx`: Records the provider-neutral policy
seam and unchanged runtime support boundary.
- [#7817](#7817) ->
`docs/changelog/2026-08-03.mdx`: Records preserved Hermes home-channel
assignments across rebuilds.
- [#7820](#7820) ->
`docs/changelog/2026-08-03.mdx`: Records the SSH-session status field
correction.
- [#7847](#7847) ->
`docs/changelog/2026-08-03.mdx`: Records fail-closed credential
filtering for migration and rebuild backups.
- [#7870](#7870) ->
`docs/changelog/2026-08-03.mdx`: Records sandbox-qualified in-sandbox
host command hints.
- [#7875](#7875) ->
`docs/changelog/2026-08-03.mdx`: Records Microsoft Teams stop and start
E2E coverage.
- [#7885](#7885) ->
`docs/changelog/2026-08-03.mdx`: Records Hermes managed gateway
detection in status.
- [#7889](#7889) ->
`docs/changelog/2026-08-03.mdx`: Records policy-authenticated HTTPS Pin
Runtime route revocation.
- [#7891](#7891) ->
`docs/changelog/2026-08-03.mdx`: Records default fallback for negative
timeout and polling overrides.
- [#7993](#7993) ->
`docs/changelog/2026-08-03.mdx`: Records correct sibling detection
during uninstall.
- [#7995](#7995) ->
`docs/changelog/2026-08-03.mdx`: Records absent configuration-hash
handling before shields lock.
- [#8001](#8001) ->
`docs/changelog/2026-08-03.mdx`: Records the dormant atomic managed
workload replacement foundation.
- [#8029](#8029) ->
`docs/changelog/2026-08-03.mdx`: Records repository terminology review
in PR Review Advisor.
- [#8031](#8031) ->
`docs/changelog/2026-08-03.mdx`: Records provider-neutral managed
snapshot authority.
- [#8032](#8032) ->
`docs/changelog/2026-08-03.mdx`: Records immutable managed clone handoff
contracts.
- [#8034](#8034) ->
`docs/changelog/2026-08-03.mdx`: Records the dormant provider-owned
clone transaction surface.
- [#8035](#8035) ->
`docs/changelog/2026-08-03.mdx`: Records the dormant Hermes managed
clone broker boundary.
- [#8036](#8036) ->
`docs/changelog/2026-08-03.mdx`: Records the dormant transactional
managed bootstrap boundary.
- [#8037](#8037) ->
`docs/changelog/2026-08-03.mdx`: Records dormant Docker bootstrap
primitives and the unchanged provider support boundary.
- [#8070](#8070) ->
`docs/changelog/2026-08-03.mdx`: Records consolidated sandbox
resource-limit E2E coverage.
- [#8071](#8071) ->
`docs/changelog/2026-08-03.mdx`: Records escaped and bounded CLI
validation diagnostics.
- [#8081](#8081) ->
`docs/changelog/2026-08-03.mdx`: Records bounded linear snapshot Base64
validation.
- [#8085](#8085) ->
`docs/changelog/2026-08-03.mdx`: Records commit-bound workflow approval
for eligible same-repository maintainers.
- [#8088](#8088) ->
`docs/changelog/2026-08-03.mdx`: Records Hermes managed-policy E2E
selection.
- [#8090](#8090) ->
`docs/changelog/2026-08-03.mdx`: Records pinned CI search-tool
provisioning.
- [#8106](#8106) ->
`docs/changelog/2026-08-03.mdx`: Records fallback from failed managed
OpenShell gateway startup.
- [#8107](#8107) ->
`docs/changelog/2026-08-03.mdx`: Records Hermes adapter lifecycle E2E
selection.
- [#8128](#8128) ->
`docs/changelog/2026-08-03.mdx`: Records the dormant transactional
Docker bootstrap adapter and rollback authority.
- [#8140](#8140) ->
`docs/changelog/2026-08-03.mdx`: Records Slack conflict scope across
independent OpenShell gateways.
- [#8147](#8147) ->
`docs/changelog/2026-08-03.mdx`: Records completion of durable v0.0.100
documentation audit follow-ups.

## Type of Change

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

## Quality Gates

- [ ] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [x] Tests not applicable — justification: This documentation-only
recovery does not change executable behavior.
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification:
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Documentation Writer Review

- [x] Documentation writer subagent reviewed the completed changes
- Result: `docs-updated`
- Evidence: Independently reviewed `docs/changelog/2026-08-03.mdx` at
commit `0bebe1f568e3dc85cf410aac1dfb8f8830070b85`. Its blob is
`82887920f9720eafd75db6b2271c35f7477edb9b`. The entry follows the
writing guide, controlled terminology, changelog structure, MDX SPDX
format, literal CLI-name rule, and root-absolute route requirements. It
accurately records the `v0.0.100...v0.0.101` release range, Announcement
#8162, accepted scope boundaries, and shipped security behavior. There
are no code samples. Focused changelog tests and the documentation build
pass for this commit.
- Agent: Codex Desktop independent documentation writer
<!-- docs-review-head-sha: 0bebe1f -->
<!-- docs-review-agents-blob-sha:
3dd7c24 -->

## Security Review

- Result: `PASS`
- Reviewed commit: `0bebe1f568e3dc85cf410aac1dfb8f8830070b85`
- Base commit: `643a4ab8b5f583d8555192a37927268b26022c51`
- Findings: None.
- Secrets and credentials: `PASS`. No credential values or secret files
are present.
- Input validation and data sanitization: `PASS`. No executable input
path changes.
- Authentication and authorization: `PASS`. No identity or permission
logic changes.
- Dependencies and third-party libraries: `PASS`. No dependency changes.
- Error handling and logging: `PASS`. No runtime path changes;
diagnostic-security claims are precise.
- Cryptography and data protection: `PASS`. No implementation changes.
- Configuration and security controls: `PASS`. No configuration,
container, port, or HTTP changes.
- Security testing: `PASS`. No coverage is removed; the entry records
shipped test and security behavior.
- System security: `PASS`. No runtime control changes; dormant and
non-activation boundaries are explicit.
- Agent: Codex Desktop independent security reviewer

## Verification

- [ ] PR description includes a `Signed-off-by:` line and every commit
appears as `Verified` in GitHub — verification is pending after commit
`0bebe1f568e3dc85cf410aac1dfb8f8830070b85` is pushed.
- [ ] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run validate:pr` passed after refreshing `origin/main` when hooks
were skipped or unavailable — commit hooks passed; pre-push is pending.
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — tests are not applicable to this
documentation-only recovery.
- [x] Applicable broad gate passed — not applicable to this
documentation-only recovery.
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, credentials, or private keys are added by
this diff.
- [ ] `npm run docs` builds without warnings (doc changes only) — GitHub
documentation checks are pending.
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only) — independent documentation review passed.
- [x] New doc pages include SPDX header and frontmatter (new pages only)
— the native changelog entry uses the required parser-safe MDX SPDX
comment and intentionally has no frontmatter.

GitHub CI is authoritative.
Focused changelog tests and `npm run docs` passed after the merge
refresh.

---
Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>


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

* **New Features**
  * Added experimental Google Chat support.
  * Improved runtime and session status visibility.
  * Added onboarding recovery and persistence safeguards.
  * Added snapshot validation and dormant managed-workload support.

* **Bug Fixes**
* Improved backup sanitization, route handling, and gateway reliability.

* **Documentation**
  * Added the v0.0.101 changelog and related updates.

* **Tests**
  * Expanded end-to-end coverage and strengthened trusted CI validation.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: Apurv Kumaria <akumaria@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Co-authored-by: Carlos Villela <cvillela@nvidia.com>
Co-authored-by: Senthil Ravichandran <senthilr@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: docs Documentation, examples, guides, or docs build area: onboarding Onboarding FSM, provider setup, sandbox launch, or first-run flow

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Onboarding stops instead of falling back after managed gateway failure

2 participants