Skip to content

Replace random generated "inventory ID"#4396

Open
Jaisheesh-2006 wants to merge 5 commits intokptdev:mainfrom
Jaisheesh-2006:fix/4387-loose-inventory-id
Open

Replace random generated "inventory ID"#4396
Jaisheesh-2006 wants to merge 5 commits intokptdev:mainfrom
Jaisheesh-2006:fix/4387-loose-inventory-id

Conversation

@Jaisheesh-2006
Copy link
Contributor

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 namespace and --name, we ensure that the same package configuration always maps to the same inventory object in the cluster.

Key Changes:

  • Deterministic ID Generation: Implemented generateHash(namespace, name) using length-prefixed SHA-1 to replace google/uuid.
  • Mandatory Flag: The --name flag is now mandatory for kpt live init to ensure the hash can be consistently generated.
  • Validation: Added DNS-1123 label validation for the --name input to ensure compatibility with Kubernetes resource naming conventions.
  • Legacy Support: Hidden the --inventory-id flag from the help menu to encourage deterministic usage while maintaining backward compatibility for existing workflows.
  • Robustness: Added guards in kpt live migrate to 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 kpt could 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

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>
Copilot AI review requested due to automatic review settings February 17, 2026 12:50
@netlify
Copy link

netlify bot commented Feb 17, 2026

Deploy Preview for kptdocs ready!

Name Link
🔨 Latest commit 51f18a4
🔍 Latest deploy log https://app.netlify.com/projects/kptdocs/deploys/699c57a14693880008e75af3
😎 Deploy Preview https://deploy-preview-4396--kptdocs.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

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 --name mandatory for kpt live init and 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 --name behavior.

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.

Comment on lines 393 to 396
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>"))
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
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)
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

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.

Suggested change
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)
}

Copilot uses AI. Check for mistakes.
Comment on lines 204 to 211
// 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)
}
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

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).

Copilot uses AI. Check for mistakes.
Comment on lines 386 to 390
@@ -390,6 +390,11 @@ func (mr *Runner) migrateKptfileToRG(args []string) error {
return errors.E(op, errors.IO, types.UniquePath(dir), err)
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
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>
Copilot AI review requested due to automatic review settings February 17, 2026 13:19
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

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.

Comment on lines 484 to 486
local count
count=$(wc -l < $OUTPUT_DIR/invname | tr -d ' ')
if [ "$count" -ge 1 ]; then
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

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).

Copilot uses AI. Check for mistakes.
Comment on lines 393 to 397
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>"))
}

Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

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".

Suggested change
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>"))
}

Copilot uses AI. Check for mistakes.
Comment on lines 335 to 337
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, "; "))
Copy link

Copilot AI Feb 17, 2026

Choose a reason for hiding this comment

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

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.

Copilot uses AI. Check for mistakes.
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Feb 20, 2026
Copilot AI review requested due to automatic review settings February 20, 2026 12:56
@Jaisheesh-2006 Jaisheesh-2006 force-pushed the fix/4387-loose-inventory-id branch from 07896b7 to 1e0c7f5 Compare February 20, 2026 12:56
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 323 to 325
h := sha1.New()
fmt.Fprintf(h, "%d:%s:%d:%s", len(namespace), namespace, len(name), name)
return hex.EncodeToString(h.Sum(nil)), nil
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

Using SHA-1 for non-cryptographic purposes (generating deterministic IDs) is acceptable. However, consider adding a code comment explicitly noting that SHA-1 is used here for deterministic hashing, not for security, to prevent future confusion and potential linter warnings from security scanners like gosec.

Copilot uses AI. Check for mistakes.
Comment on lines +476 to +477
# assertRGInventory checks that exactly one ResourceGroup inventory object
# exists in the passed namespace (selected by the inventory-id label).
Copy link

Copilot AI Feb 20, 2026

Choose a reason for hiding this comment

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

The comment says the function "checks that exactly one ResourceGroup inventory object exists," but the implementation uses ">= 1" which allows multiple ResourceGroup inventories. Consider either updating the comment to match the implementation ("at least one") or making the check stricter to truly verify exactly one inventory object exists.

Copilot uses AI. Check for mistakes.
- Replace IsDNS1123Subdomain with IsDNS1123Label for stricter
  name validation (63-char limit, no dots).
- Capture fmt.Fprintf error in generateHash.
- Validate directory-name fallback with IsDNS1123Label when
  --name is omitted by internal callers (e.g., migrate).
- Fix wrong error variable (err to rgFileErr) in os.Stat switch
  in migratecmd.go.
- Remove unreachable kf.Inventory.Name == '' guard in migratecmd.go.
- Tighten assertRGInventory bash check from -ge 1 to -eq 1.
- Remove dead generateID function and unused imports.
- Add tests for directory-name fallback validation path.

Fixes kptdev#4387

Signed-off-by: Jaisheesh-2006 <jaicodes2006@gmail.com>
- Add explanatory comment for SHA-1 usage to clarify it is not for cryptographic security.
- Align assertRGInventory bash script comment with the strict -eq 1 implementation.

Signed-off-by: Jaisheesh-2006 <jaicodes2006@gmail.com>
Copilot AI review requested due to automatic review settings February 23, 2026 13:35
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 6 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +47 to +49
var errNameRequired = fmt.Errorf(
"--name is required: provide a stable deployment name " +
"(e.g. --name=my-app-staging) that remains consistent across re-initializations")
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

Consider using fmt.Errorf with formatting on a single line or breaking the string at natural word boundaries. The current concatenation with '+' operators makes the error message harder to read and modify. For example: fmt.Errorf(\"--name is required: provide a stable deployment name (e.g. --name=my-app-staging) that remains consistent across re-initializations\")

Copilot uses AI. Check for mistakes.
Comment on lines +329 to +330
// Note: SHA-1 is used here strictly for deterministic ID generation,
// not for cryptographic security.
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

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

While the comment correctly clarifies that SHA-1 is not used for cryptographic purposes, it would be helpful to add a brief explanation of why SHA-1 was chosen over alternatives (e.g., simplicity, sufficient collision resistance for this use case, or compatibility with existing systems).

Suggested change
// Note: SHA-1 is used here strictly for deterministic ID generation,
// not for cryptographic security.
// Note: SHA-1 is used here strictly for deterministic ID generation, not for
// cryptographic security. It is chosen for its simplicity, stable 40-character
// hex output, and compatibility with existing inventory IDs; collision resistance
// is sufficient for this constrained input space (namespace + name), and no
// secrets or security-sensitive data are being protected.

Copilot uses AI. Check for mistakes.
@efiacor efiacor changed the title Fix #4387 Replace random generated "inventory ID" Feb 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/live size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Loose random generated "inventory ID" in order to make kpt less confusing to new users

2 participants