Skip to content

feat(entity-store): add seed-nat-tiles to seed the Needs attention tiles - #495

Draft
CAWilson94 wants to merge 2 commits into
elastic:mainfrom
CAWilson94:seed-nat-tiles
Draft

CAWilson94 wants to merge 2 commits into
elastic:mainfrom
CAWilson94:seed-nat-tiles

Conversation

@CAWilson94

@CAWilson94 CAWilson94 commented Oct 22, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds seed-nat-tiles, a subcommand of the entity-store commands that seeds a small, exact set of data so every Needs attention tile on the new Entity Analytics page shows a number, a change against the previous period and a sparkline. It prints the numbers each tile should show, so a tester can check the page against them.

yarn start seed-nat-tiles
  • Seeds 34 entities with 65 days of history: entities, risk scores, alerts, anomaly records, a watchlist and the security ML placeholder jobs (the Anomalous tile only counts records of installed security jobs).
  • Five resolved groups (a main entity and an alias), so the tiles are exercised the way the page judges them (see below).
  • --entities <n> seeds whole sets of 34 (every number scales), --space <id> picks the space, --clean removes what it seeded.
  • Running it again refreshes the data without duplicating anything.
  • Before writing it checks the Entity Store is installed in the space, the license is Platinum, Enterprise or trial, and the ML jobs can be installed. Each failure stops the run before anything is written and prints one line saying how to fix it.
  • Adds createPlaceholderSecurityMlJob to src/utils/kibana_api.ts, and a README recipe and a seed-ea row.

What the tiles show

number (change vs previous period). The numbers differ by range because the history is spread over time; every tile has a sparkline. The command prints these plus every sparkline (oldest dot first, ending on the number).

Tile Last 24h Last 7d Last 30d
Severely alerting 3 (+2) 4 (+3) 4 (+4)
Anomalous 2 (-2) 6 (+2) 6 (+2)
Risk movers 1 (+1) 3 (+2) 6 (+6)
Newly high-risk 1 (+1) 2 (+1) 4 (+4)
Watchlisted & alerting 3 (+2) 4 (+3) 4 (+3)
New & alerting 4 (+2) 7 (+6) 8 (+7)

The data is defined once in seed_nat_tiles.ts (event ages per entity, and which entities are aliases), and the expected numbers are computed from those same definitions, one resolved group at a time, so the data and the printed numbers cannot drift apart.

Resolved groups

Five of the 34 entities are aliases (entity.relationships.resolution.resolved_to points at the main entity), so the page lists 29 resolved entities from the seed, not 34. The groups cover what the tiles judge by group:

  • an alert or an anomaly on an alias counts for its group, once;
  • a group is on the watchlist when any member is (the main entity is watchlisted, the alert is on its alias);
  • a group is new by its earliest member (one group has a new main entity and an old alias, so it does not count; another has a newer alias and counts from its older member);
  • a group's risk score wins over the main entity's own: its resolution score documents rise while the entity's own score stays flat and low.

Why it is shaped this way

  • Not a new top-level module. It is registered in the existing entityStoreCommands (src/commands/entity_store/index.ts), next to risk-score-v2 and seed-risk-score-history.
  • Why not extend an existing command. I did not extend risk-score-v2 or nat-perf: this needs fixed data with known numbers, not generated data at scale. I did not check in detail whether either could be configured to do that.
  • Bulk writes use the shared bulkUpsert (pre-built body with custom _ids across indices). The risk score index is a data stream, so it uses create and the command deletes its own risk documents first, which also puts fresh timestamps back on a repeat run.
  • Deletes use deleteByQuery on this command's own ids, because deleteAllByIndex and deleteDataStreamSafe would remove other data.

How to test

  1. Local Elasticsearch and Kibana 9.6 with a trial license, the Entity Store installed in the space, and feature_flags.overrides: { securitySolution.useNewEntityAnalyticsPage: true } in kibana.yml.
  2. yarn start seed-nat-tiles, then open Security > Entity analytics and reload.
  3. Click through Last 24h, Last 7d and Last 30d and compare with the printed numbers.
  4. yarn start seed-nat-tiles --clean to remove it.

What I ran

  • yarn checks (typecheck, eslint, prettier) passes; the pre-commit hooks ran too.
  • Environment: Elasticsearch 9.6.0-SNAPSHOT with a trial license, Kibana 9.6.0 from elastic/kibana main at a2922eb6ced6 (2026-10-22), default space.
  • Page check: a headless browser read the six tiles on Last 24h, 7d and 30d. For all 18 tile and range combinations the number, the change and the sparkline start, end and peak matched the printed expected values. It also matched at --entities 68 (two sets, every number doubles), which checks that each alias links to the main entity of its own set.
  • Resolved entities: the page's table (Rows: Resolved entities) listed 31 = 34 seeded − 5 aliases + 2 entities my local Kibana created itself; with two sets, 60 = 68 − 10 + 2.
  • Repeat run: same document counts before and after (34 entities, 245 risk scores, 35 alerts, 21 anomaly records).
  • --clean: counts back to 0, including the watchlist, for one set and for two.
  • Prerequisite checks: with no Entity Store in the space, and with Kibana unreachable, the command stops with one clear message and writes nothing. (Run before the groups were added; that code is unchanged.)
  • Cold run: a real git clone of this branch, yarn install, then the README command only, seeded correctly.

Caveats

  • The numbers hold for about an hour. Event ages move across window edges, and the risk scores sit in the 2-hour window the tiles read before each boundary, so they stay valid for roughly 1.9 hours. Run the command again to refresh. The tiles cache results for an hour, so reload the page after seeding.
  • The group behaviour follows the tile queries on Kibana main at a2922eb6ced6 (#298158, #298326). If those rules change, the expected numbers here need to change too.
  • The low-license message is untested. The cluster I used has a trial license and I could not downgrade it.
  • Not tested with the risk engine running. It can overwrite the seeded risk scores on its hourly run.
  • The page check compared each sparkline's start, end and peak, not the middle dots, because the page only exposes those.
  • Only a local stack, default space and Entity Store v2 were tested. Not tried on a non-default space, serverless or ECH.
  • The Entity Store install path in the error message (Security > Entity analytics) was not clicked through. I installed the store through the API.
  • No automated tests. The repo has no test framework; checks are typecheck, lint and prettier.
  • --clean leaves the ML placeholder jobs in place (they are harmless). Use the same --entities you seeded with.
  • The new page needs the useNewEntityAnalyticsPage flag and a Kibana restart; the command prints this.

Related

Independent of #481 (open, seeds previous-period alert and anomaly deltas for nat-perf) and of any fork-only seeding code: it uses only what is on main.

🤖 Generated with Claude Code

CAWilson94 and others added 2 commits October 22, 2026 11:30
Adds `seed-nat-tiles` to the entity-store commands. It seeds 24 entities with
65 days of history (entities, risk scores, alerts, anomaly records, a watchlist
and the security ML placeholder jobs), so every Needs attention tile on the new
Entity Analytics page shows a number, a change against the previous period and
a sparkline. It prints the numbers each tile should show on 24h, 7d and 30d.

- `--entities` seeds whole sets of 24, `--space` picks the space, `--clean`
  removes what it seeded, and running it again refreshes the data without
  duplicates.
- It checks the Entity Store, the license and the ML jobs before writing.
- Adds `createPlaceholderSecurityMlJob` to `kibana_api.ts`.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Adds five resolved groups (a main entity and an alias) to the seeded set, so
the tiles are exercised the way the page judges them: an alert or anomaly on
an alias counts for its group once, a group is on the watchlist when any
member is, a group is new by its earliest member, and a group's risk score
(from resolution score documents) wins over the main entity's own score.

The set is now 34 entities. The expected numbers are still computed from the
same definitions, now per resolved group.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
orouz pushed a commit to orouz/kibana that referenced this pull request Nov 2, 2026
… query in the local project (elastic#302397)

## Summary

**The Needs attention tiles now only search the project you're in, not
every project linked to it through cross-project search (CPS).**

- Before: only the New & alerting tile did this. The other five searched
all linked projects, so they could count alerts, anomalies and risk
scores from other projects against your own entities.
- Now: every tile query (count, change, sparkline) is pinned to the
current project with `projectRouting: '_alias:_origin'`, the same fix
elastic#272473 made for the entities table.
- Without CPS nothing changes.

Addresses B6 in elastic/security-team#19969.

## Desk testing

**Data (small: 34 entities).** `seed-nat-tiles` gives every Needs
attention tile a count, a change and a sparkline, and prints the number
each tile should show for 24h, 7d and 30d. It is in
elastic/security-documents-generator#495 (not merged yet):

1. Kibana with a trial license, the Entity Store installed in the space,
and in `kibana.yml`:
`feature_flags.overrides: { securitySolution.useNewEntityAnalyticsPage:
true }`
2. In security-documents-generator: `gh pr checkout 495 && yarn install
&& yarn start seed-nat-tiles`. Keep the table it prints.
3. The numbers hold for about an hour; run it again to refresh, and
reload the page (the tiles cache for an hour).

**Without CPS (nothing should change):**

1. On this branch, open Security → Entity analytics.
2. For Last 24h, 7d and 30d, every tile's number and change match the
table `seed-nat-tiles` printed, and every tile has a sparkline.

**With CPS (the actual change; same setup as elastic#272473):**

1. Start the local CPS servers (Docker needs about 15 GB of memory):
`node scripts/scout start-server --arch serverless --domain
security_complete --serverConfigSet cps_local`
This starts the origin cluster (`:9220`), a linked cluster (`:9230`) and
Kibana (`:5620`).
2. Seed the origin as above, pointing the generator at `:9220` /
`:5620`.
3. Index a few high or critical alerts into the **linked** cluster's
`.alerts-security.alerts-default` (`:9230`), with
`kibana.alert.entity.id` set to entities the seed created. (How to
authenticate to the linked cluster is not verified here.)
4. On `main`: Severely alerting can count more than the printed table
(the linked alerts are counted).
5. On this branch: it matches the printed table, and every tile search
request carries `project_routing: '_alias:_origin'` (DevTools → Network,
or Inspect).

## Tests

- Each of the 5 count hooks, the previous-period query and its history
check, and all 4 sparkline hooks assert the routing.
- `node scripts/jest .../needs_attention_tiles`: 30 suites, 475 tests
pass. `.../entity_analytics/pages`: 5 suites, 94 tests pass.
- eslint clean; `type_check` on `security_solution` clean.
- Not tested on a CPS project (not available locally).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
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.

1 participant