-
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] add upload
console response action
#157208
[Security Solution][Endpoint] add upload
console response action
#157208
Conversation
…nse to return success
Pinging @elastic/security-defend-workflows (Team:Defend Workflows) |
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.
This is looking awesome. Thanks for all the changes that we talked about in the last PR. I mostly have nits and some questions.
I took it for a spin and I noticed three things:
- The history input with the up arrow key shows the file name that was used for upload but it doesn't actually take that file when I enter it from the history. It's empty. Either we should make that work or maybe show the history item with
--file=""
. See the clip. - Another thing I noticed is that for all commands or anything typed into the console input, I could do a "select all" (cmd + a) and hit delete/backspace and the text is deleted. This doesn't work for upload. Hitting delete/backspace when everything is selected only deletes the last character at the end. You can see this in the clip.
- I see a uploadAction log in the kibana console on every upload action execute when it goes through on the console . Not sure if this is just for testing. Might bloat the log for every
upload
action.
[2023-05-10T15:50:16.607+02:00][INFO ][plugins.securitySolution.uploadAction] {
"action": "create",
"outcome": "success"
}
/** Type used by the server's API for `upload` action */ | ||
export type UploadActionApiRequestBody = TypeOf<typeof UploadActionRequestSchema.body>; | ||
|
||
/** | ||
* Type used on the UI side. The `file` definition is different on the UI side, thus the | ||
* need for a separate type. | ||
*/ | ||
export type UploadActionUIRequestBody = Omit<UploadActionApiRequestBody, 'file'> & { | ||
file: File; | ||
}; |
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.
🔥
* maps the console command to the RBAC control (kibana feature control) that is required to access it via console | ||
*/ | ||
export const commandToRBACMap: Record<ConsoleResponseActionCommands, ResponseConsoleRbacControls> = | ||
Object.freeze({ | ||
isolate: 'writeHostIsolation', | ||
release: 'writeHostIsolation', | ||
'kill-process': 'writeProcessOperations', | ||
'suspend-process': 'writeProcessOperations', | ||
processes: 'writeProcessOperations', | ||
'get-file': 'writeFileOperations', | ||
execute: 'writeExecuteOperations', | ||
upload: 'writeFileOperations', | ||
}); | ||
export const RESPONSE_CONSOLE_ACTION_COMMANDS_TO_RBAC_FEATURE_CONTROL: Record< | ||
ConsoleResponseActionCommands, | ||
ResponseConsoleRbacControls | ||
> = Object.freeze({ | ||
isolate: 'writeHostIsolation', | ||
release: 'writeHostIsolation', | ||
'kill-process': 'writeProcessOperations', | ||
'suspend-process': 'writeProcessOperations', | ||
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.
🔥
export const CONSOLE_RESPONSE_ACTION_COMMANDS_TO_ENDPOINT_CAPABILITY = Object.freeze< | ||
Record<ConsoleResponseActionCommands, EndpointCapabilities> | ||
>({ | ||
isolate: 'isolation', | ||
release: 'isolation', | ||
execute: 'execute', | ||
'get-file': 'get_file', | ||
processes: 'running_processes', | ||
'kill-process': 'kill_process', | ||
'suspend-process': 'suspend_process', | ||
upload: 'upload_file', | ||
}); | ||
|
||
/** | ||
* The list of console commands mapped to the required EndpointAuthz to access that command | ||
*/ | ||
export const RESPONSE_CONSOLE_ACTION_COMMANDS_TO_REQUIRED_AUTHZ = Object.freeze< | ||
Record<ConsoleResponseActionCommands, EndpointAuthzKeyList[number]> | ||
>({ | ||
isolate: 'canIsolateHost', | ||
release: 'canUnIsolateHost', | ||
execute: 'canWriteExecuteOperations', | ||
'get-file': 'canWriteFileOperations', | ||
upload: 'canWriteFileOperations', | ||
processes: 'canGetRunningProcesses', | ||
'kill-process': 'canKillProcess', | ||
'suspend-process': 'canSuspendProcess', | ||
}); |
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 adding these!
@@ -93,6 +97,35 @@ export const RESPONSE_ACTION_API_COMMANDS_TO_CONSOLE_COMMAND_MAP = Object.freeze | |||
upload: 'upload', | |||
}); | |||
|
|||
export const CONSOLE_RESPONSE_ACTION_COMMANDS_TO_ENDPOINT_CAPABILITY = Object.freeze< |
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: Consider naming this RESPONSE_CONSOLE_ACTION_COMMANDS_TO_ENDPOINT_CAPABILITY
so that we've consistent name prefix for these constants here.
'kill-process': 'canKillProcess', | ||
'suspend-process': 'canSuspendProcess', | ||
}); | ||
|
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.
We could combine all these into a single object perhaps. Easier to read values from just one variable then. Also unifies all these different values in a single place. What do you think?
Something like:
{
'isolate': {
authz: 'canIsolateHost',
capability: 'isolation',
rbac: 'writeHostIsolation',
},
...
'execute': {
authz: 'canExecuteFileOperations',
capability: 'execute',
rbac: 'executeFileOperations',
},
'get-file': {
authz: 'canWriteFileOperations'
capability: 'get-file'
rbac: '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.
yes, I been thinking about this as well. Having one unified deeply nested object and then derive the simple maps from it. something we can refactor in the future.
@@ -659,7 +659,7 @@ describe('actions schemas', () => { | |||
}).not.toThrow(); | |||
}); | |||
|
|||
it('should allow `override` parameter', () => { | |||
it('should allow `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.
Thanks for updating this.
uploadOutput = { | ||
type: 'json', | ||
content: { | ||
code: 'ra_upload_success', |
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 think this should be ra_upload_file-success
. Unless they are two different codes.
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.
ahhh.. Yes, it will likely be the value you stated. We're still waiting for the codes to be provided by the endpoint, but I'll update it.
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 the one that's a bit below in the code.
x-pack/plugins/security_solution/common/endpoint/data_generators/endpoint_action_generator.ts
Show resolved
Hide resolved
* - `truthy`: The argument must have a value and the values must be "truthy" | ||
* (no `null` or `undefined`). Note that `0` (zero) will be considered `truthy` |
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: Maybe simpler to say that the argument must have some primitive value other than null
or 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.
hmm.. not sure about that. How would boolean
false
or ''
(empty string). Will need to think about that a little 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.
What I understood from the comment is false
/''
are also truthy
same as 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.
hmmm. no, the implemenation looks like this:
if (typeof argValue !== 'number' && !argValue) {
So number
of 0
is truthy, but everything else is not. so false
, ''
would fail validation.
I might have perhaps been too explicit on this thruthy
validator. Maybe I should just remove the typeof argValue !== 'number
and just test that value evaluates to a boolean true?
if someone wants to ensure its not an empty string, then they could use mustHaveValue: 'non-empty-string'
. And if they want to ensure the number zero can be used, then they would set the mustHaveValue: 'number'
.
What do you think?
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 indeed. Yeah, that makes sense. Let's go with verifying that that it is in fact true
.
// Update the file meta to include the action id, and if any errors (unlikely), | ||
// then just log them and still allow api to return success since the action has | ||
// already been created and potentially dispatched to Endpoint. Action ID is not | ||
// need by the Endpoint or fleet-server's API, so no need to fail 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.
nit: // needed...
Thanks for the feedback @ashokaditya . I have made just about all of the suggestions you provided. Here are responses to your overall comments: ➡️ re:
This is by design. The only thing we can show in the Unfortunately (but in the larger picture - fortunately) we can not select files from a user's system programatically. A user has to explicitly do it through he browser's file picking functionality, so we cant just re-select the file when we populate the command to the input area. ➡️ re:
This is in fact a current limitation in the console when using argument value selector components (like the file picker). See the description of this PR for more on that: #148693 ➡️ re:
This is being done by the |
💛 Build succeeded, but was flaky
Failed CI StepsTest Failures
Metrics [docs]Module Count
Async chunks
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.
Awesome stuff here. LGTM! 🔥
Summary
upload
response action to the endpoint consoleNOTE:
xpack.securitySolution.enableExperimental.responseActionUploadEnabled: true
upload
. In order to test this locally, run the endpoint agent emulator dev. tool:Checklist