[Entity Store] Adding list endpoint with query filter#258320
[Entity Store] Adding list endpoint with query filter#258320tiansivive merged 7 commits intoelastic:mainfrom
Conversation
chennn1990
left a comment
There was a problem hiding this comment.
Looking good,
Please see my comments
| import { wrapMiddlewares } from '../../middleware'; | ||
|
|
||
| const querySchema = z.object({ | ||
| filter: z.string().optional(), |
There was a problem hiding this comment.
please add a validation for the filter
There was a problem hiding this comment.
Actually, shouldnt we be using OAS?
There was a problem hiding this comment.
lets keep it internal for Now, once we will convert the CRUD API's to be public this will be addressed
@uri-weisman WDYT?
There was a problem hiding this comment.
I mean using the superRefine method in order to validate the filter string., it should be a valid DSL filter.
There was a problem hiding this comment.
superRefine is apparently deprecated?
I also didnt really see any other place doing this kind of validation, so isntead I jsut used the typical KQL to query DSL utility fns. They already throw on incorrect strings, so jus tuse that to validate.
| } | ||
| } | ||
|
|
||
| const entities = await crudClient.listEntities(parsedFilter); |
There was a problem hiding this comment.
use this one inside the try
| // An optional DSL filter can be provided and is applied as an additional | ||
| // filter clause on the search query, e.g. to scope results by additional | ||
| // field conditions. | ||
| public async listEntities(filter?: QueryDslQueryContainer): Promise<Entity[]> { |
There was a problem hiding this comment.
I would change the terminology to getEntities.
I see list as a quite confusing inside CRUD operations
There was a problem hiding this comment.
the problem with GET is that it implies a single entity? We typically use LIST for GET'ing multiple entries. I can change though, if that's the way we should look at API's in this domain?
There was a problem hiding this comment.
We don't have a convention yet, lets stick to the Kibana conventions.
If list is more common, lets keep it
| STOP: `${ENTITY_STORE_BASE_ROUTE}/stop`, | ||
| FORCE_LOG_EXTRACTION: `${ENTITY_STORE_BASE_ROUTE}/{entityType}/force_log_extraction`, | ||
| FORCE_HISTORY_SNAPSHOT: `${ENTITY_STORE_BASE_ROUTE}/force_history_snapshot`, | ||
| CRUD_LIST: `${ENTITY_STORE_BASE_ROUTE}/entities`, |
There was a problem hiding this comment.
CRUD_GET: ENTITY_STORE_BASE_ROUTE
IMO A simple get to the base route is more meaningful
uri-weisman
left a comment
There was a problem hiding this comment.
@tiansivive thanks for putting this PR 🙏
Can you please add unit tests and a Scout test (At least one happy path)?
| ? { bool: { filter: [filter] } } | ||
| : { match_all: {} }; | ||
|
|
||
| const resp = await this.esClient.search<Entity>({ |
There was a problem hiding this comment.
So today you get at most one page of 10 results (ES default), with no way to request more or skip ahead.
I suggest to extend the params to support size and searchAfter to make this endpoint more usable.
export interface ListEntitiesParams {
filter?: QueryDslQueryContainer;
size?: number;
searchAfter?: Array<string | number>;
}
uri-weisman
left a comment
There was a problem hiding this comment.
Good Job @tiansivive!
| @@ -74,6 +74,37 @@ apiTest.describe.skip('Entity Store CRUD API tests', { tag: ENTITY_STORE_TAGS }, | |||
| expect(check.found).toBe(true); | |||
| }); | |||
|
|
|||
| apiTest('Should list entities', async ({ apiClient, esClient }) => { | |||
There was a problem hiding this comment.
This test feels a bit limited, I would expect to see multiple tests that better cover the different API capabilities, especially around ListEntitiesParams (valid scenarios & invalid scenarios)
| import { wrapMiddlewares } from '../../middleware'; | ||
|
|
||
| const querySchema = z.object({ | ||
| filter: z.string().optional(), |
There was a problem hiding this comment.
I mean using the superRefine method in order to validate the filter string., it should be a valid DSL filter.
e01f3f3 to
12a6c34
Compare
💛 Build succeeded, but was flaky
Failed CI StepsTest Failures
Metrics [docs]Page load bundle
History
|
Steps 2b + 2e from refactor prompt: - Replace entityStoreDataClient param with listEntities: () => Promise<LeadEntity[]> in RunPipelineParams (dependency injection pattern) - Wire startPlugins.entityStore.createCRUDClient() + fetchAllLeadEntities() in the task runner, removing the TODO skip - Add fetchAllLeadEntities paginated helper to entity_conversion.ts - Rewrite run_pipeline.test.ts to mock listEntities function Depends on PR elastic#258320 for CRUDClient.listEntities() method.
Steps 2a, 2c, 2d from refactor prompt: - Add entityStore: EntityStoreStartContract to SecuritySolutionPluginStartDependencies - Create fetchAllLeadEntities() paginated helper in entity_conversion.ts that pages through all V2 entities via searchAfter cursors - Use startPlugins.entityStore.createCRUDClient().listEntities() in the generate_leads route instead of EntityStoreDataClient.searchEntities() - Restore getStartServices parameter to generateLeadsRoute (needed for entityStore plugin access, not for inference/chatModel) Depends on PR elastic#258320 for CRUDClient.listEntities() method.
…ra/kibana into dashboard_align_attachment_to_api * 'dashboard_align_attachment_to_api' of github.com:mbondyra/kibana: (45 commits) [OTel Tracing] HTTP instrumentation (elastic#258663) Replace deprecated EUI icons in files owned by @elastic/ml-ui (elastic#255624) [Codeowners] add missing codeowners for security_solution_api_integration tests (elastic#259223) [CI] fix bad imports that came from a merge-race (elastic#259383) Add `.claude/worktrees/` to `.gitignore` (elastic#259192) Improve unknown-key validation error message in @kbn/config-schema (elastic#258633) [ML] Update Security ML jobs to use entity analytics fields for host and user fields (elastic#255339) [Table sweep] Update table columns responsiveness in Index Management and Dashboards (elastic#259340) skip failing test suite (elastic#258790) skip failing test suite (elastic#259261) chore: util to clean cached images (elastic#259335) [Entity Store] Use last_seen for automated resolution watermark (elastic#258574) [One Workflow] Fix flaky alert trigger Scout test by removing order-dependent assertions (elastic#259299) Skip serverless Discover request counts tests for MKI (elastic#259333) [Security Solution] render header title in new document flyout in Security Solution and Discover (elastic#258166) [Agent Builder] register inference endpoint feature (elastic#259259) [Agent Builder] Skills Command Menu - Add descriptions and scope options to agent (elastic#258964) [Streams][Streamlang][API] Fully use meta({id}) to reuse schema partials in OAS output (elastic#259275) fix(files_example): add tableCaption to EuiInMemoryTable for a11y (elastic#258289) [Entity Store] Adding list endpoint with query filter (elastic#258320) ...
Steps 2b + 2e from refactor prompt: - Replace entityStoreDataClient param with listEntities: () => Promise<LeadEntity[]> in RunPipelineParams (dependency injection pattern) - Wire startPlugins.entityStore.createCRUDClient() + fetchAllLeadEntities() in the task runner, removing the TODO skip - Add fetchAllLeadEntities paginated helper to entity_conversion.ts - Rewrite run_pipeline.test.ts to mock listEntities function Depends on PR elastic#258320 for CRUDClient.listEntities() method.
# Summary This PR introduces a LIST endpoint in the entity store, filterable via query param # How to test 1. Seed some data into the store. The easiest way is via [security-document-generator](https://github.com/elastic/security-documents-generator). 2. Test the endpoint with curl ### List all entities (no filter) ```bash curl -s -u elastic:changeme \ -H "kbn-xsrf: true" \ -H "x-elastic-internal-origin: kibana" \ -H "elastic-api-version: 2" \ "http://localhost:5601/internal/security/entity_store/entities" | jq ``` Expected: `{ "entities": [ ... ] }` containing seeded entities. ### List with a DSL filter ```bash curl -s -u elastic:changeme \ -H "kbn-xsrf: true" \ -H "x-elastic-internal-origin: kibana" \ -H "elastic-api-version: 2" \ --get \ --data-urlencode 'filter={"term":{"entity.type":"host"}}' \ "http://localhost:5601/internal/security/entity_store/entities" | jq ``` Expected: only hosts entities are returned. --- ### Invalid filter (should return 400) ```bash curl -s -u elastic:changeme \ -H "kbn-xsrf: true" \ -H "x-elastic-internal-origin: kibana" \ -H "elastic-api-version: 2" \ "http://localhost:5601/internal/security/entity_store/entities?filter=not-json" | jq ``` Expected: `400 Bad Request` with `"Invalid filter: must be a valid JSON-encoded DSL query"`.
Summary
This PR introduces a LIST endpoint in the entity store, filterable via query param
How to test
Seed some data into the store. The easiest way is via security-document-generator.
Test the endpoint with curl
List all entities (no filter)
Expected:
{ "entities": [ ... ] }containing seeded entities.List with a DSL filter
Expected: only hosts entities are returned.
Invalid filter (should return 400)
Expected:
400 Bad Requestwith"Invalid filter: must be a valid JSON-encoded DSL query".