Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .buildkite/default-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@ steps:
- label: "Build"
command: "true"

- label: "Test"
# PR validation (build:catalog, lint, workflow YAML validation) runs in
# GitHub Actions (.github/workflows/validate.yml) where fork PRs are
# supported. This step is a placeholder; a post-merge backstop run can be
# added here later if needed.
- label: "Validate workflows"
command: "true"

- label: "Deploy"
Expand Down
68 changes: 68 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
name: Validate workflows

on:
pull_request:

permissions:
contents: read

jobs:
lint-and-catalog:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0
with:
node-version: '20'
cache: 'npm'
- run: npm ci --ignore-scripts
- run: npm run build:catalog
- run: npm run lint

validate:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- name: serverless
schema_url: https://workflows.elastic.co/schema/v1/serverless
blocking: true
- name: release
# Bump the version to the latest released Kibana minor. The release
# schema can lag templates targeting a newer stack (see
# `availability`), so this line reports without blocking.
schema_url: https://workflows.elastic.co/schema/v1/9.6.0/release
blocking: false
name: validate (${{ matrix.name }})
continue-on-error: ${{ !matrix.blocking }}
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-node@cdca7365b2dadb8aad0a33bc7601856ffabcc48e # v4.3.0
with:
node-version: '20'
cache: 'npm'
- run: npm ci --ignore-scripts
- name: Check schema is published
id: schema
run: |
# TODO: remove this skip once the schemas are published; from then on
# an unreachable schema must fail the job instead of passing it.
url="${{ matrix.schema_url }}"
if [ "$(curl -s -o /dev/null -w '%{http_code}' "${url}/index.json")" = "404" ]; then
echo "::warning::No schema published at ${url} yet; skipping validation."
echo "published=false" >> "$GITHUB_OUTPUT"
else
echo "published=true" >> "$GITHUB_OUTPUT"
fi
- name: Validate templates
if: steps.schema.outputs.published == 'true'
env:
WORKFLOWS_SCHEMA_CDN_URL: ${{ matrix.schema_url }}
run: npm run validate:templates
- name: Validate examples
# Run even if the templates step failed, so both results are reported.
if: ${{ !cancelled() && steps.schema.outputs.published == 'true' }}
env:
WORKFLOWS_SCHEMA_CDN_URL: ${{ matrix.schema_url }}
run: npm run validate:examples
18 changes: 17 additions & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,23 @@ The generator enforces only:
- `template-metadata` is present with all required fields (`slug`, `version`, `availability`, `name`, `description`, `categories`).
- At least one template is discovered.

Deeper authoring invariants — slug ⇄ directory parity, valid `version` semver and `availability` range, `categories[]` membership in the vocab, `install.form` ⇄ `__install__` consistency, and step/connector type validity — are delegated to the separate validation step (planned to run in CI), not the generator.
Deeper authoring invariants — slug ⇄ directory parity, valid `version` semver and `availability` range, `categories[]` membership in the vocab, `install.form` ⇄ `__install__` consistency — remain the generator's / reviewer's responsibility. Step and connector **type** validity is enforced by the schema validator below.

### Schema validation

`npm run validate` checks workflow YAML (both `examples/` and `library/` templates) against the generated workflow **step JSON Schema**, layering step-name uniqueness and LiquidJS syntax checks on top. It is a plain-JS port of Kibana's `@kbn/workflow-yaml-validate-cli`; see [`scripts/validate/README.md`](./scripts/validate/README.md) for the full flag list and what each layer covers.

The schema artifact is not bundled in this repo, so a source must be provided — a local bundle directory or a CDN base URL:

```bash
# validate everything against a local schema bundle (a dir containing index.json)
npm run validate -- examples library/workflows --recursive --schema /path/to/workflow_step_schemas/<version>/release

# or point at a CDN base URL (equivalently, set WORKFLOWS_SCHEMA_CDN_URL)
npm run validate -- examples library/workflows --recursive --schema-cdn-url https://<cdn-base>/
```

A non-zero exit means at least one file has an error. JSON-schema constraints on values that hold a LiquidJS expression (e.g. `{{ event.foo }}`) are reported as non-failing warnings, not errors. Execution-graph (DAG) validation is not part of this script yet.

---

Expand Down
148 changes: 134 additions & 14 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
},
"scripts": {
"build:catalog": "node scripts/build-catalog.mjs",
"validate": "node scripts/validate-workflows.mjs",
"validate:templates": "node scripts/validate-workflows.mjs library/workflows --recursive --variant template",
"validate:examples": "node scripts/validate-workflows.mjs examples --recursive --variant strict",
"validate:all": "npm run validate:templates && npm run validate:examples",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"format": "prettier --write .",
Expand All @@ -21,9 +25,13 @@
},
"devDependencies": {
"@eslint/js": "10.0.1",
"ajv": "^8.20.0",
"ajv-formats": "^3.0.1",
"eslint": "10.11.0",
"eslint-config-prettier": "10.1.8",
"globals": "17.12.0",
"prettier": "3.9.8"
"liquidjs": "^10.27.2",
"prettier": "3.9.8",
"yaml": "^2.9.0"
}
}
6 changes: 4 additions & 2 deletions scripts/build-catalog.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -150,10 +150,12 @@ async function discoverNamedMinors(oldest) {
maxBuffer: 16 * 1024 * 1024,
}));
} catch (err) {
const message = err instanceof Error ? err.message : String(err);
throw new Error(
`Failed to list elastic/kibana branches via 'git ls-remote ${repo}': ${err.message}\n` +
`Failed to list elastic/kibana branches via 'git ls-remote ${repo}': ${message}\n` +
`For local iteration you can skip the lookup with KIBANA_NAMED_MINORS ` +
`(e.g. KIBANA_NAMED_MINORS="9.5,9.6" or KIBANA_NAMED_MINORS="").`
`(e.g. KIBANA_NAMED_MINORS="9.5,9.6" or KIBANA_NAMED_MINORS="").`,
{ cause: err }
);
}

Expand Down
Loading
Loading