Skip to content

chore: Cherry pick#244

Merged
lockwobr merged 5 commits into
mainfrom
cherrypick
May 22, 2026
Merged

chore: Cherry pick#244
lockwobr merged 5 commits into
mainfrom
cherrypick

Conversation

@lockwobr

Copy link
Copy Markdown
Collaborator

Description

git cherry-pick 2dfec98 6d6f126 bdfa3e6

lockwobr and others added 4 commits May 19, 2026 13:07
* ci: publish keyless release attestations



* ci: drop nvcr release attestations



* ci: narrow release attestation identity



* ci: gate attestations to release tags



* docs: show immutable release subjects



* ci: attest helm chart releases



---------

Signed-off-by: AnouarMohamed <[email protected]>
Co-authored-by: Anouar Mohamed <[email protected]>
…fter-uninstall (#241)

The test left [email protected] freshly installed at chainsaw's automatic
CLEANUP, where the new delete-time uninstall finalizer (from #200) must
run uninstall pods on every node before releasing the CR. That exceeds
chainsaw's default cleanup window, causing "context deadline exceeded".

Add a final uninstall-v1 step that flips uninstall.apply=true on the
downgraded version and waits for nodeState to empty, so the CR has no
installed packages when cleanup deletes it.

Signed-off-by: Alex Yuskauskas <[email protected]>
@lockwobr lockwobr self-assigned this May 22, 2026
@lockwobr lockwobr changed the title Cherrypick chore: Cherry pick May 22, 2026
* fix(test): harden core e2e pool against finalizer-cleanup races and improve diagnosability

Two changes across the six core-pool chainsaw tests:

1. Add `timeouts.cleanup: 120s` to every core-pool test. Chainsaw's
   default cleanup window (~30s) is too tight for the project's CR
   finalizer, which must uncordon nodes, remove labels/annotations,
   and GC package pods before releasing. Same failure mode that hit
   downgrade-after-uninstall (PR #241).

2. Add `catch:` blocks to `depends-on` and `simple-skyhook`, mirroring
   the pattern used by the other four core tests. When these tests
   flake, CI now captures the Node, Skyhook CR, and package Pods for
   diagnosis instead of failing without artifacts.

No assert logic changes — this is a foundation pass to remove a known
flake class and make future flakes diagnosable.

Signed-off-by: Alex Yuskauskas <[email protected]>

* fix(operator): close StageInterrupt trap when configUpdates signal decays

A package whose only interrupt is a `configInterrupts` entry (no top-level
`interrupt` block) could get stuck at `StageInterrupt/StateSkipped`
permanently when `Status.ConfigUpdates` cleared or never persisted (e.g.
due to a 409 on the spec patch). The state machine queried the dynamic
`HasInterrupt(config)` signal at four points, and once that signal
decayed to false, the package was untouchable: `ProgressSkipped`
wouldn't promote it, `NextStage` wouldn't advance it past Interrupt,
and `GetComplete`/`IsPackageComplete` wouldn't count it complete.

Decouple progression-past-Interrupt from the dynamic signal:

- `NextStage`: add `StageInterrupt → StagePostInterrupt` to the
  no-interrupt default map. The with-interrupt full-replacement map is
  preserved as-is — PR #200 deliberately omits `StageUninstall →
  StageApply` from it so with-interrupt uninstalls route via
  `StageUninstallInterrupt`; collapsing the maps would silently
  re-enable that transition.
- `ProgressSkipped`: drop the `HasInterrupt` gate. The only writer of
  `StateSkipped` at `StageInterrupt` is `ProcessInterrupt`'s
  budget-contention branch, which already decided the package needed
  an interrupt to schedule. Stage alone is sufficient.
- `GetComplete`, `IsPackageComplete`: treat `StagePostInterrupt` as
  unconditionally terminal. The only way to reach it is via the
  interrupt cycle; gating the terminal check on a signal that can
  decay is redundant with the entry gate and only becomes load-bearing
  when the trap fires.

Reproducer in `skyhook_types_test.go` exercises all three sites.

Surfaced by the `chainsaw/config-skyhook` "update while running" step,
which patches the spec mid-flight and concurrently triggers the
`HandleMigrations` and `processSkyhooksPerNode` 409 conflict paths —
those stretch convergence enough that ConfigUpdates can be lost
between the package reaching StageInterrupt and ProgressSkipped firing.

Signed-off-by: Alex Yuskauskas <[email protected]>

* refactor(operator): GetComplete delegates to IsPackageComplete

GetComplete and IsPackageComplete encoded the same terminal-state logic
twice. Have GetComplete iterate the spec packages and call
IsPackageComplete for each, and move the explanatory comment to
IsPackageComplete where the predicate lives.

Behavior preserved: the prior implementation iterated node state and
filtered to spec packages by name+version match; the new one iterates
spec packages and looks them up in node state by unique name (name|version).
Same set of packages either way.

Signed-off-by: Alex Yuskauskas <[email protected]>

---------

Signed-off-by: Alex Yuskauskas <[email protected]>
@coderabbitai

coderabbitai Bot commented May 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds composite GitHub Actions for cosign signing/verification and OCI digest resolution; rewires agent/operator/release workflows to sign, attest, and verify images/charts. Renames Helm chart to nodewright, updates docs and Chainsaw tests. Modifies operator package state progression and introduces a separate webhook bootstrap manager/lease with concurrent startup. Updates Makefile/deps. Vendors significant golang.org/x/* updates (http2 RFC 9218, idna Unicode-16, sys/unix APIs, tools inspector/packages, text normalization).

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

  • NVIDIA/nodewright#242: Similar changes in skyhook_types logic and tests around StageInterrupt completion behavior.
  • NVIDIA/nodewright#241: Shares the downgrade-after-uninstall Chainsaw test additions and cleanup behavior.
  • NVIDIA/nodewright#243: Implements the dedicated webhook bootstrap lease and related docs/code paths.

Suggested reviewers

  • mskalka
  • rice-riley
  • ayuskauskas
✨ 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 cherrypick

@coveralls

coveralls commented May 22, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 26308524881

Coverage decreased (-0.03%) to 81.725%

Details

  • Coverage decreased (-0.03%) from the base build.
  • Patch coverage: 26 uncovered changes across 1 file (24 of 50 lines covered, 48.0%).
  • 120 coverage regressions across 4 files.

Uncovered Changes

File Changed Covered %
operator/cmd/manager/main.go 37 11 29.73%

Coverage Regressions

120 previously-covered lines in 4 files lost coverage.

File Lines Losing Coverage Coverage
operator/internal/controller/webhook_controller.go 74 54.62%
operator/cmd/manager/main.go 28 49.49%
operator/api/v1alpha1/skyhook_types.go 12 89.69%
operator/internal/controller/skyhook_controller.go 6 83.16%

Coverage Stats

Coverage Status
Relevant Lines: 9461
Covered Lines: 7732
Line Coverage: 81.72%
Coverage Strength: 9.59 hits per line

💛 - Coveralls

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

🤖 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 @.github/actions/cosign-verify-release/action.yml:
- Around line 51-57: The certificate identity regexp check must be guarded
against an empty value because bash [[ string =~ $regex ]] treats an empty
pattern as a match-all; update the verification logic that uses
CERTIFICATE_IDENTITY_REGEXP (the env var used for identity verification) to
first ensure CERTIFICATE_IDENTITY_REGEXP is non-empty (e.g., fail with an error
like "certificate-identity-regexp is required" or skip verification explicitly)
before performing the [[ "${SOME_SUBJECT_FIELD}" =~
${CERTIFICATE_IDENTITY_REGEXP} ]] test; reference the existing SUBJECT_NAME and
SUBJECT_DIGEST validation style (the surrounding checks) to implement the new
non-empty guard and error path for CERTIFICATE_IDENTITY_REGEXP.

In @.github/workflows/agent-ci.yaml:
- Around line 229-230: The checkout step ("Checkout repository" using
actions/checkout@v6) currently leaves Git credentials persisted; update that
step to include persist-credentials: false so the action does not expose
credentials to later steps (i.e., add the persist-credentials: false key under
the checkout step configuration).

In @.github/workflows/lint-ci.yaml:
- Line 104: Replace the mutable tag "actions/cache@v4" with the corresponding
full commit SHA for the actions/cache repository (e.g.,
"actions/cache@<full-commit-sha>") so the workflow uses an immutable pinned ref;
locate the "uses: actions/cache@v4" entry in the lint-ci.yaml and update it to
the exact commit SHA for the v4 release you want to track.

In @.github/workflows/operator-ci.yaml:
- Line 364: Replace mutable action tags with immutable commit SHAs for the
third-party actions used in the create-manifest job: change actions/checkout@v6,
docker/login-action@v4, and docker/setup-buildx-action@v4 to the corresponding
full commit SHA pins (e.g., actions/checkout@<commit-sha>,
docker/login-action@<commit-sha>, docker/setup-buildx-action@<commit-sha>) to
prevent supply-chain drift; additionally, for actions/checkout (the
actions/checkout entry) add with: persist-credentials: false if the job does not
require authenticated git operations so credentials are not left in the
workspace.
- Around line 363-364: Update the "Checkout repository" GitHub Actions step that
uses actions/checkout@v6 to disable credential persistence by adding
persist-credentials: false to the step configuration; specifically modify the
step with name "Checkout repository" (uses: actions/checkout@v6) so it includes
persist-credentials: false to avoid leaving the checkout token available for
later steps.

In `@chart/Chart.yaml`:
- Around line 2-11: Replace all hardcoded "skyhook-operator" identifiers in the
kustomize manifests with "nodewright": update kustomization fields namespace:
skyhook-operator-system → namespace: nodewright-system and namePrefix:
skyhook-operator- → namePrefix: nodewright-; change label values for keys
app.kubernetes.io/created-by and part-of from "skyhook-operator" to
"nodewright"; search manager/rbac/webhook/prometheus manifests and sample YAMLs
under operator/config/ for any remaining "skyhook-operator" strings (including
annotations or selector values) and replace them with the corresponding
"nodewright" names so the Helm chart name: nodewright and appVersion/app labels
are consistent across both deployment paths.

In `@chart/templates/_helpers.tpl`:
- Around line 9-24: chart.fullname now omits the conventional release-name
prefix which will change resource names on upgrade; restore backward
compatibility or provide migration guidance: update the template for define
"chart.fullname" to conditionally include .Release.Name (e.g. when a new boolean
value like .Values.preserveReleaseName is true or when detecting an existing
release) while still honoring fullnameOverride and nameOverride, and add
explicit upgrade steps to README.md and CHANGELOG.md (or implement a Helm
pre-upgrade hook) to rename/migrate previously created resources so existing
Deployments/ServiceAccount/PDB/RBAC/cleanup jobs are not orphaned.

In `@docs/release-process.md`:
- Around line 362-363: Replace the stale Helm chart OCI name used in the
examples: update the CHART variable value from
"ghcr.io/nvidia/nodewright/charts/skyhook-operator" to
"ghcr.io/nvidia/nodewright/charts/nodewright" wherever it appears (e.g., the
CHART= lines shown and the other occurrence noted), so verification commands and
tables reference the correct charts/nodewright OCI path.

In `@operator/api/v1alpha1/deployment_policy_webhook_test.go`:
- Around line 339-341: Extract the duplicated timing literals ("10s" and
"100ms") used in the Eventually blocks of deployment_policy_webhook_test.go into
file-level constants (e.g., const defaultEventuallyTimeout = "10s" and const
defaultEventuallyInterval = "100ms") and replace the inline literals in both
Eventually(...) calls (the one using errors.IsNotFound(k8sClient.Get(...), and
the other at lines ~387-389) with these constants so the timeouts are
centralized and not duplicated.

In `@operator/Makefile`:
- Line 56: The Makefile currently sets DOCKER_CMD ?= docker which forces Docker
as the default runtime; change the default to podman by setting DOCKER_CMD ?=
podman so local developer flows use podman while CI can still set
DOCKER_CMD=docker to override; update the DOCKER_CMD default (symbol DOCKER_CMD)
accordingly and ensure no other references need changing so overrides continue
to work.
🪄 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: 64936d53-18a0-4005-8b5a-13dc59d83a96

📥 Commits

Reviewing files that changed from the base of the PR and between bdfa3e6 and 226f475.

⛔ Files ignored due to path filters (1)
  • operator/go.sum is excluded by !**/*.sum
📒 Files selected for processing (205)
  • .claude/CLAUDE.md
  • .github/actions/cosign-sign-sbom/action.yml
  • .github/actions/cosign-verify-release/action.yml
  • .github/actions/resolve-oci-digest/action.yml
  • .github/workflows/agent-ci.yaml
  • .github/workflows/lint-ci.yaml
  • .github/workflows/operator-ci.yaml
  • .github/workflows/release.yml
  • README.md
  • chart/Chart.yaml
  • chart/README.md
  • chart/templates/_helpers.tpl
  • chart/values.yaml
  • docs/README.md
  • docs/designs/webhook-bootstrap-lease.md
  • docs/release-process.md
  • k8s-tests/chainsaw/helm/helm-chart-test/assert-no-schedule.yaml
  • k8s-tests/chainsaw/helm/helm-chart-test/assert-scheduled.yaml
  • k8s-tests/chainsaw/helm/helm-node-affinity-test/assert-no-schedule.yaml
  • k8s-tests/chainsaw/helm/helm-node-affinity-test/assert-scheduled.yaml
  • k8s-tests/chainsaw/helm/helm-scale-test/assert-override-resources.yaml
  • k8s-tests/chainsaw/helm/helm-scale-test/assert-scaled-resources.yaml
  • k8s-tests/chainsaw/helm/helm-webhook-test/assert-scheduled.yaml
  • k8s-tests/chainsaw/skyhook/config-skyhook/chainsaw-test.yaml
  • k8s-tests/chainsaw/skyhook/depends-on/chainsaw-test.yaml
  • k8s-tests/chainsaw/skyhook/downgrade-after-uninstall/README.md
  • k8s-tests/chainsaw/skyhook/downgrade-after-uninstall/chainsaw-test.yaml
  • k8s-tests/chainsaw/skyhook/downgrade-after-uninstall/update-trigger-uninstall-v1.yaml
  • k8s-tests/chainsaw/skyhook/simple-skyhook/chainsaw-test.yaml
  • k8s-tests/chainsaw/skyhook/simple-update-skyhook/chainsaw-test.yaml
  • k8s-tests/chainsaw/skyhook/strict-order/chainsaw-test.yaml
  • k8s-tests/chainsaw/skyhook/validate-packages/chainsaw-test.yaml
  • operator/Makefile
  • operator/api/v1alpha1/deployment_policy_webhook_test.go
  • operator/api/v1alpha1/skyhook_types.go
  • operator/api/v1alpha1/skyhook_types_test.go
  • operator/cmd/manager/main.go
  • operator/deps.mk
  • operator/go.mod
  • operator/internal/controller/webhook_controller.go
  • operator/vendor/golang.org/x/net/html/iter.go
  • operator/vendor/golang.org/x/net/html/node.go
  • operator/vendor/golang.org/x/net/html/nodetype_string.go
  • operator/vendor/golang.org/x/net/html/parse.go
  • operator/vendor/golang.org/x/net/html/render.go
  • operator/vendor/golang.org/x/net/html/token.go
  • operator/vendor/golang.org/x/net/http2/README.md
  • operator/vendor/golang.org/x/net/http2/client_conn_pool.go
  • operator/vendor/golang.org/x/net/http2/client_priority_go126.go
  • operator/vendor/golang.org/x/net/http2/client_priority_go127.go
  • operator/vendor/golang.org/x/net/http2/clientconn.go
  • operator/vendor/golang.org/x/net/http2/config.go
  • operator/vendor/golang.org/x/net/http2/frame.go
  • operator/vendor/golang.org/x/net/http2/http2.go
  • operator/vendor/golang.org/x/net/http2/server.go
  • operator/vendor/golang.org/x/net/http2/server_common.go
  • operator/vendor/golang.org/x/net/http2/server_wrap.go
  • operator/vendor/golang.org/x/net/http2/transport.go
  • operator/vendor/golang.org/x/net/http2/transport_common.go
  • operator/vendor/golang.org/x/net/http2/transport_wrap.go
  • operator/vendor/golang.org/x/net/http2/writesched.go
  • operator/vendor/golang.org/x/net/http2/writesched_common.go
  • operator/vendor/golang.org/x/net/http2/writesched_priority_rfc7540.go
  • operator/vendor/golang.org/x/net/http2/writesched_priority_rfc9218.go
  • operator/vendor/golang.org/x/net/http2/writesched_random.go
  • operator/vendor/golang.org/x/net/http2/writesched_roundrobin.go
  • operator/vendor/golang.org/x/net/idna/go118.go
  • operator/vendor/golang.org/x/net/idna/idna.go
  • operator/vendor/golang.org/x/net/idna/idna9.0.0.go
  • operator/vendor/golang.org/x/net/idna/pre_go118.go
  • operator/vendor/golang.org/x/net/idna/punycode.go
  • operator/vendor/golang.org/x/net/idna/tables10.0.0.go
  • operator/vendor/golang.org/x/net/idna/tables11.0.0.go
  • operator/vendor/golang.org/x/net/idna/tables12.0.0.go
  • operator/vendor/golang.org/x/net/idna/tables13.0.0.go
  • operator/vendor/golang.org/x/net/idna/tables15.0.0.go
  • operator/vendor/golang.org/x/net/idna/tables17.0.0.go
  • operator/vendor/golang.org/x/net/idna/tables9.0.0.go
  • operator/vendor/golang.org/x/net/idna/trie12.0.0.go
  • operator/vendor/golang.org/x/net/idna/trie13.0.0.go
  • operator/vendor/golang.org/x/net/internal/httpcommon/request.go
  • operator/vendor/golang.org/x/net/internal/httpsfv/httpsfv.go
  • operator/vendor/golang.org/x/sys/plan9/syscall_plan9.go
  • operator/vendor/golang.org/x/sys/unix/affinity_linux.go
  • operator/vendor/golang.org/x/sys/unix/ioctl_signed.go
  • operator/vendor/golang.org/x/sys/unix/ioctl_unsigned.go
  • operator/vendor/golang.org/x/sys/unix/mkall.sh
  • operator/vendor/golang.org/x/sys/unix/mkerrors.sh
  • operator/vendor/golang.org/x/sys/unix/readv_unix.go
  • operator/vendor/golang.org/x/sys/unix/syscall_darwin.go
  • operator/vendor/golang.org/x/sys/unix/syscall_linux.go
  • operator/vendor/golang.org/x/sys/unix/syscall_linux_arm.go
  • operator/vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
  • operator/vendor/golang.org/x/sys/unix/syscall_linux_loong64.go
  • operator/vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
  • operator/vendor/golang.org/x/sys/unix/syscall_openbsd.go
  • operator/vendor/golang.org/x/sys/unix/syscall_solaris.go
  • operator/vendor/golang.org/x/sys/unix/syscall_unix.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux_386.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux_amd64.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux_arm.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux_arm64.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux_loong64.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux_mips.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux_mips64.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux_mips64le.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux_mipsle.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux_ppc.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux_ppc64le.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux_riscv64.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux_s390x.go
  • operator/vendor/golang.org/x/sys/unix/zerrors_linux_sparc64.go
  • operator/vendor/golang.org/x/sys/unix/zsyscall_linux.go
  • operator/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.go
  • operator/vendor/golang.org/x/sys/unix/zsyscall_openbsd_386.s
  • operator/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.go
  • operator/vendor/golang.org/x/sys/unix/zsyscall_openbsd_amd64.s
  • operator/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.go
  • operator/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm.s
  • operator/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.go
  • operator/vendor/golang.org/x/sys/unix/zsyscall_openbsd_arm64.s
  • operator/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.go
  • operator/vendor/golang.org/x/sys/unix/zsyscall_openbsd_mips64.s
  • operator/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.go
  • operator/vendor/golang.org/x/sys/unix/zsyscall_openbsd_ppc64.s
  • operator/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.go
  • operator/vendor/golang.org/x/sys/unix/zsyscall_openbsd_riscv64.s
  • operator/vendor/golang.org/x/sys/unix/zsysnum_linux_386.go
  • operator/vendor/golang.org/x/sys/unix/zsysnum_linux_amd64.go
  • operator/vendor/golang.org/x/sys/unix/zsysnum_linux_arm.go
  • operator/vendor/golang.org/x/sys/unix/zsysnum_linux_arm64.go
  • operator/vendor/golang.org/x/sys/unix/zsysnum_linux_loong64.go
  • operator/vendor/golang.org/x/sys/unix/zsysnum_linux_mips.go
  • operator/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64.go
  • operator/vendor/golang.org/x/sys/unix/zsysnum_linux_mips64le.go
  • operator/vendor/golang.org/x/sys/unix/zsysnum_linux_mipsle.go
  • operator/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc.go
  • operator/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64.go
  • operator/vendor/golang.org/x/sys/unix/zsysnum_linux_ppc64le.go
  • operator/vendor/golang.org/x/sys/unix/zsysnum_linux_riscv64.go
  • operator/vendor/golang.org/x/sys/unix/zsysnum_linux_s390x.go
  • operator/vendor/golang.org/x/sys/unix/zsysnum_linux_sparc64.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux_386.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux_arm.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux_loong64.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux_mips.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux_mips64.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux_mips64le.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux_mipsle.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux_ppc.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux_ppc64le.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux_riscv64.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go
  • operator/vendor/golang.org/x/sys/unix/ztypes_linux_sparc64.go
  • operator/vendor/golang.org/x/sys/windows/aliases.go
  • operator/vendor/golang.org/x/sys/windows/dll_windows.go
  • operator/vendor/golang.org/x/sys/windows/security_windows.go
  • operator/vendor/golang.org/x/sys/windows/syscall_windows.go
  • operator/vendor/golang.org/x/sys/windows/types_windows.go
  • operator/vendor/golang.org/x/sys/windows/zsyscall_windows.go
  • operator/vendor/golang.org/x/text/secure/bidirule/bidirule.go
  • operator/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go
  • operator/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go
  • operator/vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go
  • operator/vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go
  • operator/vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go
  • operator/vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go
  • operator/vendor/golang.org/x/text/unicode/bidi/tables15.0.0.go
  • operator/vendor/golang.org/x/text/unicode/bidi/tables17.0.0.go
  • operator/vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go
  • operator/vendor/golang.org/x/text/unicode/norm/forminfo.go
  • operator/vendor/golang.org/x/text/unicode/norm/tables10.0.0.go
  • operator/vendor/golang.org/x/text/unicode/norm/tables11.0.0.go
  • operator/vendor/golang.org/x/text/unicode/norm/tables12.0.0.go
  • operator/vendor/golang.org/x/text/unicode/norm/tables15.0.0.go
  • operator/vendor/golang.org/x/text/unicode/norm/tables17.0.0.go
  • operator/vendor/golang.org/x/text/unicode/norm/tables9.0.0.go
  • operator/vendor/golang.org/x/tools/go/ast/inspector/cursor.go
  • operator/vendor/golang.org/x/tools/go/ast/inspector/inspector.go
  • operator/vendor/golang.org/x/tools/go/ast/inspector/iter.go
  • operator/vendor/golang.org/x/tools/go/packages/golist.go
  • operator/vendor/golang.org/x/tools/go/packages/packages.go
  • operator/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
  • operator/vendor/golang.org/x/tools/internal/aliases/aliases.go
  • operator/vendor/golang.org/x/tools/internal/aliases/aliases_go122.go
  • operator/vendor/golang.org/x/tools/internal/event/core/event.go
  • operator/vendor/golang.org/x/tools/internal/event/keys/keys.go
  • operator/vendor/golang.org/x/tools/internal/event/label/label.go
  • operator/vendor/golang.org/x/tools/internal/gcimporter/iexport.go
  • operator/vendor/golang.org/x/tools/internal/gcimporter/iimport.go
  • operator/vendor/golang.org/x/tools/internal/gcimporter/ureader.go
  • operator/vendor/golang.org/x/tools/internal/gocommand/version.go
  • operator/vendor/golang.org/x/tools/internal/pkgbits/version.go
  • operator/vendor/golang.org/x/tools/internal/stdlib/deps.go
  • operator/vendor/golang.org/x/tools/internal/typeparams/coretype.go
  • operator/vendor/golang.org/x/tools/internal/typeparams/free.go
  • operator/vendor/golang.org/x/tools/internal/typesinternal/types.go
  • operator/vendor/golang.org/x/tools/internal/versions/features.go
  • operator/vendor/modules.txt
💤 Files with no reviewable changes (11)
  • operator/vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go
  • operator/vendor/golang.org/x/net/idna/trie12.0.0.go
  • operator/vendor/golang.org/x/net/html/iter.go
  • operator/vendor/golang.org/x/net/idna/pre_go118.go
  • operator/vendor/golang.org/x/net/idna/trie13.0.0.go
  • operator/vendor/golang.org/x/net/idna/go118.go
  • operator/vendor/golang.org/x/tools/internal/aliases/aliases_go122.go
  • operator/vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go
  • operator/vendor/golang.org/x/sys/unix/syscall_solaris.go
  • operator/vendor/golang.org/x/net/idna/idna9.0.0.go
  • operator/vendor/golang.org/x/sys/unix/syscall_darwin.go

Comment thread .github/actions/cosign-verify-release/action.yml
Comment thread .github/workflows/agent-ci.yaml
Comment thread .github/workflows/lint-ci.yaml
Comment thread .github/workflows/operator-ci.yaml
Comment thread .github/workflows/operator-ci.yaml
Comment thread chart/Chart.yaml
Comment thread chart/templates/_helpers.tpl
Comment thread docs/release-process.md
Comment thread operator/api/v1alpha1/deployment_policy_webhook_test.go
Comment thread operator/Makefile
@lockwobr lockwobr merged commit e20668a into main May 22, 2026
45 checks passed
@lockwobr lockwobr deleted the cherrypick branch May 22, 2026 20:19
This was referenced May 22, 2026
rice-riley pushed a commit that referenced this pull request Jun 9, 2026
* ci: publish keyless release attestations (#232) (#240)

* ci: publish keyless release attestations

* ci: drop nvcr release attestations

* ci: narrow release attestation identity

* ci: gate attestations to release tags

* docs: show immutable release subjects

* ci: attest helm chart releases

---------

Signed-off-by: AnouarMohamed <[email protected]>
Co-authored-by: Anouar Mohamed <[email protected]>

* chore(docs): update docs around release and location of helm chart (#237) (#239)

* fix(test): uninstall downgraded package before cleanup in downgrade-after-uninstall (#241)

The test left [email protected] freshly installed at chainsaw's automatic
CLEANUP, where the new delete-time uninstall finalizer (from #200) must
run uninstall pods on every node before releasing the CR. That exceeds
chainsaw's default cleanup window, causing "context deadline exceeded".

Add a final uninstall-v1 step that flips uninstall.apply=true on the
downgraded version and waits for nodeState to empty, so the CR has no
installed packages when cleanup deletes it.

Signed-off-by: Alex Yuskauskas <[email protected]>

* fix: deadlock in webhook controller when upgrading from old versions (#243)

* fix: close StageInterrupt trap + harden core e2e pool (#242)

* fix(test): harden core e2e pool against finalizer-cleanup races and improve diagnosability

Two changes across the six core-pool chainsaw tests:

1. Add `timeouts.cleanup: 120s` to every core-pool test. Chainsaw's
   default cleanup window (~30s) is too tight for the project's CR
   finalizer, which must uncordon nodes, remove labels/annotations,
   and GC package pods before releasing. Same failure mode that hit
   downgrade-after-uninstall (PR #241).

2. Add `catch:` blocks to `depends-on` and `simple-skyhook`, mirroring
   the pattern used by the other four core tests. When these tests
   flake, CI now captures the Node, Skyhook CR, and package Pods for
   diagnosis instead of failing without artifacts.

No assert logic changes — this is a foundation pass to remove a known
flake class and make future flakes diagnosable.

Signed-off-by: Alex Yuskauskas <[email protected]>

* fix(operator): close StageInterrupt trap when configUpdates signal decays

A package whose only interrupt is a `configInterrupts` entry (no top-level
`interrupt` block) could get stuck at `StageInterrupt/StateSkipped`
permanently when `Status.ConfigUpdates` cleared or never persisted (e.g.
due to a 409 on the spec patch). The state machine queried the dynamic
`HasInterrupt(config)` signal at four points, and once that signal
decayed to false, the package was untouchable: `ProgressSkipped`
wouldn't promote it, `NextStage` wouldn't advance it past Interrupt,
and `GetComplete`/`IsPackageComplete` wouldn't count it complete.

Decouple progression-past-Interrupt from the dynamic signal:

- `NextStage`: add `StageInterrupt → StagePostInterrupt` to the
  no-interrupt default map. The with-interrupt full-replacement map is
  preserved as-is — PR #200 deliberately omits `StageUninstall →
  StageApply` from it so with-interrupt uninstalls route via
  `StageUninstallInterrupt`; collapsing the maps would silently
  re-enable that transition.
- `ProgressSkipped`: drop the `HasInterrupt` gate. The only writer of
  `StateSkipped` at `StageInterrupt` is `ProcessInterrupt`'s
  budget-contention branch, which already decided the package needed
  an interrupt to schedule. Stage alone is sufficient.
- `GetComplete`, `IsPackageComplete`: treat `StagePostInterrupt` as
  unconditionally terminal. The only way to reach it is via the
  interrupt cycle; gating the terminal check on a signal that can
  decay is redundant with the entry gate and only becomes load-bearing
  when the trap fires.

Reproducer in `skyhook_types_test.go` exercises all three sites.

Surfaced by the `chainsaw/config-skyhook` "update while running" step,
which patches the spec mid-flight and concurrently triggers the
`HandleMigrations` and `processSkyhooksPerNode` 409 conflict paths —
those stretch convergence enough that ConfigUpdates can be lost
between the package reaching StageInterrupt and ProgressSkipped firing.

Signed-off-by: Alex Yuskauskas <[email protected]>

* refactor(operator): GetComplete delegates to IsPackageComplete

GetComplete and IsPackageComplete encoded the same terminal-state logic
twice. Have GetComplete iterate the spec packages and call
IsPackageComplete for each, and move the explanatory comment to
IsPackageComplete where the predicate lives.

Behavior preserved: the prior implementation iterated node state and
filtered to spec packages by name+version match; the new one iterates
spec packages and looks them up in node state by unique name (name|version).
Same set of packages either way.

Signed-off-by: Alex Yuskauskas <[email protected]>

---------

Signed-off-by: Alex Yuskauskas <[email protected]>

---------

Signed-off-by: AnouarMohamed <[email protected]>
Signed-off-by: Alex Yuskauskas <[email protected]>
Co-authored-by: Anouar Mohamed <[email protected]>
Co-authored-by: ayuskauskas <[email protected]>
rice-riley pushed a commit that referenced this pull request Jun 9, 2026
* ci: publish keyless release attestations (#232) (#240)

* ci: publish keyless release attestations

* ci: drop nvcr release attestations

* ci: narrow release attestation identity

* ci: gate attestations to release tags

* docs: show immutable release subjects

* ci: attest helm chart releases

---------

Signed-off-by: AnouarMohamed <[email protected]>
Co-authored-by: Anouar Mohamed <[email protected]>

* chore(docs): update docs around release and location of helm chart (#237) (#239)

* fix(test): uninstall downgraded package before cleanup in downgrade-after-uninstall (#241)

The test left [email protected] freshly installed at chainsaw's automatic
CLEANUP, where the new delete-time uninstall finalizer (from #200) must
run uninstall pods on every node before releasing the CR. That exceeds
chainsaw's default cleanup window, causing "context deadline exceeded".

Add a final uninstall-v1 step that flips uninstall.apply=true on the
downgraded version and waits for nodeState to empty, so the CR has no
installed packages when cleanup deletes it.

Signed-off-by: Alex Yuskauskas <[email protected]>

* fix: deadlock in webhook controller when upgrading from old versions (#243)

* fix: close StageInterrupt trap + harden core e2e pool (#242)

* fix(test): harden core e2e pool against finalizer-cleanup races and improve diagnosability

Two changes across the six core-pool chainsaw tests:

1. Add `timeouts.cleanup: 120s` to every core-pool test. Chainsaw's
   default cleanup window (~30s) is too tight for the project's CR
   finalizer, which must uncordon nodes, remove labels/annotations,
   and GC package pods before releasing. Same failure mode that hit
   downgrade-after-uninstall (PR #241).

2. Add `catch:` blocks to `depends-on` and `simple-skyhook`, mirroring
   the pattern used by the other four core tests. When these tests
   flake, CI now captures the Node, Skyhook CR, and package Pods for
   diagnosis instead of failing without artifacts.

No assert logic changes — this is a foundation pass to remove a known
flake class and make future flakes diagnosable.

Signed-off-by: Alex Yuskauskas <[email protected]>

* fix(operator): close StageInterrupt trap when configUpdates signal decays

A package whose only interrupt is a `configInterrupts` entry (no top-level
`interrupt` block) could get stuck at `StageInterrupt/StateSkipped`
permanently when `Status.ConfigUpdates` cleared or never persisted (e.g.
due to a 409 on the spec patch). The state machine queried the dynamic
`HasInterrupt(config)` signal at four points, and once that signal
decayed to false, the package was untouchable: `ProgressSkipped`
wouldn't promote it, `NextStage` wouldn't advance it past Interrupt,
and `GetComplete`/`IsPackageComplete` wouldn't count it complete.

Decouple progression-past-Interrupt from the dynamic signal:

- `NextStage`: add `StageInterrupt → StagePostInterrupt` to the
  no-interrupt default map. The with-interrupt full-replacement map is
  preserved as-is — PR #200 deliberately omits `StageUninstall →
  StageApply` from it so with-interrupt uninstalls route via
  `StageUninstallInterrupt`; collapsing the maps would silently
  re-enable that transition.
- `ProgressSkipped`: drop the `HasInterrupt` gate. The only writer of
  `StateSkipped` at `StageInterrupt` is `ProcessInterrupt`'s
  budget-contention branch, which already decided the package needed
  an interrupt to schedule. Stage alone is sufficient.
- `GetComplete`, `IsPackageComplete`: treat `StagePostInterrupt` as
  unconditionally terminal. The only way to reach it is via the
  interrupt cycle; gating the terminal check on a signal that can
  decay is redundant with the entry gate and only becomes load-bearing
  when the trap fires.

Reproducer in `skyhook_types_test.go` exercises all three sites.

Surfaced by the `chainsaw/config-skyhook` "update while running" step,
which patches the spec mid-flight and concurrently triggers the
`HandleMigrations` and `processSkyhooksPerNode` 409 conflict paths —
those stretch convergence enough that ConfigUpdates can be lost
between the package reaching StageInterrupt and ProgressSkipped firing.

Signed-off-by: Alex Yuskauskas <[email protected]>

* refactor(operator): GetComplete delegates to IsPackageComplete

GetComplete and IsPackageComplete encoded the same terminal-state logic
twice. Have GetComplete iterate the spec packages and call
IsPackageComplete for each, and move the explanatory comment to
IsPackageComplete where the predicate lives.

Behavior preserved: the prior implementation iterated node state and
filtered to spec packages by name+version match; the new one iterates
spec packages and looks them up in node state by unique name (name|version).
Same set of packages either way.

Signed-off-by: Alex Yuskauskas <[email protected]>

---------

Signed-off-by: Alex Yuskauskas <[email protected]>

---------

Signed-off-by: AnouarMohamed <[email protected]>
Signed-off-by: Alex Yuskauskas <[email protected]>
Co-authored-by: Anouar Mohamed <[email protected]>
Co-authored-by: ayuskauskas <[email protected]>
rice-riley pushed a commit that referenced this pull request Jun 9, 2026
* ci: publish keyless release attestations (#232) (#240)

* ci: publish keyless release attestations

* ci: drop nvcr release attestations

* ci: narrow release attestation identity

* ci: gate attestations to release tags

* docs: show immutable release subjects

* ci: attest helm chart releases

---------

Signed-off-by: AnouarMohamed <[email protected]>
Co-authored-by: Anouar Mohamed <[email protected]>

* chore(docs): update docs around release and location of helm chart (#237) (#239)

* fix(test): uninstall downgraded package before cleanup in downgrade-after-uninstall (#241)

The test left [email protected] freshly installed at chainsaw's automatic
CLEANUP, where the new delete-time uninstall finalizer (from #200) must
run uninstall pods on every node before releasing the CR. That exceeds
chainsaw's default cleanup window, causing "context deadline exceeded".

Add a final uninstall-v1 step that flips uninstall.apply=true on the
downgraded version and waits for nodeState to empty, so the CR has no
installed packages when cleanup deletes it.

Signed-off-by: Alex Yuskauskas <[email protected]>

* fix: deadlock in webhook controller when upgrading from old versions (#243)

* fix: close StageInterrupt trap + harden core e2e pool (#242)

* fix(test): harden core e2e pool against finalizer-cleanup races and improve diagnosability

Two changes across the six core-pool chainsaw tests:

1. Add `timeouts.cleanup: 120s` to every core-pool test. Chainsaw's
   default cleanup window (~30s) is too tight for the project's CR
   finalizer, which must uncordon nodes, remove labels/annotations,
   and GC package pods before releasing. Same failure mode that hit
   downgrade-after-uninstall (PR #241).

2. Add `catch:` blocks to `depends-on` and `simple-skyhook`, mirroring
   the pattern used by the other four core tests. When these tests
   flake, CI now captures the Node, Skyhook CR, and package Pods for
   diagnosis instead of failing without artifacts.

No assert logic changes — this is a foundation pass to remove a known
flake class and make future flakes diagnosable.

Signed-off-by: Alex Yuskauskas <[email protected]>

* fix(operator): close StageInterrupt trap when configUpdates signal decays

A package whose only interrupt is a `configInterrupts` entry (no top-level
`interrupt` block) could get stuck at `StageInterrupt/StateSkipped`
permanently when `Status.ConfigUpdates` cleared or never persisted (e.g.
due to a 409 on the spec patch). The state machine queried the dynamic
`HasInterrupt(config)` signal at four points, and once that signal
decayed to false, the package was untouchable: `ProgressSkipped`
wouldn't promote it, `NextStage` wouldn't advance it past Interrupt,
and `GetComplete`/`IsPackageComplete` wouldn't count it complete.

Decouple progression-past-Interrupt from the dynamic signal:

- `NextStage`: add `StageInterrupt → StagePostInterrupt` to the
  no-interrupt default map. The with-interrupt full-replacement map is
  preserved as-is — PR #200 deliberately omits `StageUninstall →
  StageApply` from it so with-interrupt uninstalls route via
  `StageUninstallInterrupt`; collapsing the maps would silently
  re-enable that transition.
- `ProgressSkipped`: drop the `HasInterrupt` gate. The only writer of
  `StateSkipped` at `StageInterrupt` is `ProcessInterrupt`'s
  budget-contention branch, which already decided the package needed
  an interrupt to schedule. Stage alone is sufficient.
- `GetComplete`, `IsPackageComplete`: treat `StagePostInterrupt` as
  unconditionally terminal. The only way to reach it is via the
  interrupt cycle; gating the terminal check on a signal that can
  decay is redundant with the entry gate and only becomes load-bearing
  when the trap fires.

Reproducer in `skyhook_types_test.go` exercises all three sites.

Surfaced by the `chainsaw/config-skyhook` "update while running" step,
which patches the spec mid-flight and concurrently triggers the
`HandleMigrations` and `processSkyhooksPerNode` 409 conflict paths —
those stretch convergence enough that ConfigUpdates can be lost
between the package reaching StageInterrupt and ProgressSkipped firing.

Signed-off-by: Alex Yuskauskas <[email protected]>

* refactor(operator): GetComplete delegates to IsPackageComplete

GetComplete and IsPackageComplete encoded the same terminal-state logic
twice. Have GetComplete iterate the spec packages and call
IsPackageComplete for each, and move the explanatory comment to
IsPackageComplete where the predicate lives.

Behavior preserved: the prior implementation iterated node state and
filtered to spec packages by name+version match; the new one iterates
spec packages and looks them up in node state by unique name (name|version).
Same set of packages either way.

Signed-off-by: Alex Yuskauskas <[email protected]>

---------

Signed-off-by: Alex Yuskauskas <[email protected]>

---------

Signed-off-by: AnouarMohamed <[email protected]>
Signed-off-by: Alex Yuskauskas <[email protected]>
Co-authored-by: Anouar Mohamed <[email protected]>
Co-authored-by: ayuskauskas <[email protected]>
rice-riley pushed a commit that referenced this pull request Jun 9, 2026
* ci: publish keyless release attestations (#232) (#240)

* ci: publish keyless release attestations

* ci: drop nvcr release attestations

* ci: narrow release attestation identity

* ci: gate attestations to release tags

* docs: show immutable release subjects

* ci: attest helm chart releases

---------

Signed-off-by: AnouarMohamed <[email protected]>
Co-authored-by: Anouar Mohamed <[email protected]>

* chore(docs): update docs around release and location of helm chart (#237) (#239)

* fix(test): uninstall downgraded package before cleanup in downgrade-after-uninstall (#241)

The test left [email protected] freshly installed at chainsaw's automatic
CLEANUP, where the new delete-time uninstall finalizer (from #200) must
run uninstall pods on every node before releasing the CR. That exceeds
chainsaw's default cleanup window, causing "context deadline exceeded".

Add a final uninstall-v1 step that flips uninstall.apply=true on the
downgraded version and waits for nodeState to empty, so the CR has no
installed packages when cleanup deletes it.

Signed-off-by: Alex Yuskauskas <[email protected]>

* fix: deadlock in webhook controller when upgrading from old versions (#243)

* fix: close StageInterrupt trap + harden core e2e pool (#242)

* fix(test): harden core e2e pool against finalizer-cleanup races and improve diagnosability

Two changes across the six core-pool chainsaw tests:

1. Add `timeouts.cleanup: 120s` to every core-pool test. Chainsaw's
   default cleanup window (~30s) is too tight for the project's CR
   finalizer, which must uncordon nodes, remove labels/annotations,
   and GC package pods before releasing. Same failure mode that hit
   downgrade-after-uninstall (PR #241).

2. Add `catch:` blocks to `depends-on` and `simple-skyhook`, mirroring
   the pattern used by the other four core tests. When these tests
   flake, CI now captures the Node, Skyhook CR, and package Pods for
   diagnosis instead of failing without artifacts.

No assert logic changes — this is a foundation pass to remove a known
flake class and make future flakes diagnosable.

Signed-off-by: Alex Yuskauskas <[email protected]>

* fix(operator): close StageInterrupt trap when configUpdates signal decays

A package whose only interrupt is a `configInterrupts` entry (no top-level
`interrupt` block) could get stuck at `StageInterrupt/StateSkipped`
permanently when `Status.ConfigUpdates` cleared or never persisted (e.g.
due to a 409 on the spec patch). The state machine queried the dynamic
`HasInterrupt(config)` signal at four points, and once that signal
decayed to false, the package was untouchable: `ProgressSkipped`
wouldn't promote it, `NextStage` wouldn't advance it past Interrupt,
and `GetComplete`/`IsPackageComplete` wouldn't count it complete.

Decouple progression-past-Interrupt from the dynamic signal:

- `NextStage`: add `StageInterrupt → StagePostInterrupt` to the
  no-interrupt default map. The with-interrupt full-replacement map is
  preserved as-is — PR #200 deliberately omits `StageUninstall →
  StageApply` from it so with-interrupt uninstalls route via
  `StageUninstallInterrupt`; collapsing the maps would silently
  re-enable that transition.
- `ProgressSkipped`: drop the `HasInterrupt` gate. The only writer of
  `StateSkipped` at `StageInterrupt` is `ProcessInterrupt`'s
  budget-contention branch, which already decided the package needed
  an interrupt to schedule. Stage alone is sufficient.
- `GetComplete`, `IsPackageComplete`: treat `StagePostInterrupt` as
  unconditionally terminal. The only way to reach it is via the
  interrupt cycle; gating the terminal check on a signal that can
  decay is redundant with the entry gate and only becomes load-bearing
  when the trap fires.

Reproducer in `skyhook_types_test.go` exercises all three sites.

Surfaced by the `chainsaw/config-skyhook` "update while running" step,
which patches the spec mid-flight and concurrently triggers the
`HandleMigrations` and `processSkyhooksPerNode` 409 conflict paths —
those stretch convergence enough that ConfigUpdates can be lost
between the package reaching StageInterrupt and ProgressSkipped firing.

Signed-off-by: Alex Yuskauskas <[email protected]>

* refactor(operator): GetComplete delegates to IsPackageComplete

GetComplete and IsPackageComplete encoded the same terminal-state logic
twice. Have GetComplete iterate the spec packages and call
IsPackageComplete for each, and move the explanatory comment to
IsPackageComplete where the predicate lives.

Behavior preserved: the prior implementation iterated node state and
filtered to spec packages by name+version match; the new one iterates
spec packages and looks them up in node state by unique name (name|version).
Same set of packages either way.

Signed-off-by: Alex Yuskauskas <[email protected]>

---------

Signed-off-by: Alex Yuskauskas <[email protected]>

---------

Signed-off-by: AnouarMohamed <[email protected]>
Signed-off-by: Alex Yuskauskas <[email protected]>
Co-authored-by: Anouar Mohamed <[email protected]>
Co-authored-by: ayuskauskas <[email protected]>
rice-riley added a commit that referenced this pull request Jun 9, 2026
* feat(agent): port enums and steps for agent go rewrite

Signed-off-by: Riley Rice <[email protected]>

* chore: Cherry pick (#244)

* ci: publish keyless release attestations (#232) (#240)

* ci: publish keyless release attestations

* ci: drop nvcr release attestations

* ci: narrow release attestation identity

* ci: gate attestations to release tags

* docs: show immutable release subjects

* ci: attest helm chart releases

---------

Signed-off-by: AnouarMohamed <[email protected]>
Co-authored-by: Anouar Mohamed <[email protected]>

* chore(docs): update docs around release and location of helm chart (#237) (#239)

* fix(test): uninstall downgraded package before cleanup in downgrade-after-uninstall (#241)

The test left [email protected] freshly installed at chainsaw's automatic
CLEANUP, where the new delete-time uninstall finalizer (from #200) must
run uninstall pods on every node before releasing the CR. That exceeds
chainsaw's default cleanup window, causing "context deadline exceeded".

Add a final uninstall-v1 step that flips uninstall.apply=true on the
downgraded version and waits for nodeState to empty, so the CR has no
installed packages when cleanup deletes it.

Signed-off-by: Alex Yuskauskas <[email protected]>

* fix: deadlock in webhook controller when upgrading from old versions (#243)

* fix: close StageInterrupt trap + harden core e2e pool (#242)

* fix(test): harden core e2e pool against finalizer-cleanup races and improve diagnosability

Two changes across the six core-pool chainsaw tests:

1. Add `timeouts.cleanup: 120s` to every core-pool test. Chainsaw's
   default cleanup window (~30s) is too tight for the project's CR
   finalizer, which must uncordon nodes, remove labels/annotations,
   and GC package pods before releasing. Same failure mode that hit
   downgrade-after-uninstall (PR #241).

2. Add `catch:` blocks to `depends-on` and `simple-skyhook`, mirroring
   the pattern used by the other four core tests. When these tests
   flake, CI now captures the Node, Skyhook CR, and package Pods for
   diagnosis instead of failing without artifacts.

No assert logic changes — this is a foundation pass to remove a known
flake class and make future flakes diagnosable.

Signed-off-by: Alex Yuskauskas <[email protected]>

* fix(operator): close StageInterrupt trap when configUpdates signal decays

A package whose only interrupt is a `configInterrupts` entry (no top-level
`interrupt` block) could get stuck at `StageInterrupt/StateSkipped`
permanently when `Status.ConfigUpdates` cleared or never persisted (e.g.
due to a 409 on the spec patch). The state machine queried the dynamic
`HasInterrupt(config)` signal at four points, and once that signal
decayed to false, the package was untouchable: `ProgressSkipped`
wouldn't promote it, `NextStage` wouldn't advance it past Interrupt,
and `GetComplete`/`IsPackageComplete` wouldn't count it complete.

Decouple progression-past-Interrupt from the dynamic signal:

- `NextStage`: add `StageInterrupt → StagePostInterrupt` to the
  no-interrupt default map. The with-interrupt full-replacement map is
  preserved as-is — PR #200 deliberately omits `StageUninstall →
  StageApply` from it so with-interrupt uninstalls route via
  `StageUninstallInterrupt`; collapsing the maps would silently
  re-enable that transition.
- `ProgressSkipped`: drop the `HasInterrupt` gate. The only writer of
  `StateSkipped` at `StageInterrupt` is `ProcessInterrupt`'s
  budget-contention branch, which already decided the package needed
  an interrupt to schedule. Stage alone is sufficient.
- `GetComplete`, `IsPackageComplete`: treat `StagePostInterrupt` as
  unconditionally terminal. The only way to reach it is via the
  interrupt cycle; gating the terminal check on a signal that can
  decay is redundant with the entry gate and only becomes load-bearing
  when the trap fires.

Reproducer in `skyhook_types_test.go` exercises all three sites.

Surfaced by the `chainsaw/config-skyhook` "update while running" step,
which patches the spec mid-flight and concurrently triggers the
`HandleMigrations` and `processSkyhooksPerNode` 409 conflict paths —
those stretch convergence enough that ConfigUpdates can be lost
between the package reaching StageInterrupt and ProgressSkipped firing.

Signed-off-by: Alex Yuskauskas <[email protected]>

* refactor(operator): GetComplete delegates to IsPackageComplete

GetComplete and IsPackageComplete encoded the same terminal-state logic
twice. Have GetComplete iterate the spec packages and call
IsPackageComplete for each, and move the explanatory comment to
IsPackageComplete where the predicate lives.

Behavior preserved: the prior implementation iterated node state and
filtered to spec packages by name+version match; the new one iterates
spec packages and looks them up in node state by unique name (name|version).
Same set of packages either way.

Signed-off-by: Alex Yuskauskas <[email protected]>

---------

Signed-off-by: Alex Yuskauskas <[email protected]>

---------

Signed-off-by: AnouarMohamed <[email protected]>
Signed-off-by: Alex Yuskauskas <[email protected]>
Co-authored-by: Anouar Mohamed <[email protected]>
Co-authored-by: ayuskauskas <[email protected]>

---------

Signed-off-by: Riley Rice <[email protected]>
Signed-off-by: AnouarMohamed <[email protected]>
Signed-off-by: Alex Yuskauskas <[email protected]>
Co-authored-by: Brian Lockwood <[email protected]>
Co-authored-by: Anouar Mohamed <[email protected]>
Co-authored-by: ayuskauskas <[email protected]>
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.

3 participants