diff --git a/code/go/internal/validator/semantic/validate_sections.go b/code/go/internal/validator/semantic/validate_sections.go new file mode 100644 index 000000000..6029cec5b --- /dev/null +++ b/code/go/internal/validator/semantic/validate_sections.go @@ -0,0 +1,146 @@ +// 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 ( + "fmt" + "io/fs" + "path" + + "gopkg.in/yaml.v3" + + "github.com/elastic/package-spec/v3/code/go/internal/fspath" + "github.com/elastic/package-spec/v3/code/go/pkg/specerrors" +) + +// ValidateSections validates sections definitions in manifests. +// It checks that: +// - section names are unique within each scope +// - vars that reference a section via the `section` attribute name a section +// defined in the `sections` list at the same scope level +func ValidateSections(fsys fspath.FS) specerrors.ValidationErrors { + d, err := fs.ReadFile(fsys, "manifest.yml") + if err != nil { + return specerrors.ValidationErrors{specerrors.NewStructuredErrorf("failed to read file \"%s\": %w", fsys.Path("manifest.yml"), err)} + } + + var manifest sectionsManifest + if err := yaml.Unmarshal(d, &manifest); err != nil { + return specerrors.ValidationErrors{specerrors.NewStructuredErrorf("file \"%s\" is invalid: failed to parse manifest: %w", fsys.Path("manifest.yml"), err)} + } + + errs := validateSectionsManifest(fsys.Path("manifest.yml"), manifest) + + // Validate data stream manifests. + dataStreams, err := listDataStreams(fsys) + if err != nil { + return specerrors.ValidationErrors{specerrors.NewStructuredErrorf("failed to list data streams: %w", err)} + } + for _, ds := range dataStreams { + errs = append(errs, validateDataStreamSections(fsys, path.Join("data_stream", ds, "manifest.yml"))...) + } + + return errs +} + +type sectionsVar struct { + Name string `yaml:"name"` + Section string `yaml:"section"` +} + +type manifestSection struct { + Name string `yaml:"name"` +} + +type sectionsManifest struct { + Sections []manifestSection `yaml:"sections"` + Vars []sectionsVar `yaml:"vars"` + PolicyTemplates []struct { + Sections []manifestSection `yaml:"sections"` + Vars []sectionsVar `yaml:"vars"` + Inputs []struct { + Sections []manifestSection `yaml:"sections"` + Vars []sectionsVar `yaml:"vars"` + } `yaml:"inputs"` + } `yaml:"policy_templates"` +} + +type sectionsDataStreamStream struct { + Title string `yaml:"title"` + Input string `yaml:"input"` + Sections []manifestSection `yaml:"sections"` + Vars []sectionsVar `yaml:"vars"` +} + +type sectionsDataStreamManifest struct { + Streams []sectionsDataStreamStream `yaml:"streams"` +} + +func validateSectionsManifest(filePath string, manifest sectionsManifest) specerrors.ValidationErrors { + var errs specerrors.ValidationErrors + + errs = append(errs, validateSectionsScope(filePath, "package root", manifest.Sections, manifest.Vars)...) + + for _, pt := range manifest.PolicyTemplates { + errs = append(errs, validateSectionsScope(filePath, "policy template", pt.Sections, pt.Vars)...) + for _, input := range pt.Inputs { + errs = append(errs, validateSectionsScope(filePath, "input", input.Sections, input.Vars)...) + } + } + + return errs +} + +func validateDataStreamSections(fsys fspath.FS, filePath string) specerrors.ValidationErrors { + d, err := fs.ReadFile(fsys, filePath) + if err != nil { + // File might not exist, which is fine. + return nil + } + + var manifest sectionsDataStreamManifest + if err := yaml.Unmarshal(d, &manifest); err != nil { + return specerrors.ValidationErrors{specerrors.NewStructuredErrorf("file \"%s\" is invalid: failed to parse manifest: %w", fsys.Path(filePath), err)} + } + + var errs specerrors.ValidationErrors + for i, stream := range manifest.Streams { + streamID := stream.Title + if streamID == "" { + streamID = stream.Input + } + if streamID == "" { + streamID = fmt.Sprintf("stream[%d]", i) + } + errs = append(errs, validateSectionsScope(fsys.Path(filePath), fmt.Sprintf("stream %q", streamID), stream.Sections, stream.Vars)...) + } + + return errs +} + +func validateSectionsScope(filePath, scope string, sections []manifestSection, vars []sectionsVar) specerrors.ValidationErrors { + var errs specerrors.ValidationErrors + + // Build set of defined section names, checking for duplicates. + sectionNames := make(map[string]bool) + for _, s := range sections { + if sectionNames[s.Name] { + errs = append(errs, specerrors.NewStructuredErrorf("file \"%s\" is invalid: duplicate section name %q in %s", filePath, s.Name, scope)) + } + sectionNames[s.Name] = true + } + + // Verify that each var's section attribute references a defined section. + for _, v := range vars { + if v.Section == "" { + continue + } + if !sectionNames[v.Section] { + errs = append(errs, specerrors.NewStructuredErrorf("file \"%s\" is invalid: var %q references undefined section %q in %s", filePath, v.Name, v.Section, scope)) + } + } + + return errs +} diff --git a/code/go/internal/validator/semantic/validate_sections_test.go b/code/go/internal/validator/semantic/validate_sections_test.go new file mode 100644 index 000000000..21e6a7302 --- /dev/null +++ b/code/go/internal/validator/semantic/validate_sections_test.go @@ -0,0 +1,241 @@ +// 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 ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" +) + +func TestValidateSectionsManifest(t *testing.T) { + cases := []struct { + title string + manifest string + errors []string + }{ + { + title: "valid: sections defined, vars reference them", + manifest: ` +sections: + - name: auth_section + title: Authentication +vars: + - name: username + section: auth_section + - name: password + section: auth_section +`, + }, + { + title: "valid: no sections and no section references", + manifest: ` +vars: + - name: username + - name: password +`, + }, + { + title: "valid: sections defined but no vars reference them", + manifest: ` +sections: + - name: auth_section + title: Authentication +vars: + - name: username +`, + }, + { + title: "valid: some vars reference sections, others do not", + manifest: ` +sections: + - name: auth_section + title: Authentication +vars: + - name: region + - name: username + section: auth_section +`, + }, + { + title: "invalid: var references undefined section", + manifest: ` +vars: + - name: username + section: auth_section +`, + errors: []string{ + `file "manifest.yml" is invalid: var "username" references undefined section "auth_section" in package root`, + }, + }, + { + title: "invalid: duplicate section name", + manifest: ` +sections: + - name: auth_section + title: Authentication + - name: auth_section + title: Authentication (duplicate) +vars: + - name: username + section: auth_section +`, + errors: []string{ + `file "manifest.yml" is invalid: duplicate section name "auth_section" in package root`, + }, + }, + { + title: "valid: sections scoped to policy template", + manifest: ` +policy_templates: + - sections: + - name: auth_section + title: Authentication + vars: + - name: username + section: auth_section +`, + }, + { + title: "invalid: policy template var references section not defined at that level", + manifest: ` +sections: + - name: auth_section + title: Authentication +policy_templates: + - vars: + - name: username + section: auth_section +`, + errors: []string{ + `file "manifest.yml" is invalid: var "username" references undefined section "auth_section" in policy template`, + }, + }, + { + title: "valid: sections scoped to input", + manifest: ` +policy_templates: + - inputs: + - sections: + - name: auth_section + title: Authentication + vars: + - name: username + section: auth_section +`, + }, + { + title: "invalid: input var references section not defined at that level", + manifest: ` +policy_templates: + - inputs: + - vars: + - name: username + section: auth_section +`, + errors: []string{ + `file "manifest.yml" is invalid: var "username" references undefined section "auth_section" in input`, + }, + }, + } + + for _, c := range cases { + t.Run(c.title, func(t *testing.T) { + var manifest sectionsManifest + err := yaml.Unmarshal([]byte(c.manifest), &manifest) + require.NoError(t, err) + + errors := validateSectionsManifest("manifest.yml", manifest) + assert.Len(t, errors, len(c.errors)) + for _, err := range errors { + assert.Contains(t, c.errors, err.Error()) + } + }) + } +} + +func TestValidateSectionsScope(t *testing.T) { + cases := []struct { + title string + sections []manifestSection + vars []sectionsVar + errors []string + }{ + { + title: "valid: all section references resolve", + sections: []manifestSection{ + {Name: "auth_section"}, + {Name: "advanced_section"}, + }, + vars: []sectionsVar{ + {Name: "username", Section: "auth_section"}, + {Name: "timeout", Section: "advanced_section"}, + {Name: "region"}, + }, + }, + { + title: "valid: no vars with section attributes", + sections: []manifestSection{ + {Name: "auth_section"}, + }, + vars: []sectionsVar{ + {Name: "username"}, + }, + }, + { + title: "valid: empty sections and vars", + sections: nil, + vars: nil, + }, + { + title: "invalid: var references undefined section", + sections: nil, + vars: []sectionsVar{ + {Name: "username", Section: "missing_section"}, + }, + errors: []string{ + `file "test.yml" is invalid: var "username" references undefined section "missing_section" in package root`, + }, + }, + { + title: "invalid: duplicate section name", + sections: []manifestSection{ + {Name: "auth_section"}, + {Name: "auth_section"}, + }, + vars: nil, + errors: []string{ + `file "test.yml" is invalid: duplicate section name "auth_section" in package root`, + }, + }, + { + title: "invalid: multiple vars reference undefined sections", + sections: []manifestSection{ + {Name: "auth_section"}, + }, + vars: []sectionsVar{ + {Name: "username", Section: "auth_section"}, + {Name: "api_key", Section: "missing_section"}, + {Name: "token", Section: "another_missing"}, + }, + errors: []string{ + `file "test.yml" is invalid: var "api_key" references undefined section "missing_section" in package root`, + `file "test.yml" is invalid: var "token" references undefined section "another_missing" in package root`, + }, + }, + } + + for _, c := range cases { + t.Run(c.title, func(t *testing.T) { + errors := validateSectionsScope("test.yml", "package root", c.sections, c.vars) + assert.Len(t, errors, len(c.errors)) + for _, err := range errors { + assert.Contains(t, c.errors, err.Error()) + } + }) + } +} diff --git a/code/go/internal/validator/spec.go b/code/go/internal/validator/spec.go index 3247e42eb..67ff8171e 100644 --- a/code/go/internal/validator/spec.go +++ b/code/go/internal/validator/spec.go @@ -225,6 +225,7 @@ func (s Spec) rules(pkgType string, rootSpec spectypes.ItemSpec) validationRules {fn: semantic.ValidateCapabilitiesRequired, since: semver.MustParse("2.10.0")}, // capabilities definition was added in spec version 2.10.0 {fn: semantic.ValidateRequiredVarGroups}, {fn: semantic.ValidateVarGroups, since: semver.MustParse("3.6.0")}, + {fn: semantic.ValidateSections}, {fn: semantic.ValidateDocsStructure}, {fn: semantic.ValidateDeploymentModes, types: []string{"integration"}}, {fn: semantic.ValidateDurationVariables, since: semver.MustParse("3.5.0")}, diff --git a/code/go/pkg/validator/validator_test.go b/code/go/pkg/validator/validator_test.go index 7512e1477..1aca10265 100644 --- a/code/go/pkg/validator/validator_test.go +++ b/code/go/pkg/validator/validator_test.go @@ -345,6 +345,18 @@ func TestValidateFile(t *testing.T) { `var "non_existent_var" referenced in var_group "credential_type" option "direct_access_key" is not defined`, }, }, + "bad_sections_undefined_ref": { + "manifest.yml", + []string{ + `var "secret_access_key" references undefined section "nonexistent_section" in package root`, + }, + }, + "bad_sections_duplicate_name": { + "manifest.yml", + []string{ + `duplicate section name "auth_section" in package root`, + }, + }, "bad_var_groups_duplicate_name": { "manifest.yml", []string{ diff --git a/spec/changelog.yml b/spec/changelog.yml index 5209fc912..7123d0df5 100644 --- a/spec/changelog.yml +++ b/spec/changelog.yml @@ -8,6 +8,13 @@ - description: Add support for semantic_text field definition. type: enhancement link: https://github.com/elastic/package-spec/pull/807 + # pending on https://github.com/elastic/kibana/pull/262129 + - description: Add top-level `sections` list for defining named section headers, and `section` attribute on vars for assigning variables to a section in the Fleet UI. + type: enhancement + link: https://github.com/elastic/package-spec/pull/1133 + - description: Add `show_divider` optional boolean to input objects to suppress horizontal dividers in the Fleet UI. + type: enhancement + link: https://github.com/elastic/package-spec/pull/1133 - version: 3.6.1-next changes: - description: Add var_groups support to policy template and input levels in integration packages, and to policy template and package root levels in input packages. diff --git a/spec/input/manifest.spec.yml b/spec/input/manifest.spec.yml index 465c76676..8cc68dd65 100644 --- a/spec/input/manifest.spec.yml +++ b/spec/input/manifest.spec.yml @@ -82,6 +82,8 @@ spec: $ref: "../integration/data_stream/manifest.spec.yml#/definitions/vars" var_groups: $ref: "../integration/manifest.spec.yml#/definitions/var_groups" + sections: + $ref: "../integration/manifest.spec.yml#/definitions/sections" input: type: string examples: @@ -142,6 +144,8 @@ spec: $ref: "../integration/data_stream/manifest.spec.yml#/definitions/vars" var_groups: $ref: "../integration/manifest.spec.yml#/definitions/var_groups" + sections: + $ref: "../integration/manifest.spec.yml#/definitions/sections" owner: $ref: "../integration/manifest.spec.yml#/definitions/owner" agent: diff --git a/spec/integration/data_stream/manifest.spec.yml b/spec/integration/data_stream/manifest.spec.yml index 82ba27a8d..640ca5cf6 100644 --- a/spec/integration/data_stream/manifest.spec.yml +++ b/spec/integration/data_stream/manifest.spec.yml @@ -141,6 +141,13 @@ spec: enum: - default - agentless + section: + description: > + Name of the section this variable belongs to. + Must match a section name defined in the `sections` list at the same level. + type: string + examples: + - auth_section url_allowed_schemes: description: > List of allowed URL schemes for the url type. If empty, any scheme is allowed. @@ -636,6 +643,8 @@ spec: $ref: "#/definitions/vars" var_groups: $ref: "../../integration/manifest.spec.yml#/definitions/var_groups" + sections: + $ref: "../../integration/manifest.spec.yml#/definitions/sections" dynamic_signal_types: $ref: "../../integration/manifest.spec.yml#/definitions/dynamic_signal_types" migrate_from: diff --git a/spec/integration/manifest.spec.yml b/spec/integration/manifest.spec.yml index 5b4589a89..7e525da3d 100644 --- a/spec/integration/manifest.spec.yml +++ b/spec/integration/manifest.spec.yml @@ -586,6 +586,37 @@ spec: type: array items: $ref: "#/definitions/package_dependency" + show_divider: + description: When false, suppresses the automatic horizontal divider rendered after this section. + type: boolean + default: true + sections: + description: > + Defines named sections used to group and visually organize variables in the Fleet UI. + Variables reference a section by name using the `section` attribute. + Sections are rendered in the order they are defined. + type: array + items: + type: object + additionalProperties: false + properties: + name: + description: Unique identifier for this section. + type: string + pattern: '^[a-z][a-z0-9_]*$' + examples: + - auth_section + title: + description: Display title for this section header in the Fleet UI. + type: string + examples: + - Authentication + description: + description: Optional help text displayed below the section header. + type: string + required: + - name + - title var_groups: description: > Defines mutually exclusive groups of variables. When an option is selected, @@ -627,6 +658,8 @@ spec: have required: true - the requirement is controlled entirely by this field. type: boolean default: false + show_divider: + $ref: "#/definitions/show_divider" options: description: Available options. First option is the default. type: array @@ -832,6 +865,10 @@ spec: $ref: "./data_stream/manifest.spec.yml#/definitions/vars" var_groups: $ref: "#/definitions/var_groups" + sections: + $ref: "#/definitions/sections" + show_divider: + $ref: "#/definitions/show_divider" dynamic_signal_types: $ref: "#/definitions/dynamic_signal_types" deprecated: @@ -863,6 +900,8 @@ spec: $ref: "./data_stream/manifest.spec.yml#/definitions/vars" var_groups: $ref: "#/definitions/var_groups" + sections: + $ref: "#/definitions/sections" deprecated: $ref: "#/definitions/deprecated" required: @@ -877,6 +916,8 @@ spec: $ref: "./data_stream/manifest.spec.yml#/definitions/vars" var_groups: $ref: "#/definitions/var_groups" + sections: + $ref: "#/definitions/sections" owner: $ref: "#/definitions/owner" agent: diff --git a/test/packages/bad_sections_duplicate_name/LICENSE.txt b/test/packages/bad_sections_duplicate_name/LICENSE.txt new file mode 100644 index 000000000..f2d489e45 --- /dev/null +++ b/test/packages/bad_sections_duplicate_name/LICENSE.txt @@ -0,0 +1,7 @@ +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. diff --git a/test/packages/bad_sections_duplicate_name/changelog.yml b/test/packages/bad_sections_duplicate_name/changelog.yml new file mode 100644 index 000000000..e00f88133 --- /dev/null +++ b/test/packages/bad_sections_duplicate_name/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 diff --git a/test/packages/bad_sections_duplicate_name/docs/README.md b/test/packages/bad_sections_duplicate_name/docs/README.md new file mode 100644 index 000000000..bc92ff2b2 --- /dev/null +++ b/test/packages/bad_sections_duplicate_name/docs/README.md @@ -0,0 +1,4 @@ +# Bad Var Groups - Missing Var Reference + +This test package has var_groups referencing a var that does not exist. +Should fail validation with an error about `non_existent_var` not being defined. diff --git a/test/packages/bad_sections_duplicate_name/img/sample-logo.svg b/test/packages/bad_sections_duplicate_name/img/sample-logo.svg new file mode 100644 index 000000000..6268dd88f --- /dev/null +++ b/test/packages/bad_sections_duplicate_name/img/sample-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/packages/bad_sections_duplicate_name/img/sample-screenshot.png b/test/packages/bad_sections_duplicate_name/img/sample-screenshot.png new file mode 100644 index 000000000..d7a56a3ec Binary files /dev/null and b/test/packages/bad_sections_duplicate_name/img/sample-screenshot.png differ diff --git a/test/packages/bad_sections_duplicate_name/manifest.yml b/test/packages/bad_sections_duplicate_name/manifest.yml new file mode 100644 index 000000000..267f76bc5 --- /dev/null +++ b/test/packages/bad_sections_duplicate_name/manifest.yml @@ -0,0 +1,55 @@ +format_version: 3.6.0 +name: bad_sections_duplicate_name +title: Bad Sections - Duplicate Section Name +description: This package has duplicate section names in the sections list. +version: 0.0.1 +type: integration +source: + license: "Apache-2.0" +conditions: + kibana: + version: '^8.10.0' + elastic: + subscription: 'basic' + agent: + version: '^9.1.0' +sections: + - name: auth_section + title: Authentication + # Duplicate name - should cause validation error + - name: auth_section + title: Authentication (duplicate) +vars: + - name: access_key_id + type: text + title: Access Key ID + show_user: true + secret: false + section: auth_section + - name: secret_access_key + type: password + title: Secret Access Key + show_user: true + secret: true +policy_templates: + - name: sample + title: Sample + description: Sample policy template + inputs: + - type: httpjson + title: Collect via API + description: Collecting data + multi: false +owner: + github: elastic/ecosystem + type: elastic +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 diff --git a/test/packages/bad_sections_undefined_ref/LICENSE.txt b/test/packages/bad_sections_undefined_ref/LICENSE.txt new file mode 100644 index 000000000..f2d489e45 --- /dev/null +++ b/test/packages/bad_sections_undefined_ref/LICENSE.txt @@ -0,0 +1,7 @@ +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. diff --git a/test/packages/bad_sections_undefined_ref/changelog.yml b/test/packages/bad_sections_undefined_ref/changelog.yml new file mode 100644 index 000000000..e00f88133 --- /dev/null +++ b/test/packages/bad_sections_undefined_ref/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 diff --git a/test/packages/bad_sections_undefined_ref/docs/README.md b/test/packages/bad_sections_undefined_ref/docs/README.md new file mode 100644 index 000000000..bc92ff2b2 --- /dev/null +++ b/test/packages/bad_sections_undefined_ref/docs/README.md @@ -0,0 +1,4 @@ +# Bad Var Groups - Missing Var Reference + +This test package has var_groups referencing a var that does not exist. +Should fail validation with an error about `non_existent_var` not being defined. diff --git a/test/packages/bad_sections_undefined_ref/img/sample-logo.svg b/test/packages/bad_sections_undefined_ref/img/sample-logo.svg new file mode 100644 index 000000000..6268dd88f --- /dev/null +++ b/test/packages/bad_sections_undefined_ref/img/sample-logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/test/packages/bad_sections_undefined_ref/img/sample-screenshot.png b/test/packages/bad_sections_undefined_ref/img/sample-screenshot.png new file mode 100644 index 000000000..d7a56a3ec Binary files /dev/null and b/test/packages/bad_sections_undefined_ref/img/sample-screenshot.png differ diff --git a/test/packages/bad_sections_undefined_ref/manifest.yml b/test/packages/bad_sections_undefined_ref/manifest.yml new file mode 100644 index 000000000..e35bd9e70 --- /dev/null +++ b/test/packages/bad_sections_undefined_ref/manifest.yml @@ -0,0 +1,54 @@ +format_version: 3.6.0 +name: bad_sections_undefined_ref +title: Bad Sections - Undefined Section Reference +description: This package has a var referencing a section name that is not defined in the sections list. +version: 0.0.1 +type: integration +source: + license: "Apache-2.0" +conditions: + kibana: + version: '^8.10.0' + elastic: + subscription: 'basic' + agent: + version: '^9.1.0' +sections: + - name: auth_section + title: Authentication +vars: + - name: access_key_id + type: text + title: Access Key ID + show_user: true + secret: false + section: auth_section + - name: secret_access_key + type: password + title: Secret Access Key + show_user: true + secret: true + # References a section that is not defined + section: nonexistent_section +policy_templates: + - name: sample + title: Sample + description: Sample policy template + inputs: + - type: httpjson + title: Collect via API + description: Collecting data + multi: false +owner: + github: elastic/ecosystem + type: elastic +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 diff --git a/test/packages/good_var_groups/manifest.yml b/test/packages/good_var_groups/manifest.yml index e441dc13b..ac56a414e 100644 --- a/test/packages/good_var_groups/manifest.yml +++ b/test/packages/good_var_groups/manifest.yml @@ -13,31 +13,40 @@ conditions: subscription: 'basic' agent: version: '^9.1.0' +sections: + - name: auth_section + title: Authentication + description: Configure AWS authentication credentials. vars: - name: access_key_id type: text title: Access Key ID show_user: true secret: false + section: auth_section - name: secret_access_key type: password title: Secret Access Key show_user: true secret: true + section: auth_section - name: session_token type: password title: Session Token show_user: true secret: true + section: auth_section - name: role_arn type: text title: Role ARN show_user: true + section: auth_section - name: external_id type: password title: External ID show_user: true secret: true + section: auth_section var_groups: - name: credential_type title: Setup Access @@ -121,6 +130,7 @@ policy_templates: title: Collect via API description: Collecting data from HTTP JSON API multi: false + show_divider: false vars: - name: url type: url