Skip to content

fix(cleanup): backstop check namespaces; fence out-of-band installs#1773

Merged
lockwobr merged 2 commits into
mainfrom
fix/cleanup-safety
Jul 17, 2026
Merged

fix(cleanup): backstop check namespaces; fence out-of-band installs#1773
lockwobr merged 2 commits into
mainfrom
fix/cleanup-safety

Conversation

@lockwobr

Copy link
Copy Markdown
Contributor

Summary

Stops tools/cleanup from missing the gang-scheduling-test namespace and from destroying out-of-band / operator-owned installs during a live cluster reset.

Motivation / Context

Two gaps surfaced during a live cluster reset:

  1. The gang-scheduling conformance check creates a gang-scheduling-test namespace that survived a "complete" cleanup: the Go check retained it intentionally, and cleanup's namespace list did not include it.
  2. tools/cleanup had no way to protect a registry component that is deliberately installed and owned outside AICR (in our case nodewright/skyhook, installed out-of-band by the platform team, excluded from the AICR recipe). Stock cleanup destroyed such an install three ways: Helm uninstall in its namespace, CRD pattern match (the broad nvidia.com pattern also matches skyhook.nvidia.com), and namespace deletion. That is data loss for an install AICR does not own.

Fixes: #1672
Related: N/A

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update
  • Refactoring (no functional changes)
  • Build/CI/tooling

Component(s) Affected

  • Validator (pkg/validator)
  • Docs/examples (docs/, examples/)
  • Other: tools/cleanup, validators/conformance

Implementation Notes

Namespace leak (two-sided fix):

  • validators/conformance/gang_scheduling_check.go: cleanupGangTestResources now deletes the gang-scheduling-test namespace after pods and the PodGroup are gone. It is a single bounded background-propagation call under defaults.K8sCleanupTimeout, so cleanup stays bounded.
  • tools/cleanup: new AICR_CHECK_NAMESPACES=(gang-scheduling-test) list, merged into phase 4 as a backstop for interrupted runs.

Exclusions for out-of-band installs:

  • New repeatable, comma-separated --exclude-ns <ns> and --exclude-crd <match> flags.
    • --exclude-ns skips phase 1 (Helm uninstall) and phase 4 (namespace deletion + finalizer rescue).
    • --exclude-crd skips matching CRDs in phase 3, applied after pattern matching so the broad nvidia.com pattern cannot pull skyhook.nvidia.com CRDs back in.
  • Both flags are echoed in the preamble and honored under --dry-run for a pre-flight preview.
  • Warns on an asymmetric invocation (only one of the pair), since fencing just the namespace still lets phase 3 cascade-delete the install's CRs.

The prior workaround now reduces to:

tools/cleanup --exclude-ns skyhook --exclude-crd skyhook.nvidia.com

Testing

shellcheck -x tools/cleanup                                       # clean
golangci-lint run -c .golangci.yaml ./validators/conformance/...  # 0 issues
go test -race ./validators/conformance/ -count=1                  # PASS

Manual --dry-run verification: exclusions echoed and applied in phases 1/3/4; excluded namespace skipped while the gang-scheduling-test backstop is still deleted; asymmetric-flag warnings fire; missing/flag-shaped values are rejected; the no-flag path runs cleanly under set -u (macOS bash 3.2).

Not run locally: the full make qualify (e2e + Grype scan need cluster/network access unavailable in this environment). The only Go surface touched is validators/conformance, covered above with -race and lint; tools/cleanup is a bash script covered by shellcheck and dry-run exercises. A new unit test (gang_scheduling_check_test.go) covers the namespace teardown, raising coverage on the previously-untested cleanup path.

Risk Assessment

  • Low — Isolated change to a dev/reset tool plus one conformance-check cleanup path; additive flags with safe defaults; easy to revert.

Rollout notes: Backwards compatible. Default behavior is unchanged except that phase 4 now also deletes gang-scheduling-test (a check-created namespace) and the gang check tears down its own namespace. New flags are opt-in.

Checklist

  • Tests pass locally (make test with -race) — ran go test -race ./validators/conformance/; full make test not run (see Testing)
  • Linter passes (make lint) — ran golangci-lint on the affected package + shellcheck; full make lint not run (see Testing)
  • I did not skip/disable tests to make CI green
  • I added/updated tests for new functionality
  • I updated docs if user-facing behavior changed
  • Changes follow existing patterns in the codebase
  • Commits are cryptographically signed (git commit -S)

@lockwobr
lockwobr requested a review from a team as a code owner July 15, 2026 22:56
@lockwobr lockwobr added the theme/ci-dx CI pipelines, developer experience, and build tooling label Jul 15, 2026
@lockwobr lockwobr self-assigned this Jul 15, 2026
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

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

Walkthrough

tools/cleanup adds repeatable, comma-separated --exclude-ns and --exclude-crd options, applies exclusions to Helm, CRD, namespace, and finalizer cleanup phases, and includes validator-created namespaces in its scope. Documentation covers the new flags and dry-run usage. Gang scheduling conformance cleanup now deletes its test namespace, with tests verifying the cleanup behavior.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Suggested labels: area/tests, area/cli

Suggested reviewers: mchmarny

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed It clearly summarizes the cleanup namespace backstop and out-of-band install exclusions.
Description check ✅ Passed The description matches the code changes and explains the namespace cleanup and exclusion mechanism.
Linked Issues check ✅ Passed The PR addresses #1672 by deleting gang-scheduling-test and adding namespace/CRD exclusions to protect operator-owned installs.
Out of Scope Changes check ✅ Passed The docs, tests, and Makefile update support the stated cleanup changes and don't introduce unrelated functionality.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/cleanup-safety

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

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown
Contributor

Coverage Report ✅

Metric Value
Coverage 79.7%
Threshold 75%
Status Pass
Coverage Badge
![Coverage](https://img.shields.io/badge/coverage-79.7%25-green)

Coverage unchanged by this PR.

@lockwobr
lockwobr force-pushed the fix/cleanup-safety branch from fc47888 to b351f69 Compare July 16, 2026 16:22

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@tools/cleanup`:
- Around line 73-96: Add automated shell regression coverage for the cleanup
script’s exclusion handling, including repeatable comma-separated --exclude-ns
and --exclude-crd parsing. Exercise exclusions across Helm, CRD,
namespace/finalizer, and --dry-run paths, verifying excluded resources are
preserved and non-excluded resources are processed.

In `@validators/conformance/gang_scheduling_check.go`:
- Around line 441-446: Give the namespace deletion in the gang-scheduling
cleanup flow its own bounded timeout context instead of reusing the potentially
exhausted cleanupCtx. Create and cancel the dedicated context immediately around
the Namespaces().Delete call, while preserving the existing IgnoreNotFound
handling and deletion options.
🪄 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: ASSERTIVE

Plan: Enterprise

Run ID: 41fe1202-452d-4559-b26c-2b11b686d078

📥 Commits

Reviewing files that changed from the base of the PR and between fc47888 and b351f69.

📒 Files selected for processing (4)
  • DEVELOPMENT.md
  • tools/cleanup
  • validators/conformance/gang_scheduling_check.go
  • validators/conformance/gang_scheduling_check_test.go

Comment thread tools/cleanup
Comment thread validators/conformance/gang_scheduling_check.go Outdated
@lockwobr

Copy link
Copy Markdown
Contributor Author

Addressed both CodeRabbit findings in the latest push:

  • Namespace deletion timeout: the gang-scheduling namespace Delete now uses its own bounded deadline (K8sCleanupTimeout off a fresh context) rather than the shared cleanup context, so a pod stuck on a finalizer in the earlier waits cannot starve the teardown.
  • Exclusion regression coverage: added tools/cleanup_test.sh, a hermetic shell unit test (stubs kubectl/helm, drives --dry-run) covering parsing, per-phase exclusion, the backstop, asymmetric-flag warnings, and fail-closed arg handling. Wired into make test via a new test-shell target.

Also filed #1791 to capture a larger follow-up discussed on this PR: rewriting tools/cleanup as a standalone Go test-automation binary (not an aicr subcommand) that reuses pkg/recipe for recipe-scoped cleanup, with a crdGroups field added to the registry. That is out of scope here; this PR remains the focused fix for the data-loss bug.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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 `@tools/cleanup`:
- Around line 73-83: Update split_csv_append to trim leading and trailing
whitespace from each comma-separated token before appending it, and reject
tokens that are empty after trimming. Ensure comma-only and whitespace-only
values produce no exclusions and do not permit cleanup to proceed with
ineffective filters.

In `@tools/cleanup_test.sh`:
- Around line 99-100: Extend tools/cleanup_test.sh beyond the dry-run assertion
around phase3-excluded-crd-echoed by adding a hermetic --yes test with stateful
kubectl stubs. Exercise both is_excluded_crd and the finalizer-rescue skip
branches, then assert excluded resources receive neither delete nor patch calls
while preserving the existing dry-run check.
🪄 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: ASSERTIVE

Plan: Enterprise

Run ID: 495016bc-19c3-421e-8851-f12737a19840

📥 Commits

Reviewing files that changed from the base of the PR and between b351f69 and 2fbcfee.

📒 Files selected for processing (6)
  • DEVELOPMENT.md
  • Makefile
  • tools/cleanup
  • tools/cleanup_test.sh
  • validators/conformance/gang_scheduling_check.go
  • validators/conformance/gang_scheduling_check_test.go

Comment thread tools/cleanup
Comment thread tools/cleanup_test.sh
Comment thread validators/conformance/gang_scheduling_check.go Outdated
@lockwobr
lockwobr force-pushed the fix/cleanup-safety branch 2 times, most recently from 9e46d1e to 91460ab Compare July 16, 2026 18:23
@lockwobr
lockwobr enabled auto-merge (squash) July 16, 2026 18:23

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 `@Makefile`:
- Around line 219-229: Update the test-shell recipe to stay within checkmake’s
five-line maxbodylength limit by compacting the shell loop or extracting it into
a separate script/target. Preserve its behavior of discovering tools/*_test.sh
files, skipping missing matches, printing each test name, and executing each
with bash; keep the test target’s dependency on test-shell unchanged.
🪄 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: ASSERTIVE

Plan: Enterprise

Run ID: 1cc3c533-4161-48cf-ae3f-ddc6d76164ce

📥 Commits

Reviewing files that changed from the base of the PR and between 9e46d1e and 91460ab.

📒 Files selected for processing (6)
  • DEVELOPMENT.md
  • Makefile
  • tools/cleanup
  • tools/cleanup_test.sh
  • validators/conformance/gang_scheduling_check.go
  • validators/conformance/gang_scheduling_check_test.go

Comment thread Makefile
@lockwobr
lockwobr force-pushed the fix/cleanup-safety branch 3 times, most recently from 96535f9 to ffa4fd9 Compare July 16, 2026 20:28
@lockwobr
lockwobr requested a review from mchmarny July 16, 2026 20:28
tools/cleanup missed the gang-scheduling-test namespace and had no way to
protect out-of-band / operator-owned installs, both hit during a live
cluster reset.

Namespace leak (two-sided):
- The gang-scheduling conformance check now deletes its own
  gang-scheduling-test namespace once pods and the PodGroup are gone. The
  namespace delete uses its own bounded deadline rather than the shared
  cleanup context, so a pod stuck on a finalizer in the earlier waits
  cannot starve the teardown (the leak this fixes).
- tools/cleanup lists gang-scheduling-test in a new AICR_CHECK_NAMESPACES
  backstop, merged into phase 4 for interrupted runs.

Exclusions for out-of-band installs:
- New repeatable, comma-separated --exclude-ns and --exclude-crd flags.
  --exclude-ns skips phase 1 Helm uninstall and phase 4 namespace deletion
  + finalizer rescue; --exclude-crd skips matching CRDs in phase 3, applied
  after pattern matching so the broad nvidia.com pattern cannot pull
  skyhook.nvidia.com CRDs back in.
- Warn on an asymmetric invocation (only one of the pair), since fencing
  just the namespace still lets phase 3 cascade-delete the install's CRs.

Testing:
- tools/cleanup_test.sh: hermetic shell unit test (stubs kubectl/helm on
  PATH, drives --dry-run) covering CSV/repeat parsing, per-phase exclusion,
  the backstop, asymmetric-flag warnings, and fail-closed arg handling.
  Wired into 'make test' via a new test-shell target.
- Unit test covering the gang-scheduling namespace teardown.
- Documented the flags in DEVELOPMENT.md.

Fixes #1672

Signed-off-by: Brian Lockwood <lockwobr@gmail.com>
@lockwobr
lockwobr force-pushed the fix/cleanup-safety branch from ffa4fd9 to bea0fc6 Compare July 16, 2026 23:22

@njhensley njhensley left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Overall assessment — ✅ Approve with comments

Multi-persona review (shell-correctness, data-loss-safety, go-correctness), each finding independently confirmed or refuted by a senior meta-reviewer against the resolved code at head bea0fc6.

Adds --exclude-ns/--exclude-crd fencing to tools/cleanup, a hermetic shell-test harness wired into make test, a check-namespace backstop, and fixes the gang-scheduling check to actually delete its namespace and report the true outcome (uses pkg/errors + a fresh deadline for teardown per repo conventions). The eval in split_csv_append is injection-safe ("$__tok" defers to a variable ref), empty-array expansions are guarded under set -u, and arg parsing fails closed. Both persona findings describe real behavior but are correctly nitpick-grade.

✅ Confirmed non-issues (examined and cleared)

  • eval safetyeval "${__arr}+=(\"\$__tok\")" is injection-safe; $__tok is a deferred variable reference, not interpolated.
  • set -u + empty arraysEXCLUDE_CRD[@]:+ guard present; no unbound-variable abort on the no-exclusion path.
  • Fencing completeness — helm uninstall (Phase 1), CRD delete (Phase 3, applied post-pattern so nvidia.com can't pull skyhook.nvidia.com back), and namespace delete + finalizer rescue (Phase 4) are all gated by is_excluded_ns/is_excluded_crd.
  • Gang namespace delete — single bounded background-propagation call on a fresh K8sCleanupTimeout deadline; correct pkg/errors wrap; new test exercises delete + IsNotFound.

Summary

Tier Count
🔴 Blocker 0
🟠 Major 0
🟡 Minor 0
🔵 Nitpick 2

Recommendation: Approve with comments. Neither nitpick blocks merge.

Comment thread tools/cleanup
local __arr="$1" __val="$2" __tok
local __ifs="$IFS"
IFS=','
for __tok in $__val; do

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🔵 Nitpick — CSV split glob-expands tokens (no set -f)

for __tok in $__val with IFS=',' suppresses whitespace splitting but not pathname/glob expansion, and the script runs set -euo pipefail with no set -f. A token with glob metacharacters (--exclude-ns 'skyhook,*') expands against cwd, or unmatched stays literal * and silently protects nothing. Real but non-triggering in practice: Kubernetes namespace / CRD-group names never contain glob chars. The eval itself is injection-safe.

Blast radius: Exclusion parsing only; cannot trigger with valid k8s names — direction of error is over-exclusion (safe) or a no-op exclusion.

Fix: IFS=',' read -ra __toks <<<"$__val" (which does not glob) and iterate "${__toks[@]}", or wrap the loop in set -f/set +f.

Comment thread tools/cleanup
# namespace. Warn on an asymmetric invocation so a half-fenced install is not
# silently destroyed.
if (( ${#EXCLUDE_NS[@]} > 0 )) && (( ${#EXCLUDE_CRD[@]} == 0 )); then
log_warning "--exclude-ns given without --exclude-crd: Phase 3 will still delete the install's CRDs (and cascade its CRs). Add --exclude-crd for its API group(s)."

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

🔵 Nitpick — Asymmetric --exclude-ns/--exclude-crd warns but still destroys under --yes

cleanup -y --exclude-ns skyhook (no --exclude-crd) emits only log_warning and continues, so Phase 3 still deletes the skyhook CRDs (cascade-deleting its CRs); under -y there is no prompt, so the warning scrolls past in automation. This is intentional, documented behavior (the warning names exactly what will still be destroyed, and DEVELOPMENT.md states the flags are almost always needed as a pair) — hard-failing would break the legitimate additive-protection model. Flagged as a hardening option, not a defect.

Blast radius: Only when an operator supplies one of the paired flags in non-interactive mode.

Fix: Optionally fail closed on asymmetric invocation behind an explicit --allow-asymmetric-exclusion, or force a confirmation prompt (ignore -y) when exclusions are asymmetric.

@lockwobr
lockwobr merged commit e105808 into main Jul 17, 2026
37 checks passed
@lockwobr
lockwobr deleted the fix/cleanup-safety branch July 17, 2026 19:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docs size/L theme/ci-dx CI pipelines, developer experience, and build tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

tools/cleanup: misses check-created namespaces; deletes out-of-band installs

2 participants