Skip to content

Conversation

@teresaromero
Copy link
Contributor

@teresaromero teresaromero commented Nov 28, 2025

What does this PR do?

Includes a validation rule for verifying the static .hbs files used at input tempate and stream template are correct.
Also adds more information on the spec regarding the format of these templates and the helpers that are available at fleet when rendering them.
Linked file are also verified .hbs.link

The validation is done over the static syntax of handlebars, does not validate the render of the template taking into account the values of the values.

Why is it important?

If a template arrives fleet without being checked, the can be errors when fleet renders the template. This is a way to prevent this before the package is installed.

Checklist

Added unit tests and validation test with test packages

Related issues

Resolves #21

@teresaromero teresaromero requested a review from a team as a code owner November 28, 2025 09:19
@teresaromero
Copy link
Contributor Author

test integrations

Comment on lines 69 to 72
pkgEntries, err := fs.Glob(fsys, "agent/**/*.hbs")
if err != nil && !errors.Is(err, fs.ErrNotExist) {
return nil, err
}
Copy link
Contributor

Choose a reason for hiding this comment

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

According to the spec, this files could also be links.
Would this catch even the links thanks to the filesystem ? Or is it needed to add a special case for link files?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

i've updated the PR to include the linked files. For this i've changed the aproach of glob and used nested readDirs to get into the files.
i've added tests and test packages to check this works as expected with the links 👍🏻


// 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 {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd rename this to be more specific, what about validateHandlebarTemplateFile or validateHandlebarTemplate?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yup, i've gone around this one :D as the "parent" function is very similar... i will think around this

@teresaromero teresaromero marked this pull request as draft December 1, 2025 14:09
@teresaromero teresaromero marked this pull request as ready for review December 1, 2025 15:56
@teresaromero
Copy link
Contributor Author

test integrations

@elastic-vault-github-plugin-prod

Created or updated PR in integrations repository to test this version. Check elastic/integrations#16224

Comment on lines +103 to +108
// 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
}
Copy link
Contributor

Choose a reason for hiding this comment

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

According to the comment, is this already done by the linkedfiles.FS ? If so, maybe it could be removed from here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this refers to the logic at getLinkedFileChecksum where the file content is read to get the checksum. If the file is not within fsys fs.ReadFile fails, as is not in its scope. If this happens, we use os.ReadFile (like in getLinkedFileChecksum) to read the file with the absolute path of it

}
err = validateHandlebarsEntry(fsys, dir, linkFile.IncludedFilePath)
if err != nil {
return err
Copy link
Contributor

Choose a reason for hiding this comment

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

Could it be defined a specerrors.ValidationErrors here in this function and add all the errors found in a given folder?
I was thinking if it could be possible to show all the errors at once to the user.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

fixed this and adding more context to the error 👍🏻

an example of the output when testing one of the failed integration:

Error: building package failed: invalid content found in built zip package: found 1 validation error:
   1. invalid handlebars template: error validating data_stream/alerts_events_v2/agent/stream/gcs.yml.hbs: Parse error on line 49:
Expecting OpenEndBlock, got: 'EOF'

@teresaromero
Copy link
Contributor Author

after running the test against the current integrations, two of them had errors regarding some template parsing.
I opened a draft elastic/integrations#16230 to solve this. pending to test this changes

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:
Copy link
Member

Choose a reason for hiding this comment

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

Can you please document the metadata variables that are available in templates too. See elastic/kibana#241140

Copy link
Contributor Author

Choose a reason for hiding this comment

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

udpated the pr bd2358e with more docs on variables

@teresaromero teresaromero changed the title Handlebars template validation and documentation Handlebars template static validation and documentation Dec 11, 2025
@elasticmachine
Copy link

💚 Build Succeeded

History

Copy link
Contributor

@mrodm mrodm left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

@teresaromero teresaromero merged commit bea6555 into elastic:main Dec 15, 2025
3 checks passed
Copy link
Member

@jsoriano jsoriano left a comment

Choose a reason for hiding this comment

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

Only a couple of comments, but I am fine with implemented approach.

func TestValidateTemplateDir(t *testing.T) {
t.Run("empty directory", func(t *testing.T) {
tmpDir := t.TempDir()
pkgDir := path.Join(tmpDir, "package")
Copy link
Member

Choose a reason for hiding this comment

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

Nit. Most paths in these tests are native paths, they should be joined with filepath.Join.

{fn: semantic.ValidateMinimumAgentVersion},
{fn: semantic.ValidateIntegrationPolicyTemplates, types: []string{"integration"}},
{fn: semantic.ValidatePipelineTags, types: []string{"integration"}, since: semver.MustParse("3.6.0")},
{fn: semantic.ValidateStaticHandlebarsFiles, types: []string{"integration", "input"}},
Copy link
Member

Choose a reason for hiding this comment

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

Did you consider to place the validation in the spec? It could have been done by using a content media type and something like the validateContentType method.

But using a semantic validator LGTM too in any case.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I did not. Thanks for this suggestion, i see now that adding this to the spec, perhaps with a custom type application/x-hbs could simplify the validation, as it will detect the files, instead of looking for them under the folders as the current implementation does.... 🤔 although for linked files i am not sure how it will work, i guess we could rely on the internal linked file to exist, and this being validated as hbs where originally is placed.

i think this approach could be an improvement

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add documentation and handlebars validation for helpers

5 participants