Skip to content

Fix #4387#4396

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

Fix #4387#4396
Jaisheesh-2006 wants to merge 3 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 1e0c7f5
🔍 Latest deploy log https://app.netlify.com/projects/kptdocs/deploys/69946af4855dfa0008e357d4
😎 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
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)
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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

1 participant