Conversation
Replaces random UUIDs with SHA-1 hashes derived from namespace and name to prevent lost inventory bugs. Makes --name mandatory and adds DNS-1123 validation. Hides --inventory-id to favor deterministic generation. Fixes kptdev#4387 Signed-off-by: Jaisheesh-2006 <jaicodes2006@gmail.com>
✅ Deploy Preview for kptdocs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
There was a problem hiding this comment.
Pull request overview
This PR addresses lost-inventory behavior by making kpt live init inventory IDs deterministic (derived from namespace + --name) instead of random UUID-based values, and updates related CLI guidance/tests/docs.
Changes:
- Make
--namemandatory forkpt live initand validate it against Kubernetes DNS-1123 naming rules. - Replace auto-generated inventory IDs with a deterministic, length-prefixed SHA-1 hash.
- Update migrate/init flows, generated docs, and e2e coverage to reflect the new required
--namebehavior.
Reviewed changes
Copilot reviewed 5 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/lib/errors/resolver/live.go | Updates user-facing resolver messages to instruct using kpt live init --name=.... |
| internal/docs/generated/livedocs/docs.go | Updates generated CLI docs to reflect required --name and “advanced” inventory-id override semantics. |
| e2e/live/end-to-end-test.sh | Updates e2e invocations/assertions to pass --name and expect stable RG names. |
| commands/live/migrate/migratecmd.go | Adds guardrails in migration; however, introduces/retains error-handling issues in RG-file existence checks and malformed inventory handling. |
| commands/live/init/cmdliveinit_test.go | Reworks tests for name validation and deterministic hash expectations. |
| commands/live/init/cmdliveinit.go | Implements deterministic hash ID generation, mandatory --name, hides --inventory-id, and updates init behavior. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if kf.Inventory.Name == "" { | ||
| return errors.E(op, types.UniquePath(dir), | ||
| fmt.Errorf("Kptfile inventory has empty name; re-run: kpt live init --name=<name>")) | ||
| } |
There was a problem hiding this comment.
This empty-name guard is likely unreachable: kptfileutil.ValidateInventory(kf.Inventory) earlier returns an error when Inventory.Name is empty, and the current code treats any validation error as “no inventory” and returns nil. To actually guard malformed inventories, handle the validation error explicitly (e.g., distinguish nil inventory vs missing fields) or move the check before the early return.
| timeStr := strconv.FormatInt(t.UTC().UnixNano(), 10) | ||
| return fmt.Sprintf("%s-%s", hashStr, timeStr), nil | ||
| h := sha1.New() | ||
| fmt.Fprintf(h, "%d:%s:%d:%s", len(namespace), namespace, len(name), name) |
There was a problem hiding this comment.
fmt.Fprintf's return values are ignored here. Since this repo enables the errcheck linter, this will fail CI. Capture and handle the returned error (or explicitly assign to _ and document why it can’t fail for a hash.Hash) so errcheck passes.
| fmt.Fprintf(h, "%d:%s:%d:%s", len(namespace), namespace, len(name), name) | |
| if _, err := fmt.Fprintf(h, "%d:%s:%d:%s", len(namespace), namespace, len(name), name); err != nil { | |
| return "", fmt.Errorf("failed to write hash input: %w", err) | |
| } |
| // Internal callers (e.g. migrate) may pass empty Name with an explicit | ||
| // InventoryID; derive a stable name from the package directory. | ||
| if c.Name == "" { | ||
| randomSuffix := common.RandomStr() | ||
| c.Name = fmt.Sprintf("%s-%s", defaultInventoryName, randomSuffix) | ||
| if c.InventoryID != "" { | ||
| c.Name = filepath.Base(c.Pkg.UniquePath.String()) | ||
| } else { | ||
| return errors.E(op, c.Pkg.UniquePath, errNameRequired) | ||
| } |
There was a problem hiding this comment.
When Name is empty but InventoryID is provided, this derives the ResourceGroup name from the package directory base without validating it. Directory names can be invalid for Kubernetes metadata.name (uppercase, underscore, etc.), which would create an invalid ResourceGroup YAML and break later operations. Consider validating/sanitizing the derived name (or returning an error that requires an explicit --name in the internal caller).
| switch { | ||
| case rgFileErr == nil: | ||
| return errors.E(op, errors.IO, types.UniquePath(dir), "the resourcegroup file already exists and inventory information cannot be migrated") | ||
| case err != nil && !goerrors.Is(err, os.ErrNotExist): | ||
| return errors.E(op, errors.IO, types.UniquePath(dir), err) |
There was a problem hiding this comment.
In the os.Stat error handling switch, the second case checks err (from earlier operations) instead of rgFileErr. This will silently ignore filesystem errors from os.Stat (e.g., permission errors) and can lead to migrating into an invalid state. Update the condition to use rgFileErr and return that error when it's not os.ErrNotExist.
Signed-off-by: Jaisheesh-2006 <jaicodes2006@gmail.com>
The quiet init test was changing the inventory name from inventory-18030002 back to rg-test-case-1a, causing the downstream 'status on symlink' assertion to fail. Signed-off-by: Jaisheesh-2006 <jaicodes2006@gmail.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 6 changed files in this pull request and generated 3 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| local count | ||
| count=$(wc -l < $OUTPUT_DIR/invname | tr -d ' ') | ||
| if [ "$count" -ge 1 ]; then |
There was a problem hiding this comment.
assertRGInventory claims to verify exactly one ResourceGroup inventory object, but the check currently passes when any count >= 1. This can hide regressions where multiple inventories exist in the same namespace. Update the condition to assert the count is exactly 1 (and ideally include the matching rows in the error output for debugging).
| if kf.Inventory.Name == "" { | ||
| return errors.E(op, types.UniquePath(dir), | ||
| fmt.Errorf("kptfile inventory has empty name; re-run: kpt live init --name=<name>")) | ||
| } | ||
|
|
There was a problem hiding this comment.
This kf.Inventory.Name == "" guard is effectively unreachable because kptfileutil.ValidateInventory(kf.Inventory) above already rejects empty/whitespace names and returns early. If the intent is to surface a clearer error for malformed inventory, handle the specific ValidateInventory error (or move the check before the validation/early-return) so malformed inventory doesn't get silently treated as "migration not needed".
| if kf.Inventory.Name == "" { | |
| return errors.E(op, types.UniquePath(dir), | |
| fmt.Errorf("kptfile inventory has empty name; re-run: kpt live init --name=<name>")) | |
| } |
| if errs := validation.IsDNS1123Subdomain(trimmed); len(errs) > 0 { | ||
| return "", fmt.Errorf("--name %q is not a valid Kubernetes resource name: %s", | ||
| trimmed, strings.Join(errs, "; ")) |
There was a problem hiding this comment.
PR description says --name is validated as a DNS-1123 label, but the implementation uses validation.IsDNS1123Subdomain (which permits dots and longer names). Either update the PR description/docs to say “DNS-1123 subdomain” (which matches Kubernetes metadata.name rules) or switch to label validation if dots should be rejected.
Description
This PR replaces the generation of random UUIDs for inventory IDs with a deterministic SHA-1 hashing mechanism. By deriving the inventory ID from the package
namespaceand--name, we ensure that the same package configuration always maps to the same inventory object in the cluster.Key Changes:
generateHash(namespace, name)using length-prefixed SHA-1 to replacegoogle/uuid.--nameflag is now mandatory forkpt live initto ensure the hash can be consistently generated.--nameinput to ensure compatibility with Kubernetes resource naming conventions.--inventory-idflag from the help menu to encourage deterministic usage while maintaining backward compatibility for existing workflows.kpt live migrateto prevent operations on empty or malformed inventory names.Motivation
Previously, re-fetching or re-initializing a package would generate a new random UUID. This led to "lost inventory" bugs where
kptcould no longer track or prune resources previously applied to the cluster because the association (the ID) had changed. Deterministic hashing ensures that as long as the namespace and name remain constant, the inventory remains trackable across different environments and local clones.Fixes
Fixes #4387