[Threat Intel 5/11] Index templates, catalog seeding, and inference features - #287201
Conversation
7d4ad78 to
203704e
Compare
|
Pinging @elastic/security-threat-hunting (Team:Threat Hunting) |
|
Pinging @elastic/security-solution (Team: SecuritySolution) |
kibanamachine
left a comment
There was a problem hiding this comment.
Libra found 2 issues.
Generated by Libra
|
Both addressed, and I took a different approach on the migration one than suggested, so worth a look. Propagating each migration error would mean changing all 13 signatures and would still miss the failure mode this file worries about most: a migration that runs cleanly but takes a wrong branch and skips its field reports success while leaving the schema just as broken. So the install verifies the outcome instead, re-reading the mappings after every migration and throwing if a migration-owned field is still missing. That gets the retry and unresolved-readiness behaviour asked for, and covers the silent no-op too. Also carries |
Use Object.hasOwn for catalog URL lookups, drop config from the fetch_source hit schema, paginate legacy-source disable with search_after, and surface disable failures in the seed result so bootstrap retries. Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
💛 Build succeeded, but was flaky
Failed CI StepsMetrics [docs]
Test Failures
History
|
After elastic#287201, feed URLs are no longer stored on source documents. Co-authored-by: Cursor <cursoragent@cursor.com>
After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
…de catalog After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
…de catalog After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
After elastic#287201, feed URLs are no longer stored on source documents. Co-authored-by: Cursor <cursoragent@cursor.com>
After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
…de catalog After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
After elastic#287201, feed URLs are no longer stored on source documents. Co-authored-by: Cursor <cursoragent@cursor.com>
After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
…de catalog After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
…de catalog After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
…de catalog After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
…de catalog After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
…de catalog After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
…og API (#287204) ## Summary Adds LLM enrichment services and Threat Intelligence HTTP routes, including the fixed-catalog source list and enable/disable API. Manual report creation and provenance URLs go through the shared HTTP/HTTPS normalizer. Also wires the routes, inference features, and one-time bootstrap into `plugin.ts`, gated by `threatIntelSupplyEnabled`. This wiring is interim: it exists so the enrichment eval suite (see Evaluation below) has routes to call ahead of the full pipeline wiring. `#287207` replaces it with a proper `wiring.ts` module; that PR's description has a rebase note covering the `plugin.ts` conflict resolution. ## Where this sits | # | PR | Depends on | Status | |---|---|---|---| | 1 | #287197 workflow gate correction + fixtures | nothing | ✅ merged | | 2 | #287198 contracts, constants, shared libs | nothing | ✅ merged | | 3 | #287199 content parsing | #287198 | closed | | 4 | #287200 SSRF-guarded HTTP client | #287198 | ✅ merged | | 5 | #287201 index templates, seeding, inference features | #287198, #287200 | ✅ merged | | 6 | #287202 indicator alias | #287198, #287201 | ✅ merged | | 7 | #287203 IOC extraction | #287198, #287200 | ✅ merged | | 8 | #287204 LLM services, routes, source catalog API **← this PR** | #287198, #287200, #287202, #287203 | 👀 ready | | 9 | #287205 RSS adapter | #287198, #287200, #287203, #287204 | draft | | 10 | #287206 remaining adapters, dispatcher, fetch_source step | #287198, #287200, #287203, #287205 | draft | | 11 | #287207 promote/scrub tasks and plugin wiring | #287198–#287206 | draft | | 12 | #287479 generator fixture article URLs | nothing | ✅ merged | | 13 | #289343 Scout API tests for the deterministic routes | #287204 | draft | | 14 | #289345 enrichment eval suite | #287204 | draft | #287479 came first in the merge train and is already on `main`. The numbered series (#287197–#287207) stacks on top in dependency order. #287199 (content parsing) was closed; IOC extraction ships its own section-header classifier. ## Scope review follow-up - Shared `normalizeProvenanceUrl` helper (HTTP/HTTPS only, strips credentials, bounded length). - Source create/delete routes removed. Updates may change only `enabled`. - Lists and mutations reject catalog IDs outside the approved set. - Ensures the per-space indicator alias on `list_sources` (idempotent). ## Evaluation A `@kbn/evals` suite exercises all four enrichment stages against the BlackHat demo pack article text, posting each input directly to the internal route and scoring the structured response. It runs as a tracked baseline (scores recorded, no build-failing thresholds yet). Latest full run, EIS Claude Sonnet 4.6 as model and judge, 1 repetition, 20 examples: | Stage | Evaluator | Score | |---|---|---| | assess_relevance | IsIntelligenceMatch | 1.00 | | assess_relevance | RelevanceShapeValid | 1.00 | | classify_severity | SeverityExactMatch | 0.83 | | classify_severity | SeverityWithinOneLevel | 1.00 | | enrich_taxonomy | CategoryRecall | 0.80 | | enrich_taxonomy | RegionRecall | 1.00 | | extract_diamond | DiamondNoIocLeak | 1.00 | | extract_diamond | DiamondSignalCount | 1.00 | | extract_diamond | criteria (LLM judge, majority vote) | 1.00 | The suite ships in #289345, a separate eval-only PR that stacks on this one (it needs the routes and the flag-gated wiring added here). The four deterministic routes are covered separately by Scout API tests in #289343. Any prompt or calibration fix the evals surface lands by amending this PR, not the eval PR. ## To test ``` node scripts/jest --config x-pack/solutions/security/plugins/security_solution/server/threat_intel/jest.config.js routes/list_sources.test.ts services/provenance_url.test.ts ``` _PR developed with Cursor + Auto_ --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Jon Wålstedt <jon.walstedt@elastic.co> Co-authored-by: Cursor <cursoragent@cursor.com>
After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
…de catalog After elastic#287201, feed URLs live in catalog_source_urls rather than source config. Co-authored-by: Cursor <cursoragent@cursor.com>
…d the flag (#287207) ## Summary Wires Threat Intelligence behind `threatIntelSupplyEnabled`: bootstrap, managed workflow installation, promote/scrub tasks, and route registration. Promote mirrors extracted IOCs into `.threat-intel-indicators` for Indicator Match rules. ## Where this sits | # | PR | Depends on | Status | |---|---|---|---| | 1 | #287197 workflow gate correction + fixtures | nothing | ✅ merged | | 2 | #287198 contracts, constants, shared libs | nothing | ✅ merged | | 3 | #287199 content parsing | #287198 | closed | | 4 | #287200 SSRF-guarded HTTP client | #287198 | ✅ merged | | 5 | #287201 index templates, seeding, inference features | #287198, #287200 | ✅ merged | | 6 | #287202 indicator alias | #287198, #287201 | ✅ merged | | 7 | #287203 IOC extraction | #287198, #287200 | ✅ merged | | 8 | #287204 LLM services, routes, source catalog API | #287198, #287200, #287202, #287203 | ✅ merged | | 9 | #287205 RSS adapter | #287198, #287200, #287203, #287204 | ✅ merged | | 10 | #287206 remaining adapters, dispatcher, fetch_source step | #287198, #287200, #287203, #287205 | ✅ merged | | 11 | #287207 promote/scrub tasks and plugin wiring **← this PR** | #287198–#287206 | ready for review | | 12 | #287479 generator fixture article URLs | nothing | ✅ merged | | 13 | #289343 Scout API tests for the deterministic routes | #287204 | ready for review | | 14 | #289345 enrichment eval suite | #287204 | ready for review | | 15 | #290144 read APIs, readiness, space-keyed attribution | #287207 | draft | #287479 came first in the merge train and is already on `main`. The numbered series (#287197–#287205) is merged; #287206 and #287207 now sit directly on `main`. #287199 (content parsing) was closed; IOC extraction ships its own section-header classifier. ## Scope review follow-up - Installs the managed workflows with the right space topology: `attribute_alerts_to_reports` installs per space (it queries `.alerts-security.alerts-*` and writes per-space hit totals, so a global install would clobber every space's totals onto one shared doc), while `ingest_threat_feeds` and `enrich_threat_report` install once globally. Alert analysis and threat intel share a single `ready()` call so neither install set is dropped, and spaces created after boot are reconciled on the promote task. All three ship `enabled: false`, and enrich routes its HTTP calls through a fixed space (`default`) instead of the install-time `workflow.spaceId` (which is `'*'` globally). - Ensures the default-space indicator alias on start. - Chunks promotion bulk writes and treats HTTP 408/500 as retryable bulk failures. - Sanitizes provenance and extracted IOC reference URLs during promotion. - Documents direct-index cross-space isolation as the blocker to enabling the feature. ## Bootstrap fix folded in from #289343 `seed_default_sources.ts` sorted the legacy-source disable scan on `_id`, which Elasticsearch rejects with `illegal_argument_exception: Fielddata access on the _id field is disallowed` unless `indices.id_field_data.enabled` is set, so it failed bootstrap on a stock cluster. Found this while getting #289343's Scout suite green and moved the fix here since this PR is the one wiring up bootstrap and already needs `security-threat-hunting` review, so it isn't adding a reviewer #289343 wouldn't otherwise need. ## Product boundary `threatIntelSupplyEnabled` defaults to false. Do not enable until direct-index cross-space isolation is hardened or the administrator trust model is explicitly accepted. ## To test ``` node scripts/jest --config x-pack/solutions/security/plugins/security_solution/server/threat_intel/jest.config.js wiring.test.ts tasks/promote_threat_indicators.test.ts node scripts/jest x-pack/solutions/security/plugins/security_solution/server/workflows/ node scripts/jest src/platform/packages/shared/kbn-workflows/managed/definitions/threat_intel/ ``` _PR developed with Cursor + Auto + Sonnet 5 + Opus 4.8_ --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: Jon Wålstedt <jon.walstedt@elastic.co> Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Summary
Installs Threat Intelligence index templates, semantic-text readiness checks, and fixed-catalog source seeding. The catalog is code-authoritative: missing entries are created, code-owned fields are reconciled, and operator
enabledchoices are preserved.Where this sits
#287479 came first in the merge train and is already on
main. The numbered series (#287197–#287207) stacks on top in dependency order. #287199 (content parsing) was closed; IOC extraction ships its own section-header classifier.Scope review follow-up
vendor_api:elastic-security-labsas the stable document ID while reconcilingadapter_typetorss.Product boundary
Operators can only toggle
enabledon approved sources.threatIntelSupplyEnabledstays off until direct-index cross-space isolation is hardened.To test
PR developed with Cursor + Auto