-
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][Endpoint] Upload response action create API #156303
[Security Solution][Endpoint] Upload response action create API #156303
Conversation
…d-response-action-api
…tion-api' into task/olm-5369-upload-response-action-api
…d-response-action-api # Conflicts: # x-pack/plugins/security_solution/tsconfig.json
Pinging @elastic/security-defend-workflows (Team:Defend Workflows) |
…d-response-action-api # Conflicts: # x-pack/plugins/security_solution/server/endpoint/services/actions/create/index.ts
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.
Rules Area changes LGTM
💚 Build Succeeded
Metrics [docs]Async chunks
Page load bundle
Unknown metric groupsESLint disabled line counts
Total ESLint disabled count
History
To update your PR or re-run it, just comment 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.
LGTM, left a few questions 👍
@@ -56,7 +57,9 @@ export const createFileMock = (): DeeplyMockedKeys<File> => { | |||
share: jest.fn(), | |||
listShares: jest.fn(), | |||
unshare: jest.fn(), | |||
toJSON: jest.fn(), | |||
toJSON: jest.fn(() => { | |||
return clone(fileMock.data); |
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.
Just out of curiosity: why clone?
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 used clone()
so that the data being return by this mock is not a reference to the data stored in the instance. Thus, the data returned can be Mutated (in a tests) without impacting the state of the File
class instance
@@ -239,6 +241,24 @@ export class EndpointActionGenerator extends BaseDataGenerator { | |||
} | |||
} | |||
|
|||
if (command === 'upload') { |
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.
Why don't you prepare an enum with all command names?
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.
Don't really like using Enums
from TS. They are a bit strange to use and I often find my self casting the type of a string
to match the Enum
definition when attempting to look up a value in the Enum
if (command === 'upload') { | ||
if (!details.parameters) { | ||
( | ||
details as ActionDetails< |
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.
Do we need the cast?
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.
Yes because in order to set the parameters below, the ActionDetails
must be an upload
action details, so the cast here using the output content and parameters type does that.
}); | ||
|
||
it('should NOT register route if feature flag is false', () => { | ||
// @ts-expect-error |
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.
any specific error here?
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, assignment to a Readonly property. I'll have to adjust the test render mock at some point to perhaps not set these to readonly
so that we don't have to do this.
await file.update({ | ||
meta: { | ||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion | ||
...file.data.meta!, |
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.
can we get rid of the bang somehow?
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.
Let me see in the next PR is I can somehow narrow the type. The issue here is that meta
is optional in the Files
plugin interface, but required in our use case. Will look into it.
@@ -77,10 +78,13 @@ export const actionCreateService = ( | |||
return createAction({ ...payload }, { minimumLicenseRequired: 'enterprise' }); | |||
}; | |||
|
|||
const createAction = async ( | |||
const createAction = async < | |||
TOutputContent extends object = 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.
TILT: Could you explain the syntax? what is this = object? A default type if the type was not provided or anything else? Thanks!
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.
Yes, exactly. This is the definition of a generic where they generic types have default values, thus you are not required to set them if attempting to use the method, but could be set if you want to narrow down the ActionDetails
type that is returned.
More about generics here.
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.
LGTM, left a few questions 👍
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've a few nits and questions, but otherwise it is looking good to 🚢
fileStream = createHapiReadableStreamMock(); | ||
}); | ||
|
||
it('should not error if `override` parameter is not defined', () => { |
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.
nit: overwrite
parameter
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.
Will correct in next PR. 👍
}).not.toThrow(); | ||
}); | ||
|
||
it('should allow `override` parameter', () => { |
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.
nit: overwrite
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 here. Thanks for catching this
UploadActionRequestSchema.body.validate({ | ||
endpoint_ids: ['endpoint_id'], | ||
parameters: { | ||
override: true, |
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.
override: true, | |
overwrite: true, |
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.
😱
Good catch. this was actually probably throw
'ing an incorrect error for what the test is attempting to validate. Will correct it in next PR.
...BaseActionRequestSchema, | ||
|
||
parameters: schema.object({ | ||
overwrite: schema.maybe(schema.boolean()), |
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.
There should be a default value of false
for overwrite
here. No?
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.
Good point. I can set it a default in next PR
@@ -74,6 +77,7 @@ export const commandToRBACMap: Record<ConsoleResponseActionCommands, ResponseCon | |||
processes: 'writeProcessOperations', | |||
'get-file': 'writeFileOperations', | |||
execute: 'writeExecuteOperations', | |||
upload: 'writeFileOperations', |
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.
Maybe this should be right after get-file
just so that all writeFileOperations
are bunched together.
* NOTE: Most of the parameters below are NOT accepted via the API. They are inserted into | ||
* the action's parameters via the API route handler | ||
*/ |
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.
🔥
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.
Should we also mention in the note above, which parameters are provided in the API?
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 it is necessary. One can just go look at the API parameters type/schema
|
||
uploadParameters.file.file_id = createdFile.file.id; | ||
uploadParameters.file.file_name = createdFile.file.name; | ||
uploadParameters.file.sha256 = createdFile.file.hash?.sha256; |
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.
uploadParameters.file.sha256 = createdFile.file.hash?.sha256; | |
uploadParameters.file.sha256 = createdFile.file.hash.sha256; |
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.
file.hash
is an optional attribute.
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 I see. I saw it typed as a required string
in the PR so I suggested the change.
{ casesClient } | ||
); | ||
|
||
await setFileActionId(esClient, logger, data); |
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.
Q: What happens if the setFileActionId
fails?
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.
Then we fail the API request. But - thats a good point that I will need to think through. At this point in the code, a failure is unlikely, but perhaps if it happens to fail here, we just catch it and log it, but allow the api call to succeed, since the action has already been "sent" to the Endpoint. Failing here as is right now will cause the file to be deleted (in the catch()
below)` which would in turn cause the endpoint to fail to down the file.
Good catch @ashokaditya . Will correct it in next PR.
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 for the explanation. Sounds good with later updates. 🚀
This was reverted with c75d1c5 due to a type failure - https://buildkite.com/elastic/kibana-on-merge/builds/30174#018800e0-d266-4ec4-ac05-cd972bfb9e12/229-232 |
…create API (elastic#156303)"" This reverts commit c75d1c5.
Trying again: 🤞 |
commit c899f1d Author: Paul Tavares <paul.tavares@elastic.co> Date: Tue May 9 17:30:04 2023 -0400 Fix execute mapped authz property commit 4c460c5 Author: Paul Tavares <paul.tavares@elastic.co> Date: Tue May 9 16:07:39 2023 -0400 fix sending `undefined` for `comment` commit 02f9d07 Author: Paul Tavares <paul.tavares@elastic.co> Date: Tue May 9 11:47:03 2023 -0400 Upload API: log failure to file's action ID and still allow API response to return success commit 5d6990c Author: Paul Tavares <paul.tavares@elastic.co> Date: Tue May 9 11:40:44 2023 -0400 add default value to `overwrite` param of upload command (feedback from PR elastic#156303) commit a44b08b Author: Paul Tavares <paul.tavares@elastic.co> Date: Tue May 9 11:39:33 2023 -0400 fix tests (feedback from PR elastic#156303) commit c221c56 Author: Paul Tavares <paul.tavares@elastic.co> Date: Tue May 9 10:02:42 2023 -0400 tests for upload result component commit 955c706 Author: Paul Tavares <paul.tavares@elastic.co> Date: Mon May 8 17:44:33 2023 -0400 tests for upload action handler component commit f5a0bae Author: Paul Tavares <paul.tavares@elastic.co> Date: Mon May 8 15:37:55 2023 -0400 tests for argument `mustHaveValue` validators commit b9d9525 Author: Paul Tavares <paul.tavares@elastic.co> Date: Mon May 8 09:43:31 2023 -0400 test scaffold for `mustHaveValue` console argument value validators commit e6df2cf Author: Paul Tavares <paul.tavares@elastic.co> Date: Fri May 5 17:01:54 2023 -0400 fix type error commit fb574e1 Author: Paul Tavares <paul.tavares@elastic.co> Date: Fri May 5 16:46:53 2023 -0400 Support upload output for actions sent to multiple agents commit d578647 Author: Paul Tavares <paul.tavares@elastic.co> Date: Fri May 5 16:45:38 2023 -0400 Fix style in Console to ensure that whitespace is preserved commit 9c436d2 Author: Paul Tavares <paul.tavares@elastic.co> Date: Fri May 5 13:44:32 2023 -0400 add command `upload` result to the UI commit 2f9c07f Author: Paul Tavares <paul.tavares@elastic.co> Date: Fri May 5 13:42:48 2023 -0400 Added `upload` output data to endpint generator when generating repsonse commit ca6596a Author: Paul Tavares <paul.tavares@elastic.co> Date: Fri May 5 10:40:20 2023 -0400 Add `truthy` validation to the `file` argument commit 0f43c54 Author: Paul Tavares <paul.tavares@elastic.co> Date: Fri May 5 10:31:00 2023 -0400 Console: add new `mustHaveValue` argument value validation of `truthy` commit 0044d5c Author: Paul Tavares <paul.tavares@elastic.co> Date: Fri May 5 09:51:58 2023 -0400 UI: hook to build and send request + command sends action to server commit ee91d9d Author: Paul Tavares <paul.tavares@elastic.co> Date: Thu May 4 17:42:39 2023 -0400 Add `upload` command to list of console commands commit d8adbf1 Author: Paul Tavares <paul.tavares@elastic.co> Date: Thu May 4 16:55:52 2023 -0400 Removed `commandToCapabilitiesPrivilegesMap` and started using const's
Summary
upload
response action request. API route mounted at:/api/endpoint/action/upload
maxUploadResponseActionFileBytes
- that controls how large uploaded files can be. Defaults to 25MB. Max is 100MBupload
response action:responseActionUploadEnabled
. Must be set totrue
in kibana yaml in order to access this new APIAPI Request body (MUST BE SENT AS
multipart/form-data
). JSON representation of it below:File Created (in
.fleet-files-endpoint
index)Checklist