Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a73ef71
Update .gitignore to include .scratch directory
teresaromero May 28, 2026
a246398
internal/validation: add ValidateSourceFromPath, ValidateBuiltFromPat…
teresaromero May 28, 2026
4942eac
cmd/lint: migrate validateSourceCommandAction to ValidateSourceFromPath
teresaromero May 28, 2026
b1e1a84
internal/validation: document error filtering in godoc for new functions
teresaromero May 28, 2026
b52e130
cmd/builder,installer: migrate call sites to ValidateBuilt* functions
teresaromero May 28, 2026
5a34ddb
internal/validation: remove dead ValidateFromPath/Zip and ValidateAnd…
teresaromero May 28, 2026
9cf389c
internal/validation: add tests for new validation functions
teresaromero May 28, 2026
3849d7b
go.mod: remove local package-spec replace directive
teresaromero May 28, 2026
e3e5bd5
go.mod: pin package-spec to PR #1175 via local replace
teresaromero May 28, 2026
8703b2b
internal/validation: fix filter-error loss and zip root entry count
teresaromero May 28, 2026
d91ca7e
Merge branch 'main' of github.com:elastic/elastic-package into 549-va…
teresaromero Jun 2, 2026
232d6c6
Merge branch 'main' of github.com:elastic/elastic-package into 549-va…
teresaromero Jun 16, 2026
86536ed
Refactor validation modes in internal validation package
teresaromero Jun 16, 2026
4f5faa4
Remove .scratch entry from .gitignore
teresaromero Jun 16, 2026
acda4eb
Enhance validation tests for built packages
teresaromero Jun 16, 2026
b98f50d
Merge branch 'main' of github.com:elastic/elastic-package into 549-va…
teresaromero Jun 22, 2026
90099fe
chore: remove local replace directive for package-spec in go.mod
teresaromero Jun 22, 2026
f243dad
fix: restore logger import in validation.go
teresaromero Jun 22, 2026
3a1e196
Merge branch 'main' into 549-validation-modes
teresaromero Jun 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/lint.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func validateSourceCommandAction(cmd *cobra.Command, args []string) error {
if err != nil {
return fmt.Errorf("locating package root failed: %w", err)
}
errs, skipped := validation.ValidateAndFilterFromPath(packageRoot)
errs, skipped := validation.ValidateSourceFromPath(packageRoot)
if skipped != nil {
logger.Infof("Skipped errors: %v", skipped)
}
Expand Down
4 changes: 2 additions & 2 deletions internal/builder/packages.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ func BuildPackage(options BuildOptions) (string, error) {
}

logger.Debugf("Validating built package (path: %s)", buildPackageRoot)
errs, skipped := validation.ValidateAndFilterFromPath(buildPackageRoot)
errs, skipped := validation.ValidateBuiltFromPath(buildPackageRoot)
if skipped != nil {
logger.Infof("Skipped errors: %v", skipped)
}
Expand Down Expand Up @@ -300,7 +300,7 @@ func buildZippedPackage(options BuildOptions, buildPackageRoot string) (string,
logger.Debug("Skip validation of the built .zip package")
} else {
logger.Debugf("Validating built .zip package (path: %s)", zippedPackagePath)
errs, skipped := validation.ValidateAndFilterFromZip(zippedPackagePath)
errs, skipped := validation.ValidateBuiltFromZip(zippedPackagePath)
if skipped != nil {
logger.Infof("Skipped errors: %v", skipped)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/packages/installer/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func NewForPackage(options Options) (Installer, error) {
logger.Debug("Skip validation of the built .zip package")
} else {
logger.Debugf("Validating built .zip package (path: %s)", options.ZipPath)
errs, skipped := validation.ValidateAndFilterFromZip(options.ZipPath)
errs, skipped := validation.ValidateBuiltFromZip(options.ZipPath)
if skipped != nil {
logger.Infof("Skipped errors: %v", skipped)
}
Expand Down
3 changes: 3 additions & 0 deletions internal/validation/testdata/built_package/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Elastic License 2.0

URL: https://www.elastic.co/licensing/elastic-license
6 changes: 6 additions & 0 deletions internal/validation/testdata/built_package/changelog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# newer versions go on top
- version: "0.0.1"
changes:
- description: Initial draft of the package
type: enhancement
link: https://github.com/elastic/integrations/pull/1
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
paths:
{{#each paths}}
- {{this}}
{{/each}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
- name: data_stream.type
type: constant_keyword
description: Data stream type.
- name: data_stream.dataset
type: constant_keyword
description: Data stream dataset.
- name: data_stream.namespace
type: constant_keyword
description: Data stream namespace.
- name: "@timestamp"
type: date
description: Event timestamp.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- name: message
type: keyword
description: Log message.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
title: Events
type: logs
elasticsearch:
index_template:
mappings:
dynamic_templates:
- _embedded_ecs:
match_mapping_type: string
mapping:
type: keyword
streams:
- input: logfile
title: Events logs
description: Collect events log data
vars:
- name: paths
type: text
title: Paths
multi: true
required: true
show_user: true
default:
- /var/log/*.log
3 changes: 3 additions & 0 deletions internal/validation/testdata/built_package/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Built Package

Minimal built-package fixture for ValidateBuiltFromPath/Zip tests.
23 changes: 23 additions & 0 deletions internal/validation/testdata/built_package/manifest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
format_version: 3.6.0
name: built_package
title: Built Package
description: Minimal built-package fixture for ValidateBuiltFromPath/Zip tests.
version: 0.0.1
type: integration
source:
license: "Apache-2.0"
conditions:
kibana:
version: '^8.0.0 || ^9.0.0'
policy_templates:
- name: events
title: Events logs
description: Collect events data
inputs:
- type: logfile
title: Collect events logs
description: Collecting events log data
multi: false
owner:
github: elastic/foobar
type: community
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Elastic License 2.0

URL: https://www.elastic.co/licensing/elastic-license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# {{package.title}}

{{package.description}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# newer versions go on top
- version: "0.0.1"
changes:
- description: Initial draft of the package
type: enhancement
link: https://github.com/elastic/integrations/pull/1
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
paths:
{{#each paths}}
- {{this}}
{{/each}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
- name: data_stream.type
type: constant_keyword
description: Data stream type.
- name: data_stream.dataset
type: constant_keyword
description: Data stream dataset.
- name: data_stream.namespace
type: constant_keyword
description: Data stream namespace.
- name: "@timestamp"
type: date
description: Event timestamp.
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
title: Events
type: logs
streams:
- package: test_input
title: Events logs
description: Collect events log data via composable input
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Composable Source Package

Minimal composable source-package fixture for ValidateSourceFromPath tests.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
format_version: 3.6.0
name: composable_source_package
title: Composable Source Package
description: "Minimal composable source-package fixture; uses package: references that are source-only."
version: 0.0.1
type: integration
source:
license: "Apache-2.0"
conditions:
kibana:
version: '^8.0.0 || ^9.0.0'
requires:
input:
- package: test_input
version: "1.0.0"
policy_templates:
- name: events
title: Events logs
description: Collect events data
inputs:
- package: test_input
title: Collect events logs
description: Collecting events log data via composable input
owner:
github: elastic/foobar
type: community
3 changes: 3 additions & 0 deletions internal/validation/testdata/source_package/LICENSE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Elastic License 2.0

URL: https://www.elastic.co/licensing/elastic-license
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# {{package.title}}

{{package.description}}
6 changes: 6 additions & 0 deletions internal/validation/testdata/source_package/changelog.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# newer versions go on top
- version: "0.0.1"
changes:
- description: Initial draft of the package
type: enhancement
link: https://github.com/elastic/integrations/pull/1
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
paths:
{{#each paths}}
- {{this}}
{{/each}}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
- name: data_stream.type
type: constant_keyword
description: Data stream type.
- name: data_stream.dataset
type: constant_keyword
description: Data stream dataset.
- name: data_stream.namespace
type: constant_keyword
description: Data stream namespace.
- name: "@timestamp"
type: date
description: Event timestamp.
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- name: message
type: keyword
description: Log message.
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
title: Events
type: logs
streams:
- input: logfile
title: Events logs
description: Collect events log data
vars:
- name: paths
type: text
title: Paths
multi: true
required: true
show_user: true
default:
- /var/log/*.log
3 changes: 3 additions & 0 deletions internal/validation/testdata/source_package/docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Source Package

Minimal source-package fixture for ValidateSourceFromPath tests.
23 changes: 23 additions & 0 deletions internal/validation/testdata/source_package/manifest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
format_version: 3.6.0
name: source_package
title: Source Package
description: Minimal source-package fixture for ValidateSourceFromPath tests.
version: 0.0.1
type: integration
source:
license: "Apache-2.0"
conditions:
kibana:
version: '^8.0.0 || ^9.0.0'
policy_templates:
- name: events
title: Events logs
description: Collect events data
inputs:
- type: logfile
title: Collect events logs
description: Collecting events log data
multi: false
owner:
github: elastic/foobar
type: community
70 changes: 53 additions & 17 deletions internal/validation/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,59 +13,94 @@ import (

"github.com/elastic/package-spec/v3/code/go/pkg/specerrors"
"github.com/elastic/package-spec/v3/code/go/pkg/validator"

"github.com/elastic/elastic-package/internal/logger"
)

func ValidateFromPath(rootPath string) error {
return validator.ValidateFromPath(rootPath)
// ValidateSourceFromPath validates a package source tree — checked out from version
// control, not yet built. Source-only artifacts (_dev/, .link files, external: ecs
// references) are permitted. Validation errors are filtered against the package's
// validation.yml config; the first return value is the remaining errors after filtering,
// the second is the errors that were filtered out.
func ValidateSourceFromPath(packageRoot string) (error, error) {
return validateFromPath(validator.SourceMode, packageRoot)
}

func ValidateFromZip(packagePath string) error {
return validator.ValidateFromZip(packagePath)
// ValidateBuiltFromPath validates a built (unzipped) package directory. Source-only
// artifacts (_dev/, .link files, external: ecs references) are rejected. Validation
// errors are filtered against the package's validation.yml config; the first return
// value is the remaining errors after filtering, the second is the errors that were
// filtered out.
func ValidateBuiltFromPath(packageRoot string) (error, error) {
return validateFromPath(validator.BuildMode, packageRoot)
}

func ValidateAndFilterFromPath(packageRoot string) (error, error) {
allErrors := validator.ValidateFromPath(packageRoot)
func validateFromPath(mode validator.Mode, packageRoot string) (error, error) {
v, err := validator.New(mode)
if err != nil {
return fmt.Errorf("failed to create validator: %w", err), nil
}
allErrors := v.ValidateFromPath(packageRoot)
if allErrors == nil {
return nil, nil
}

fsys := os.DirFS(packageRoot)
result, err := filterErrors(allErrors, fsys)
if err != nil {
return err, nil
logger.Debugf("failed to filter validation errors: %v", err)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

at this point allErrors is not nil; so in case any error happens during the filering, they were ignored... i've added a debug log with the error and return allErrors unfiltered; same un the zip case

return allErrors, nil
}
return result.Processed, result.Removed
}

func ValidateAndFilterFromZip(zipPackagePath string) (error, error) {
allErrors := validator.ValidateFromZip(zipPackagePath)
// ValidateBuiltFromZip validates a built package zip archive. Zip files are always
// treated as built artifacts; source-only artifacts are rejected. Validation errors
// are filtered against the package's validation.yml config; the first return value
// is the remaining errors after filtering, the second is the errors that were
// filtered out.
func ValidateBuiltFromZip(zipPackagePath string) (error, error) {
v, err := validator.New(validator.BuildMode)
if err != nil {
return fmt.Errorf("failed to create validator: %w", err), nil
}

allErrors := v.ValidateFromZip(zipPackagePath)
if allErrors == nil {
return nil, nil
}

// Open a separate, independent zip reader for filterErrors.
fsys, err := zip.OpenReader(zipPackagePath)
if err != nil {
return fmt.Errorf("failed to open zip file (%s): %w", zipPackagePath, err), nil
logger.Debugf("failed to open zip for filter: %v", err)
return allErrors, nil
}
defer fsys.Close()

// fsFromPackageZip navigates into the single package subdirectory so that
// filterErrors can locate validation.yml at the package root, not the zip root.
fsZip, err := fsFromPackageZip(fsys)
if err != nil {
return fmt.Errorf("failed to extract filesystem from zip file (%s): %w", zipPackagePath, err), nil
logger.Debugf("failed to extract filesystem from zip for filter: %v", err)
return allErrors, nil
}

result, err := filterErrors(allErrors, fsZip)
if err != nil {
return err, nil
logger.Debugf("failed to filter validation errors: %v", err)
return allErrors, nil
}
return result.Processed, result.Removed
}

func fsFromPackageZip(fsys fs.FS) (fs.FS, error) {
dirs, err := fs.ReadDir(fsys, ".")
entries, err := fs.ReadDir(fsys, ".")
if err != nil {
return nil, fmt.Errorf("failed to read root directory in zip file fs: %w", err)
}
var dirs []fs.DirEntry
for _, e := range entries {
if e.IsDir() {
dirs = append(dirs, e)
}
}
if len(dirs) != 1 {
return nil, fmt.Errorf("a single directory is expected in zip file, %d found", len(dirs))
}
Expand All @@ -77,6 +112,7 @@ func fsFromPackageZip(fsys fs.FS) (fs.FS, error) {
return subDir, nil
}

// TODO: follow-up issue — move this logic into specerrors as an exported function so consumers don't reimplement it.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

filed issue #3618

func filterErrors(allErrors error, fsys fs.FS) (specerrors.FilterResult, error) {
var errs specerrors.ValidationErrors
if !errors.As(allErrors, &errs) {
Expand Down
Loading