-
Notifications
You must be signed in to change notification settings - Fork 8.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Security Solution] Use safe type in resolver backend #76969
[Security Solution] Use safe type in resolver backend #76969
Conversation
@@ -46,12 +46,12 @@ export function values<T>(valueOrCollection: ECSField<T>): T[] { | |||
if (Array.isArray(valueOrCollection)) { | |||
const nonNullValues: T[] = []; | |||
for (const value of valueOrCollection) { | |||
if (value !== null) { | |||
if (value !== null && value !== undefined) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid having [undefined]
); | ||
} | ||
|
||
export function timestampSafeVersion(event: SafeResolverEvent): string | undefined | number { | ||
return isLegacyEventSafeVersion(event) | ||
? firstNonNullValue(event.endgame?.timestamp_utc) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't seem to find references to event.endgame.timestamp_utc
in the endgame test data we have in es archiver or the endgame schema. evrelay
populates @timestamp
, so I think it'd be simpler to keep these consistent between the legacy events and endpoint events. If we end up needing to use event.created
we can create a new function to retrieve that and do the legacy check there.
@@ -75,11 +67,7 @@ export function timestampAsDateSafeVersion(event: SafeResolverEvent): Date | und | |||
} | |||
|
|||
export function eventTimestamp(event: ResolverEvent): string | undefined | number { | |||
if (isLegacyEvent(event)) { | |||
return event.endgame.timestamp_utc; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as above.
@@ -105,14 +93,7 @@ export function eventId(event: ResolverEvent): number | undefined | string { | |||
return event.event.id; | |||
} | |||
|
|||
export function eventSequence(event: ResolverEvent): number | undefined { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The backend was the only one using this function so I just removed it and switched the name of the safe version.
@@ -112,6 +112,27 @@ export interface ResolverChildNode extends ResolverLifecycleNode { | |||
nextChild?: string | null; | |||
} | |||
|
|||
/** |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now I'm duplicating all the types that are used between the frontend and backend. The backend uses the safe versions and the frontend will use the unsafe ones for now.
@@ -198,7 +281,7 @@ export interface SafeResolverRelatedEvents { | |||
*/ | |||
export interface ResolverRelatedAlerts { | |||
entityID: string; | |||
alerts: ResolverEvent[]; | |||
alerts: SafeResolverEvent[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The frontend isn't referencing the related alerts yet so switching it over to use the safe version.
executable: string; | ||
start: number; | ||
thread?: ThreadFields[]; | ||
export type AlertEvent = Partial<{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrapping everything in ECSField
and removing the duplication between this type and SafeEndpointEvent
since we'll just combine them
@@ -578,7 +642,7 @@ export type ResolverEvent = EndpointEvent | LegacyEndpointEvent; | |||
* All mappings in Elasticsearch support arrays. They can also return null values or be missing. For example, a `keyword` mapping could return `null` or `[null]` or `[]` or `'hi'`, or `['hi', 'there']`. We need to handle these cases in order to avoid throwing an error. | |||
* When dealing with an value that comes from ES, wrap the underlying type in `ECSField`. For example, if you have a `keyword` or `text` value coming from ES, cast it to `ECSField<string>`. | |||
*/ | |||
export type ECSField<T> = T | null | Array<T | null>; | |||
export type ECSField<T> = T | null | undefined | Array<T | null>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needed to add undefined
here even though ES won't ever return that. This avoids types errors that TS was giving me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. This is safe since we want to account for the case of missing fields.
@@ -212,6 +212,10 @@ Object { | |||
}, | |||
Object { | |||
"metadata": Object { | |||
"elapsedTime": Object { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These changed because the timestampSafeVersion
now retrieves the @timestamp
field on the legacy event type as well. Previously, we were the isometric code was receiving an empty string which resulted in null
be used for this field so it was excluded from the metadata.
Pinging @elastic/endpoint-data-visibility-team (Team:Endpoint Data Visibility) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great. Thank you so much.
My only request is to have any TODO
comments removed before merge. I only noticed one and I commented on it.
@@ -420,7 +434,7 @@ describe('data generator', () => { | |||
} | |||
} | |||
// The root node must be first in the array or this fails | |||
return tree[events[0].process.entity_id]; | |||
return tree[entityIDSafeVersion(events[0]) ?? '']; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think ''
would be correct here. Maybe this instead?
return tree[entityIDSafeVersion(events[0]) ?? '']; | |
const entityID = entityIDSafeVersion(events[0]) | |
if (entityID === undefined) { | |
// this should never happen. | |
throw new Error() | |
} | |
return tree[entityIDSafeVersion(events[0])]; |
Or this?
return tree[entityIDSafeVersion(events[0]) ?? '']; | |
return tree[entityIDSafeVersion(events[0])!]; |
I'm not that familiar with the code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah good point, I'll throw an error like you suggested 👍
|
||
describe('Generated documents', () => { | ||
let generator: EndpointDocGenerator; | ||
beforeEach(() => { | ||
generator = new EndpointDocGenerator('seed'); | ||
}); | ||
|
||
// TODO what should I do about the cast? We can create a new safe descriptive name but | ||
// the front end won't use that until the rest of it is converted |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cast is fine. This code doesn't belong in the model anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you remove this comment before merging? ty
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh oops, thanks for catching that.
@@ -578,7 +642,7 @@ export type ResolverEvent = EndpointEvent | LegacyEndpointEvent; | |||
* All mappings in Elasticsearch support arrays. They can also return null values or be missing. For example, a `keyword` mapping could return `null` or `[null]` or `[]` or `'hi'`, or `['hi', 'there']`. We need to handle these cases in order to avoid throwing an error. | |||
* When dealing with an value that comes from ES, wrap the underlying type in `ECSField`. For example, if you have a `keyword` or `text` value coming from ES, cast it to `ECSField<string>`. | |||
*/ | |||
export type ECSField<T> = T | null | Array<T | null>; | |||
export type ECSField<T> = T | null | undefined | Array<T | null>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. This is safe since we want to account for the case of missing fields.
@@ -40,7 +41,9 @@ describe('Resolver Data Middleware', () => { | |||
// Generate a 'tree' using the Resolver generator code. This structure isn't the same as what the API returns. | |||
const baseTree = generateBaseTree(); | |||
const tree = mockResolverTree({ | |||
events: baseTree.allEvents, | |||
// Casting here because the generator returns the SafeResolverEvent type which isn't yet compatible with |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 Created this issue to handle the front end side of things: https://github.com/elastic/security-team/issues/239
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh nice, thanks Mike!
@elasticmachine merge upstream |
💚 Build SucceededBuild metricsasync chunks size
History
To update your PR or re-run it, just comment with: |
* Moving generator to safe type version * Finished generator and alert * Gzipping again * Finishing type conversions for backend * Trying to cast front end tests back to unsafe type for now * Working reducer tests * Adding more comments and fixing alert type * Restoring resolver test data * Updating snapshot with timestamp info * Removing todo and fixing test Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
* Moving generator to safe type version * Finished generator and alert * Gzipping again * Finishing type conversions for backend * Trying to cast front end tests back to unsafe type for now * Working reducer tests * Adding more comments and fixing alert type * Restoring resolver test data * Updating snapshot with timestamp info * Removing todo and fixing test Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com> Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
…s-for-710 * 'master' of github.com:elastic/kibana: (65 commits) Separate url forwarding logic and legacy services (elastic#76892) Bump yargs-parser to v13.1.2+ (elastic#77009) [Ingest Manager] Shared Fleet agent policy action (elastic#76013) [Search] Re-add support for aborting when a connection is closed (elastic#76470) [Search] Remove long-running query pop-up (elastic#75385) [Monitoring] Fix UI error when alerting is not available (elastic#77179) do not log plugin id format warning in dist mode (elastic#77134) [ML] Improving client side error handling (elastic#76743) [Alerting][Connectors] Refactor IBM Resilient: Generic Implementation (phase one) (elastic#74357) [Docs] some basic searchsource api docs (elastic#77038) add cGroupOverrides to the legacy config (elastic#77180) Change saved object bulkUpdate to work across multiple namespaces (elastic#75478) [Security Solution][Resolver] Replace Selectable popover with badges (elastic#76997) Removing ml-state index from archive (elastic#77143) [Security Solution] Add unit tests for histograms (elastic#77081) [Lens] Filters aggregation (elastic#75635) [Enterprise Search] Update WS Overview logic to use new config data (elastic#77122) Cleanup type output before building new types (elastic#77211) [Security Solution] Use safe type in resolver backend (elastic#76969) Use proper lodash syntax (elastic#77105) ... # Conflicts: # x-pack/plugins/index_lifecycle_management/public/application/sections/edit_policy/components/node_allocation.tsx
This PR refactors the backend to use the
SafeResolverEvent
type to enforce checking for arrays and single values in ECS fields.A couple places in front end tests had to be switched to casting the type back to
ResolverEvent
. This is because the resolver generator is now returning the safe type and the front end doesn't use it in all places yet. Once the front end is switched we can remove the casts.