[Library] Create build-catalog script and examples relocation#16
Draft
semd wants to merge 1 commit into
Draft
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
[Library] Phase 1 — initial templates, categories vocab, build pipeline, and
/examplesrelocationFirst end-to-end pass at the Kibana Workflow Template Library source repo. Tech Preview target: Kibana 9.5+. Covers four merge-units worth of work that are easier to review as one body:
The CDN endpoint, the
publish-catalog.ymlGitHub Action, and Marco's PR-time schema validator are explicitly out of scope and will follow.Library content
Seven starter templates landed under
library/workflows/<slug>/<slug>.yaml, each with atemplate-metadatablock (slug, version, availability, name, description, optional solutions, categories, optional icon, optional install form). Picked for solution diversity and to exercise every codepath in the metadata schema:ip-reputation-check— AbuseIPDB + IP-API enrichment. Two install fields (connector, lookback days).hash-threat-check— VirusTotal lookup. Connector install field.mark-alert-as-acknowledged— security alert status flip. Minimal: no install form.semantic-knowledge-search— Elasticsearch semantic search with adata.parseJson-built filter clause. One install field (index name).web-search— Brave search via dedicated step type. Cross-solution (nosolutions:).create-slack-channel— Slack v2createConversation. Cross-solution.root-cause-analysis— alert-triggered, eight-step Agent Builder + Cases composition. One install field (agent id).All seven use dedicated vendor step types where the schema offers them (
abuseipdb.checkIp,virustotal.scanFileHash,slack2.createConversation,brave-search.webSearch,ai.agent, …). Generichttpandkibana.requestonly appear as documented escape hatches when no dedicated step exists.The closed categories vocabulary lives at
library/categories.yaml(16 entries: enrichment, detection, response, hunting, threat-intel, notification, case-management, monitoring, root-cause-analysis, data-ingestion, data-transformation, reporting, search, ai-agent, integration, utility). New categories require a PR adding the entry in the same change.Build infrastructure
scripts/build-catalog.mjsis the catalog generator. Inputs:kibana-versions.json(policy),library/categories.yaml(vocab),library/workflows/*/*.yaml(templates). Output: a completedist/v1/tree ready to upload to the CDN.Notable design points:
kibana-versions.jsonis a policy file, not an enumerated list. Three fields:latest(channel pointer; currently"main"),oldest(semver floor; currently"9.5.0"),cataloguePer(granularity;"minor"). The generator computes the live Kibana version set at run time, so we don't need a human PR every time Kibana cuts a new minor.mainis resolved live fromelastic/kibana@main'spackage.json.version, with any pre-release suffix stripped viasemver.coerce. Falls back toKIBANA_MAIN_VERSIONenv override for local-dev and incident recovery.elastic/kibana's branch list via the GitHub API, filtered to branches matching^X.Y$and>= policy.oldest. Falls back toKIBANA_NAMED_MINORSenv override (or""to skip the API entirely) for local iteration without burning the 60/h unauth rate limit.__install__.<name>reference with no matchinginstall.formentry, an unreachable Kibana main, or an unauthenticated rate-limit exhaustion aborts the run with a non-zero exit. Never falls back to stale data — a failed publish is preferable to a wrong one.GITHUB_TOKEN, useKIBANA_NAMED_MINORS="", or wait). Saves the next person from a confused stack trace.effectiveKibanaSemveron each per-versionmanifest.jsonso consumers and humanscurling the CDN can see exactly whatmain(or any named minor) resolved to at publish time.package.jsonpinsjs-yaml ^4.2.0+semver ^7.8.4, setsengines.node >=20, and exposesnpm run build:catalog. Noglobdep — the script usesfs.readdirsince the template directory layout is predictable.solutionsfield: optionaltemplate-metadata.solutionsis optional. Three cases the build script handles:[]: same as absent; the script normalizes this to absent in the catalog row, so consumers always see "nosolutionskey" for both cases.[security]/[security, observability]/[observability]: solution-scoped to those values.Two of the seven templates (
web-search,create-slack-channel) ship as cross-solution; the other five carry an explicitsolutions:.Repository reorganization
The historical
/workflows/directory has been moved wholesale to/examples/. ~140 files, all detected as renames by git.Rationale: the repo's primary artifact going forward is the library under
/library/workflows/. The legacy directory is reference material — useful for browsing the raw YAML grammar and as a sandbox for things that don't (yet) carrytemplate-metadata. Renaming it to/examples/makes that asymmetry honest without removing the content. External consumers that link at the old paths will need to update, but git's rename tracking keepsgit log --followandgit blamecontinuity intact.Build infrastructure stays at the repo root (
package.json,scripts/,dist/,kibana-versions.json) — these are repo-level concerns, not library-internal artifacts.Documentation
CONTRIBUTING.mdwas rewritten end-to-end as the library authoring guide. Sections: file layout and slug rules, thetemplate-metadatablock (required vs optional), categories vocabulary, install-form discipline including the kebab-case naming convention for__install__.<name>placeholders, the connector-type rule (.<vendor>equals the step-type prefix), style conventions (2-space indentation, no legacy banner headers, snake_case for workflow-body identifiers, preferdata.*steps over abusingconsole), local validation vianpm run build:catalogincluding the env-var override table, semver policy, and PR flow.README.mdwas slimmed from 608 lines to ~150 and refocused on the library. Kept the Elastic logo + header (as requested) and the badge strip. Covers: overview, repo structure, a minimal template format snippet, how Kibana consumes the catalog at install time, and pointers to the docs for deeper reading.docs/was largely left alone —concepts.mdandschema.mdare general workflow-engine references that apply to both library and example authors and didn't need changes.docs/importing.mdgot path updates (workflows/→examples/) but kept its original content: it documents the raw-YAML import paths (Kibana UI / API / bulk) which remain useful for local dev. Library templates are NOT installed this way — they go through the catalog UI in Kibana 9.5+ (Phase 2) which renders the install form and substitutes__install__.*placeholders.Validation
Every template parses with
js-yaml, has the requiredtemplate-metadatafields, has matchinginstall.form↔__install__.<name>references with no orphans, and uses only category ids declared inlibrary/categories.yaml. The build script enforces all of this.End-to-end smoke test:
npm install KIBANA_MAIN_VERSION=9.6.0 KIBANA_NAMED_MINORS="" npm run build:catalogProduces
dist/v1/{kibana-versions.json, main/catalogs/templates.json, main/manifest.json, templates/<slug>/<version>.yaml}. WithKIBANA_NAMED_MINORS="9.5"you get the named-minor branch too. With no overrides (CI default), the script fetches the live values fromelastic/kibana.What the script does not yet enforce: the workflow body itself against the engine's step-type schema. That's Marco's PR-time validator, a separate piece coordinated for a sibling CI job. The publish workflow reserves a slot for it.
Decisions worth a second look
A handful of judgment calls during the template migrations are worth a reviewer's eye:
hash-threat-check: categories are[enrichment, threat-intel]. The legacy directory placed it undersecurity/detection/, but the operation is a vendor intel lookup that produces a verdict — same shape asip-reputation-check. If you'd prefer[detection, threat-intel], the swap is one line.hash-threat-check: dropped theget_detailed_analysisstep from the source. It hit/files/{hash}/behavioursvia rawhttpand its output was never consumed by the report. No dedicated step type exists for that endpoint and a second.<vendor>connector would have been required. Easy to restore if there's a use case I missed.mark-alert-as-acknowledged: switched step type tosecurity.setAlertStatus(the post-9.5 successor to the legacykibana.SetAlertsStatus). Confirmed during migration.root-cause-analysis: the threekibana.request POST /api/agent_builder/conversecalls collapsed toai.agent. The conversation fetch (step 6) stays onkibana.requestbecause noai.*step exists for that. I assumedai.agent's output exposesoutput.conversation_idandoutput.message— the JSON Schema describes inputs only, so the output shape is best-effort. If a real run shows different paths, the three references need adjusting in lockstep.root-cause-analysis: fixed a broken{{ consts.basePath }}reference in the source (the const was never declared). Replaced with the canonical{{ context.kibanaUrl }}. Tell me ifcontext.kibanaUrldoesn't include the base path in your deployment model.ip-reputation-check: output paths forabuseipdb.checkIpare guessed asoutput.data.X(the source mixedoutput.data.data.Xandoutput.data.Xinconsistently — the latter was a bug). I normalized everything tooutput.data.X. If the dedicated step preserves the vendor envelope, the paths needoutput.data.data.X.Out of scope (deliberate)
.github/workflows/publish-catalog.yml— the script is ready; the GH Action is the next PR.__snippet__:/__role__:) — Kibana 9.6.Acceptance checklist
library/workflows/<slug>/<slug>.yamlwith validtemplate-metadata.library/categories.yamlexists with the initial closed vocab.kibana-versions.jsonat the repo root (policy shape:latest,oldest,cataloguePer).scripts/build-catalog.mjsgenerates a completedist/v1/tree locally.CONTRIBUTING.mdupdated to describe the library authoring layout..github/workflows/publish-catalog.yml(next PR).