Skip to content

[chore] Add workflow validation step in CI - #47

Open
dej611 wants to merge 8 commits into
mainfrom
feat/validation-ci
Open

dej611 wants to merge 8 commits into
mainfrom
feat/validation-ci

Conversation

@dej611

@dej611 dej611 commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

This PR contains most of the logic within the elastic/kibana#281827 Kibana counter part.
The idea is to have a lightweight version of it, so things like DAG consistency has been removed to avoid to have 2K LoC moved over for a single check for now.

The new script gets as input a JSON schema via either a CDN url or a file path. If none are provided then it fails gracefully skipping it.

Example of execution:

npm run validate -- library/workflows --recursive --variant template --schema <path-to-json-schema>/9.6.0/release

> @elastic/workflows-library@0.0.0 validate
> node scripts/validate-workflows.mjs library/workflows --recursive --variant template --schema <path-to-json-schema>/9.6.0/release

[validate] Validating 18 file(s) against schema from <path-to-json-schema>/9.6.0/release
PASS  library/workflows/browser-extension-daily-reputation/browser-extension-daily-reputation.yaml
PASS  library/workflows/create-slack-channel/create-slack-channel.yaml
PASS  library/workflows/disk-capacity-forecast-alert/disk-capacity-forecast-alert.yaml
PASS  library/workflows/hash-threat-check/hash-threat-check.yaml
PASS  library/workflows/ip-reputation-check/ip-reputation-check.yaml
PASS  library/workflows/mark-alert-as-acknowledged/mark-alert-as-acknowledged.yaml
PASS  library/workflows/remediate-behavior-windows-script-file/remediate-behavior-windows-script-file.yaml
PASS  library/workflows/remediate-identity-suspected-phishing-kit-or-aitm-compromise/remediate-identity-suspected-phishing-kit-or-aitm-compromise.yaml
PASS  library/workflows/remediate-persistence-windows-run-key/remediate-persistence-windows-run-key.yaml
PASS  library/workflows/remediate-persistence-windows-scheduled-task/remediate-persistence-windows-scheduled-task.yaml
PASS  library/workflows/remediate-persistence-windows-startup-folder/remediate-persistence-windows-startup-folder.yaml
PASS  library/workflows/remediate-ransomware-smb-block-user/remediate-ransomware-smb-block-user.yaml
PASS  library/workflows/root-cause-analysis/root-cause-analysis.yaml
PASS  library/workflows/semantic-knowledge-search/semantic-knowledge-search.yaml
PASS  library/workflows/siem-rule-tuning/siem-rule-tuning.yaml
PASS  library/workflows/sync-rule-exceptions-across-spaces/sync-rule-exceptions-across-spaces.yaml
PASS  library/workflows/web-search/web-search.yaml
PASS  library/workflows/windows-clickfix-investigation/windows-clickfix-investigation.yaml (2 warnings)
        [liquidjs exp] steps.0.cases.1.steps.11.steps.0.with.url: strict validation skipped (liquidjs expression)
        [liquidjs exp] steps.0.cases.1.steps.24.cases.1.steps.1.cases.2.steps.1.cases.3.steps.0.with.category: strict validation skipped (liquidjs expression)
Validated 18 file(s): 18 passed, 0 failed (2 warnings).

@dej611
dej611 requested a review from semd July 31, 2026 14:29
@dej611
dej611 requested a review from a team as a code owner July 31, 2026 14:29
Comment on lines +263 to +264
const isTemplate = isRecord(json) && METADATA_KEY in json;
const variant = variantMode === 'auto' ? (isTemplate ? 'template' : 'strict') : variantMode;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

If somebody just copies a valid yaml from /examples to the template directory /library/workflows, without adding the template-metradata, the validation should fail.
The auto should not choose the variant based on the shape of the file, but on the location of the file.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The script was copied over from kibana without changes. The idea is to not make it drift too much from there so we have almost aligned implementations.
I think the CI responsibility would be to decide to which folder to point each variant of the script, without hardcoding it at the script level. That gives us more flexibility also for users who wants to use this script locally to check other scripts.

@semd semd Aug 12, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Okay, that makes sense.
Then I think we should also add scoped options using the target directories in the package.json scripts:

    "validate": "node scripts/validate-workflows.mjs",
    "validate:templates": "node run validate library/workflows --recursive --variant template",
    "validate:examples": "node run validate examples --recursive --variant strict",
    "validate:all": "node run validate:templates & node run validate:examples",

(handwritten, not tested)

In the pipeline:

npm run validate:templates --schema "${WORKFLOWS_SCHEMA}"
npm run validate:examples --schema "${WORKFLOWS_SCHEMA}"

What do you think?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

sure, I'll add it to the PR

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added with fde8d0c

}
};

export const discoverFiles = (target, { recursive = false } = {}) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

How do we prevent an arbitrary config YAML from breaking the validation process?
If the target is root, I don't think we should assume every yaml file in the repo is a workflow. We could have arbitrary yamls in the repo (configs, partial workflow yamls, the "template of templates") that should not be validated.

Would it be possible to scope the validation to just 2 directories

  • /examples: using always variant 'strict'
  • /library/workflows: using always variant 'template'

@semd

semd commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

@dej611 Thanks for this,
The validator itself looks great, and importantly, it's CI-agnostic, so nothing below touches scripts/. My concern is only about where we run it.

Wiring it into .buildkite/default-pipeline.yml means it won't run on the PRs we actually need it for. elastic/workflows is a public repo, and Buildkite doesn't build fork PRs here: this PR is a same-repo branch so it got buildkite/workflows (Build #74), but every fork PR I checked (#52, #49, #44, #35) has only the CLA check and no Buildkite build at all. Of the last 30 PRs, 15 come from forks, and that includes essentially every template contribution — Samirbous, w0rk3r, eric-forte-elastic, terrancedejesus, valeriy42, nastasha-solomon, semd, JM-elastic. The only non-fork human PRs in that window are yours. So as wired, the validation would cover maintainer PRs and skip all the community/content ones.

This isn't something we can just toggle on. Per eng-prod (elastic/ci#290), enabling fork builds means Buildkite uploads the pipeline definition from the fork and runs it on our agents with brokered Vault secrets, plus the DoS surface on a public repo — their conclusion is "we should avoid this for public repos", and they've told us it will not be permitted on public repos. We already encoded that in catalog-info.yaml when we set up the publish pipeline:

# Only build the main branch for the credentialed publish. Fork PRs are
# not built on public repos (platform constraint); PR validation is a
# separate, secret-free GitHub Actions workflow.

So the plan of record is already that PR validation lives in GitHub Actions, and Buildkite stays for the credentialed publish on main.

Concretely, what I think we should do instead:

  • Move the validation step out of .buildkite/default-pipeline.yml into .github/workflows/validate.yml, triggered on pull_request. Fork PRs then run on GitHub-hosted runners with a read-only GITHUB_TOKEN and no access to repo secrets, which is exactly right for us since validation needs no credentials at all.
  • Use pull_request, not pull_request_target — the latter would run with our secrets in scope against fork-authored code.
  • Set permissions: contents: read explicitly, pin the actions, and use npm ci --ignore-scripts since package.json and lockfile come from the fork.
  • While we're there, the same job should also run npm run build:catalog and npm run lint. Neither runs on PRs today, so a template that breaks the generator is only caught after merge at publish time.
  • Keep Buildkite as-is for the publish pipeline on main; the Test step in default-pipeline.yml can stay a placeholder (or we add a post-merge run of the same script as a backstop).

Happy to push the Actions workflow onto this branch if that's easier — the rest of the PR is good to go as far as I'm concerned.

@semd semd left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

LGTM! 🚀

@semd semd mentioned this pull request Aug 13, 2026
@talboren

talboren commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Copilot AI and others added 2 commits September 8, 2026 06:49
# Conflicts:
#	package-lock.json
#	package.json

Co-authored-by: talboren <68807791+talboren@users.noreply.github.com>
Co-authored-by: talboren <68807791+talboren@users.noreply.github.com>

Copilot AI commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved by merging main into this branch in e61744c and fixing the post-merge lint fallout in 573766e.

@talboren

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

# Conflicts:
#	package-lock.json
#	package.json

Co-authored-by: talboren <68807791+talboren@users.noreply.github.com>

Copilot AI commented Sep 17, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved by merging the latest main into this branch in da773c8.

@dej611

dej611 commented Sep 30, 2026

Copy link
Copy Markdown
Contributor Author

@copilot resolve the merge conflicts in this pull request

# Conflicts:
#	package-lock.json
#	package.json

Co-authored-by: dej611 <924948+dej611@users.noreply.github.com>

Copilot AI commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved by merging the latest main into this branch in 00167dd.

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.

4 participants