From d6d204ef166cf87ad792810ca84c1eb160b19358 Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Fri, 28 Nov 2025 09:46:30 +0100 Subject: [PATCH 01/26] Add Handlebars template validation and corresponding tests --- .../semantic/validate_hbs_templates.go | 79 +++++++++++++++++++ .../semantic/validate_hbs_templates_test.go | 46 +++++++++++ code/go/internal/validator/spec.go | 1 + go.mod | 3 + go.sum | 10 +++ 5 files changed, 139 insertions(+) create mode 100644 code/go/internal/validator/semantic/validate_hbs_templates.go create mode 100644 code/go/internal/validator/semantic/validate_hbs_templates_test.go diff --git a/code/go/internal/validator/semantic/validate_hbs_templates.go b/code/go/internal/validator/semantic/validate_hbs_templates.go new file mode 100644 index 00000000..cacdea8c --- /dev/null +++ b/code/go/internal/validator/semantic/validate_hbs_templates.go @@ -0,0 +1,79 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package semantic + +import ( + "errors" + "io/fs" + "strings" + + "github.com/elastic/package-spec/v3/code/go/internal/fspath" + "github.com/elastic/package-spec/v3/code/go/pkg/specerrors" + "github.com/mailgun/raymond/v2" +) + +var ( + ErrInvalidHandlebarsTemplate = errors.New("invalid handlebars template") +) + +func ValidateHandlebarsFiles(fsys fspath.FS) specerrors.ValidationErrors { + entries, err := getHandlebarsFiles(fsys) + if err != nil { + return specerrors.ValidationErrors{ + specerrors.NewStructuredErrorf( + "error finding Handlebars files: %w", err, + ), + } + } + if len(entries) == 0 { + return nil + } + + var validationErrors specerrors.ValidationErrors + for _, entry := range entries { + if !strings.HasSuffix(entry, ".hbs") { + continue + } + + filePath := fsys.Path(entry) + err := validateFile(filePath) + if err != nil { + validationErrors = append(validationErrors, specerrors.NewStructuredErrorf( + "%w: file %s: %w", ErrInvalidHandlebarsTemplate, entry, err, + )) + } + } + + return validationErrors +} + +// validateFile validates a single Handlebars file located at filePath. +// it parses the file using the raymond library to check for syntax errors. +func validateFile(filePath string) error { + if filePath == "" { + return nil + } + _, err := raymond.ParseFile(filePath) + return err +} + +// getHandlebarsFiles returns all Handlebars (.hbs) files in the package filesystem. +// It searches in both the package root and data stream directories under the agent folder. +func getHandlebarsFiles(fsys fspath.FS) ([]string, error) { + entries := make([]string, 0) + pkgEntries, err := fs.Glob(fsys, "agent/**/*.hbs") + if err != nil && !errors.Is(err, fs.ErrNotExist) { + return nil, err + } + entries = append(entries, pkgEntries...) + + dataStreamEntries, err := fs.Glob(fsys, "data_stream/*/agent/**/*.hbs") + if err != nil && !errors.Is(err, fs.ErrNotExist) { + return nil, err + } + entries = append(entries, dataStreamEntries...) + + return entries, nil +} diff --git a/code/go/internal/validator/semantic/validate_hbs_templates_test.go b/code/go/internal/validator/semantic/validate_hbs_templates_test.go new file mode 100644 index 00000000..cef1a28d --- /dev/null +++ b/code/go/internal/validator/semantic/validate_hbs_templates_test.go @@ -0,0 +1,46 @@ +// Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +// or more contributor license agreements. Licensed under the Elastic License; +// you may not use this file except in compliance with the Elastic License. + +package semantic + +import ( + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestValidateFile(t *testing.T) { + + t.Run("no handlebars files", func(t *testing.T) { + err := validateFile("") + assert.NoError(t, err) + }) + + t.Run("valid handlebars files", func(t *testing.T) { + tmp := t.TempDir() + + filePath := filepath.Join(tmp, "template.yml.hbs") + err := os.WriteFile(filePath, []byte("{{#if foo}}hello{{/if}}"), 0o644) + require.NoError(t, err) + + errs := validateFile(filePath) + assert.Empty(t, errs) + }) + + t.Run("invalid handlebars files", func(t *testing.T) { + tmp := t.TempDir() + + filePath := filepath.Join(tmp, "bad.hbs") + // Unclosed block should produce a parse error. + err := os.WriteFile(filePath, []byte("{{#if foo}}no end"), 0o644) + require.NoError(t, err) + + err = validateFile(filePath) + require.Error(t, err) + }) + +} diff --git a/code/go/internal/validator/spec.go b/code/go/internal/validator/spec.go index 3ac4e57f..56187cc0 100644 --- a/code/go/internal/validator/spec.go +++ b/code/go/internal/validator/spec.go @@ -224,6 +224,7 @@ func (s Spec) rules(pkgType string, rootSpec spectypes.ItemSpec) validationRules {fn: semantic.ValidateInputPackagesPolicyTemplates, types: []string{"input"}}, {fn: semantic.ValidateMinimumAgentVersion}, {fn: semantic.ValidateIntegrationPolicyTemplates, types: []string{"integration"}}, + {fn: semantic.ValidateHandlebarsFiles, types: []string{"integration", "input"}}, } var validationRules validationRules diff --git a/go.mod b/go.mod index e110d48f..a749446d 100644 --- a/go.mod +++ b/go.mod @@ -13,6 +13,7 @@ require ( github.com/evanphx/json-patch/v5 v5.9.11 github.com/go-viper/mapstructure/v2 v2.4.0 github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 + github.com/mailgun/raymond/v2 v2.0.48 github.com/otiai10/copy v1.14.1 github.com/stretchr/testify v1.11.1 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 @@ -24,6 +25,8 @@ require ( honnef.co/go/tools v0.6.1 ) +require github.com/sirupsen/logrus v1.8.1 // indirect + require ( github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect github.com/PaesslerAG/gval v1.0.0 // indirect diff --git a/go.sum b/go.sum index 295e7f05..002f3fff 100644 --- a/go.sum +++ b/go.sum @@ -43,6 +43,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw= +github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -58,10 +60,14 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= @@ -86,6 +92,7 @@ golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= @@ -106,6 +113,9 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/gotestsum v1.13.0 h1:+Lh454O9mu9AMG1APV4o0y7oDYKyik/3kBOiCqiEpRo= From ea6d4bd06cecbb8cfc0c49433ba11fd4626fd985 Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Fri, 28 Nov 2025 09:58:08 +0100 Subject: [PATCH 02/26] add validator test cases with bad packages --- code/go/pkg/validator/validator_test.go | 22 ++ test/packages/bad_input_hbs/LICENSE.txt | 93 +++++++ .../bad_input_hbs/_dev/build/docs/README.md | 101 +++++++ .../bad_input_hbs/agent/input/input.yml.hbs | 9 + test/packages/bad_input_hbs/changelog.yml | 6 + test/packages/bad_input_hbs/docs/README.md | 101 +++++++ .../bad_input_hbs/fields/base-fields.yml | 12 + .../bad_input_hbs/img/sample-logo.svg | 1 + .../bad_input_hbs/img/sample-screenshot.png | Bin 0 -> 18849 bytes test/packages/bad_input_hbs/manifest.yml | 47 ++++ test/packages/bad_integration_hbs/LICENSE.txt | 93 +++++++ .../_dev/build/docs/README.md | 101 +++++++ .../bad_integration_hbs/changelog.yml | 6 + .../foo/agent/stream/filestream.yml.hbs | 43 +++ .../elasticsearch/ingest_pipeline/default.yml | 10 + .../data_stream/foo/fields/base-fields.yml | 12 + .../data_stream/foo/manifest.yml | 256 ++++++++++++++++++ .../bad_integration_hbs/docs/README.md | 101 +++++++ .../bad_integration_hbs/img/sample-logo.svg | 1 + .../img/sample-screenshot.png | Bin 0 -> 18849 bytes .../packages/bad_integration_hbs/manifest.yml | 37 +++ .../bad_integration_hbs/sample_event.json | 3 + 22 files changed, 1055 insertions(+) create mode 100644 test/packages/bad_input_hbs/LICENSE.txt create mode 100644 test/packages/bad_input_hbs/_dev/build/docs/README.md create mode 100644 test/packages/bad_input_hbs/agent/input/input.yml.hbs create mode 100644 test/packages/bad_input_hbs/changelog.yml create mode 100644 test/packages/bad_input_hbs/docs/README.md create mode 100644 test/packages/bad_input_hbs/fields/base-fields.yml create mode 100644 test/packages/bad_input_hbs/img/sample-logo.svg create mode 100644 test/packages/bad_input_hbs/img/sample-screenshot.png create mode 100644 test/packages/bad_input_hbs/manifest.yml create mode 100644 test/packages/bad_integration_hbs/LICENSE.txt create mode 100644 test/packages/bad_integration_hbs/_dev/build/docs/README.md create mode 100644 test/packages/bad_integration_hbs/changelog.yml create mode 100644 test/packages/bad_integration_hbs/data_stream/foo/agent/stream/filestream.yml.hbs create mode 100644 test/packages/bad_integration_hbs/data_stream/foo/elasticsearch/ingest_pipeline/default.yml create mode 100644 test/packages/bad_integration_hbs/data_stream/foo/fields/base-fields.yml create mode 100644 test/packages/bad_integration_hbs/data_stream/foo/manifest.yml create mode 100644 test/packages/bad_integration_hbs/docs/README.md create mode 100644 test/packages/bad_integration_hbs/img/sample-logo.svg create mode 100644 test/packages/bad_integration_hbs/img/sample-screenshot.png create mode 100644 test/packages/bad_integration_hbs/manifest.yml create mode 100644 test/packages/bad_integration_hbs/sample_event.json diff --git a/code/go/pkg/validator/validator_test.go b/code/go/pkg/validator/validator_test.go index 4eb98109..f26e1995 100644 --- a/code/go/pkg/validator/validator_test.go +++ b/code/go/pkg/validator/validator_test.go @@ -912,6 +912,28 @@ func TestLinksAreBlocked(t *testing.T) { t.Error("links should not be allowed in package") } +func TestValidateHandlebarsFiles(t *testing.T) { + tests := map[string]string{ + "bad_input_hbs": "invalid handlebars template: file agent/input/input.yml.hbs: Parse error on line 10:\nExpecting OpenEndBlock, got: 'EOF'", + "bad_integration_hbs": "invalid handlebars template: file data_stream/foo/agent/stream/filestream.yml.hbs: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'", + } + + for pkgName, expectedErrorMessage := range tests { + t.Run(pkgName, func(t *testing.T) { + errs := ValidateFromPath(filepath.Join("..", "..", "..", "..", "test", "packages", pkgName)) + require.Error(t, errs) + vErrs, ok := errs.(specerrors.ValidationErrors) + require.True(t, ok) + + var errMessages []string + for _, vErr := range vErrs { + errMessages = append(errMessages, vErr.Error()) + } + require.Contains(t, errMessages, expectedErrorMessage) + }) + } +} + func requireErrorMessage(t *testing.T, pkgName string, invalidItemsPerFolder map[string][]string, expectedErrorMessage string) { pkgRootPath := filepath.Join("..", "..", "..", "..", "test", "packages", pkgName) diff --git a/test/packages/bad_input_hbs/LICENSE.txt b/test/packages/bad_input_hbs/LICENSE.txt new file mode 100644 index 00000000..809108b8 --- /dev/null +++ b/test/packages/bad_input_hbs/LICENSE.txt @@ -0,0 +1,93 @@ +Elastic License 2.0 + +URL: https://www.elastic.co/licensing/elastic-license + +## Acceptance + +By using the software, you agree to all of the terms and conditions below. + +## Copyright License + +The licensor grants you a non-exclusive, royalty-free, worldwide, +non-sublicensable, non-transferable license to use, copy, distribute, make +available, and prepare derivative works of the software, in each case subject to +the limitations and conditions below. + +## Limitations + +You may not provide the software to third parties as a hosted or managed +service, where the service provides users with access to any substantial set of +the features or functionality of the software. + +You may not move, change, disable, or circumvent the license key functionality +in the software, and you may not remove or obscure any functionality in the +software that is protected by the license key. + +You may not alter, remove, or obscure any licensing, copyright, or other notices +of the licensor in the software. Any use of the licensor’s trademarks is subject +to applicable law. + +## Patents + +The licensor grants you a license, under any patent claims the licensor can +license, or becomes able to license, to make, have made, use, sell, offer for +sale, import and have imported the software, in each case subject to the +limitations and conditions in this license. This license does not cover any +patent claims that you cause to be infringed by modifications or additions to +the software. If you or your company make any written claim that the software +infringes or contributes to infringement of any patent, your patent license for +the software granted under these terms ends immediately. If your company makes +such a claim, your patent license ends immediately for work on behalf of your +company. + +## Notices + +You must ensure that anyone who gets a copy of any part of the software from you +also gets a copy of these terms. + +If you modify the software, you must include in any modified copies of the +software prominent notices stating that you have modified the software. + +## No Other Rights + +These terms do not imply any licenses other than those expressly granted in +these terms. + +## Termination + +If you use the software in violation of these terms, such use is not licensed, +and your licenses will automatically terminate. If the licensor provides you +with a notice of your violation, and you cease all violation of this license no +later than 30 days after you receive that notice, your licenses will be +reinstated retroactively. However, if you violate these terms after such +reinstatement, any additional violation of these terms will cause your licenses +to terminate automatically and permanently. + +## No Liability + +*As far as the law allows, the software comes as is, without any warranty or +condition, and the licensor will not be liable to you for any damages arising +out of these terms or the use or nature of the software, under any kind of +legal claim.* + +## Definitions + +The **licensor** is the entity offering these terms, and the **software** is the +software the licensor makes available under these terms, including any portion +of it. + +**you** refers to the individual or entity agreeing to these terms. + +**your company** is any legal entity, sole proprietorship, or other kind of +organization that you work for, plus all organizations that have control over, +are under the control of, or are under common control with that +organization. **control** means ownership of substantially all the assets of an +entity, or the power to direct its management and policies by vote, contract, or +otherwise. Control can be direct or indirect. + +**your licenses** are all the licenses granted to you for the software under +these terms. + +**use** means anything you do with the software requiring one of your licenses. + +**trademark** means trademarks, service marks, and similar rights. diff --git a/test/packages/bad_input_hbs/_dev/build/docs/README.md b/test/packages/bad_input_hbs/_dev/build/docs/README.md new file mode 100644 index 00000000..a1114799 --- /dev/null +++ b/test/packages/bad_input_hbs/_dev/build/docs/README.md @@ -0,0 +1,101 @@ +{{- generatedHeader }} +{{/* +This template can be used as a starting point for writing documentation for your new integration. For each section, fill in the details +described in the comments. + +Find more detailed documentation guidelines in https://www.elastic.co/docs/extend/integrations/documentation-guidelines +*/}} +# bad input hbs Integration for Elastic + +## Overview +{{/* Complete this section with a short summary of what data this integration collects and what use cases it enables */}} +The bad input hbs integration for Elastic enables collection of ... +This integration facilitates ... + +### Compatibility +{{/* Complete this section with information on what 3rd party software or hardware versions this integration is compatible with */}} +This integration is compatible with ... + +### How it works +{{/* Add a high level overview on how this integration works. For example, does it collect data from API calls or recieving data from a network or file.*/}} + +## What data does this integration collect? +{{/* Complete this section with information on what types of data the integration collects, and link to reference documentation if available */}} +The bad input hbs integration collects log messages of the following types: +* ... + +### Supported use cases +{{/* Add details on the use cases that can be enabled by using this integration. Explain why a user would want to install and use this integration. */}} + +## What do I need to use this integration? +{{/* List any vendor-specific prerequisites needed before starting to install the integration. */}} + +## How do I deploy this integration? + +### Agent-based deployment + +Elastic Agent must be installed. For more details, check the Elastic Agent [installation instructions](docs-content://reference/fleet/install-elastic-agents.md). You can install only one Elastic Agent per host. + +Elastic Agent is required to stream data from the syslog or log file receiver and ship the data to Elastic, where the events will then be processed via the integration's ingest pipelines. + +{{/* If agentless is available for this integration, we'll want to include that here as well. +### Agentless deployment + +Agentless deployments are only supported in Elastic Serverless and Elastic Cloud environments. Agentless deployments provide a means to ingest data while avoiding the orchestration, management, and maintenance needs associated with standard ingest infrastructure. Using an agentless deployment makes manual agent deployment unnecessary, allowing you to focus on your data instead of the agent that collects it. + +For more information, refer to [Agentless integrations](https://www.elastic.co/guide/en/serverless/current/security-agentless-integrations.html) and [Agentless integrations FAQ](https://www.elastic.co/guide/en/serverless/current/agentless-integration-troubleshooting.html) +*/}} + +### Onboard / configure +{{/* List the steps that will need to be followed in order to completely set up a working integration. +For integrations that support multiple input types, be sure to add steps for all inputs. +*/}} + +### Validation +{{/* How can the user test whether the integration is working? Including example commands or test files if applicable */}} + +## Troubleshooting + +For help with Elastic ingest tools, check [Common problems](https://www.elastic.co/docs/troubleshoot/ingest/fleet/common-problems). +{{/* +Add any vendor specific troubleshooting here. + +Are there common issues or “gotchas” for deploying this integration? If so, how can they be resolved? +If applicable, links to the third-party software’s troubleshooting documentation. +*/}} + +## Scaling + +For more information on architectures that can be used for scaling this integration, check the [Ingest Architectures](https://www.elastic.co/docs/manage-data/ingest/ingest-reference-architectures) documentation. +{{/* Add any vendor specific scaling information here */}} + +## Reference +{{/* Repeat for each data stream of the current type +### {Data stream name} + +The `{data stream name}` data stream provides events from {source} of the following types: {list types}. + +For each data_stream_name, include an optional summary of the datastream, the exported fields reference table and the sample event. + +The fields template function will be replaced by a generated list of all fields from the `fields/` directory of the data stream when building the integration. + +#### {data stream name} fields + +To include a generated list of fields from the `fields/` directory, uncomment and use: +{{ fields "data_stream_name" }} + +The event template function will be replace by a sample event, taken from `sample_event.json`, when building this integration. + +To include a sample event from `sample_event.json`, uncomment and use: +{{ event "data_stream_name" }} + +*/}} + +### Inputs used +{{/* All inputs used by this package will be automatically listed here. */}} +{{ inputDocs }} + +### API usage +{{/* For integrations that use APIs to collect data, document all the APIs that are used, and link to relevent information */}} +These APIs are used with this integration: +* ... diff --git a/test/packages/bad_input_hbs/agent/input/input.yml.hbs b/test/packages/bad_input_hbs/agent/input/input.yml.hbs new file mode 100644 index 00000000..3bd54a4d --- /dev/null +++ b/test/packages/bad_input_hbs/agent/input/input.yml.hbs @@ -0,0 +1,9 @@ +data_stream: + dataset: {{data_stream.dataset}} +paths: +{{#each paths as |path i|}} + - {{path}} +exclude_files: [".gz$"] +processors: + - add_locale: ~ + diff --git a/test/packages/bad_input_hbs/changelog.yml b/test/packages/bad_input_hbs/changelog.yml new file mode 100644 index 00000000..bb0320a5 --- /dev/null +++ b/test/packages/bad_input_hbs/changelog.yml @@ -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 # FIXME Replace with the real PR link diff --git a/test/packages/bad_input_hbs/docs/README.md b/test/packages/bad_input_hbs/docs/README.md new file mode 100644 index 00000000..a1114799 --- /dev/null +++ b/test/packages/bad_input_hbs/docs/README.md @@ -0,0 +1,101 @@ +{{- generatedHeader }} +{{/* +This template can be used as a starting point for writing documentation for your new integration. For each section, fill in the details +described in the comments. + +Find more detailed documentation guidelines in https://www.elastic.co/docs/extend/integrations/documentation-guidelines +*/}} +# bad input hbs Integration for Elastic + +## Overview +{{/* Complete this section with a short summary of what data this integration collects and what use cases it enables */}} +The bad input hbs integration for Elastic enables collection of ... +This integration facilitates ... + +### Compatibility +{{/* Complete this section with information on what 3rd party software or hardware versions this integration is compatible with */}} +This integration is compatible with ... + +### How it works +{{/* Add a high level overview on how this integration works. For example, does it collect data from API calls or recieving data from a network or file.*/}} + +## What data does this integration collect? +{{/* Complete this section with information on what types of data the integration collects, and link to reference documentation if available */}} +The bad input hbs integration collects log messages of the following types: +* ... + +### Supported use cases +{{/* Add details on the use cases that can be enabled by using this integration. Explain why a user would want to install and use this integration. */}} + +## What do I need to use this integration? +{{/* List any vendor-specific prerequisites needed before starting to install the integration. */}} + +## How do I deploy this integration? + +### Agent-based deployment + +Elastic Agent must be installed. For more details, check the Elastic Agent [installation instructions](docs-content://reference/fleet/install-elastic-agents.md). You can install only one Elastic Agent per host. + +Elastic Agent is required to stream data from the syslog or log file receiver and ship the data to Elastic, where the events will then be processed via the integration's ingest pipelines. + +{{/* If agentless is available for this integration, we'll want to include that here as well. +### Agentless deployment + +Agentless deployments are only supported in Elastic Serverless and Elastic Cloud environments. Agentless deployments provide a means to ingest data while avoiding the orchestration, management, and maintenance needs associated with standard ingest infrastructure. Using an agentless deployment makes manual agent deployment unnecessary, allowing you to focus on your data instead of the agent that collects it. + +For more information, refer to [Agentless integrations](https://www.elastic.co/guide/en/serverless/current/security-agentless-integrations.html) and [Agentless integrations FAQ](https://www.elastic.co/guide/en/serverless/current/agentless-integration-troubleshooting.html) +*/}} + +### Onboard / configure +{{/* List the steps that will need to be followed in order to completely set up a working integration. +For integrations that support multiple input types, be sure to add steps for all inputs. +*/}} + +### Validation +{{/* How can the user test whether the integration is working? Including example commands or test files if applicable */}} + +## Troubleshooting + +For help with Elastic ingest tools, check [Common problems](https://www.elastic.co/docs/troubleshoot/ingest/fleet/common-problems). +{{/* +Add any vendor specific troubleshooting here. + +Are there common issues or “gotchas” for deploying this integration? If so, how can they be resolved? +If applicable, links to the third-party software’s troubleshooting documentation. +*/}} + +## Scaling + +For more information on architectures that can be used for scaling this integration, check the [Ingest Architectures](https://www.elastic.co/docs/manage-data/ingest/ingest-reference-architectures) documentation. +{{/* Add any vendor specific scaling information here */}} + +## Reference +{{/* Repeat for each data stream of the current type +### {Data stream name} + +The `{data stream name}` data stream provides events from {source} of the following types: {list types}. + +For each data_stream_name, include an optional summary of the datastream, the exported fields reference table and the sample event. + +The fields template function will be replaced by a generated list of all fields from the `fields/` directory of the data stream when building the integration. + +#### {data stream name} fields + +To include a generated list of fields from the `fields/` directory, uncomment and use: +{{ fields "data_stream_name" }} + +The event template function will be replace by a sample event, taken from `sample_event.json`, when building this integration. + +To include a sample event from `sample_event.json`, uncomment and use: +{{ event "data_stream_name" }} + +*/}} + +### Inputs used +{{/* All inputs used by this package will be automatically listed here. */}} +{{ inputDocs }} + +### API usage +{{/* For integrations that use APIs to collect data, document all the APIs that are used, and link to relevent information */}} +These APIs are used with this integration: +* ... diff --git a/test/packages/bad_input_hbs/fields/base-fields.yml b/test/packages/bad_input_hbs/fields/base-fields.yml new file mode 100644 index 00000000..7c798f45 --- /dev/null +++ b/test/packages/bad_input_hbs/fields/base-fields.yml @@ -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. diff --git a/test/packages/bad_input_hbs/img/sample-logo.svg b/test/packages/bad_input_hbs/img/sample-logo.svg new file mode 100644 index 00000000..6268dd88 --- /dev/null +++ b/test/packages/bad_input_hbs/img/sample-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/packages/bad_input_hbs/img/sample-screenshot.png b/test/packages/bad_input_hbs/img/sample-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..d7a56a3ecc078c38636698cefba33f86291dd178 GIT binary patch literal 18849 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

}qal5$moSACwfNXLXG5|3R0AtBcN` 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 literal 0 HcmV?d00001 diff --git a/test/packages/bad_input_hbs/manifest.yml b/test/packages/bad_input_hbs/manifest.yml new file mode 100644 index 00000000..36c8c320 --- /dev/null +++ b/test/packages/bad_input_hbs/manifest.yml @@ -0,0 +1,47 @@ +format_version: 3.5.4 +name: bad_input_hbs +title: "bad input hbs" +version: 0.0.1 +source: + license: "Elastic-2.0" +description: "A package with wrong hbs template" +type: input +categories: + - config_management + - custom +conditions: + kibana: + version: "^9.2.1" + elastic: + subscription: "basic" +screenshots: + - src: /img/sample-screenshot.png + title: Sample screenshot + size: 600x600 + type: image/png +icons: + - src: /img/sample-logo.svg + title: Sample logo + size: 32x32 + type: image/svg+xml +policy_templates: + - name: sample + type: logs + title: Sample logs + description: Collect sample logs + input: logfile + template_path: input.yml.hbs + vars: + - name: paths + type: text + title: Paths + multi: true + default: + - /var/log/*.log +elasticsearch: + index_template: + mappings: + subobjects: false +owner: + github: elastic/integrations + type: elastic diff --git a/test/packages/bad_integration_hbs/LICENSE.txt b/test/packages/bad_integration_hbs/LICENSE.txt new file mode 100644 index 00000000..809108b8 --- /dev/null +++ b/test/packages/bad_integration_hbs/LICENSE.txt @@ -0,0 +1,93 @@ +Elastic License 2.0 + +URL: https://www.elastic.co/licensing/elastic-license + +## Acceptance + +By using the software, you agree to all of the terms and conditions below. + +## Copyright License + +The licensor grants you a non-exclusive, royalty-free, worldwide, +non-sublicensable, non-transferable license to use, copy, distribute, make +available, and prepare derivative works of the software, in each case subject to +the limitations and conditions below. + +## Limitations + +You may not provide the software to third parties as a hosted or managed +service, where the service provides users with access to any substantial set of +the features or functionality of the software. + +You may not move, change, disable, or circumvent the license key functionality +in the software, and you may not remove or obscure any functionality in the +software that is protected by the license key. + +You may not alter, remove, or obscure any licensing, copyright, or other notices +of the licensor in the software. Any use of the licensor’s trademarks is subject +to applicable law. + +## Patents + +The licensor grants you a license, under any patent claims the licensor can +license, or becomes able to license, to make, have made, use, sell, offer for +sale, import and have imported the software, in each case subject to the +limitations and conditions in this license. This license does not cover any +patent claims that you cause to be infringed by modifications or additions to +the software. If you or your company make any written claim that the software +infringes or contributes to infringement of any patent, your patent license for +the software granted under these terms ends immediately. If your company makes +such a claim, your patent license ends immediately for work on behalf of your +company. + +## Notices + +You must ensure that anyone who gets a copy of any part of the software from you +also gets a copy of these terms. + +If you modify the software, you must include in any modified copies of the +software prominent notices stating that you have modified the software. + +## No Other Rights + +These terms do not imply any licenses other than those expressly granted in +these terms. + +## Termination + +If you use the software in violation of these terms, such use is not licensed, +and your licenses will automatically terminate. If the licensor provides you +with a notice of your violation, and you cease all violation of this license no +later than 30 days after you receive that notice, your licenses will be +reinstated retroactively. However, if you violate these terms after such +reinstatement, any additional violation of these terms will cause your licenses +to terminate automatically and permanently. + +## No Liability + +*As far as the law allows, the software comes as is, without any warranty or +condition, and the licensor will not be liable to you for any damages arising +out of these terms or the use or nature of the software, under any kind of +legal claim.* + +## Definitions + +The **licensor** is the entity offering these terms, and the **software** is the +software the licensor makes available under these terms, including any portion +of it. + +**you** refers to the individual or entity agreeing to these terms. + +**your company** is any legal entity, sole proprietorship, or other kind of +organization that you work for, plus all organizations that have control over, +are under the control of, or are under common control with that +organization. **control** means ownership of substantially all the assets of an +entity, or the power to direct its management and policies by vote, contract, or +otherwise. Control can be direct or indirect. + +**your licenses** are all the licenses granted to you for the software under +these terms. + +**use** means anything you do with the software requiring one of your licenses. + +**trademark** means trademarks, service marks, and similar rights. diff --git a/test/packages/bad_integration_hbs/_dev/build/docs/README.md b/test/packages/bad_integration_hbs/_dev/build/docs/README.md new file mode 100644 index 00000000..7cc03b51 --- /dev/null +++ b/test/packages/bad_integration_hbs/_dev/build/docs/README.md @@ -0,0 +1,101 @@ +{{- generatedHeader }} +{{/* +This template can be used as a starting point for writing documentation for your new integration. For each section, fill in the details +described in the comments. + +Find more detailed documentation guidelines in https://www.elastic.co/docs/extend/integrations/documentation-guidelines +*/}} +# bad integration hbs Integration for Elastic + +## Overview +{{/* Complete this section with a short summary of what data this integration collects and what use cases it enables */}} +The bad integration hbs integration for Elastic enables collection of ... +This integration facilitates ... + +### Compatibility +{{/* Complete this section with information on what 3rd party software or hardware versions this integration is compatible with */}} +This integration is compatible with ... + +### How it works +{{/* Add a high level overview on how this integration works. For example, does it collect data from API calls or recieving data from a network or file.*/}} + +## What data does this integration collect? +{{/* Complete this section with information on what types of data the integration collects, and link to reference documentation if available */}} +The bad integration hbs integration collects log messages of the following types: +* ... + +### Supported use cases +{{/* Add details on the use cases that can be enabled by using this integration. Explain why a user would want to install and use this integration. */}} + +## What do I need to use this integration? +{{/* List any vendor-specific prerequisites needed before starting to install the integration. */}} + +## How do I deploy this integration? + +### Agent-based deployment + +Elastic Agent must be installed. For more details, check the Elastic Agent [installation instructions](docs-content://reference/fleet/install-elastic-agents.md). You can install only one Elastic Agent per host. + +Elastic Agent is required to stream data from the syslog or log file receiver and ship the data to Elastic, where the events will then be processed via the integration's ingest pipelines. + +{{/* If agentless is available for this integration, we'll want to include that here as well. +### Agentless deployment + +Agentless deployments are only supported in Elastic Serverless and Elastic Cloud environments. Agentless deployments provide a means to ingest data while avoiding the orchestration, management, and maintenance needs associated with standard ingest infrastructure. Using an agentless deployment makes manual agent deployment unnecessary, allowing you to focus on your data instead of the agent that collects it. + +For more information, refer to [Agentless integrations](https://www.elastic.co/guide/en/serverless/current/security-agentless-integrations.html) and [Agentless integrations FAQ](https://www.elastic.co/guide/en/serverless/current/agentless-integration-troubleshooting.html) +*/}} + +### Onboard / configure +{{/* List the steps that will need to be followed in order to completely set up a working integration. +For integrations that support multiple input types, be sure to add steps for all inputs. +*/}} + +### Validation +{{/* How can the user test whether the integration is working? Including example commands or test files if applicable */}} + +## Troubleshooting + +For help with Elastic ingest tools, check [Common problems](https://www.elastic.co/docs/troubleshoot/ingest/fleet/common-problems). +{{/* +Add any vendor specific troubleshooting here. + +Are there common issues or “gotchas” for deploying this integration? If so, how can they be resolved? +If applicable, links to the third-party software’s troubleshooting documentation. +*/}} + +## Scaling + +For more information on architectures that can be used for scaling this integration, check the [Ingest Architectures](https://www.elastic.co/docs/manage-data/ingest/ingest-reference-architectures) documentation. +{{/* Add any vendor specific scaling information here */}} + +## Reference +{{/* Repeat for each data stream of the current type +### {Data stream name} + +The `{data stream name}` data stream provides events from {source} of the following types: {list types}. + +For each data_stream_name, include an optional summary of the datastream, the exported fields reference table and the sample event. + +The fields template function will be replaced by a generated list of all fields from the `fields/` directory of the data stream when building the integration. + +#### {data stream name} fields + +To include a generated list of fields from the `fields/` directory, uncomment and use: +{{ fields "data_stream_name" }} + +The event template function will be replace by a sample event, taken from `sample_event.json`, when building this integration. + +To include a sample event from `sample_event.json`, uncomment and use: +{{ event "data_stream_name" }} + +*/}} + +### Inputs used +{{/* All inputs used by this package will be automatically listed here. */}} +{{ inputDocs }} + +### API usage +{{/* For integrations that use APIs to collect data, document all the APIs that are used, and link to relevent information */}} +These APIs are used with this integration: +* ... diff --git a/test/packages/bad_integration_hbs/changelog.yml b/test/packages/bad_integration_hbs/changelog.yml new file mode 100644 index 00000000..bb0320a5 --- /dev/null +++ b/test/packages/bad_integration_hbs/changelog.yml @@ -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 # FIXME Replace with the real PR link diff --git a/test/packages/bad_integration_hbs/data_stream/foo/agent/stream/filestream.yml.hbs b/test/packages/bad_integration_hbs/data_stream/foo/agent/stream/filestream.yml.hbs new file mode 100644 index 00000000..85078497 --- /dev/null +++ b/test/packages/bad_integration_hbs/data_stream/foo/agent/stream/filestream.yml.hbs @@ -0,0 +1,43 @@ +paths: +{{#each paths as |path|}} + - {{path}} +{{/each}} +{{#if exclude_files}} +prospector.scanner.exclude_files: +{{#each exclude_files as |pattern f|}} + - {{pattern}} +{{/each}} +{{/if}} +{{#if multiline_json}} +multiline.pattern: '^{' +multiline.negate: true +multiline.match: after +multiline.max_lines: 5000 +multiline.timeout: 10 +{{/if}} +{{#if custom}} +{{custom}} +{{/if}} + +{{#if tags.length}} +tags: +{{#each tags as |tag|}} +- {{tag}} +{{/each}} +{{#if preserve_original_event}} +- preserve_original_event +{{/if}} +{{else}} +{{#if preserve_original_event}} +tags: +- preserve_original_event +{{/if}} + +{{#contains "forwarded" tags}} +publisher_pipeline.disable_host: true +{{/contains}} + +{{#if processors}} +processors: +{{processors}} +{{/if}} \ No newline at end of file diff --git a/test/packages/bad_integration_hbs/data_stream/foo/elasticsearch/ingest_pipeline/default.yml b/test/packages/bad_integration_hbs/data_stream/foo/elasticsearch/ingest_pipeline/default.yml new file mode 100644 index 00000000..1a308fde --- /dev/null +++ b/test/packages/bad_integration_hbs/data_stream/foo/elasticsearch/ingest_pipeline/default.yml @@ -0,0 +1,10 @@ +--- +description: Pipeline for processing sample logs +processors: +- set: + field: sample_field + value: "1" +on_failure: +- set: + field: error.message + value: '{{ _ingest.on_failure_message }}' diff --git a/test/packages/bad_integration_hbs/data_stream/foo/fields/base-fields.yml b/test/packages/bad_integration_hbs/data_stream/foo/fields/base-fields.yml new file mode 100644 index 00000000..7c798f45 --- /dev/null +++ b/test/packages/bad_integration_hbs/data_stream/foo/fields/base-fields.yml @@ -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. diff --git a/test/packages/bad_integration_hbs/data_stream/foo/manifest.yml b/test/packages/bad_integration_hbs/data_stream/foo/manifest.yml new file mode 100644 index 00000000..251bec6c --- /dev/null +++ b/test/packages/bad_integration_hbs/data_stream/foo/manifest.yml @@ -0,0 +1,256 @@ +title: "New Data Stream" +type: logs +streams: + - input: filestream + title: "logs via filestream" + description: |- + Collect logs with filestream + template_path: filestream.yml.hbs + vars: + - name: paths + type: text + title: "Paths" + multi: true + required: true + show_user: true + default: + - /var/log/*.log + - name: data_stream.dataset + type: text + title: "Dataset name" + description: |- + Dataset to write data to. Changing the dataset will send the data to a different index. You can't use `-` in the name of a dataset and only valid characters for [Elasticsearch index names](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html). + required: true + show_user: true + default: filestream.generic + - name: pipeline + type: text + title: "Ingest Pipeline" + description: |- + The Ingest Node pipeline ID to be used by the integration. + show_user: true + - name: parsers + type: yaml + title: "Parsers" + description: |- + This option expects a list of parsers that the log line has to go through. For more information see [Parsers](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-filestream.html#_parsers) + show_user: true + default: "" + #- ndjson: + # target: "" + # message_key: msg + #- multiline: + # type: count + # count_lines: 3 + - name: exclude_files + type: text + title: "Exclude Files" + description: |- + A list of regular expressions to match the files that you want Elastic Agent to ignore. By default no files are excluded. + multi: true + show_user: true + default: + - \.gz$ + - name: include_files + type: text + title: "Include Files" + description: |- + A list of regular expressions to match the files that you want Elastic Agent to include. If a list of regexes is provided, only the files that are allowed by the patterns are harvested. + multi: true + show_user: true + - name: processors + type: yaml + title: "Processors" + description: |- + Processors are used to reduce the number of fields in the exported event or to enhance the event with metadata. This executes in the agent before the logs are parsed. See [Processors](https://www.elastic.co/guide/en/beats/filebeat/current/filtering-and-enhancing-data.html) for details. + - name: tags + type: text + title: "Tags" + description: |- + Tags to include in the published event + multi: true + show_user: true + - name: encoding + type: text + title: "Encoding" + description: |- + The file encoding to use for reading data that contains international characters. For a full list of valid encodings, see the [Documentation](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-filestream.html#_encoding_2) + - name: recursive_glob + type: bool + title: "Recursive Glob" + description: |- + Enable expanding `**` into recursive glob patterns. With this feature enabled, the rightmost `**` in each path is expanded into a fixed number of glob patterns. For example: `/foo/**` expands to `/foo`, `/foo/*`, `/foo/*/*`, and so on. If enabled it expands a single `**` into a 8-level deep `*` pattern. + This feature is enabled by default. Set prospector.scanner.recursive_glob to false to disable it. + default: true + - name: symlinks + type: bool + title: "Enable symlinks" + description: |- + The symlinks option allows Elastic Agent to harvest symlinks in addition to regular files. When harvesting symlinks, Elastic Agent opens and reads the original file even though it reports the path of the symlink. + **Because this option may lead to data loss, it is disabled by default.** + - name: resend_on_touch + type: bool + title: "Resend on touch" + description: |- + If this option is enabled a file is resent if its size has not changed but its modification time has changed to a later time than before. It is disabled by default to avoid accidentally resending files. + - name: check_interval + type: text + title: "Check Interval" + description: |- + How often Elastic Agent checks for new files in the paths that are specified for harvesting. For example Specify 1s to scan the directory as frequently as possible without causing Elastic Agent to scan too frequently. **We do not recommend to set this value <1s.** + - name: ignore_older + type: text + title: "Ignore Older" + description: |- + If this option is enabled, Elastic Agent ignores any files that were modified before the specified timespan. You can use time strings like 2h (2 hours) and 5m (5 minutes). The default is 0, which disables the setting. + You must set Ignore Older to be greater than On State Change Inactive. + For more information, please see the [Documentation](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-filestream.html#filebeat-input-filestream-ignore-older) + - name: ignore_inactive + type: text + title: "Ignore Inactive" + description: |- + If this option is enabled, Elastic Agent ignores every file that has not been updated since the selected time. Possible options are since_first_start and since_last_start. + - name: close_on_state_changed_inactive + type: text + title: "Close on State Changed Inactive" + description: |- + When this option is enabled, Elastic Agent closes the file handle if a file has not been harvested for the specified duration. The counter for the defined period starts when the last log line was read by the harvester. It is not based on the modification time of the file. If the closed file changes again, a new harvester is started and the latest changes will be picked up after Check Interval has elapsed. + - name: close_on_state_changed_renamed + type: bool + title: "Close on State Changed Renamed" + description: |- + **Only use this option if you understand that data loss is a potential side effect.** + When this option is enabled, Elastic Agent closes the file handler when a file is renamed. This happens, for example, when rotating files. By default, the harvester stays open and keeps reading the file because the file handler does not depend on the file name. + - name: close_on_state_changed_removed + type: bool + title: "Close on State Changed Removed" + description: |- + When this option is enabled, Elastic Agent closes the harvester when a file is removed. Normally a file should only be removed after it’s inactive for the duration specified by close.on_state_change.inactive. + - name: close_reader_eof + type: bool + title: "Close Reader EOF" + description: |- + **Only use this option if you understand that data loss is a potential side effect.** + When this option is enabled, Elastic Agent closes a file as soon as the end of a file is reached. This is useful when your files are only written once and not updated from time to time. For example, this happens when you are writing every single log event to a new file. This option is disabled by default. + - name: close_reader_after_interval + type: text + title: "Close Reader After Interval" + description: |- + **Only use this option if you understand that data loss is a potential side effect. Another side effect is that multiline events might not be completely sent before the timeout expires.** + This option is particularly useful in case the output is blocked, which makes Elastic Agent keep open file handlers even for files that were deleted from the disk. + For more information see the [documentation](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-filestream.html#filebeat-input-filestream-close-timeout). + - name: clean_inactive + type: text + title: "Clean Inactive" + description: |- + **Only use this option if you understand that data loss is a potential side effect.** + When this option is enabled, Elastic Agent removes the state of a file after the specified period of inactivity has elapsed. + E.g: "30m", Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". By default cleaning inactive states is disabled, -1 is used to disable it. + default: -1 + - name: clean_removed + type: bool + title: "Clean Removed" + description: |- + When this option is enabled, Elastic Agent cleans files from the registry if they cannot be found on disk anymore under the last known name. + **You must disable this option if you also disable Close Removed.** + - name: harvester_limit + type: integer + title: "Harvester Limit" + description: |- + The harvester_limit option limits the number of harvesters + that are started in parallel for one input. This directly + relates to the maximum number of file handlers that are + opened. The default is 0 (no limit). + default: 0 + - name: backoff_init + type: text + title: "Backoff Init" + description: |- + The backoff option defines how long Elastic Agent waits before checking a file again after EOF is reached. The default is 1s. + - name: backoff_max + type: text + title: "Backoff Max" + description: |- + The maximum time for Elastic Agent to wait before checking a file again after EOF is reached. The default is 10s. + **Requirement: Set Backoff Max to be greater than or equal to Backoff Init and less than or equal to Check Interval (Backoff Init <= Backoff Max <= Check Interval).** + - name: fingerprint + type: bool + title: "File identity: Fingerprint" + description: |- + **Changing file_identity methods between runs may result in + duplicated events in the output.** + Uses a fingerprint generated from the first few bytes (1k is + the default, this can be configured via Fingerprint offset + and length) to identify a file instead inode + device ID. + Refer to https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-filestream.html#_file_identity_2 + for more details. If this option is disabled (and 'Native + file identity is not enabled'), Elastic-Agent < 9.0.0 will + use Native as the file identity, and >= 9.0.0 will use + Fingerprint with the default offset and length. + default: true + - name: fingerprint_offset + type: integer + title: "File identity: Fingerprint offset" + description: |- + Offset from the beginning of the file to start calculating + the fingerprint. The default is 0. Only used when the + fingerprint file identity is selected + default: 0 + - name: fingerprint_length + type: integer + title: "File identity: Fingerprint length" + description: |- + The number of bytes used to calculate the fingerprint. The + default is 1024. Only used when the fingerprint file + identity is selected. + default: 1024 + - name: file_identity_native + type: bool + title: "File identity: Native" + description: |- + **Changing file_identity methods between runs may result in + duplicated events in the output.** + Uses a native identifier for files, on most Unix-like + file systems this is the inode + device ID. On file systems + that do not support inode, the native equivalent is used. + If you enable this option you **MUST disable Fingerprint + file identity**. Refer to + https://www.elastic.co/docs/reference/beats/filebeat/filebeat-input-filestream + for more details. + default: false + - name: rotation_external_strategy_copytruncate + type: yaml + title: "Rotation Strategy" + description: "If the log rotating application copies the contents of the active file and then truncates the original file, use these options to help Elastic Agent to read files correctly.\nSet the option suffix_regex so Elastic Agent can tell active and rotated files apart. \nThere are two supported suffix types in the input: numberic and date." + - name: exclude_lines + type: text + title: "Exclude Lines" + description: |- + A list of regular expressions to match the lines that you want Elastic Agent to exclude. Elastic Agent drops any lines that match a regular expression in the list. By default, no lines are dropped. Empty lines are ignored. + multi: true + - name: include_lines + type: text + title: "Include Lines" + description: |- + A list of regular expressions to match the lines that you want Elastic Agent to include. Elastic Agent exports only the lines that match a regular expression in the list. By default, all lines are exported. Empty lines are ignored. + multi: true + - name: buffer_size + type: text + title: "Buffer Size" + description: |- + The size in bytes of the buffer that each harvester uses when fetching a file. The default is 16384. + - name: message_max_bytes + type: text + title: "Message Max Bytes" + description: |- + The maximum number of bytes that a single log message can have. All bytes after mesage_max_bytes are discarded and not sent. The default is 10MB (10485760). + - name: condition + type: text + title: "Condition" + description: |- + Condition to filter when to collect this input. See [Dynamic Input Configuration](https://www.elastic.co/guide/en/fleet/current/dynamic-input-configuration.html) for details. + show_user: true +elasticsearch: + index_template: + mappings: + subobjects: false diff --git a/test/packages/bad_integration_hbs/docs/README.md b/test/packages/bad_integration_hbs/docs/README.md new file mode 100644 index 00000000..7cc03b51 --- /dev/null +++ b/test/packages/bad_integration_hbs/docs/README.md @@ -0,0 +1,101 @@ +{{- generatedHeader }} +{{/* +This template can be used as a starting point for writing documentation for your new integration. For each section, fill in the details +described in the comments. + +Find more detailed documentation guidelines in https://www.elastic.co/docs/extend/integrations/documentation-guidelines +*/}} +# bad integration hbs Integration for Elastic + +## Overview +{{/* Complete this section with a short summary of what data this integration collects and what use cases it enables */}} +The bad integration hbs integration for Elastic enables collection of ... +This integration facilitates ... + +### Compatibility +{{/* Complete this section with information on what 3rd party software or hardware versions this integration is compatible with */}} +This integration is compatible with ... + +### How it works +{{/* Add a high level overview on how this integration works. For example, does it collect data from API calls or recieving data from a network or file.*/}} + +## What data does this integration collect? +{{/* Complete this section with information on what types of data the integration collects, and link to reference documentation if available */}} +The bad integration hbs integration collects log messages of the following types: +* ... + +### Supported use cases +{{/* Add details on the use cases that can be enabled by using this integration. Explain why a user would want to install and use this integration. */}} + +## What do I need to use this integration? +{{/* List any vendor-specific prerequisites needed before starting to install the integration. */}} + +## How do I deploy this integration? + +### Agent-based deployment + +Elastic Agent must be installed. For more details, check the Elastic Agent [installation instructions](docs-content://reference/fleet/install-elastic-agents.md). You can install only one Elastic Agent per host. + +Elastic Agent is required to stream data from the syslog or log file receiver and ship the data to Elastic, where the events will then be processed via the integration's ingest pipelines. + +{{/* If agentless is available for this integration, we'll want to include that here as well. +### Agentless deployment + +Agentless deployments are only supported in Elastic Serverless and Elastic Cloud environments. Agentless deployments provide a means to ingest data while avoiding the orchestration, management, and maintenance needs associated with standard ingest infrastructure. Using an agentless deployment makes manual agent deployment unnecessary, allowing you to focus on your data instead of the agent that collects it. + +For more information, refer to [Agentless integrations](https://www.elastic.co/guide/en/serverless/current/security-agentless-integrations.html) and [Agentless integrations FAQ](https://www.elastic.co/guide/en/serverless/current/agentless-integration-troubleshooting.html) +*/}} + +### Onboard / configure +{{/* List the steps that will need to be followed in order to completely set up a working integration. +For integrations that support multiple input types, be sure to add steps for all inputs. +*/}} + +### Validation +{{/* How can the user test whether the integration is working? Including example commands or test files if applicable */}} + +## Troubleshooting + +For help with Elastic ingest tools, check [Common problems](https://www.elastic.co/docs/troubleshoot/ingest/fleet/common-problems). +{{/* +Add any vendor specific troubleshooting here. + +Are there common issues or “gotchas” for deploying this integration? If so, how can they be resolved? +If applicable, links to the third-party software’s troubleshooting documentation. +*/}} + +## Scaling + +For more information on architectures that can be used for scaling this integration, check the [Ingest Architectures](https://www.elastic.co/docs/manage-data/ingest/ingest-reference-architectures) documentation. +{{/* Add any vendor specific scaling information here */}} + +## Reference +{{/* Repeat for each data stream of the current type +### {Data stream name} + +The `{data stream name}` data stream provides events from {source} of the following types: {list types}. + +For each data_stream_name, include an optional summary of the datastream, the exported fields reference table and the sample event. + +The fields template function will be replaced by a generated list of all fields from the `fields/` directory of the data stream when building the integration. + +#### {data stream name} fields + +To include a generated list of fields from the `fields/` directory, uncomment and use: +{{ fields "data_stream_name" }} + +The event template function will be replace by a sample event, taken from `sample_event.json`, when building this integration. + +To include a sample event from `sample_event.json`, uncomment and use: +{{ event "data_stream_name" }} + +*/}} + +### Inputs used +{{/* All inputs used by this package will be automatically listed here. */}} +{{ inputDocs }} + +### API usage +{{/* For integrations that use APIs to collect data, document all the APIs that are used, and link to relevent information */}} +These APIs are used with this integration: +* ... diff --git a/test/packages/bad_integration_hbs/img/sample-logo.svg b/test/packages/bad_integration_hbs/img/sample-logo.svg new file mode 100644 index 00000000..6268dd88 --- /dev/null +++ b/test/packages/bad_integration_hbs/img/sample-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/packages/bad_integration_hbs/img/sample-screenshot.png b/test/packages/bad_integration_hbs/img/sample-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..d7a56a3ecc078c38636698cefba33f86291dd178 GIT binary patch literal 18849 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

}qal5$moSACwfNXLXG5|3R0AtBcN` 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 literal 0 HcmV?d00001 diff --git a/test/packages/bad_integration_hbs/manifest.yml b/test/packages/bad_integration_hbs/manifest.yml new file mode 100644 index 00000000..30b0184b --- /dev/null +++ b/test/packages/bad_integration_hbs/manifest.yml @@ -0,0 +1,37 @@ +format_version: 3.5.4 +name: bad_integration_hbs +title: "bad integration hbs" +version: 0.0.1 +source: + license: "Elastic-2.0" +description: "package with wrong hbs templates at data stream" +type: integration +categories: + - custom + - aws +conditions: + kibana: + version: "^9.2.1" + elastic: + subscription: "basic" +screenshots: + - src: /img/sample-screenshot.png + title: Sample screenshot + size: 600x600 + type: image/png +icons: + - src: /img/sample-logo.svg + title: Sample logo + size: 32x32 + type: image/svg+xml +policy_templates: + - name: sample + title: Sample logs + description: Collect sample logs + inputs: + - type: logfile + title: Collect sample logs from instances + description: Collecting sample logs +owner: + github: elastic/integrations + type: elastic diff --git a/test/packages/bad_integration_hbs/sample_event.json b/test/packages/bad_integration_hbs/sample_event.json new file mode 100644 index 00000000..e302589f --- /dev/null +++ b/test/packages/bad_integration_hbs/sample_event.json @@ -0,0 +1,3 @@ +{ + "description": "This is an example sample-event for bad integration hbs. Replace it with a real sample event. Hint: If system tests exist, running `elastic-package test system --generate` will generate this file." +} From 67389f6a191a8e5f3ec08f4c1f366088dcca1edf Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Fri, 28 Nov 2025 10:00:20 +0100 Subject: [PATCH 03/26] Add validation for Handlebars template files in input and integration packages --- spec/changelog.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/changelog.yml b/spec/changelog.yml index d6c27d2c..ddf45141 100644 --- a/spec/changelog.yml +++ b/spec/changelog.yml @@ -15,6 +15,9 @@ - description: Require defining agent version constraints in input and integration packages. type: breaking-change link: https://github.com/elastic/package-spec/pull/999 + - description: Handlebars template files are now validated in input and integration packages. + type: enhancement + link: TBD - version: 3.5.4 changes: - description: Fix rule matching processor for event.original handling. From 97a32b2693b2c6d47bdd23172a0fd8b697bf1ea9 Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Fri, 28 Nov 2025 10:16:57 +0100 Subject: [PATCH 04/26] Refactor Handlebars definition specifications for clarity and consistency --- spec/integration/agent/spec.yml | 31 +++++++++++++-------- spec/integration/data_stream/agent/spec.yml | 31 +++++++++++++-------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/spec/integration/agent/spec.yml b/spec/integration/agent/spec.yml index d1236d0b..8c9f9eab 100644 --- a/spec/integration/agent/spec.yml +++ b/spec/integration/agent/spec.yml @@ -1,15 +1,24 @@ spec: additionalContents: false contents: - - description: Folder containing input definitions - type: folder - name: input - required: true - additionalContents: false - contents: - - description: Config template file for inputs defined in the policy_templates section of the top level manifest - type: file - sizeLimit: 2MB - pattern: '^.+\.yml\.hbs$' + - description: Folder containing input definitions + type: folder + name: input required: true - allowLink: true + additionalContents: false + contents: + - description: | + Config template file for inputs defined in the policy_templates section of the top level manifest. + The template should use standard Handlebars syntax (e.g., `{{vars.key}}`, `{{#if vars.condition}}`, `{{#each vars.items}}`) + and must compile to valid YAML. + Available Handlebars helpers include: + - `contains` (checks if item is in array/string), + - `escape_string` (wraps string in single quotes and escapes them), + - `escape_multiline_string` (escapes multiline strings without wrapping), + - `to_json` (converts object to JSON string), and + - `url_encode` (URI encodes string). + type: file + sizeLimit: 2MB + pattern: '^.+\.yml\.hbs$' + required: true + allowLink: true diff --git a/spec/integration/data_stream/agent/spec.yml b/spec/integration/data_stream/agent/spec.yml index 86951478..8f51146f 100644 --- a/spec/integration/data_stream/agent/spec.yml +++ b/spec/integration/data_stream/agent/spec.yml @@ -1,15 +1,24 @@ spec: additionalContents: false contents: - - description: Folder containing input definitions - type: folder - name: stream - required: true - additionalContents: false - contents: - - description: Config template file for inputs defined in the policy_templates section of the top level manifest - type: file - sizeLimit: 2MB - pattern: '^.+\.yml\.hbs$' + - description: Folder containing input definitions + type: folder + name: stream required: true - allowLink: true + additionalContents: false + contents: + - description: | + Config template file for inputs defined in the policy_templates section of the top level manifest. + The template should use standard Handlebars syntax (e.g., `{{vars.key}}`, `{{#if vars.condition}}`, `{{#each vars.items}}`) + and must compile to valid YAML. + Available Handlebars helpers include: + - `contains` (checks if item is in array/string), + - `escape_string` (wraps string in single quotes and escapes them), + - `escape_multiline_string` (escapes multiline strings without wrapping), + - `to_json` (converts object to JSON string), and + - `url_encode` (URI encodes string). + type: file + sizeLimit: 2MB + pattern: '^.+\.yml\.hbs$' + required: true + allowLink: true From f5854eab0c141abf9da0215630c366c902565c25 Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Fri, 28 Nov 2025 10:20:09 +0100 Subject: [PATCH 05/26] Update changelog with link --- spec/changelog.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/changelog.yml b/spec/changelog.yml index ddf45141..1251c08a 100644 --- a/spec/changelog.yml +++ b/spec/changelog.yml @@ -17,7 +17,7 @@ link: https://github.com/elastic/package-spec/pull/999 - description: Handlebars template files are now validated in input and integration packages. type: enhancement - link: TBD + link: https://github.com/elastic/package-spec/pull/1030 - version: 3.5.4 changes: - description: Fix rule matching processor for event.original handling. From 32ebc29b57fccc04f9ef8b642183b09c85112691 Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Fri, 28 Nov 2025 10:28:29 +0100 Subject: [PATCH 06/26] Fix variable naming for handlebars template validation error --- .../internal/validator/semantic/validate_hbs_templates.go | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/code/go/internal/validator/semantic/validate_hbs_templates.go b/code/go/internal/validator/semantic/validate_hbs_templates.go index cacdea8c..c51d3a63 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates.go @@ -15,9 +15,12 @@ import ( ) var ( - ErrInvalidHandlebarsTemplate = errors.New("invalid handlebars template") + errInvalidHandlebarsTemplate = errors.New("invalid handlebars template") ) +// ValidateHandlebarsFiles validates all Handlebars (.hbs) files in the package filesystem. +// It returns a list of validation errors if any Handlebars files are invalid. +// hbs are located in both the package root and data stream directories under the agent folder. func ValidateHandlebarsFiles(fsys fspath.FS) specerrors.ValidationErrors { entries, err := getHandlebarsFiles(fsys) if err != nil { @@ -41,7 +44,7 @@ func ValidateHandlebarsFiles(fsys fspath.FS) specerrors.ValidationErrors { err := validateFile(filePath) if err != nil { validationErrors = append(validationErrors, specerrors.NewStructuredErrorf( - "%w: file %s: %w", ErrInvalidHandlebarsTemplate, entry, err, + "%w: file %s: %w", errInvalidHandlebarsTemplate, entry, err, )) } } From e76c19a4ee4df4c9344a3a3cfac57ca303e79d44 Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Fri, 28 Nov 2025 10:30:52 +0100 Subject: [PATCH 07/26] Fix syntax error in sql_query definition across multiple Handlebars templates --- test/packages/bad_input_template_path/agent/input/input.yml.hbs | 2 +- test/packages/good_input/agent/input/input.yml.hbs | 2 +- test/packages/sql_input/agent/input/input.yml.hbs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/test/packages/bad_input_template_path/agent/input/input.yml.hbs b/test/packages/bad_input_template_path/agent/input/input.yml.hbs index 6eb03670..7baca13f 100644 --- a/test/packages/bad_input_template_path/agent/input/input.yml.hbs +++ b/test/packages/bad_input_template_path/agent/input/input.yml.hbs @@ -5,5 +5,5 @@ hosts: - {{this}} {{/each}} driver: {{driver}} -sql_query: {{sql_query} +sql_query: {{sql_query}} sql_response_format: {{sql_response_format}} \ No newline at end of file diff --git a/test/packages/good_input/agent/input/input.yml.hbs b/test/packages/good_input/agent/input/input.yml.hbs index 6eb03670..7baca13f 100644 --- a/test/packages/good_input/agent/input/input.yml.hbs +++ b/test/packages/good_input/agent/input/input.yml.hbs @@ -5,5 +5,5 @@ hosts: - {{this}} {{/each}} driver: {{driver}} -sql_query: {{sql_query} +sql_query: {{sql_query}} sql_response_format: {{sql_response_format}} \ No newline at end of file diff --git a/test/packages/sql_input/agent/input/input.yml.hbs b/test/packages/sql_input/agent/input/input.yml.hbs index 6eb03670..7baca13f 100644 --- a/test/packages/sql_input/agent/input/input.yml.hbs +++ b/test/packages/sql_input/agent/input/input.yml.hbs @@ -5,5 +5,5 @@ hosts: - {{this}} {{/each}} driver: {{driver}} -sql_query: {{sql_query} +sql_query: {{sql_query}} sql_response_format: {{sql_response_format}} \ No newline at end of file From 49c9c5a1c2cf2a62b48c7b5853ffd0ef028567a1 Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Fri, 28 Nov 2025 11:17:53 +0100 Subject: [PATCH 08/26] Reorder import statements for consistency in validate_hbs_templates.go --- code/go/internal/validator/semantic/validate_hbs_templates.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/go/internal/validator/semantic/validate_hbs_templates.go b/code/go/internal/validator/semantic/validate_hbs_templates.go index c51d3a63..3e2aa03d 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates.go @@ -9,9 +9,10 @@ import ( "io/fs" "strings" + "github.com/mailgun/raymond/v2" + "github.com/elastic/package-spec/v3/code/go/internal/fspath" "github.com/elastic/package-spec/v3/code/go/pkg/specerrors" - "github.com/mailgun/raymond/v2" ) var ( From 86281bb578cf1f72490e1fc7b64740bd18d39efd Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Fri, 28 Nov 2025 11:53:17 +0100 Subject: [PATCH 09/26] update compliace gomod --- compliance/go.mod | 2 ++ compliance/go.sum | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/compliance/go.mod b/compliance/go.mod index 9d5988e8..babac722 100644 --- a/compliance/go.mod +++ b/compliance/go.mod @@ -110,6 +110,7 @@ require ( github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect github.com/magefile/mage v1.15.0 // indirect + github.com/mailgun/raymond/v2 v2.0.48 // indirect github.com/mailru/easyjson v0.7.7 // indirect github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect @@ -145,6 +146,7 @@ require ( github.com/shirou/gopsutil/v3 v3.24.5 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/shopspring/decimal v1.4.0 // indirect + github.com/sirupsen/logrus v1.9.3 // indirect github.com/spf13/afero v1.15.0 // indirect github.com/spf13/cast v1.7.0 // indirect github.com/spf13/cobra v1.10.1 // indirect diff --git a/compliance/go.sum b/compliance/go.sum index 851e6ec1..a8e7d6f0 100644 --- a/compliance/go.sum +++ b/compliance/go.sum @@ -248,6 +248,8 @@ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= +github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw= +github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= @@ -337,6 +339,9 @@ github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnj github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I= github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg= github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w= @@ -354,6 +359,7 @@ github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSS github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= @@ -456,6 +462,7 @@ golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -464,6 +471,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= From 3e481302b85d024225447eac99d1a277b7477b64 Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Fri, 28 Nov 2025 16:34:02 +0100 Subject: [PATCH 10/26] Refactor Handlebars validation logic to include linked files --- .../semantic/validate_hbs_templates.go | 96 ++++++++------- .../semantic/validate_hbs_templates_test.go | 111 +++++++++++++++--- code/go/pkg/validator/validator_test.go | 4 +- 3 files changed, 151 insertions(+), 60 deletions(-) diff --git a/code/go/internal/validator/semantic/validate_hbs_templates.go b/code/go/internal/validator/semantic/validate_hbs_templates.go index 3e2aa03d..96a737ec 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates.go @@ -7,11 +7,13 @@ package semantic import ( "errors" "io/fs" - "strings" + "path" + "path/filepath" "github.com/mailgun/raymond/v2" "github.com/elastic/package-spec/v3/code/go/internal/fspath" + "github.com/elastic/package-spec/v3/code/go/internal/linkedfiles" "github.com/elastic/package-spec/v3/code/go/pkg/specerrors" ) @@ -23,61 +25,75 @@ var ( // It returns a list of validation errors if any Handlebars files are invalid. // hbs are located in both the package root and data stream directories under the agent folder. func ValidateHandlebarsFiles(fsys fspath.FS) specerrors.ValidationErrors { - entries, err := getHandlebarsFiles(fsys) + // template files are placed at /agent/input directory or + // at the datastream /agent/stream directory + inputDir := filepath.Join("agent", "input") + err := validateTemplateDir(fsys, inputDir) if err != nil { return specerrors.ValidationErrors{ - specerrors.NewStructuredErrorf( - "error finding Handlebars files: %w", err, - ), + specerrors.NewStructuredErrorf("%w in %s: %w", errInvalidHandlebarsTemplate, inputDir, err), } } - if len(entries) == 0 { - return nil - } - var validationErrors specerrors.ValidationErrors - for _, entry := range entries { - if !strings.HasSuffix(entry, ".hbs") { + datastreamEntries, err := fs.ReadDir(fsys, "data_stream") + if err != nil && !errors.Is(err, fs.ErrNotExist) { + return specerrors.ValidationErrors{ + specerrors.NewStructuredErrorf("error reading data_stream directory: %w", err), + } + } + for _, dsEntry := range datastreamEntries { + if !dsEntry.IsDir() { continue } - - filePath := fsys.Path(entry) - err := validateFile(filePath) + streamDir := filepath.Join("data_stream", dsEntry.Name(), "agent", "stream") + err := validateTemplateDir(fsys, streamDir) if err != nil { - validationErrors = append(validationErrors, specerrors.NewStructuredErrorf( - "%w: file %s: %w", errInvalidHandlebarsTemplate, entry, err, - )) + return specerrors.ValidationErrors{ + specerrors.NewStructuredErrorf("%w in %s: %w", errInvalidHandlebarsTemplate, streamDir, err), + } } } - return validationErrors + return nil +} + +// validateTemplateDir validates all Handlebars files in the given directory. +func validateTemplateDir(fsys fspath.FS, dir string) error { + entries, err := fs.ReadDir(fsys, dir) + if err != nil && !errors.Is(err, fs.ErrNotExist) { + return err + } + for _, entry := range entries { + if filepath.Ext(entry.Name()) == ".hbs" { + err := validateHandlebarsEntry(fsys, dir, entry.Name()) + if err != nil { + return err + } + continue + } + if filepath.Ext(entry.Name()) == ".link" { + linkFilePath := path.Join(dir, entry.Name()) + linkFile, err := linkedfiles.NewLinkedFile(fsys.Path(linkFilePath)) + if err != nil { + return err + } + err = validateHandlebarsEntry(fsys, dir, linkFile.IncludedFilePath) + if err != nil { + return err + } + continue + } + } + return nil } -// validateFile validates a single Handlebars file located at filePath. +// validateHandlebarsEntry validates a single Handlebars file located at filePath. // it parses the file using the raymond library to check for syntax errors. -func validateFile(filePath string) error { - if filePath == "" { +func validateHandlebarsEntry(fsys fspath.FS, dir, entryName string) error { + if entryName == "" { return nil } + filePath := fsys.Path(path.Join(dir, entryName)) _, err := raymond.ParseFile(filePath) return err } - -// getHandlebarsFiles returns all Handlebars (.hbs) files in the package filesystem. -// It searches in both the package root and data stream directories under the agent folder. -func getHandlebarsFiles(fsys fspath.FS) ([]string, error) { - entries := make([]string, 0) - pkgEntries, err := fs.Glob(fsys, "agent/**/*.hbs") - if err != nil && !errors.Is(err, fs.ErrNotExist) { - return nil, err - } - entries = append(entries, pkgEntries...) - - dataStreamEntries, err := fs.Glob(fsys, "data_stream/*/agent/**/*.hbs") - if err != nil && !errors.Is(err, fs.ErrNotExist) { - return nil, err - } - entries = append(entries, dataStreamEntries...) - - return entries, nil -} diff --git a/code/go/internal/validator/semantic/validate_hbs_templates_test.go b/code/go/internal/validator/semantic/validate_hbs_templates_test.go index cef1a28d..fc3714f7 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates_test.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates_test.go @@ -9,38 +9,113 @@ import ( "path/filepath" "testing" - "github.com/stretchr/testify/assert" + "github.com/elastic/package-spec/v3/code/go/internal/fspath" "github.com/stretchr/testify/require" ) -func TestValidateFile(t *testing.T) { +func TestValidateTemplateDir(t *testing.T) { + t.Run("empty directory", func(t *testing.T) { + tmpDir := t.TempDir() + pkgDir := filepath.Join(tmpDir, "package") + err := os.MkdirAll(pkgDir, 0o755) + require.NoError(t, err) + + templateDir := filepath.Join(pkgDir, "agent", "input") + err = os.MkdirAll(templateDir, 0o755) + require.NoError(t, err) + + fsys := fspath.DirFS(pkgDir) + err = validateTemplateDir(fsys, filepath.Join("agent", "input")) + require.NoError(t, err) + + }) + t.Run("valid handlebars file", func(t *testing.T) { + tmpDir := t.TempDir() + pkgDir := filepath.Join(tmpDir, "package") + err := os.MkdirAll(pkgDir, 0o755) + require.NoError(t, err) + + templateDir := filepath.Join(pkgDir, "agent", "input") + err = os.MkdirAll(templateDir, 0o755) + require.NoError(t, err) + hbsFilePath := filepath.Join(templateDir, "template.hbs") + hbsContent := `{{#if condition}}Valid Handlebars{{/if}}` + err = os.WriteFile(hbsFilePath, []byte(hbsContent), 0o644) + require.NoError(t, err) + + fsys := fspath.DirFS(pkgDir) + err = validateTemplateDir(fsys, filepath.Join("agent", "input")) + require.NoError(t, err) + }) + t.Run("invalid handlebars file", func(t *testing.T) { + tmpDir := t.TempDir() + pkgDir := filepath.Join(tmpDir, "package") + err := os.MkdirAll(pkgDir, 0o755) + require.NoError(t, err) - t.Run("no handlebars files", func(t *testing.T) { - err := validateFile("") - assert.NoError(t, err) + templateDir := filepath.Join(pkgDir, "agent", "input") + err = os.MkdirAll(templateDir, 0o755) + require.NoError(t, err) + hbsFilePath := filepath.Join(templateDir, "template.hbs") + hbsContent := `{{#if condition}}Valid Handlebars` + err = os.WriteFile(hbsFilePath, []byte(hbsContent), 0o644) + require.NoError(t, err) + + fsys := fspath.DirFS(pkgDir) + err = validateTemplateDir(fsys, filepath.Join("agent", "input")) + require.Error(t, err) }) + t.Run("valid linked handlebars file", func(t *testing.T) { + tmpDir := t.TempDir() + pkgDir := filepath.Join(tmpDir, "package") + err := os.MkdirAll(pkgDir, 0o755) + require.NoError(t, err) - t.Run("valid handlebars files", func(t *testing.T) { - tmp := t.TempDir() + pkgDirLinked := filepath.Join(tmpDir, "linked") + err = os.MkdirAll(pkgDirLinked, 0o755) + require.NoError(t, err) + linkedHbsFilePath := filepath.Join(pkgDirLinked, "linked_template.hbs") + linkedHbsContent := `{{#if condition}}Valid Linked Handlebars{{/if}}` + err = os.WriteFile(linkedHbsFilePath, []byte(linkedHbsContent), 0o644) + require.NoError(t, err) - filePath := filepath.Join(tmp, "template.yml.hbs") - err := os.WriteFile(filePath, []byte("{{#if foo}}hello{{/if}}"), 0o644) + templateDir := filepath.Join(pkgDir, "agent", "input") + err = os.MkdirAll(templateDir, 0o755) + require.NoError(t, err) + hbsFilePath := filepath.Join(templateDir, "template.hbs.link") + hbsContent := `../../../linked/linked_template.hbs` + err = os.WriteFile(hbsFilePath, []byte(hbsContent), 0o644) + require.NoError(t, err) + + fsys := fspath.DirFS(pkgDir) + err = validateTemplateDir(fsys, filepath.Join("agent", "input")) require.NoError(t, err) - errs := validateFile(filePath) - assert.Empty(t, errs) }) + t.Run("invalid linked handlebars file", func(t *testing.T) { + tmpDir := t.TempDir() + pkgDir := filepath.Join(tmpDir, "package") + err := os.MkdirAll(pkgDir, 0o755) + require.NoError(t, err) - t.Run("invalid handlebars files", func(t *testing.T) { - tmp := t.TempDir() + pkgDirLinked := filepath.Join(tmpDir, "linked") + err = os.MkdirAll(pkgDirLinked, 0o755) + require.NoError(t, err) + linkedHbsFilePath := filepath.Join(pkgDirLinked, "linked_template.hbs") + linkedHbsContent := `{{#if condition}}Valid Linked Handlebars` + err = os.WriteFile(linkedHbsFilePath, []byte(linkedHbsContent), 0o644) + require.NoError(t, err) - filePath := filepath.Join(tmp, "bad.hbs") - // Unclosed block should produce a parse error. - err := os.WriteFile(filePath, []byte("{{#if foo}}no end"), 0o644) + templateDir := filepath.Join(pkgDir, "agent", "input") + err = os.MkdirAll(templateDir, 0o755) + require.NoError(t, err) + hbsFilePath := filepath.Join(templateDir, "template.hbs.link") + hbsContent := `../../../linked/linked_template.hbs` + err = os.WriteFile(hbsFilePath, []byte(hbsContent), 0o644) require.NoError(t, err) - err = validateFile(filePath) + fsys := fspath.DirFS(pkgDir) + err = validateTemplateDir(fsys, filepath.Join("agent", "input")) require.Error(t, err) }) - } diff --git a/code/go/pkg/validator/validator_test.go b/code/go/pkg/validator/validator_test.go index f26e1995..15ec9fca 100644 --- a/code/go/pkg/validator/validator_test.go +++ b/code/go/pkg/validator/validator_test.go @@ -914,8 +914,8 @@ func TestLinksAreBlocked(t *testing.T) { func TestValidateHandlebarsFiles(t *testing.T) { tests := map[string]string{ - "bad_input_hbs": "invalid handlebars template: file agent/input/input.yml.hbs: Parse error on line 10:\nExpecting OpenEndBlock, got: 'EOF'", - "bad_integration_hbs": "invalid handlebars template: file data_stream/foo/agent/stream/filestream.yml.hbs: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'", + "bad_input_hbs": "invalid handlebars template in agent/input: Parse error on line 10:\nExpecting OpenEndBlock, got: 'EOF'", + "bad_integration_hbs": "invalid handlebars template in data_stream/foo/agent/stream: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'", } for pkgName, expectedErrorMessage := range tests { From 32ab54d286fab839827f9daa47900156b44b2c75 Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Fri, 28 Nov 2025 16:42:31 +0100 Subject: [PATCH 11/26] Add bad integration Handlebars templates with linked files --- code/go/pkg/validator/validator_test.go | 5 +- .../bad_integration_hbs_linked/LICENSE.txt | 93 +++++++ .../_dev/build/docs/README.md | 101 +++++++ .../bad_integration_hbs_linked/changelog.yml | 6 + .../foo/agent/stream/filestream.yml.hbs.link | 1 + .../elasticsearch/ingest_pipeline/default.yml | 10 + .../data_stream/foo/fields/base-fields.yml | 12 + .../data_stream/foo/manifest.yml | 256 ++++++++++++++++++ .../bad_integration_hbs_linked/docs/README.md | 101 +++++++ .../img/sample-logo.svg | 1 + .../img/sample-screenshot.png | Bin 0 -> 18849 bytes .../bad_integration_hbs_linked/manifest.yml | 37 +++ .../sample_event.json | 3 + 13 files changed, 624 insertions(+), 2 deletions(-) create mode 100644 test/packages/bad_integration_hbs_linked/LICENSE.txt create mode 100644 test/packages/bad_integration_hbs_linked/_dev/build/docs/README.md create mode 100644 test/packages/bad_integration_hbs_linked/changelog.yml create mode 100644 test/packages/bad_integration_hbs_linked/data_stream/foo/agent/stream/filestream.yml.hbs.link create mode 100644 test/packages/bad_integration_hbs_linked/data_stream/foo/elasticsearch/ingest_pipeline/default.yml create mode 100644 test/packages/bad_integration_hbs_linked/data_stream/foo/fields/base-fields.yml create mode 100644 test/packages/bad_integration_hbs_linked/data_stream/foo/manifest.yml create mode 100644 test/packages/bad_integration_hbs_linked/docs/README.md create mode 100644 test/packages/bad_integration_hbs_linked/img/sample-logo.svg create mode 100644 test/packages/bad_integration_hbs_linked/img/sample-screenshot.png create mode 100644 test/packages/bad_integration_hbs_linked/manifest.yml create mode 100644 test/packages/bad_integration_hbs_linked/sample_event.json diff --git a/code/go/pkg/validator/validator_test.go b/code/go/pkg/validator/validator_test.go index 15ec9fca..1f026de5 100644 --- a/code/go/pkg/validator/validator_test.go +++ b/code/go/pkg/validator/validator_test.go @@ -914,8 +914,9 @@ func TestLinksAreBlocked(t *testing.T) { func TestValidateHandlebarsFiles(t *testing.T) { tests := map[string]string{ - "bad_input_hbs": "invalid handlebars template in agent/input: Parse error on line 10:\nExpecting OpenEndBlock, got: 'EOF'", - "bad_integration_hbs": "invalid handlebars template in data_stream/foo/agent/stream: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'", + "bad_input_hbs": "invalid handlebars template in agent/input: Parse error on line 10:\nExpecting OpenEndBlock, got: 'EOF'", + "bad_integration_hbs": "invalid handlebars template in data_stream/foo/agent/stream: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'", + "bad_integration_hbs_linked": "invalid handlebars template in data_stream/foo/agent/stream: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'", } for pkgName, expectedErrorMessage := range tests { diff --git a/test/packages/bad_integration_hbs_linked/LICENSE.txt b/test/packages/bad_integration_hbs_linked/LICENSE.txt new file mode 100644 index 00000000..809108b8 --- /dev/null +++ b/test/packages/bad_integration_hbs_linked/LICENSE.txt @@ -0,0 +1,93 @@ +Elastic License 2.0 + +URL: https://www.elastic.co/licensing/elastic-license + +## Acceptance + +By using the software, you agree to all of the terms and conditions below. + +## Copyright License + +The licensor grants you a non-exclusive, royalty-free, worldwide, +non-sublicensable, non-transferable license to use, copy, distribute, make +available, and prepare derivative works of the software, in each case subject to +the limitations and conditions below. + +## Limitations + +You may not provide the software to third parties as a hosted or managed +service, where the service provides users with access to any substantial set of +the features or functionality of the software. + +You may not move, change, disable, or circumvent the license key functionality +in the software, and you may not remove or obscure any functionality in the +software that is protected by the license key. + +You may not alter, remove, or obscure any licensing, copyright, or other notices +of the licensor in the software. Any use of the licensor’s trademarks is subject +to applicable law. + +## Patents + +The licensor grants you a license, under any patent claims the licensor can +license, or becomes able to license, to make, have made, use, sell, offer for +sale, import and have imported the software, in each case subject to the +limitations and conditions in this license. This license does not cover any +patent claims that you cause to be infringed by modifications or additions to +the software. If you or your company make any written claim that the software +infringes or contributes to infringement of any patent, your patent license for +the software granted under these terms ends immediately. If your company makes +such a claim, your patent license ends immediately for work on behalf of your +company. + +## Notices + +You must ensure that anyone who gets a copy of any part of the software from you +also gets a copy of these terms. + +If you modify the software, you must include in any modified copies of the +software prominent notices stating that you have modified the software. + +## No Other Rights + +These terms do not imply any licenses other than those expressly granted in +these terms. + +## Termination + +If you use the software in violation of these terms, such use is not licensed, +and your licenses will automatically terminate. If the licensor provides you +with a notice of your violation, and you cease all violation of this license no +later than 30 days after you receive that notice, your licenses will be +reinstated retroactively. However, if you violate these terms after such +reinstatement, any additional violation of these terms will cause your licenses +to terminate automatically and permanently. + +## No Liability + +*As far as the law allows, the software comes as is, without any warranty or +condition, and the licensor will not be liable to you for any damages arising +out of these terms or the use or nature of the software, under any kind of +legal claim.* + +## Definitions + +The **licensor** is the entity offering these terms, and the **software** is the +software the licensor makes available under these terms, including any portion +of it. + +**you** refers to the individual or entity agreeing to these terms. + +**your company** is any legal entity, sole proprietorship, or other kind of +organization that you work for, plus all organizations that have control over, +are under the control of, or are under common control with that +organization. **control** means ownership of substantially all the assets of an +entity, or the power to direct its management and policies by vote, contract, or +otherwise. Control can be direct or indirect. + +**your licenses** are all the licenses granted to you for the software under +these terms. + +**use** means anything you do with the software requiring one of your licenses. + +**trademark** means trademarks, service marks, and similar rights. diff --git a/test/packages/bad_integration_hbs_linked/_dev/build/docs/README.md b/test/packages/bad_integration_hbs_linked/_dev/build/docs/README.md new file mode 100644 index 00000000..7cc03b51 --- /dev/null +++ b/test/packages/bad_integration_hbs_linked/_dev/build/docs/README.md @@ -0,0 +1,101 @@ +{{- generatedHeader }} +{{/* +This template can be used as a starting point for writing documentation for your new integration. For each section, fill in the details +described in the comments. + +Find more detailed documentation guidelines in https://www.elastic.co/docs/extend/integrations/documentation-guidelines +*/}} +# bad integration hbs Integration for Elastic + +## Overview +{{/* Complete this section with a short summary of what data this integration collects and what use cases it enables */}} +The bad integration hbs integration for Elastic enables collection of ... +This integration facilitates ... + +### Compatibility +{{/* Complete this section with information on what 3rd party software or hardware versions this integration is compatible with */}} +This integration is compatible with ... + +### How it works +{{/* Add a high level overview on how this integration works. For example, does it collect data from API calls or recieving data from a network or file.*/}} + +## What data does this integration collect? +{{/* Complete this section with information on what types of data the integration collects, and link to reference documentation if available */}} +The bad integration hbs integration collects log messages of the following types: +* ... + +### Supported use cases +{{/* Add details on the use cases that can be enabled by using this integration. Explain why a user would want to install and use this integration. */}} + +## What do I need to use this integration? +{{/* List any vendor-specific prerequisites needed before starting to install the integration. */}} + +## How do I deploy this integration? + +### Agent-based deployment + +Elastic Agent must be installed. For more details, check the Elastic Agent [installation instructions](docs-content://reference/fleet/install-elastic-agents.md). You can install only one Elastic Agent per host. + +Elastic Agent is required to stream data from the syslog or log file receiver and ship the data to Elastic, where the events will then be processed via the integration's ingest pipelines. + +{{/* If agentless is available for this integration, we'll want to include that here as well. +### Agentless deployment + +Agentless deployments are only supported in Elastic Serverless and Elastic Cloud environments. Agentless deployments provide a means to ingest data while avoiding the orchestration, management, and maintenance needs associated with standard ingest infrastructure. Using an agentless deployment makes manual agent deployment unnecessary, allowing you to focus on your data instead of the agent that collects it. + +For more information, refer to [Agentless integrations](https://www.elastic.co/guide/en/serverless/current/security-agentless-integrations.html) and [Agentless integrations FAQ](https://www.elastic.co/guide/en/serverless/current/agentless-integration-troubleshooting.html) +*/}} + +### Onboard / configure +{{/* List the steps that will need to be followed in order to completely set up a working integration. +For integrations that support multiple input types, be sure to add steps for all inputs. +*/}} + +### Validation +{{/* How can the user test whether the integration is working? Including example commands or test files if applicable */}} + +## Troubleshooting + +For help with Elastic ingest tools, check [Common problems](https://www.elastic.co/docs/troubleshoot/ingest/fleet/common-problems). +{{/* +Add any vendor specific troubleshooting here. + +Are there common issues or “gotchas” for deploying this integration? If so, how can they be resolved? +If applicable, links to the third-party software’s troubleshooting documentation. +*/}} + +## Scaling + +For more information on architectures that can be used for scaling this integration, check the [Ingest Architectures](https://www.elastic.co/docs/manage-data/ingest/ingest-reference-architectures) documentation. +{{/* Add any vendor specific scaling information here */}} + +## Reference +{{/* Repeat for each data stream of the current type +### {Data stream name} + +The `{data stream name}` data stream provides events from {source} of the following types: {list types}. + +For each data_stream_name, include an optional summary of the datastream, the exported fields reference table and the sample event. + +The fields template function will be replaced by a generated list of all fields from the `fields/` directory of the data stream when building the integration. + +#### {data stream name} fields + +To include a generated list of fields from the `fields/` directory, uncomment and use: +{{ fields "data_stream_name" }} + +The event template function will be replace by a sample event, taken from `sample_event.json`, when building this integration. + +To include a sample event from `sample_event.json`, uncomment and use: +{{ event "data_stream_name" }} + +*/}} + +### Inputs used +{{/* All inputs used by this package will be automatically listed here. */}} +{{ inputDocs }} + +### API usage +{{/* For integrations that use APIs to collect data, document all the APIs that are used, and link to relevent information */}} +These APIs are used with this integration: +* ... diff --git a/test/packages/bad_integration_hbs_linked/changelog.yml b/test/packages/bad_integration_hbs_linked/changelog.yml new file mode 100644 index 00000000..bb0320a5 --- /dev/null +++ b/test/packages/bad_integration_hbs_linked/changelog.yml @@ -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 # FIXME Replace with the real PR link diff --git a/test/packages/bad_integration_hbs_linked/data_stream/foo/agent/stream/filestream.yml.hbs.link b/test/packages/bad_integration_hbs_linked/data_stream/foo/agent/stream/filestream.yml.hbs.link new file mode 100644 index 00000000..758fdf51 --- /dev/null +++ b/test/packages/bad_integration_hbs_linked/data_stream/foo/agent/stream/filestream.yml.hbs.link @@ -0,0 +1 @@ +../../../../../bad_integration_hbs/data_stream/foo/agent/stream/filestream.yml.hbs fc8773ba7c0efda3fadd617e6fc4385a54effd8fd715683ff2c3b2ad7be894d0 \ No newline at end of file diff --git a/test/packages/bad_integration_hbs_linked/data_stream/foo/elasticsearch/ingest_pipeline/default.yml b/test/packages/bad_integration_hbs_linked/data_stream/foo/elasticsearch/ingest_pipeline/default.yml new file mode 100644 index 00000000..1a308fde --- /dev/null +++ b/test/packages/bad_integration_hbs_linked/data_stream/foo/elasticsearch/ingest_pipeline/default.yml @@ -0,0 +1,10 @@ +--- +description: Pipeline for processing sample logs +processors: +- set: + field: sample_field + value: "1" +on_failure: +- set: + field: error.message + value: '{{ _ingest.on_failure_message }}' diff --git a/test/packages/bad_integration_hbs_linked/data_stream/foo/fields/base-fields.yml b/test/packages/bad_integration_hbs_linked/data_stream/foo/fields/base-fields.yml new file mode 100644 index 00000000..7c798f45 --- /dev/null +++ b/test/packages/bad_integration_hbs_linked/data_stream/foo/fields/base-fields.yml @@ -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. diff --git a/test/packages/bad_integration_hbs_linked/data_stream/foo/manifest.yml b/test/packages/bad_integration_hbs_linked/data_stream/foo/manifest.yml new file mode 100644 index 00000000..251bec6c --- /dev/null +++ b/test/packages/bad_integration_hbs_linked/data_stream/foo/manifest.yml @@ -0,0 +1,256 @@ +title: "New Data Stream" +type: logs +streams: + - input: filestream + title: "logs via filestream" + description: |- + Collect logs with filestream + template_path: filestream.yml.hbs + vars: + - name: paths + type: text + title: "Paths" + multi: true + required: true + show_user: true + default: + - /var/log/*.log + - name: data_stream.dataset + type: text + title: "Dataset name" + description: |- + Dataset to write data to. Changing the dataset will send the data to a different index. You can't use `-` in the name of a dataset and only valid characters for [Elasticsearch index names](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-index_.html). + required: true + show_user: true + default: filestream.generic + - name: pipeline + type: text + title: "Ingest Pipeline" + description: |- + The Ingest Node pipeline ID to be used by the integration. + show_user: true + - name: parsers + type: yaml + title: "Parsers" + description: |- + This option expects a list of parsers that the log line has to go through. For more information see [Parsers](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-filestream.html#_parsers) + show_user: true + default: "" + #- ndjson: + # target: "" + # message_key: msg + #- multiline: + # type: count + # count_lines: 3 + - name: exclude_files + type: text + title: "Exclude Files" + description: |- + A list of regular expressions to match the files that you want Elastic Agent to ignore. By default no files are excluded. + multi: true + show_user: true + default: + - \.gz$ + - name: include_files + type: text + title: "Include Files" + description: |- + A list of regular expressions to match the files that you want Elastic Agent to include. If a list of regexes is provided, only the files that are allowed by the patterns are harvested. + multi: true + show_user: true + - name: processors + type: yaml + title: "Processors" + description: |- + Processors are used to reduce the number of fields in the exported event or to enhance the event with metadata. This executes in the agent before the logs are parsed. See [Processors](https://www.elastic.co/guide/en/beats/filebeat/current/filtering-and-enhancing-data.html) for details. + - name: tags + type: text + title: "Tags" + description: |- + Tags to include in the published event + multi: true + show_user: true + - name: encoding + type: text + title: "Encoding" + description: |- + The file encoding to use for reading data that contains international characters. For a full list of valid encodings, see the [Documentation](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-filestream.html#_encoding_2) + - name: recursive_glob + type: bool + title: "Recursive Glob" + description: |- + Enable expanding `**` into recursive glob patterns. With this feature enabled, the rightmost `**` in each path is expanded into a fixed number of glob patterns. For example: `/foo/**` expands to `/foo`, `/foo/*`, `/foo/*/*`, and so on. If enabled it expands a single `**` into a 8-level deep `*` pattern. + This feature is enabled by default. Set prospector.scanner.recursive_glob to false to disable it. + default: true + - name: symlinks + type: bool + title: "Enable symlinks" + description: |- + The symlinks option allows Elastic Agent to harvest symlinks in addition to regular files. When harvesting symlinks, Elastic Agent opens and reads the original file even though it reports the path of the symlink. + **Because this option may lead to data loss, it is disabled by default.** + - name: resend_on_touch + type: bool + title: "Resend on touch" + description: |- + If this option is enabled a file is resent if its size has not changed but its modification time has changed to a later time than before. It is disabled by default to avoid accidentally resending files. + - name: check_interval + type: text + title: "Check Interval" + description: |- + How often Elastic Agent checks for new files in the paths that are specified for harvesting. For example Specify 1s to scan the directory as frequently as possible without causing Elastic Agent to scan too frequently. **We do not recommend to set this value <1s.** + - name: ignore_older + type: text + title: "Ignore Older" + description: |- + If this option is enabled, Elastic Agent ignores any files that were modified before the specified timespan. You can use time strings like 2h (2 hours) and 5m (5 minutes). The default is 0, which disables the setting. + You must set Ignore Older to be greater than On State Change Inactive. + For more information, please see the [Documentation](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-filestream.html#filebeat-input-filestream-ignore-older) + - name: ignore_inactive + type: text + title: "Ignore Inactive" + description: |- + If this option is enabled, Elastic Agent ignores every file that has not been updated since the selected time. Possible options are since_first_start and since_last_start. + - name: close_on_state_changed_inactive + type: text + title: "Close on State Changed Inactive" + description: |- + When this option is enabled, Elastic Agent closes the file handle if a file has not been harvested for the specified duration. The counter for the defined period starts when the last log line was read by the harvester. It is not based on the modification time of the file. If the closed file changes again, a new harvester is started and the latest changes will be picked up after Check Interval has elapsed. + - name: close_on_state_changed_renamed + type: bool + title: "Close on State Changed Renamed" + description: |- + **Only use this option if you understand that data loss is a potential side effect.** + When this option is enabled, Elastic Agent closes the file handler when a file is renamed. This happens, for example, when rotating files. By default, the harvester stays open and keeps reading the file because the file handler does not depend on the file name. + - name: close_on_state_changed_removed + type: bool + title: "Close on State Changed Removed" + description: |- + When this option is enabled, Elastic Agent closes the harvester when a file is removed. Normally a file should only be removed after it’s inactive for the duration specified by close.on_state_change.inactive. + - name: close_reader_eof + type: bool + title: "Close Reader EOF" + description: |- + **Only use this option if you understand that data loss is a potential side effect.** + When this option is enabled, Elastic Agent closes a file as soon as the end of a file is reached. This is useful when your files are only written once and not updated from time to time. For example, this happens when you are writing every single log event to a new file. This option is disabled by default. + - name: close_reader_after_interval + type: text + title: "Close Reader After Interval" + description: |- + **Only use this option if you understand that data loss is a potential side effect. Another side effect is that multiline events might not be completely sent before the timeout expires.** + This option is particularly useful in case the output is blocked, which makes Elastic Agent keep open file handlers even for files that were deleted from the disk. + For more information see the [documentation](https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-filestream.html#filebeat-input-filestream-close-timeout). + - name: clean_inactive + type: text + title: "Clean Inactive" + description: |- + **Only use this option if you understand that data loss is a potential side effect.** + When this option is enabled, Elastic Agent removes the state of a file after the specified period of inactivity has elapsed. + E.g: "30m", Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". By default cleaning inactive states is disabled, -1 is used to disable it. + default: -1 + - name: clean_removed + type: bool + title: "Clean Removed" + description: |- + When this option is enabled, Elastic Agent cleans files from the registry if they cannot be found on disk anymore under the last known name. + **You must disable this option if you also disable Close Removed.** + - name: harvester_limit + type: integer + title: "Harvester Limit" + description: |- + The harvester_limit option limits the number of harvesters + that are started in parallel for one input. This directly + relates to the maximum number of file handlers that are + opened. The default is 0 (no limit). + default: 0 + - name: backoff_init + type: text + title: "Backoff Init" + description: |- + The backoff option defines how long Elastic Agent waits before checking a file again after EOF is reached. The default is 1s. + - name: backoff_max + type: text + title: "Backoff Max" + description: |- + The maximum time for Elastic Agent to wait before checking a file again after EOF is reached. The default is 10s. + **Requirement: Set Backoff Max to be greater than or equal to Backoff Init and less than or equal to Check Interval (Backoff Init <= Backoff Max <= Check Interval).** + - name: fingerprint + type: bool + title: "File identity: Fingerprint" + description: |- + **Changing file_identity methods between runs may result in + duplicated events in the output.** + Uses a fingerprint generated from the first few bytes (1k is + the default, this can be configured via Fingerprint offset + and length) to identify a file instead inode + device ID. + Refer to https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-input-filestream.html#_file_identity_2 + for more details. If this option is disabled (and 'Native + file identity is not enabled'), Elastic-Agent < 9.0.0 will + use Native as the file identity, and >= 9.0.0 will use + Fingerprint with the default offset and length. + default: true + - name: fingerprint_offset + type: integer + title: "File identity: Fingerprint offset" + description: |- + Offset from the beginning of the file to start calculating + the fingerprint. The default is 0. Only used when the + fingerprint file identity is selected + default: 0 + - name: fingerprint_length + type: integer + title: "File identity: Fingerprint length" + description: |- + The number of bytes used to calculate the fingerprint. The + default is 1024. Only used when the fingerprint file + identity is selected. + default: 1024 + - name: file_identity_native + type: bool + title: "File identity: Native" + description: |- + **Changing file_identity methods between runs may result in + duplicated events in the output.** + Uses a native identifier for files, on most Unix-like + file systems this is the inode + device ID. On file systems + that do not support inode, the native equivalent is used. + If you enable this option you **MUST disable Fingerprint + file identity**. Refer to + https://www.elastic.co/docs/reference/beats/filebeat/filebeat-input-filestream + for more details. + default: false + - name: rotation_external_strategy_copytruncate + type: yaml + title: "Rotation Strategy" + description: "If the log rotating application copies the contents of the active file and then truncates the original file, use these options to help Elastic Agent to read files correctly.\nSet the option suffix_regex so Elastic Agent can tell active and rotated files apart. \nThere are two supported suffix types in the input: numberic and date." + - name: exclude_lines + type: text + title: "Exclude Lines" + description: |- + A list of regular expressions to match the lines that you want Elastic Agent to exclude. Elastic Agent drops any lines that match a regular expression in the list. By default, no lines are dropped. Empty lines are ignored. + multi: true + - name: include_lines + type: text + title: "Include Lines" + description: |- + A list of regular expressions to match the lines that you want Elastic Agent to include. Elastic Agent exports only the lines that match a regular expression in the list. By default, all lines are exported. Empty lines are ignored. + multi: true + - name: buffer_size + type: text + title: "Buffer Size" + description: |- + The size in bytes of the buffer that each harvester uses when fetching a file. The default is 16384. + - name: message_max_bytes + type: text + title: "Message Max Bytes" + description: |- + The maximum number of bytes that a single log message can have. All bytes after mesage_max_bytes are discarded and not sent. The default is 10MB (10485760). + - name: condition + type: text + title: "Condition" + description: |- + Condition to filter when to collect this input. See [Dynamic Input Configuration](https://www.elastic.co/guide/en/fleet/current/dynamic-input-configuration.html) for details. + show_user: true +elasticsearch: + index_template: + mappings: + subobjects: false diff --git a/test/packages/bad_integration_hbs_linked/docs/README.md b/test/packages/bad_integration_hbs_linked/docs/README.md new file mode 100644 index 00000000..7cc03b51 --- /dev/null +++ b/test/packages/bad_integration_hbs_linked/docs/README.md @@ -0,0 +1,101 @@ +{{- generatedHeader }} +{{/* +This template can be used as a starting point for writing documentation for your new integration. For each section, fill in the details +described in the comments. + +Find more detailed documentation guidelines in https://www.elastic.co/docs/extend/integrations/documentation-guidelines +*/}} +# bad integration hbs Integration for Elastic + +## Overview +{{/* Complete this section with a short summary of what data this integration collects and what use cases it enables */}} +The bad integration hbs integration for Elastic enables collection of ... +This integration facilitates ... + +### Compatibility +{{/* Complete this section with information on what 3rd party software or hardware versions this integration is compatible with */}} +This integration is compatible with ... + +### How it works +{{/* Add a high level overview on how this integration works. For example, does it collect data from API calls or recieving data from a network or file.*/}} + +## What data does this integration collect? +{{/* Complete this section with information on what types of data the integration collects, and link to reference documentation if available */}} +The bad integration hbs integration collects log messages of the following types: +* ... + +### Supported use cases +{{/* Add details on the use cases that can be enabled by using this integration. Explain why a user would want to install and use this integration. */}} + +## What do I need to use this integration? +{{/* List any vendor-specific prerequisites needed before starting to install the integration. */}} + +## How do I deploy this integration? + +### Agent-based deployment + +Elastic Agent must be installed. For more details, check the Elastic Agent [installation instructions](docs-content://reference/fleet/install-elastic-agents.md). You can install only one Elastic Agent per host. + +Elastic Agent is required to stream data from the syslog or log file receiver and ship the data to Elastic, where the events will then be processed via the integration's ingest pipelines. + +{{/* If agentless is available for this integration, we'll want to include that here as well. +### Agentless deployment + +Agentless deployments are only supported in Elastic Serverless and Elastic Cloud environments. Agentless deployments provide a means to ingest data while avoiding the orchestration, management, and maintenance needs associated with standard ingest infrastructure. Using an agentless deployment makes manual agent deployment unnecessary, allowing you to focus on your data instead of the agent that collects it. + +For more information, refer to [Agentless integrations](https://www.elastic.co/guide/en/serverless/current/security-agentless-integrations.html) and [Agentless integrations FAQ](https://www.elastic.co/guide/en/serverless/current/agentless-integration-troubleshooting.html) +*/}} + +### Onboard / configure +{{/* List the steps that will need to be followed in order to completely set up a working integration. +For integrations that support multiple input types, be sure to add steps for all inputs. +*/}} + +### Validation +{{/* How can the user test whether the integration is working? Including example commands or test files if applicable */}} + +## Troubleshooting + +For help with Elastic ingest tools, check [Common problems](https://www.elastic.co/docs/troubleshoot/ingest/fleet/common-problems). +{{/* +Add any vendor specific troubleshooting here. + +Are there common issues or “gotchas” for deploying this integration? If so, how can they be resolved? +If applicable, links to the third-party software’s troubleshooting documentation. +*/}} + +## Scaling + +For more information on architectures that can be used for scaling this integration, check the [Ingest Architectures](https://www.elastic.co/docs/manage-data/ingest/ingest-reference-architectures) documentation. +{{/* Add any vendor specific scaling information here */}} + +## Reference +{{/* Repeat for each data stream of the current type +### {Data stream name} + +The `{data stream name}` data stream provides events from {source} of the following types: {list types}. + +For each data_stream_name, include an optional summary of the datastream, the exported fields reference table and the sample event. + +The fields template function will be replaced by a generated list of all fields from the `fields/` directory of the data stream when building the integration. + +#### {data stream name} fields + +To include a generated list of fields from the `fields/` directory, uncomment and use: +{{ fields "data_stream_name" }} + +The event template function will be replace by a sample event, taken from `sample_event.json`, when building this integration. + +To include a sample event from `sample_event.json`, uncomment and use: +{{ event "data_stream_name" }} + +*/}} + +### Inputs used +{{/* All inputs used by this package will be automatically listed here. */}} +{{ inputDocs }} + +### API usage +{{/* For integrations that use APIs to collect data, document all the APIs that are used, and link to relevent information */}} +These APIs are used with this integration: +* ... diff --git a/test/packages/bad_integration_hbs_linked/img/sample-logo.svg b/test/packages/bad_integration_hbs_linked/img/sample-logo.svg new file mode 100644 index 00000000..6268dd88 --- /dev/null +++ b/test/packages/bad_integration_hbs_linked/img/sample-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/packages/bad_integration_hbs_linked/img/sample-screenshot.png b/test/packages/bad_integration_hbs_linked/img/sample-screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..d7a56a3ecc078c38636698cefba33f86291dd178 GIT binary patch literal 18849 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

}qal5$moSACwfNXLXG5|3R0AtBcN` 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 literal 0 HcmV?d00001 diff --git a/test/packages/bad_integration_hbs_linked/manifest.yml b/test/packages/bad_integration_hbs_linked/manifest.yml new file mode 100644 index 00000000..30b0184b --- /dev/null +++ b/test/packages/bad_integration_hbs_linked/manifest.yml @@ -0,0 +1,37 @@ +format_version: 3.5.4 +name: bad_integration_hbs +title: "bad integration hbs" +version: 0.0.1 +source: + license: "Elastic-2.0" +description: "package with wrong hbs templates at data stream" +type: integration +categories: + - custom + - aws +conditions: + kibana: + version: "^9.2.1" + elastic: + subscription: "basic" +screenshots: + - src: /img/sample-screenshot.png + title: Sample screenshot + size: 600x600 + type: image/png +icons: + - src: /img/sample-logo.svg + title: Sample logo + size: 32x32 + type: image/svg+xml +policy_templates: + - name: sample + title: Sample logs + description: Collect sample logs + inputs: + - type: logfile + title: Collect sample logs from instances + description: Collecting sample logs +owner: + github: elastic/integrations + type: elastic diff --git a/test/packages/bad_integration_hbs_linked/sample_event.json b/test/packages/bad_integration_hbs_linked/sample_event.json new file mode 100644 index 00000000..e302589f --- /dev/null +++ b/test/packages/bad_integration_hbs_linked/sample_event.json @@ -0,0 +1,3 @@ +{ + "description": "This is an example sample-event for bad integration hbs. Replace it with a real sample event. Hint: If system tests exist, running `elastic-package test system --generate` will generate this file." +} From bc7eee5a19869c6db2771b33fa43a48db3f06281 Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Fri, 28 Nov 2025 16:44:44 +0100 Subject: [PATCH 12/26] Reorder import statements for consistency in validate_hbs_templates_test.go --- .../internal/validator/semantic/validate_hbs_templates_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/go/internal/validator/semantic/validate_hbs_templates_test.go b/code/go/internal/validator/semantic/validate_hbs_templates_test.go index fc3714f7..1cf914fe 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates_test.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates_test.go @@ -9,8 +9,9 @@ import ( "path/filepath" "testing" - "github.com/elastic/package-spec/v3/code/go/internal/fspath" "github.com/stretchr/testify/require" + + "github.com/elastic/package-spec/v3/code/go/internal/fspath" ) func TestValidateTemplateDir(t *testing.T) { From 0f1ae93800d6715c327295d861d71385e78f0e89 Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Mon, 1 Dec 2025 10:04:27 +0100 Subject: [PATCH 13/26] use path instead of filepath --- .../semantic/validate_hbs_templates.go | 9 ++-- .../semantic/validate_hbs_templates_test.go | 48 +++++++++---------- 2 files changed, 28 insertions(+), 29 deletions(-) diff --git a/code/go/internal/validator/semantic/validate_hbs_templates.go b/code/go/internal/validator/semantic/validate_hbs_templates.go index 96a737ec..fc93a423 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates.go @@ -8,7 +8,6 @@ import ( "errors" "io/fs" "path" - "path/filepath" "github.com/mailgun/raymond/v2" @@ -27,7 +26,7 @@ var ( func ValidateHandlebarsFiles(fsys fspath.FS) specerrors.ValidationErrors { // template files are placed at /agent/input directory or // at the datastream /agent/stream directory - inputDir := filepath.Join("agent", "input") + inputDir := path.Join("agent", "input") err := validateTemplateDir(fsys, inputDir) if err != nil { return specerrors.ValidationErrors{ @@ -45,7 +44,7 @@ func ValidateHandlebarsFiles(fsys fspath.FS) specerrors.ValidationErrors { if !dsEntry.IsDir() { continue } - streamDir := filepath.Join("data_stream", dsEntry.Name(), "agent", "stream") + streamDir := path.Join("data_stream", dsEntry.Name(), "agent", "stream") err := validateTemplateDir(fsys, streamDir) if err != nil { return specerrors.ValidationErrors{ @@ -64,14 +63,14 @@ func validateTemplateDir(fsys fspath.FS, dir string) error { return err } for _, entry := range entries { - if filepath.Ext(entry.Name()) == ".hbs" { + if path.Ext(entry.Name()) == ".hbs" { err := validateHandlebarsEntry(fsys, dir, entry.Name()) if err != nil { return err } continue } - if filepath.Ext(entry.Name()) == ".link" { + if path.Ext(entry.Name()) == ".link" { linkFilePath := path.Join(dir, entry.Name()) linkFile, err := linkedfiles.NewLinkedFile(fsys.Path(linkFilePath)) if err != nil { diff --git a/code/go/internal/validator/semantic/validate_hbs_templates_test.go b/code/go/internal/validator/semantic/validate_hbs_templates_test.go index 1cf914fe..fbccc7fd 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates_test.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates_test.go @@ -6,7 +6,7 @@ package semantic import ( "os" - "path/filepath" + "path" "testing" "github.com/stretchr/testify/require" @@ -17,106 +17,106 @@ import ( func TestValidateTemplateDir(t *testing.T) { t.Run("empty directory", func(t *testing.T) { tmpDir := t.TempDir() - pkgDir := filepath.Join(tmpDir, "package") + pkgDir := path.Join(tmpDir, "package") err := os.MkdirAll(pkgDir, 0o755) require.NoError(t, err) - templateDir := filepath.Join(pkgDir, "agent", "input") + templateDir := path.Join(pkgDir, "agent", "input") err = os.MkdirAll(templateDir, 0o755) require.NoError(t, err) fsys := fspath.DirFS(pkgDir) - err = validateTemplateDir(fsys, filepath.Join("agent", "input")) + err = validateTemplateDir(fsys, path.Join("agent", "input")) require.NoError(t, err) }) t.Run("valid handlebars file", func(t *testing.T) { tmpDir := t.TempDir() - pkgDir := filepath.Join(tmpDir, "package") + pkgDir := path.Join(tmpDir, "package") err := os.MkdirAll(pkgDir, 0o755) require.NoError(t, err) - templateDir := filepath.Join(pkgDir, "agent", "input") + templateDir := path.Join(pkgDir, "agent", "input") err = os.MkdirAll(templateDir, 0o755) require.NoError(t, err) - hbsFilePath := filepath.Join(templateDir, "template.hbs") + hbsFilePath := path.Join(templateDir, "template.hbs") hbsContent := `{{#if condition}}Valid Handlebars{{/if}}` err = os.WriteFile(hbsFilePath, []byte(hbsContent), 0o644) require.NoError(t, err) fsys := fspath.DirFS(pkgDir) - err = validateTemplateDir(fsys, filepath.Join("agent", "input")) + err = validateTemplateDir(fsys, path.Join("agent", "input")) require.NoError(t, err) }) t.Run("invalid handlebars file", func(t *testing.T) { tmpDir := t.TempDir() - pkgDir := filepath.Join(tmpDir, "package") + pkgDir := path.Join(tmpDir, "package") err := os.MkdirAll(pkgDir, 0o755) require.NoError(t, err) - templateDir := filepath.Join(pkgDir, "agent", "input") + templateDir := path.Join(pkgDir, "agent", "input") err = os.MkdirAll(templateDir, 0o755) require.NoError(t, err) - hbsFilePath := filepath.Join(templateDir, "template.hbs") + hbsFilePath := path.Join(templateDir, "template.hbs") hbsContent := `{{#if condition}}Valid Handlebars` err = os.WriteFile(hbsFilePath, []byte(hbsContent), 0o644) require.NoError(t, err) fsys := fspath.DirFS(pkgDir) - err = validateTemplateDir(fsys, filepath.Join("agent", "input")) + err = validateTemplateDir(fsys, path.Join("agent", "input")) require.Error(t, err) }) t.Run("valid linked handlebars file", func(t *testing.T) { tmpDir := t.TempDir() - pkgDir := filepath.Join(tmpDir, "package") + pkgDir := path.Join(tmpDir, "package") err := os.MkdirAll(pkgDir, 0o755) require.NoError(t, err) - pkgDirLinked := filepath.Join(tmpDir, "linked") + pkgDirLinked := path.Join(tmpDir, "linked") err = os.MkdirAll(pkgDirLinked, 0o755) require.NoError(t, err) - linkedHbsFilePath := filepath.Join(pkgDirLinked, "linked_template.hbs") + linkedHbsFilePath := path.Join(pkgDirLinked, "linked_template.hbs") linkedHbsContent := `{{#if condition}}Valid Linked Handlebars{{/if}}` err = os.WriteFile(linkedHbsFilePath, []byte(linkedHbsContent), 0o644) require.NoError(t, err) - templateDir := filepath.Join(pkgDir, "agent", "input") + templateDir := path.Join(pkgDir, "agent", "input") err = os.MkdirAll(templateDir, 0o755) require.NoError(t, err) - hbsFilePath := filepath.Join(templateDir, "template.hbs.link") + hbsFilePath := path.Join(templateDir, "template.hbs.link") hbsContent := `../../../linked/linked_template.hbs` err = os.WriteFile(hbsFilePath, []byte(hbsContent), 0o644) require.NoError(t, err) fsys := fspath.DirFS(pkgDir) - err = validateTemplateDir(fsys, filepath.Join("agent", "input")) + err = validateTemplateDir(fsys, path.Join("agent", "input")) require.NoError(t, err) }) t.Run("invalid linked handlebars file", func(t *testing.T) { tmpDir := t.TempDir() - pkgDir := filepath.Join(tmpDir, "package") + pkgDir := path.Join(tmpDir, "package") err := os.MkdirAll(pkgDir, 0o755) require.NoError(t, err) - pkgDirLinked := filepath.Join(tmpDir, "linked") + pkgDirLinked := path.Join(tmpDir, "linked") err = os.MkdirAll(pkgDirLinked, 0o755) require.NoError(t, err) - linkedHbsFilePath := filepath.Join(pkgDirLinked, "linked_template.hbs") + linkedHbsFilePath := path.Join(pkgDirLinked, "linked_template.hbs") linkedHbsContent := `{{#if condition}}Valid Linked Handlebars` err = os.WriteFile(linkedHbsFilePath, []byte(linkedHbsContent), 0o644) require.NoError(t, err) - templateDir := filepath.Join(pkgDir, "agent", "input") + templateDir := path.Join(pkgDir, "agent", "input") err = os.MkdirAll(templateDir, 0o755) require.NoError(t, err) - hbsFilePath := filepath.Join(templateDir, "template.hbs.link") + hbsFilePath := path.Join(templateDir, "template.hbs.link") hbsContent := `../../../linked/linked_template.hbs` err = os.WriteFile(hbsFilePath, []byte(hbsContent), 0o644) require.NoError(t, err) fsys := fspath.DirFS(pkgDir) - err = validateTemplateDir(fsys, filepath.Join("agent", "input")) + err = validateTemplateDir(fsys, path.Join("agent", "input")) require.Error(t, err) }) } From d4898fe9496e4d15ac94530bf5f0fd97a09a7719 Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Mon, 1 Dec 2025 10:22:37 +0100 Subject: [PATCH 14/26] Replace filepath.Join with path.Join in TestValidateHandlebarsFiles for consistency --- code/go/pkg/validator/validator_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/go/pkg/validator/validator_test.go b/code/go/pkg/validator/validator_test.go index 1f026de5..a406c231 100644 --- a/code/go/pkg/validator/validator_test.go +++ b/code/go/pkg/validator/validator_test.go @@ -921,7 +921,7 @@ func TestValidateHandlebarsFiles(t *testing.T) { for pkgName, expectedErrorMessage := range tests { t.Run(pkgName, func(t *testing.T) { - errs := ValidateFromPath(filepath.Join("..", "..", "..", "..", "test", "packages", pkgName)) + errs := ValidateFromPath(path.Join("..", "..", "..", "..", "test", "packages", pkgName)) require.Error(t, errs) vErrs, ok := errs.(specerrors.ValidationErrors) require.True(t, ok) From d6ee0cd3eb040bbe7c502b622ddb777ff9faf708 Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Mon, 1 Dec 2025 16:29:37 +0100 Subject: [PATCH 15/26] fix validateHandlebarsEntry to read file content from filesystem or absolute path for linked files --- .../semantic/validate_hbs_templates.go | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/code/go/internal/validator/semantic/validate_hbs_templates.go b/code/go/internal/validator/semantic/validate_hbs_templates.go index fc93a423..9d88f2ef 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates.go @@ -7,6 +7,7 @@ package semantic import ( "errors" "io/fs" + "os" "path" "github.com/mailgun/raymond/v2" @@ -92,7 +93,22 @@ func validateHandlebarsEntry(fsys fspath.FS, dir, entryName string) error { if entryName == "" { return nil } - filePath := fsys.Path(path.Join(dir, entryName)) - _, err := raymond.ParseFile(filePath) + + var content []byte + var err error + + // First try to read from filesystem (works for regular files and files within zip) + filePath := path.Join(dir, entryName) + if content, err = fs.ReadFile(fsys, filePath); err != nil { + // If fs.ReadFile fails (likely due to linked file path outside filesystem boundary), + // fall back to absolute path approach like linkedfiles.FS does + absolutePath := fsys.Path(filePath) + if content, err = os.ReadFile(absolutePath); err != nil { + return err + } + } + + // Parse from content string instead of file path + _, err = raymond.Parse(string(content)) return err } From ab1a5417ae9507c48b8a2d5f3d5e3a86b2a0848b Mon Sep 17 00:00:00 2001 From: Teresa Romero Date: Wed, 3 Dec 2025 12:01:53 +0100 Subject: [PATCH 16/26] Reorder logrus dependency in go.mod for consistency --- go.mod | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/go.mod b/go.mod index a749446d..9f4dea54 100644 --- a/go.mod +++ b/go.mod @@ -25,8 +25,6 @@ require ( honnef.co/go/tools v0.6.1 ) -require github.com/sirupsen/logrus v1.8.1 // indirect - require ( github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect github.com/PaesslerAG/gval v1.0.0 // indirect @@ -42,6 +40,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/otiai10/mint v1.6.3 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/sirupsen/logrus v1.8.1 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 // indirect From 0d298e7a338f4843d6740d74c272f04ed1f5a7cd Mon Sep 17 00:00:00 2001 From: Tere Date: Wed, 3 Dec 2025 14:31:34 +0100 Subject: [PATCH 17/26] Improve error messages in Handlebars validation for clarity --- .../validator/semantic/validate_hbs_templates.go | 13 +++++++------ code/go/pkg/validator/validator_test.go | 6 +++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/code/go/internal/validator/semantic/validate_hbs_templates.go b/code/go/internal/validator/semantic/validate_hbs_templates.go index 9d88f2ef..5bd091ba 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates.go @@ -6,6 +6,7 @@ package semantic import ( "errors" + "fmt" "io/fs" "os" "path" @@ -31,7 +32,7 @@ func ValidateHandlebarsFiles(fsys fspath.FS) specerrors.ValidationErrors { err := validateTemplateDir(fsys, inputDir) if err != nil { return specerrors.ValidationErrors{ - specerrors.NewStructuredErrorf("%w in %s: %w", errInvalidHandlebarsTemplate, inputDir, err), + specerrors.NewStructuredErrorf("%w: %w", errInvalidHandlebarsTemplate, err), } } @@ -49,7 +50,7 @@ func ValidateHandlebarsFiles(fsys fspath.FS) specerrors.ValidationErrors { err := validateTemplateDir(fsys, streamDir) if err != nil { return specerrors.ValidationErrors{ - specerrors.NewStructuredErrorf("%w in %s: %w", errInvalidHandlebarsTemplate, streamDir, err), + specerrors.NewStructuredErrorf("%w: %w", errInvalidHandlebarsTemplate, err), } } } @@ -61,13 +62,13 @@ func ValidateHandlebarsFiles(fsys fspath.FS) specerrors.ValidationErrors { func validateTemplateDir(fsys fspath.FS, dir string) error { entries, err := fs.ReadDir(fsys, dir) if err != nil && !errors.Is(err, fs.ErrNotExist) { - return err + return fmt.Errorf("error trying to read :%s", dir) } for _, entry := range entries { if path.Ext(entry.Name()) == ".hbs" { err := validateHandlebarsEntry(fsys, dir, entry.Name()) if err != nil { - return err + return fmt.Errorf("error validating %s: %w", path.Join(dir, entry.Name()), err) } continue } @@ -75,11 +76,11 @@ func validateTemplateDir(fsys fspath.FS, dir string) error { linkFilePath := path.Join(dir, entry.Name()) linkFile, err := linkedfiles.NewLinkedFile(fsys.Path(linkFilePath)) if err != nil { - return err + return fmt.Errorf("error reading linked file %s: %w", linkFilePath, err) } err = validateHandlebarsEntry(fsys, dir, linkFile.IncludedFilePath) if err != nil { - return err + return fmt.Errorf("error validating %s: %w", path.Join(dir, linkFile.IncludedFilePath), err) } continue } diff --git a/code/go/pkg/validator/validator_test.go b/code/go/pkg/validator/validator_test.go index a406c231..40fe0bc0 100644 --- a/code/go/pkg/validator/validator_test.go +++ b/code/go/pkg/validator/validator_test.go @@ -914,9 +914,9 @@ func TestLinksAreBlocked(t *testing.T) { func TestValidateHandlebarsFiles(t *testing.T) { tests := map[string]string{ - "bad_input_hbs": "invalid handlebars template in agent/input: Parse error on line 10:\nExpecting OpenEndBlock, got: 'EOF'", - "bad_integration_hbs": "invalid handlebars template in data_stream/foo/agent/stream: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'", - "bad_integration_hbs_linked": "invalid handlebars template in data_stream/foo/agent/stream: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'", + "bad_input_hbs": "invalid handlebars template: error validating agent/input/input.yml.hbs: Parse error on line 10:\nExpecting OpenEndBlock, got: 'EOF'", + "bad_integration_hbs": "invalid handlebars template: error validating data_stream/foo/agent/stream/filestream.yml.hbs: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'", + "bad_integration_hbs_linked": "invalid handlebars template: error validating ../bad_integration_hbs/data_stream/foo/agent/stream/filestream.yml.hbs: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'", } for pkgName, expectedErrorMessage := range tests { From e69975909653bebab1d024da4c099a48d9282de6 Mon Sep 17 00:00:00 2001 From: Tere Date: Wed, 3 Dec 2025 14:42:57 +0100 Subject: [PATCH 18/26] Add link to Fleet implementation link for available Handlebars helpers in spec files --- spec/integration/agent/spec.yml | 2 ++ spec/integration/data_stream/agent/spec.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/spec/integration/agent/spec.yml b/spec/integration/agent/spec.yml index 8c9f9eab..97c7974c 100644 --- a/spec/integration/agent/spec.yml +++ b/spec/integration/agent/spec.yml @@ -17,6 +17,8 @@ spec: - `escape_multiline_string` (escapes multiline strings without wrapping), - `to_json` (converts object to JSON string), and - `url_encode` (URI encodes string). + Check the Fleet implementation for the complete list of available helpers: + https://github.com/elastic/kibana/blob/70749d9216d7a5de6ce1e7a028d153d5390ad3ac/x-pack/platform/plugins/shared/fleet/server/services/epm/agent/agent.ts#L1). type: file sizeLimit: 2MB pattern: '^.+\.yml\.hbs$' diff --git a/spec/integration/data_stream/agent/spec.yml b/spec/integration/data_stream/agent/spec.yml index 8f51146f..d9a25d20 100644 --- a/spec/integration/data_stream/agent/spec.yml +++ b/spec/integration/data_stream/agent/spec.yml @@ -17,6 +17,8 @@ spec: - `escape_multiline_string` (escapes multiline strings without wrapping), - `to_json` (converts object to JSON string), and - `url_encode` (URI encodes string). + Check the Fleet implementation for the complete list of available helpers: + https://github.com/elastic/kibana/blob/70749d9216d7a5de6ce1e7a028d153d5390ad3ac/x-pack/platform/plugins/shared/fleet/server/services/epm/agent/agent.ts#L1). type: file sizeLimit: 2MB pattern: '^.+\.yml\.hbs$' From 31644e8b1e083fadd409464230d4c01165bf5b5f Mon Sep 17 00:00:00 2001 From: Tere Date: Wed, 3 Dec 2025 14:53:53 +0100 Subject: [PATCH 19/26] Refactor Handlebars validation to return structured errors and update tests for clarity --- .../semantic/validate_hbs_templates.go | 21 +++++++++-------- .../semantic/validate_hbs_templates_test.go | 23 +++++++++++-------- code/go/pkg/validator/validator_test.go | 6 ++--- 3 files changed, 27 insertions(+), 23 deletions(-) diff --git a/code/go/internal/validator/semantic/validate_hbs_templates.go b/code/go/internal/validator/semantic/validate_hbs_templates.go index 5bd091ba..cfa437c4 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates.go @@ -6,7 +6,6 @@ package semantic import ( "errors" - "fmt" "io/fs" "os" "path" @@ -29,8 +28,7 @@ func ValidateHandlebarsFiles(fsys fspath.FS) specerrors.ValidationErrors { // template files are placed at /agent/input directory or // at the datastream /agent/stream directory inputDir := path.Join("agent", "input") - err := validateTemplateDir(fsys, inputDir) - if err != nil { + if err := validateTemplateDir(fsys, inputDir); err != nil { return specerrors.ValidationErrors{ specerrors.NewStructuredErrorf("%w: %w", errInvalidHandlebarsTemplate, err), } @@ -59,16 +57,19 @@ func ValidateHandlebarsFiles(fsys fspath.FS) specerrors.ValidationErrors { } // validateTemplateDir validates all Handlebars files in the given directory. -func validateTemplateDir(fsys fspath.FS, dir string) error { +func validateTemplateDir(fsys fspath.FS, dir string) specerrors.ValidationErrors { entries, err := fs.ReadDir(fsys, dir) if err != nil && !errors.Is(err, fs.ErrNotExist) { - return fmt.Errorf("error trying to read :%s", dir) + return specerrors.ValidationErrors{ + specerrors.NewStructuredErrorf("error trying to read :%s", dir), + } } + var errs specerrors.ValidationErrors for _, entry := range entries { if path.Ext(entry.Name()) == ".hbs" { err := validateHandlebarsEntry(fsys, dir, entry.Name()) if err != nil { - return fmt.Errorf("error validating %s: %w", path.Join(dir, entry.Name()), err) + errs = append(errs, specerrors.NewStructuredErrorf("error validating %s: %w", path.Join(dir, entry.Name()), err)) } continue } @@ -76,16 +77,16 @@ func validateTemplateDir(fsys fspath.FS, dir string) error { linkFilePath := path.Join(dir, entry.Name()) linkFile, err := linkedfiles.NewLinkedFile(fsys.Path(linkFilePath)) if err != nil { - return fmt.Errorf("error reading linked file %s: %w", linkFilePath, err) + errs = append(errs, specerrors.NewStructuredErrorf("error reading linked file %s: %w", linkFilePath, err)) + continue } err = validateHandlebarsEntry(fsys, dir, linkFile.IncludedFilePath) if err != nil { - return fmt.Errorf("error validating %s: %w", path.Join(dir, linkFile.IncludedFilePath), err) + errs = append(errs, specerrors.NewStructuredErrorf("error validating %s: %w", path.Join(dir, linkFile.IncludedFilePath), err)) } - continue } } - return nil + return errs } // validateHandlebarsEntry validates a single Handlebars file located at filePath. diff --git a/code/go/internal/validator/semantic/validate_hbs_templates_test.go b/code/go/internal/validator/semantic/validate_hbs_templates_test.go index fbccc7fd..89541a45 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates_test.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates_test.go @@ -9,6 +9,7 @@ import ( "path" "testing" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/elastic/package-spec/v3/code/go/internal/fspath" @@ -26,8 +27,8 @@ func TestValidateTemplateDir(t *testing.T) { require.NoError(t, err) fsys := fspath.DirFS(pkgDir) - err = validateTemplateDir(fsys, path.Join("agent", "input")) - require.NoError(t, err) + errs := validateTemplateDir(fsys, path.Join("agent", "input")) + require.Empty(t, errs) }) t.Run("valid handlebars file", func(t *testing.T) { @@ -45,8 +46,8 @@ func TestValidateTemplateDir(t *testing.T) { require.NoError(t, err) fsys := fspath.DirFS(pkgDir) - err = validateTemplateDir(fsys, path.Join("agent", "input")) - require.NoError(t, err) + errs := validateTemplateDir(fsys, path.Join("agent", "input")) + require.Empty(t, errs) }) t.Run("invalid handlebars file", func(t *testing.T) { tmpDir := t.TempDir() @@ -63,8 +64,9 @@ func TestValidateTemplateDir(t *testing.T) { require.NoError(t, err) fsys := fspath.DirFS(pkgDir) - err = validateTemplateDir(fsys, path.Join("agent", "input")) - require.Error(t, err) + errs := validateTemplateDir(fsys, path.Join("agent", "input")) + require.NotEmpty(t, errs) + assert.Len(t, errs, 1) }) t.Run("valid linked handlebars file", func(t *testing.T) { tmpDir := t.TempDir() @@ -89,8 +91,8 @@ func TestValidateTemplateDir(t *testing.T) { require.NoError(t, err) fsys := fspath.DirFS(pkgDir) - err = validateTemplateDir(fsys, path.Join("agent", "input")) - require.NoError(t, err) + errs := validateTemplateDir(fsys, path.Join("agent", "input")) + require.Empty(t, errs) }) t.Run("invalid linked handlebars file", func(t *testing.T) { @@ -116,7 +118,8 @@ func TestValidateTemplateDir(t *testing.T) { require.NoError(t, err) fsys := fspath.DirFS(pkgDir) - err = validateTemplateDir(fsys, path.Join("agent", "input")) - require.Error(t, err) + errs := validateTemplateDir(fsys, path.Join("agent", "input")) + require.NotEmpty(t, errs) + assert.Len(t, errs, 1) }) } diff --git a/code/go/pkg/validator/validator_test.go b/code/go/pkg/validator/validator_test.go index 40fe0bc0..c8b6a86d 100644 --- a/code/go/pkg/validator/validator_test.go +++ b/code/go/pkg/validator/validator_test.go @@ -914,9 +914,9 @@ func TestLinksAreBlocked(t *testing.T) { func TestValidateHandlebarsFiles(t *testing.T) { tests := map[string]string{ - "bad_input_hbs": "invalid handlebars template: error validating agent/input/input.yml.hbs: Parse error on line 10:\nExpecting OpenEndBlock, got: 'EOF'", - "bad_integration_hbs": "invalid handlebars template: error validating data_stream/foo/agent/stream/filestream.yml.hbs: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'", - "bad_integration_hbs_linked": "invalid handlebars template: error validating ../bad_integration_hbs/data_stream/foo/agent/stream/filestream.yml.hbs: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'", + "bad_input_hbs": "invalid handlebars template: found 1 validation error:\n 1. error validating agent/input/input.yml.hbs: Parse error on line 10:\nExpecting OpenEndBlock, got: 'EOF'\n", + "bad_integration_hbs": "invalid handlebars template: found 1 validation error:\n 1. error validating data_stream/foo/agent/stream/filestream.yml.hbs: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'\n", + "bad_integration_hbs_linked": "invalid handlebars template: found 1 validation error:\n 1. error validating ../bad_integration_hbs/data_stream/foo/agent/stream/filestream.yml.hbs: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'\n", } for pkgName, expectedErrorMessage := range tests { From 17b18dbb08bfe959f65a5a27a74fc8fbe40c5904 Mon Sep 17 00:00:00 2001 From: Tere Date: Wed, 3 Dec 2025 15:03:34 +0100 Subject: [PATCH 20/26] append errors instead of return --- .../semantic/validate_hbs_templates.go | 22 +++++++++---------- code/go/pkg/validator/validator_test.go | 6 ++--- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/code/go/internal/validator/semantic/validate_hbs_templates.go b/code/go/internal/validator/semantic/validate_hbs_templates.go index cfa437c4..56bec026 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates.go @@ -25,13 +25,13 @@ var ( // It returns a list of validation errors if any Handlebars files are invalid. // hbs are located in both the package root and data stream directories under the agent folder. func ValidateHandlebarsFiles(fsys fspath.FS) specerrors.ValidationErrors { + var errs specerrors.ValidationErrors + // template files are placed at /agent/input directory or // at the datastream /agent/stream directory inputDir := path.Join("agent", "input") - if err := validateTemplateDir(fsys, inputDir); err != nil { - return specerrors.ValidationErrors{ - specerrors.NewStructuredErrorf("%w: %w", errInvalidHandlebarsTemplate, err), - } + if inputErrs := validateTemplateDir(fsys, inputDir); inputErrs != nil { + errs = append(errs, inputErrs...) } datastreamEntries, err := fs.ReadDir(fsys, "data_stream") @@ -45,15 +45,13 @@ func ValidateHandlebarsFiles(fsys fspath.FS) specerrors.ValidationErrors { continue } streamDir := path.Join("data_stream", dsEntry.Name(), "agent", "stream") - err := validateTemplateDir(fsys, streamDir) - if err != nil { - return specerrors.ValidationErrors{ - specerrors.NewStructuredErrorf("%w: %w", errInvalidHandlebarsTemplate, err), - } + dsErrs := validateTemplateDir(fsys, streamDir) + if dsErrs != nil { + errs = append(errs, dsErrs...) } } - return nil + return errs } // validateTemplateDir validates all Handlebars files in the given directory. @@ -69,7 +67,7 @@ func validateTemplateDir(fsys fspath.FS, dir string) specerrors.ValidationErrors if path.Ext(entry.Name()) == ".hbs" { err := validateHandlebarsEntry(fsys, dir, entry.Name()) if err != nil { - errs = append(errs, specerrors.NewStructuredErrorf("error validating %s: %w", path.Join(dir, entry.Name()), err)) + errs = append(errs, specerrors.NewStructuredErrorf("%w: error validating %s: %w", errInvalidHandlebarsTemplate, path.Join(dir, entry.Name()), err)) } continue } @@ -82,7 +80,7 @@ func validateTemplateDir(fsys fspath.FS, dir string) specerrors.ValidationErrors } err = validateHandlebarsEntry(fsys, dir, linkFile.IncludedFilePath) if err != nil { - errs = append(errs, specerrors.NewStructuredErrorf("error validating %s: %w", path.Join(dir, linkFile.IncludedFilePath), err)) + errs = append(errs, specerrors.NewStructuredErrorf("%w: error validating %s: %w", errInvalidHandlebarsTemplate, path.Join(dir, linkFile.IncludedFilePath), err)) } } } diff --git a/code/go/pkg/validator/validator_test.go b/code/go/pkg/validator/validator_test.go index d17b9fff..ad8fffe3 100644 --- a/code/go/pkg/validator/validator_test.go +++ b/code/go/pkg/validator/validator_test.go @@ -936,9 +936,9 @@ func TestLinksAreBlocked(t *testing.T) { func TestValidateHandlebarsFiles(t *testing.T) { tests := map[string]string{ - "bad_input_hbs": "invalid handlebars template: found 1 validation error:\n 1. error validating agent/input/input.yml.hbs: Parse error on line 10:\nExpecting OpenEndBlock, got: 'EOF'\n", - "bad_integration_hbs": "invalid handlebars template: found 1 validation error:\n 1. error validating data_stream/foo/agent/stream/filestream.yml.hbs: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'\n", - "bad_integration_hbs_linked": "invalid handlebars template: found 1 validation error:\n 1. error validating ../bad_integration_hbs/data_stream/foo/agent/stream/filestream.yml.hbs: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'\n", + "bad_input_hbs": "invalid handlebars template: error validating agent/input/input.yml.hbs: Parse error on line 10:\nExpecting OpenEndBlock, got: 'EOF'", + "bad_integration_hbs": "invalid handlebars template: error validating data_stream/foo/agent/stream/filestream.yml.hbs: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'", + "bad_integration_hbs_linked": "invalid handlebars template: error validating ../bad_integration_hbs/data_stream/foo/agent/stream/filestream.yml.hbs: Parse error on line 43:\nExpecting OpenEndBlock, got: 'EOF'", } for pkgName, expectedErrorMessage := range tests { From bd2358e7e0359236b03e60d723bace2a3214a92e Mon Sep 17 00:00:00 2001 From: Tere Date: Fri, 5 Dec 2025 09:43:18 +0100 Subject: [PATCH 21/26] Update Handlebars documentation to include available meta variables and clarify helper list --- spec/integration/agent/spec.yml | 10 +++++++--- spec/integration/data_stream/agent/spec.yml | 6 +++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/spec/integration/agent/spec.yml b/spec/integration/agent/spec.yml index 97c7974c..e40ed604 100644 --- a/spec/integration/agent/spec.yml +++ b/spec/integration/agent/spec.yml @@ -9,15 +9,19 @@ spec: contents: - description: | Config template file for inputs defined in the policy_templates section of the top level manifest. - The template should use standard Handlebars syntax (e.g., `{{vars.key}}`, `{{#if vars.condition}}`, `{{#each vars.items}}`) - and must compile to valid YAML. + The template should use standard Handlebars syntax (e.g., `{{vars.key}}`, `{{#if vars.condition}}`, + `{{#each vars.items}}`) and must compile to valid YAML. Available Handlebars helpers include: - `contains` (checks if item is in array/string), - `escape_string` (wraps string in single quotes and escapes them), - `escape_multiline_string` (escapes multiline strings without wrapping), - `to_json` (converts object to JSON string), and - `url_encode` (URI encodes string). - Check the Fleet implementation for the complete list of available helpers: + Available meta variables include: + - _meta.package.name, _meta.package.title, _meta.package.version + - _meta.stream.id, _meta.stream.data_stream.dataset, _meta.stream.data_stream.type + - _meta.input.id + Check the Fleet implementation for the updated list of available helpers and variables: https://github.com/elastic/kibana/blob/70749d9216d7a5de6ce1e7a028d153d5390ad3ac/x-pack/platform/plugins/shared/fleet/server/services/epm/agent/agent.ts#L1). type: file sizeLimit: 2MB diff --git a/spec/integration/data_stream/agent/spec.yml b/spec/integration/data_stream/agent/spec.yml index d9a25d20..23bd93b0 100644 --- a/spec/integration/data_stream/agent/spec.yml +++ b/spec/integration/data_stream/agent/spec.yml @@ -17,7 +17,11 @@ spec: - `escape_multiline_string` (escapes multiline strings without wrapping), - `to_json` (converts object to JSON string), and - `url_encode` (URI encodes string). - Check the Fleet implementation for the complete list of available helpers: + Available meta variables include: + - _meta.package.name, _meta.package.title, _meta.package.version + - _meta.stream.id, _meta.stream.data_stream.dataset, _meta.stream.data_stream.type + - _meta.input.id + Check the Fleet implementation for the updated list of available helpers and variables: https://github.com/elastic/kibana/blob/70749d9216d7a5de6ce1e7a028d153d5390ad3ac/x-pack/platform/plugins/shared/fleet/server/services/epm/agent/agent.ts#L1). type: file sizeLimit: 2MB From 70547b914dff65e212761f67a4cabbab3105503b Mon Sep 17 00:00:00 2001 From: Tere Date: Thu, 11 Dec 2025 11:41:28 +0100 Subject: [PATCH 22/26] Add test for valid multiline Handlebars file template --- .../semantic/validate_hbs_templates_test.go | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/code/go/internal/validator/semantic/validate_hbs_templates_test.go b/code/go/internal/validator/semantic/validate_hbs_templates_test.go index 89541a45..a7766215 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates_test.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates_test.go @@ -49,6 +49,25 @@ func TestValidateTemplateDir(t *testing.T) { errs := validateTemplateDir(fsys, path.Join("agent", "input")) require.Empty(t, errs) }) + + t.Run("valid handlebars file template with multiline", func(t *testing.T) { + tmpDir := t.TempDir() + pkgDir := path.Join(tmpDir, "package") + err := os.MkdirAll(pkgDir, 0o755) + require.NoError(t, err) + + templateDir := path.Join(pkgDir, "agent", "input") + err = os.MkdirAll(templateDir, 0o755) + require.NoError(t, err) + hbsFilePath := path.Join(templateDir, "template.hbs") + hbsContent := `audit_rules: "# Session data audit rules\n-a always,exit -F arch=b64 -S execve,execveat -k exec\n-a always,exit -F arch=b64 -S exit_group\n-a always,exit -F arch=b64 -S setsid\n{{escape_multiline_string audit_rules}}"` + err = os.WriteFile(hbsFilePath, []byte(hbsContent), 0o644) + require.NoError(t, err) + + fsys := fspath.DirFS(pkgDir) + errs := validateTemplateDir(fsys, path.Join("agent", "input")) + require.Empty(t, errs) + }) t.Run("invalid handlebars file", func(t *testing.T) { tmpDir := t.TempDir() pkgDir := path.Join(tmpDir, "package") From b896c6888e41137e7c499ad63c724f4c1001e8d5 Mon Sep 17 00:00:00 2001 From: Tere Date: Thu, 11 Dec 2025 11:41:43 +0100 Subject: [PATCH 23/26] Replace mailgun/raymond with aymerick/raymond and update dependencies --- .../validator/semantic/validate_hbs_templates.go | 3 +-- go.mod | 4 ++-- go.sum | 10 ++-------- 3 files changed, 5 insertions(+), 12 deletions(-) diff --git a/code/go/internal/validator/semantic/validate_hbs_templates.go b/code/go/internal/validator/semantic/validate_hbs_templates.go index 56bec026..1d5258b2 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates.go @@ -10,8 +10,7 @@ import ( "os" "path" - "github.com/mailgun/raymond/v2" - + "github.com/aymerick/raymond" "github.com/elastic/package-spec/v3/code/go/internal/fspath" "github.com/elastic/package-spec/v3/code/go/internal/linkedfiles" "github.com/elastic/package-spec/v3/code/go/pkg/specerrors" diff --git a/go.mod b/go.mod index b1bf5d64..a92f94db 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.24.0 require ( github.com/Masterminds/semver/v3 v3.4.0 github.com/PaesslerAG/jsonpath v0.1.1 + github.com/aymerick/raymond v2.0.2+incompatible github.com/boumenot/gocover-cobertura v1.4.0 github.com/creasty/defaults v1.8.0 github.com/elastic/go-licenser v0.4.2 @@ -13,7 +14,6 @@ require ( github.com/evanphx/json-patch/v5 v5.9.11 github.com/go-viper/mapstructure/v2 v2.4.0 github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901 - github.com/mailgun/raymond/v2 v2.0.48 github.com/otiai10/copy v1.14.1 github.com/stretchr/testify v1.11.1 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 @@ -40,7 +40,6 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/otiai10/mint v1.6.3 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/sirupsen/logrus v1.8.1 // indirect github.com/stretchr/objx v0.5.2 // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 // indirect @@ -52,4 +51,5 @@ require ( golang.org/x/text v0.17.0 // indirect golang.org/x/tools/go/expect v0.1.1-deprecated // indirect gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 11536d07..c4bcb32f 100644 --- a/go.sum +++ b/go.sum @@ -7,6 +7,8 @@ github.com/PaesslerAG/gval v1.0.0/go.mod h1:y/nm5yEyTeX6av0OfKJNp9rBNj2XrGhAf5+v github.com/PaesslerAG/jsonpath v0.1.0/go.mod h1:4BzmtoM/PI8fPO4aQGIusjGxGir2BzcV0grWtFzq1Y8= github.com/PaesslerAG/jsonpath v0.1.1 h1:c1/AToHQMVsduPAa4Vh6xp2U0evy4t8SWp8imEsylIk= github.com/PaesslerAG/jsonpath v0.1.1/go.mod h1:lVboNxFGal/VwW6d9JzIy56bUsYAP6tH/x80vjnCseY= +github.com/aymerick/raymond v2.0.2+incompatible h1:VEp3GpgdAnv9B2GFyTvqgcKvY+mfKMjPOA3SbKLtnU0= +github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g= github.com/bitfield/gotestdox v0.2.2 h1:x6RcPAbBbErKLnapz1QeAlf3ospg8efBsedU93CDsnE= github.com/bitfield/gotestdox v0.2.2/go.mod h1:D+gwtS0urjBrzguAkTM2wodsTQYFHdpx8eqRJ3N+9pY= github.com/boumenot/gocover-cobertura v1.4.0 h1:ACJAt5wRi1HU+P9xNDgzWXgLMEVYUWeOgQWZwH+36kU= @@ -43,8 +45,6 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw= -github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= @@ -60,14 +60,10 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= -github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= @@ -92,7 +88,6 @@ golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= @@ -115,7 +110,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gotest.tools/gotestsum v1.13.0 h1:+Lh454O9mu9AMG1APV4o0y7oDYKyik/3kBOiCqiEpRo= From 75e87b67a88f3e7b61e8d4c6630dc5a81c17a5b2 Mon Sep 17 00:00:00 2001 From: Tere Date: Thu, 11 Dec 2025 11:43:44 +0100 Subject: [PATCH 24/26] Rename Handlebars validation functions for clarity and update changelog --- .../validator/semantic/validate_hbs_templates.go | 12 ++++++------ code/go/internal/validator/spec.go | 2 +- spec/changelog.yml | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/code/go/internal/validator/semantic/validate_hbs_templates.go b/code/go/internal/validator/semantic/validate_hbs_templates.go index 1d5258b2..b1495305 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates.go @@ -20,10 +20,10 @@ var ( errInvalidHandlebarsTemplate = errors.New("invalid handlebars template") ) -// ValidateHandlebarsFiles validates all Handlebars (.hbs) files in the package filesystem. +// ValidateStaticHandlebarsFiles validates all Handlebars (.hbs) files in the package filesystem. // It returns a list of validation errors if any Handlebars files are invalid. // hbs are located in both the package root and data stream directories under the agent folder. -func ValidateHandlebarsFiles(fsys fspath.FS) specerrors.ValidationErrors { +func ValidateStaticHandlebarsFiles(fsys fspath.FS) specerrors.ValidationErrors { var errs specerrors.ValidationErrors // template files are placed at /agent/input directory or @@ -64,7 +64,7 @@ func validateTemplateDir(fsys fspath.FS, dir string) specerrors.ValidationErrors var errs specerrors.ValidationErrors for _, entry := range entries { if path.Ext(entry.Name()) == ".hbs" { - err := validateHandlebarsEntry(fsys, dir, entry.Name()) + err := validateStaticHandlebarsEntry(fsys, dir, entry.Name()) if err != nil { errs = append(errs, specerrors.NewStructuredErrorf("%w: error validating %s: %w", errInvalidHandlebarsTemplate, path.Join(dir, entry.Name()), err)) } @@ -77,7 +77,7 @@ func validateTemplateDir(fsys fspath.FS, dir string) specerrors.ValidationErrors errs = append(errs, specerrors.NewStructuredErrorf("error reading linked file %s: %w", linkFilePath, err)) continue } - err = validateHandlebarsEntry(fsys, dir, linkFile.IncludedFilePath) + err = validateStaticHandlebarsEntry(fsys, dir, linkFile.IncludedFilePath) if err != nil { errs = append(errs, specerrors.NewStructuredErrorf("%w: error validating %s: %w", errInvalidHandlebarsTemplate, path.Join(dir, linkFile.IncludedFilePath), err)) } @@ -86,9 +86,9 @@ func validateTemplateDir(fsys fspath.FS, dir string) specerrors.ValidationErrors return errs } -// validateHandlebarsEntry validates a single Handlebars file located at filePath. +// validateStaticHandlebarsEntry validates a single Handlebars file located at filePath. // it parses the file using the raymond library to check for syntax errors. -func validateHandlebarsEntry(fsys fspath.FS, dir, entryName string) error { +func validateStaticHandlebarsEntry(fsys fspath.FS, dir, entryName string) error { if entryName == "" { return nil } diff --git a/code/go/internal/validator/spec.go b/code/go/internal/validator/spec.go index f4c215a8..cb0dafaf 100644 --- a/code/go/internal/validator/spec.go +++ b/code/go/internal/validator/spec.go @@ -225,7 +225,7 @@ func (s Spec) rules(pkgType string, rootSpec spectypes.ItemSpec) validationRules {fn: semantic.ValidateMinimumAgentVersion}, {fn: semantic.ValidateIntegrationPolicyTemplates, types: []string{"integration"}}, {fn: semantic.ValidatePipelineTags, types: []string{"integration"}, since: semver.MustParse("3.6.0")}, - {fn: semantic.ValidateHandlebarsFiles, types: []string{"integration", "input"}}, + {fn: semantic.ValidateStaticHandlebarsFiles, types: []string{"integration", "input"}}, } var validationRules validationRules diff --git a/spec/changelog.yml b/spec/changelog.yml index 5fc86e12..382717b0 100644 --- a/spec/changelog.yml +++ b/spec/changelog.yml @@ -23,7 +23,7 @@ - description: Run validation semantic rules also in transform fields. type: enhancement link: https://github.com/elastic/package-spec/pull/1027 - - description: Handlebars template files are now validated in input and integration packages. + - description: Run static validation for handlebars templates in input and integration packages. type: enhancement link: https://github.com/elastic/package-spec/pull/1030 - version: 3.5.4 From 76d18358e4c4c8f5a4c645e94265f9b2d78cf414 Mon Sep 17 00:00:00 2001 From: Tere Date: Thu, 11 Dec 2025 11:47:09 +0100 Subject: [PATCH 25/26] Add missing newline in import section of validate_hbs_templates.go --- code/go/internal/validator/semantic/validate_hbs_templates.go | 1 + 1 file changed, 1 insertion(+) diff --git a/code/go/internal/validator/semantic/validate_hbs_templates.go b/code/go/internal/validator/semantic/validate_hbs_templates.go index b1495305..b6d241cc 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates.go @@ -11,6 +11,7 @@ import ( "path" "github.com/aymerick/raymond" + "github.com/elastic/package-spec/v3/code/go/internal/fspath" "github.com/elastic/package-spec/v3/code/go/internal/linkedfiles" "github.com/elastic/package-spec/v3/code/go/pkg/specerrors" From 5b236f1e85920916500ae6a3f16cd154201009b9 Mon Sep 17 00:00:00 2001 From: Tere Date: Fri, 12 Dec 2025 11:11:30 +0100 Subject: [PATCH 26/26] Handlebars validation: improve error handling for invalid file reads --- code/go/internal/validator/semantic/validate_hbs_templates.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/code/go/internal/validator/semantic/validate_hbs_templates.go b/code/go/internal/validator/semantic/validate_hbs_templates.go index b6d241cc..5693a603 100644 --- a/code/go/internal/validator/semantic/validate_hbs_templates.go +++ b/code/go/internal/validator/semantic/validate_hbs_templates.go @@ -100,6 +100,9 @@ func validateStaticHandlebarsEntry(fsys fspath.FS, dir, entryName string) error // First try to read from filesystem (works for regular files and files within zip) filePath := path.Join(dir, entryName) if content, err = fs.ReadFile(fsys, filePath); err != nil { + if !errors.Is(err, fs.ErrInvalid) { + return err + } // If fs.ReadFile fails (likely due to linked file path outside filesystem boundary), // fall back to absolute path approach like linkedfiles.FS does absolutePath := fsys.Path(filePath)