feat(storage): add reusable retained PV provisioning #18
No reviewers
Labels
No labels
app-migration
bug
ci-cd
cluster
Documentation
duplicate
enhancement
gpu
invalid
networking
question
security
Storage
wontfix
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
Homelab/workflows!18
Loading…
Reference in a new issue
No description provided.
Delete branch "kiyi/retained-pv-provisioning"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Automate retained static NFS PV provisioning before application delivery. An approved owner dispatch from a protected branch scans the caller and validates one prebound Retain PV before supplying cluster credentials. Preview performs server-side dry-run creation; create leaves matching volumes unchanged and refuses conflicts or concurrent creation without patching or deleting storage. Uses UDS-bundled kubectl and requires no Cosign keys.
Includes a scoped kubeconfig contract, evidence receipts, documentation and eight passing local tests covering preview/create, conflicts, defaults, races and credential gates. Hosted checks pending. No live cluster changes.
Release intent: v1.3.0 (new reusable capability). The platform caller will depend on that release. Related to #5 and Homelab/actual-budget#1.
Validation complete for
b17b73844f: all checks passed. Library checks ran 49 unit tests (including eight PV provisioning tests), Bash/YAML checks and Kubernetes/security integration checks; workflow acceptance and repository security also passed.The dependent platform caller, retained Actual PV and bootstrap instructions are in Homelab/platform#22. Merge this library change and publish v1.3.0 before activating that caller. Live provisioning has not been run.
Requesting changes for two fail-closed contract gaps in the new privileged storage path:
unchanged()compares only keys present in the desired manifest and ignores claim identity beyond namespace/name. A live PV with an additional material field such asspec.nodeAffinity, or an unverified/stale claim UID, is reportedunchangedrather than conflicting. Normalize only explicitly reviewed API defaults/server metadata, reject unapproved extra spec fields, and verify or fail closed on claim identity. Add regressions for material extra spec and stale claim identity.certificate-authority-data, and acurrent-contextvalue that is not linked to the sole context/cluster/user entries. Require embedded CA data; require exactly one supported authentication form (non-empty token or a complete certificate/key pair); and verify the selected context name and references resolve to the sole cluster and user. Add negative regressions for each malformed shape.Other verification passed: 49 unit tests, scaffold checks, Kubernetes negative integration fixtures,
git diff --check, and the clean worktree check. Hosted acceptance, repository security, and library checks are green; the exact security artifact reportspassed: true, zero blockers, and zero scanner errors. The full local scanner integration could not be reproduced because this host lackspython3.12-venv; the exact hosted library run supplies that evidence.@ -0,0 +45,4 @@def unchanged(existing, desired):# Ignore server-owned metadata/defaults and claim UID, but compare all requested fields.require(existing.get('metadata', {}).get('deletionTimestamp') is None, 'Existing PV is being deleted')require(existing.get('status', {}).get('phase') not in ('Released', 'Failed'), 'PV requires manual recovery')Blocking: this only compares fields requested by the desired manifest, so material extra live spec is silently accepted. I passed an otherwise matching PV with
spec.nodeAffinityrestricting it to a different node;unchanged()accepted it. The same path ignores claim UID, so namespace/name alone can classify a different PVC identity as matching. Normalize only known API defaults/server metadata, reject other extra spec, and verify or fail closed on claim identity; add both regressions.@ -0,0 +56,4 @@require(actual == value, f'Existing PV differs at spec.{key}; no changes made')require(existing['metadata']['name'] == desired['metadata']['name'], 'PV name differs')def kubeconfig(encoded, context):Blocking: this does not enforce the documented embedded-CA and scoped credential contract. Synthetic configs with no CA and an empty user, and with
current-context: rke2not linked to the sole context/cluster/user, are accepted. Requirecertificate-authority-data, exactly one non-empty auth form (token or complete cert/key pair), and a selected context whose references resolve to the sole named cluster/user. Add negative tests for these shapes.Addressed both blockers in
ff92ba83fc.Nine provisioning tests pass locally; hosted checks are running. Library documentation and the dependent platform PR #22 instructions now explain that bound volumes require owner review, including binding during post-create verification.
Re-review complete. Both blocking findings are resolved:
nodeAffinityand stale claim UID variants fail closed.Verified at this head: 50 unit tests pass, including the expanded provisioning matrix; scaffold and Kubernetes negative-integration checks pass;
git diff --checkpasses and the worktree is clean. All four hosted statuses are successful. The exact acceptance artifact reportspassed: true, and the security artifact reportspassed: true, zero blockers, and zero scanner errors. The documented post-create binding race remains fail-closed for owner review rather than mutating or rebinding storage.