From 8861be23f0b23e3a92b1a71e632e9a1c9a5f2f62 Mon Sep 17 00:00:00 2001 From: Vishnu Kothakapu Date: Mon, 7 Sep 2026 02:01:46 +0530 Subject: [PATCH] feat: validate Kptfile Inventory and Upstream Signed-off-by: Vishnu Kothakapu --- api/kptfile/v1/validation.go | 55 ++++++++++++++++++++++++- api/kptfile/v1/validation_test.go | 68 +++++++++++++++++++++++++++++++ make/testing.mk | 2 + 3 files changed, 124 insertions(+), 1 deletion(-) diff --git a/api/kptfile/v1/validation.go b/api/kptfile/v1/validation.go index b0c34bda92..8a11de60a2 100644 --- a/api/kptfile/v1/validation.go +++ b/api/kptfile/v1/validation.go @@ -37,7 +37,16 @@ func (kf *KptFile) Validate(fsys filesys.FileSystem, pkgPath UniquePath) error { if err := kf.Pipeline.validate(fsys, pkgPath); err != nil { return fmt.Errorf("invalid pipeline: %w", err) } - // TODO: validate other fields + if kf.Inventory != nil { + if err := kf.Inventory.validate(); err != nil { + return err + } + } + if kf.Upstream != nil { + if err := kf.Upstream.validate(); err != nil { + return err + } + } return nil } @@ -325,3 +334,47 @@ func RecognizedKustomizationFileNames() []string { "Kustomization", } } + +func (i *Inventory) validate() error { + if !i.IsValid() { + return &ValidateError{ + Field: "inventory", + Reason: "inventory must have name, namespace, and inventoryID", + } + } + return nil +} + +func (u *Upstream) validate() error { + if u.Type != GitOrigin && u.Type != GenericOrigin && u.Type != "" { + return &ValidateError{ + Field: "upstream.type", + Value: string(u.Type), + Reason: "upstream type must be one of: git, generic", + } + } + if u.UpdateStrategy != "" { + if _, err := ToUpdateStrategy(string(u.UpdateStrategy)); err != nil { + return &ValidateError{ + Field: "upstream.updateStrategy", + Value: string(u.UpdateStrategy), + Reason: err.Error(), + } + } + } + if u.Type == GitOrigin { + if u.Git == nil { + return &ValidateError{ + Field: "upstream.git", + Reason: "git origin must specify git locator", + } + } + if u.Git.Repo == "" { + return &ValidateError{ + Field: "upstream.git.repo", + Reason: "git locator must specify repo", + } + } + } + return nil +} diff --git a/api/kptfile/v1/validation_test.go b/api/kptfile/v1/validation_test.go index 121f50ee67..8d7e811da7 100644 --- a/api/kptfile/v1/validation_test.go +++ b/api/kptfile/v1/validation_test.go @@ -31,6 +31,74 @@ func TestKptfileValidate(t *testing.T) { } cases := []input{ + { + name: "inventory: valid", + kptfile: KptFile{ + Inventory: &Inventory{ + Name: "my-inv", + Namespace: "default", + InventoryID: "123", + }, + }, + valid: true, + }, + { + name: "inventory: invalid (missing name)", + kptfile: KptFile{ + Inventory: &Inventory{ + Namespace: "default", + InventoryID: "123", + }, + }, + valid: false, + }, + { + name: "upstream: valid git", + kptfile: KptFile{ + Upstream: &Upstream{ + Type: GitOrigin, + UpdateStrategy: ResourceMerge, + Git: &Git{ + Repo: "https://github.com/a/b.git", + }, + }, + }, + valid: true, + }, + { + name: "upstream: invalid (invalid strategy)", + kptfile: KptFile{ + Upstream: &Upstream{ + Type: GitOrigin, + UpdateStrategy: "invalid-strategy", + Git: &Git{ + Repo: "https://github.com/a/b.git", + }, + }, + }, + valid: false, + }, + { + name: "upstream: invalid (git missing repo)", + kptfile: KptFile{ + Upstream: &Upstream{ + Type: GitOrigin, + UpdateStrategy: ResourceMerge, + Git: &Git{}, + }, + }, + valid: false, + }, + { + name: "upstream: invalid (git missing git locator)", + kptfile: KptFile{ + Upstream: &Upstream{ + Type: GitOrigin, + UpdateStrategy: ResourceMerge, + }, + }, + valid: false, + }, { name: "pipeline: empty", kptfile: KptFile{ diff --git a/make/testing.mk b/make/testing.mk index eedd529868..2858b5246b 100644 --- a/make/testing.mk +++ b/make/testing.mk @@ -23,6 +23,8 @@ TEST_COVERAGE_FUNC_FILE=func_coverage.out .PHONY: test-coverage test-coverage: ## Generate coverage reports (runs tests with coverage instrumentation) go test -cover -coverprofile=$(TEST_COVERAGE_FILE) ${LDFLAGS} ./... + cd api && go test -cover -coverprofile=coverage.out ${LDFLAGS} ./... + tail -n +2 api/coverage.out >> $(TEST_COVERAGE_FILE) go tool cover -html=$(TEST_COVERAGE_FILE) -o $(TEST_COVERAGE_HTML_FILE) go tool cover -func=$(TEST_COVERAGE_FILE) -o $(TEST_COVERAGE_FUNC_FILE) @echo "Coverage reports generated:"