Skip to content

fix(installer): classify an unreachable systemd user manager before the upstream gateway gate - #8945

Closed
Dongni-Yang wants to merge 3 commits into
mainfrom
fix/8926-installer-static-user-unit
Closed

fix(installer): classify an unreachable systemd user manager before the upstream gateway gate#8945
Dongni-Yang wants to merge 3 commits into
mainfrom
fix/8926-installer-static-user-unit

Conversation

@Dongni-Yang

@Dongni-Yang Dongni-Yang commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

On Linux, scripts/install.sh treated a packaged static openshell-gateway.service unit file as proof that the upstream user service is inspectable. Without a systemd user session, systemctl --user show fails with Failed to connect to bus: No medium found; the installer discarded that diagnostic (2>/dev/null) and exited before onboarding with the unrelated message:

Could not locate the gateway binary used by the existing upstream OpenShell user service.

The TypeScript gateway lifecycle already classifies an unavailable user manager (userManagerLooksUnavailable + activation-link gate in src/lib/onboard/docker-driver-gateway-service.ts:561-583,981-986); the installer preflight did not.

Change

  • openshell_user_manager_unavailable_reason: classifies systemctl stderr with the same pattern as the TS userManagerLooksUnavailable.
  • upstream_openshell_gateway_user_manager_unavailable: probes systemctl --user show openshell-gateway.service and classifies only its stderr; any other failure keeps the existing fail-closed path.
  • upstream_openshell_gateway_user_service_activation_link_installed: detects *.wants/ / *.requires/ enablement links for the packaged unit across the persistent directories the user manager honors: the env-derived config home, ~/.config (the manager resolves its config home from the login environment, not the installer shell), $XDG_DATA_HOME/~/.local/share, /etc/xdg/systemd/user, /etc/systemd/user, and the three static unit directories. Directory heads are quoted so glob metacharacters in HOME/XDG_CONFIG_HOME stay literal; dangling links count (fail closed).
  • install_nemoclaw_openshell_gateway_user_service: when the manager is unavailable and no activation link exists, falls through to staging the NemoClaw-managed unit (the packaged static unit can never activate, so no port-8080 competition is possible); when the manager is unavailable but an enabled link exists, fails closed with a topology-specific remediation; when the manager is reachable, the identity/version gate is unchanged.

Acceptance criteria mapping

  • Classify only known user-manager-unavailable errors → stderr regex parity with the TS classifier; every non-matching failure keeps the existing fail-closed error.
  • Reject fallback when an enabled unit can later activate and compete for port 8080 → activation-link probe across the persistent user unit directories.
  • Preserve identity/version checks when the manager is reachable → require_compatible_upstream_openshell_gateway_service path unchanged.
  • No static unit file is parsed; no package-owned or foreign unit is replaced or modified.
  • Regression coverage (4 new tests): No medium found fall-through, unavailable manager + enabled activation link, enabled link under a glob-metacharacter config home, and non-classified systemctl failure staying fail-closed.

Testing

  • npx vitest run --project integration test/install-openshell-gateway-service.test.ts — 21/21. The fall-through and enabled-link tests are red→green against the unmodified tree; the fail-closed guard is a characterization test (passes before and after by design).
  • Full --project integration suite green.
  • shfmt -i 2 -ci -bn -d scripts/install.sh clean; shellcheck introduces no new findings; prek hooks (source-shape budget, test size budget, repository checks) pass.
  • An adversarial multi-agent review of the diff confirmed and led to fixing: glob-metacharacter escape in the link probe, the manager's-config-home vs installer-env mismatch, missing persistent enablement directories, a remediation hint that could not run in the triggering state, and test hermeticity against hosts with globally enabled OpenShell units.

Closes #8926

Signed-off-by: Dongni Yang dongniy@nvidia.com

Summary by CodeRabbit

  • Tests
    • Added coverage for gateway service installation when the systemd user manager is unreachable.
    • Verified safe handling when no activation link is available.
    • Confirmed installation is blocked when an upstream service is enabled or unrelated systemctl errors occur.
    • Added coverage for configuration paths containing special wildcard characters.

…he upstream gateway gate

A packaged static openshell-gateway.service unit file was treated as
proof that the upstream user service is inspectable. Without a systemd
user session, systemctl --user fails with "Failed to connect to bus:
No medium found"; the installer discarded that stderr and exited with
the unrelated "Could not locate the gateway binary" error.

Classify only known user-manager-unavailable diagnostics (same pattern
as userManagerLooksUnavailable on the TypeScript side) as eligible for
the NemoClaw-managed fallback, and reject the fallback when an
enablement link in any persistent user unit directory could let the
packaged unit activate later and compete for gateway port 8080. Every
other service-query failure keeps the existing fail-closed error, and
the reachable-manager identity/version gate is unchanged.

Closes #8926

Signed-off-by: Dongni Yang <dongniy@nvidia.com>
@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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: a5e5099d-4cf3-421b-8c9b-a841479d4be5

📥 Commits

Reviewing files that changed from the base of the PR and between 7a51156 and 46096e2.

📒 Files selected for processing (1)
  • test/install-openshell-gateway-service.test.ts

📝 Walkthrough

Walkthrough

The pull request adds installer tests for unavailable systemd user managers. The tests cover safe service staging, enabled upstream activation links, glob characters in configuration paths, and fail-closed handling of unrelated systemctl errors.

Changes

Gateway installation

Layer / File(s) Summary
User manager and activation detection
test/install-openshell-gateway-service.test.ts
Tests cover staging without an upstream activation link, rejecting enabled upstream units, and detecting activation links when XDG_CONFIG_HOME contains glob metacharacters.
Fail-closed gateway installation
test/install-openshell-gateway-service.test.ts
Tests ensure unrelated systemctl failures prevent gateway binary resolution and service staging.

Estimated code review effort: 2 (Simple) | ~10 minutes

Mergeability Score: ⚪ Minimal · up to 46096

The installer now distinguishes an unavailable systemd user manager from a reachable manager while preserving existing compatibility checks and preventing fallback when an activation link exists. No actionable merge-blocking risk remains after normal checks and review.

Possibly related PRs

  • NVIDIA/NemoClaw#8949: Extends installer test coverage for unavailable systemd --user managers, activation links, and fail-closed behavior.

Suggested labels: v0.0.109

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The tests cover key acceptance cases [#8926], but no installer implementation changes appear in the summarized changes. Include the installer implementation that classifies unavailable managers, checks activation links, and fails closed for conflicting or unclassified failures.
✅ 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 clearly describes the installer behavior tested by this pull request.
Out of Scope Changes check ✅ Passed The added installer tests directly support the requirements in linked issue [#8926].
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ 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 fix/8926-installer-static-user-unit

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

@github-code-quality

github-code-quality Bot commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage in commit f2f0038 in the fix/8926-installer-s... branch remains at 96%, unchanged from commit 75564da in the main branch.

TypeScript / code-coverage/cli

The overall coverage in commit f2f0038 in the fix/8926-installer-s... branch remains at 82%, unchanged from commit ce96811 in the main branch.

Show a code coverage summary of the most impacted files.
File main ce96811 fix/8926-installer-s... f2f0038 +/-
src/lib/actions...ocker-health.ts 78% 61% -17%
src/lib/actions...ence-gateway.ts 91% 82% -9%
src/lib/onboard...eway-process.ts 90% 90% 0%
src/lib/sandbox...rce-identity.ts 86% 86% 0%
src/lib/sandbox...rsion-scheme.ts 100% 100% 0%
src/lib/adapter...ateway-drift.ts 60% 61% +1%
src/lib/inferen...ollama/proxy.ts 33% 36% +3%

Updated August 13, 2026 03:47 UTC

@github-actions

github-actions Bot commented Aug 13, 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 · high 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.
7 terminology differences from the second opinion

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

  • static unit at scripts/install.sh:1502: primary classified it as justified; the second opinion classified it as define.
  • fail-closed at scripts/install.sh:1503: selected only by the second-opinion lane as established.
  • glob metacharacter at scripts/install.sh:1367: selected only by the second-opinion lane as established.
  • upstream unit at test/install-openshell-gateway-service.test.ts:250: selected only by the second-opinion lane as established.
  • systemd user manager at scripts/install.sh:1352: selected only by the second-opinion lane as established.
  • enablement link at scripts/install.sh:1353: selected only by the second-opinion lane as define.
  • packaged unit at scripts/install.sh:1499: selected only by the second-opinion lane as define.
3 additional E2E selections from the second opinion

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

  • bootstrap-install-smoke: The completed second-opinion lane identified E2E coverage that the primary lane omitted.
  • onboard-repair: The completed second-opinion lane identified E2E coverage that the primary lane omitted.
  • onboard-resume: The completed second-opinion lane identified E2E coverage that the primary lane omitted.

Second-opinion terminology and E2E selections are advisory. Live E2E does not run automatically for pull requests.

2 semantic terminology decisions

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

  • established — user manager at scripts/install.sh:1352: Use systemd user manager when the systemd scope must be explicit.
  • justified — static unit at scripts/install.sh:1502: Keep static unit where the contrast with an enabled unit determines the fallback decision.

E2E guidance

Advisory only. A maintainer can dispatch the default E2E suite for the commit under review.

Recommended E2E: None

Manual-only E2E: cloud-onboard, managed-image-multiarch-startup
The manual PR workflow does not run these selectors for the commit under review. Run them from reviewed code on main.

Workflow run details

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

@prekshivyas prekshivyas 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 based on code review. Required CI checks remain merge gates.

cv pushed a commit that referenced this pull request Aug 13, 2026
## Summary

When `systemctl --user` reports a known unavailable-manager error,
installation now keeps an existing standalone gateway. Installation
stops if activation or uncertain evidence could create a second gateway
on port 8080.

## Related Issue

Fixes #8926

Supersedes #8945 by Dongni Yang. This implementation was developed
independently and does not reuse or modify that contributor's commits.

## Changes

- Add a three-state user-service inspection: reachable, known
unavailable, or failed. A failed command cannot prove service identity.
- Permit standalone fallback only for known manager failures with no
activation path. A port check cannot prevent later systemd activation.
- Validate the effective unit path, executable path, and gateway version
when the user manager is reachable.
- Inspect both gateway service names across configuration, package,
runtime, control, transient, and generator activation roots.
- Reject custom unit search paths, inaccessible paths, dangling links,
ambiguous metadata, unknown errors, and version mismatches.
- Apply the same lifecycle rules to TypeScript onboarding. Require
explicit fallback permission before standalone startup.
- Add installer and CLI regression tests for fallback, refusal,
identity, version, and activation behavior.
- Document host gateway ownership, the fallback boundary, and the
required remediation.
- Preserve the original report attribution with `Reported-by: Hadi
Askari` in the commit.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [x] 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] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [x] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [x] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification: Independent security
review completed on the published branch revision. The focused follow-up
escaped the environment-controlled systemd override diagnostic and added
a log-line-injection regression test; all nine review categories now
pass with no open findings.
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue: No waiver requested.
Current `main` fails the test-size budget because
`test/managed-image-publication-workflow.test.ts` has 1,529 lines. This
PR does not change that file and must not merge until the gate passes.

## Documentation Writer Review

- [x] Documentation writer subagent reviewed the completed changes
- Result: `docs-updated`
- Evidence: Updated `docs/deployment/gateway-lifecycle-authority.mdx`,
`docs/reference/architecture.mdx`, and
`docs/reference/troubleshooting.mdx`. Reviewed the OpenClaw, Hermes, and
Deep Agents generated variants.
- Agent: Codex Desktop
<!-- docs-review-head-sha: b62d5a5 -->
<!-- docs-review-agents-blob-sha: c4923a3 -->

## 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 commit
appears as `Verified` in GitHub
- [x] 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
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — command/result or justification: The
focused gateway lifecycle suites passed 98 tests, including all 34
installer lifecycle tests. ShellCheck, shfmt, Biome, repository checks,
source-shape checks, the test-conditional guardrail, the full CLI build,
and `npm run typecheck:cli` passed.
- [ ] 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. The change
affects the installer and gateway lifecycle, which the targeted suites
cover.
- [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) — The
build passed with no errors and two existing Fern warnings.
- [x] 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: Apurv Kumaria <akumaria@nvidia.com>


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

- **Bug Fixes**
- Improved gateway installation checks for service identity, executable
paths, versions, and systemd metadata.
- Prevented unsafe standalone fallback when another gateway service may
claim port 8080.
- Installation now stops with clearer diagnostics for missing, invalid,
untrusted, or incompatible service information.
- Preserved standalone installation only when systemd is genuinely
unavailable and no conflicting activation is detected.
  - Revalidated service conditions before making lifecycle changes.

- **Documentation**
- Added guidance for systemd availability issues, service conflicts,
activation paths, inspection commands, and remediation steps.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

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

copy-pr-bot Bot commented Aug 13, 2026

Copy link
Copy Markdown

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

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@Dongni-Yang

Copy link
Copy Markdown
Contributor Author

Closing: #8949 merged and covers this fix's full scope, including the activation-link hardening (glob-metachar-safe probes, ~/.config fallback, XDG_DATA_HOME / XDG_CONFIG_DIRS roots). Nothing left here to land separately.

@Dongni-Yang
Dongni-Yang deleted the fix/8926-installer-static-user-unit branch August 13, 2026 06:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Installer mistakes a static OpenShell user unit for a reachable systemd user service

2 participants