Skip to content

feat(credential-rotation): add durable NVOS password rotation state#3591

Merged
jayzhudev merged 7 commits into
NVIDIA:mainfrom
jayzhudev:nvos/password-rotation-03
Jul 16, 2026
Merged

feat(credential-rotation): add durable NVOS password rotation state#3591
jayzhudev merged 7 commits into
NVIDIA:mainfrom
jayzhudev:nvos/password-rotation-03

Conversation

@jayzhudev

Copy link
Copy Markdown
Contributor

This continues the previous PR #3409, which added component-manager NVOS password rotation job contract. This PR adds restart-safe persistence for future controller orchestration. NVOS password rotation is not enabled yet.

Review areas:

  • Migration and credential key: the database stores metadata and job IDs; passwords remain in the credential backend.
  • SQLx tests: cover retries, quarantine, failures, stale workers, and reconciliation.
  • Unknown outcomes require reconciliation before retry.

Key decisions:

  • Job status is evidence, not credential truth.
  • Unknown outcomes are not unconditionally retried.
  • Only authoritative credential reconciliation can promote a version.
  • Existing runtime behavior remains unchanged.

Follow-up PRs will cover switch controller, target publication, activation, and admin-cli.

Related issues

Supports #2041 and #3522

Type of Change

  • Add - New feature or capability
  • Change - Changes in existing functionality
  • Fix - Bug fixes
  • Remove - Removed features or deprecated functionality
  • Internal - Internal changes (refactoring, tests, docs, etc.)

Breaking Changes

  • This PR contains breaking changes

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • No testing required

@jayzhudev jayzhudev self-assigned this Jul 16, 2026
@jayzhudev
jayzhudev requested a review from a team as a code owner July 16, 2026 01:27
@jayzhudev jayzhudev added the rack lifecycle Issues that relate to managing the lifecycle of a full rack (compute, switches and powershelves) label Jul 16, 2026
@jayzhudev jayzhudev changed the title feat(credential-rotation): add durable NVOS state feat(credential-rotation): add durable NVOS password rotation state Jul 16, 2026
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

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

Use the following commands to manage reviews:

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

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

NVOS credential rotation now persists staged per-device operations, backend job IDs, retry attempts, and outcomes. NVOS status requires an initialized site-wide target and uses live switches. ComponentManager exposes backend rotation operations, while controller execution remains disabled and fails closed.

Changes

NVOS credential rotation

Layer / File(s) Summary
Target publication and status semantics
crates/api-db/src/credential_rotation.rs, crates/api-db/src/credential_rotation/test_backfill.rs, crates/api-core/src/handlers/credential_rotation.rs
NVOS target initialization, aggregate and per-device status, backfill expectations, and handler messaging now reflect the absent-until-published target model.
Durable device rotation lifecycle
crates/api-db/migrations/..., crates/api-db/src/credential_rotation.rs, crates/api-db/src/migrations/mod.rs
A durable job identifier and guarded per-device lifecycle APIs support staging, submission, retries, rejection, completion, restart recovery, and migration validation.
Backend job and credential-key wiring
crates/component-manager/src/component_manager.rs, crates/secrets/src/credentials.rs
ComponentManager delegates rotation start/status operations to the NV switch backend, and versioned NVOS site-admin credential construction is centralized.
Controller fail-closed behavior
crates/switch-controller/src/configuring.rs, crates/api-db/src/credential_rotation.rs
NVOS password updating remains disabled; enabling the guarded path produces an explicit controller error without recording convergence.

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

Sequence Diagram(s)

sequenceDiagram
  participant SwitchController
  participant CredentialRotationDB
  participant ComponentManager
  participant NVSwitchBackend
  SwitchController->>CredentialRotationDB: stage rotation attempt
  SwitchController->>ComponentManager: start switch password rotation
  ComponentManager->>NVSwitchBackend: submit rotation request
  NVSwitchBackend-->>ComponentManager: return job ID
  ComponentManager-->>SwitchController: return job ID
  SwitchController->>CredentialRotationDB: persist submitted job
  SwitchController->>ComponentManager: fetch job status
  ComponentManager->>NVSwitchBackend: query rotation job
  NVSwitchBackend-->>ComponentManager: return job state
  SwitchController->>CredentialRotationDB: reconcile device operation
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: durable NVOS password rotation state.
Description check ✅ Passed The description matches the PR scope, covering restart-safe persistence, tests, and the fact that NVOS rotation remains disabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@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

Caution

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

⚠️ Outside diff range comments (1)
crates/api-db/src/credential_rotation/test_backfill.rs (1)

235-251: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the v0 assertion reject NULL versions.

current_version <> 0 excludes NULL rows, so the test can pass even when a backfilled device has no confirmed version.

Proposed fix
-        "SELECT count(*) FROM device_credential_rotation WHERE current_version <> 0",
+        "SELECT count(*) FROM device_credential_rotation \
+         WHERE current_version IS DISTINCT FROM 0",
🤖 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 `@crates/api-db/src/credential_rotation/test_backfill.rs` around lines 235 -
251, Update the non_v0 assertion in the backfill test to count NULL
current_version values as invalid alongside nonzero versions. Ensure the query
rejects any backfilled device whose current_version is not confirmed as 0, while
preserving the existing assertion and message.
🧹 Nitpick comments (1)
crates/api-db/src/credential_rotation.rs (1)

1079-1130: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Cover every conditional-baseline outcome with table-driven tests.

The test exercises TargetChanged and Recorded, but leaves AlreadyPresent, TargetMissing, and negative-version rejection unverified. These are public initialization and idempotency contracts.

As per coding guidelines, functions mapping inputs to outcomes or errors should use table-driven tests.

🤖 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 `@crates/api-db/src/credential_rotation.rs` around lines 1079 - 1130, The test
coverage around record_device_converged_if_target_matches is incomplete and not
table-driven. Expand or add a table-driven test suite covering Recorded,
AlreadyPresent, TargetChanged, TargetMissing, and rejection of negative
authenticated versions, asserting each expected outcome or error while
preserving the existing race scenario coverage.

Source: Coding guidelines

🤖 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 `@crates/api-core/src/handlers/credential_rotation.rs`:
- Around line 32-34: Update the NVOS rejection response in the relevant handler
to state that the end-to-end NVOS rotation path remains disabled, replacing the
outdated NICo ownership and REQ-6 explanation. Keep the surrounding rejection
behavior unchanged and align it with the module documentation.

---

Outside diff comments:
In `@crates/api-db/src/credential_rotation/test_backfill.rs`:
- Around line 235-251: Update the non_v0 assertion in the backfill test to count
NULL current_version values as invalid alongside nonzero versions. Ensure the
query rejects any backfilled device whose current_version is not confirmed as 0,
while preserving the existing assertion and message.

---

Nitpick comments:
In `@crates/api-db/src/credential_rotation.rs`:
- Around line 1079-1130: The test coverage around
record_device_converged_if_target_matches is incomplete and not table-driven.
Expand or add a table-driven test suite covering Recorded, AlreadyPresent,
TargetChanged, TargetMissing, and rejection of negative authenticated versions,
asserting each expected outcome or error while preserving the existing race
scenario coverage.
🪄 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: 67beced7-d749-4526-ad46-f3a423b10759

📥 Commits

Reviewing files that changed from the base of the PR and between deb41ac and 69dbbed.

📒 Files selected for processing (7)
  • crates/api-core/src/handlers/credential_rotation.rs
  • crates/api-db/migrations/20260715120000_nvos_credential_rotation_state.sql
  • crates/api-db/src/credential_rotation.rs
  • crates/api-db/src/credential_rotation/test_backfill.rs
  • crates/component-manager/src/component_manager.rs
  • crates/secrets/src/credentials.rs
  • crates/switch-controller/src/configuring.rs

Comment thread crates/api-core/src/handlers/credential_rotation.rs
@github-actions

github-actions Bot commented Jul 16, 2026

Copy link
Copy Markdown

🔍 Container Scan Summary

Service Total Critical High Medium Low Other
boot-artifacts-aarch64 3 0 0 3 0 0
boot-artifacts-x86_64 3 0 0 3 0 0
forge-admin-cli-x86_64 259 16 29 79 7 128
machine-validation-runner 532 39 113 184 15 181
machine_validation 532 39 113 184 15 181
machine_validation-aarch64 532 39 113 184 15 181
nvmetal-carbide 532 39 113 184 15 181
TOTAL 2393 172 481 821 67 852

Per-CVE detail lives in the per-service grype-* artifacts (JSON + SARIF). Severity counts only — no CVE IDs published here.

Comment thread crates/api-db/src/credential_rotation.rs

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

overall lgtm

Comment thread crates/api-db/src/credential_rotation.rs
/// Matching the staged target and attempt number prevents stale reconciliation
/// from releasing a newer operation. Returns `false` when that exact operation
/// is no longer active.
pub async fn record_device_rotation_reconciled_to_previous(

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.

record_device_rotation_failed may be a better name

Comment thread crates/api-db/src/credential_rotation.rs Outdated
Comment thread crates/api-db/src/credential_rotation.rs
Signed-off-by: Jay Zhu <jayzhu@nvidia.com>
Signed-off-by: Jay Zhu <jayzhu@nvidia.com>
Signed-off-by: Jay Zhu <jayzhu@nvidia.com>
@jayzhudev
jayzhudev force-pushed the nvos/password-rotation-03 branch from 198bcd1 to a370346 Compare July 16, 2026 18:49
@github-actions

Copy link
Copy Markdown

Signed-off-by: Jay Zhu <jayzhu@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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
crates/api-db/src/credential_rotation.rs (1)

824-848: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Accept a DbReader here.
This is a single-query read-only helper, so it should follow the existing impl DbReader<'_> pattern and stay callable from pooled readers, transactions, and connections.

🤖 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 `@crates/api-db/src/credential_rotation.rs` around lines 824 - 848, Update
device_rotation_operation_state to use the existing DbReader<'_> abstraction
instead of requiring &mut PgConnection, following the established impl DbReader
pattern. Preserve the query, bindings, result type, and error mapping, while
ensuring the helper remains callable with pooled readers, transactions, and
direct connections.

Source: Coding guidelines

🤖 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 `@crates/api-db/src/credential_rotation.rs`:
- Around line 894-927: Update nvos_device_rotation_status to distinguish a live
switch with no published site-wide NVOS target from an unknown device: preserve
the device row via the query’s join structure, return a status/result that lets
the handler produce MissingSitewideRotationTarget when no target exists, and
retain None/NotFound behavior for unknown devices. Ensure this also covers
requests made before publish_nvos_target.

---

Nitpick comments:
In `@crates/api-db/src/credential_rotation.rs`:
- Around line 824-848: Update device_rotation_operation_state to use the
existing DbReader<'_> abstraction instead of requiring &mut PgConnection,
following the established impl DbReader pattern. Preserve the query, bindings,
result type, and error mapping, while ensuring the helper remains callable with
pooled readers, transactions, and direct connections.
🪄 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: 57a8b665-e845-46ea-b3ca-5805e667314b

📥 Commits

Reviewing files that changed from the base of the PR and between 198bcd1 and 46e089d.

📒 Files selected for processing (8)
  • crates/api-core/src/handlers/credential_rotation.rs
  • crates/api-db/migrations/20260715120000_nvos_credential_rotation_state.sql
  • crates/api-db/src/credential_rotation.rs
  • crates/api-db/src/credential_rotation/test_backfill.rs
  • crates/api-db/src/migrations/mod.rs
  • crates/component-manager/src/component_manager.rs
  • crates/secrets/src/credentials.rs
  • crates/switch-controller/src/configuring.rs
🚧 Files skipped from review as they are similar to previous changes (6)
  • crates/api-db/migrations/20260715120000_nvos_credential_rotation_state.sql
  • crates/api-db/src/credential_rotation/test_backfill.rs
  • crates/component-manager/src/component_manager.rs
  • crates/api-core/src/handlers/credential_rotation.rs
  • crates/api-db/src/migrations/mod.rs
  • crates/secrets/src/credentials.rs

Comment thread crates/api-db/src/credential_rotation.rs
@jayzhudev
jayzhudev force-pushed the nvos/password-rotation-03 branch from aa9cbb1 to e49ec8d Compare July 16, 2026 19:42
Signed-off-by: Jay Zhu <jayzhu@nvidia.com>
@jayzhudev
jayzhudev force-pushed the nvos/password-rotation-03 branch from e49ec8d to 51d4a3c Compare July 16, 2026 19:45
@jayzhudev
jayzhudev merged commit 766b93b into NVIDIA:main Jul 16, 2026
59 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rack lifecycle Issues that relate to managing the lifecycle of a full rack (compute, switches and powershelves)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants