Skip to content
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

[EDR Workflows] Add RunScript CS Command - UI #202012

Merged
merged 46 commits into from
Dec 10, 2024
Merged
Show file tree
Hide file tree
Changes from 39 commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
01e79af
add console command
tomsonpl Nov 27, 2024
ac4fdec
fix
tomsonpl Nov 28, 2024
61743fc
remove new lines
tomsonpl Nov 28, 2024
bf9766d
fix
tomsonpl Nov 28, 2024
0acea0f
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Nov 28, 2024
067fb0c
fix test
tomsonpl Nov 28, 2024
61623bd
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Nov 28, 2024
ecf0773
fix tests
tomsonpl Nov 28, 2024
d833f7f
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Nov 28, 2024
9c31946
fix tests
tomsonpl Nov 29, 2024
d3a5ce4
Merge remote-tracking branch 'origin/runscript-cs-input' into runscri…
tomsonpl Nov 29, 2024
992699b
Merge branch 'main' into runscript-cs-input
tomsonpl Nov 29, 2024
500697d
Merge branch 'main' into runscript-cs-input
tomsonpl Nov 29, 2024
de6feec
fix test
tomsonpl Nov 29, 2024
7da7d70
Merge remote-tracking branch 'origin/runscript-cs-input' into runscri…
tomsonpl Nov 29, 2024
9a8537d
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Nov 29, 2024
18402f6
fix test
tomsonpl Nov 30, 2024
d2ddf72
Merge remote-tracking branch 'origin/runscript-cs-input' into runscri…
tomsonpl Nov 30, 2024
80f7be2
Merge branch 'main' into runscript-cs-input
tomsonpl Dec 2, 2024
48acdd7
fix i18n
tomsonpl Dec 2, 2024
cb9275c
Merge remote-tracking branch 'origin/runscript-cs-input' into runscri…
tomsonpl Dec 2, 2024
a5f9605
revert testing list
tomsonpl Dec 2, 2024
2647466
[CI] Auto-commit changed files from 'node scripts/eslint --no-cache -…
kibanamachine Dec 2, 2024
6a0648d
fix
tomsonpl Dec 3, 2024
cdbc6d9
Merge remote-tracking branch 'origin/runscript-cs-input' into runscri…
tomsonpl Dec 3, 2024
221bc77
fix
tomsonpl Dec 3, 2024
c743d45
fix
tomsonpl Dec 3, 2024
adeb2f4
fix
tomsonpl Dec 3, 2024
5519a47
fix
tomsonpl Dec 3, 2024
f1293fb
fix
tomsonpl Dec 3, 2024
8302bc9
Merge branch 'main' into runscript-cs-input
tomsonpl Dec 4, 2024
da1a2f8
change help example
tomsonpl Dec 5, 2024
3822bf5
Merge remote-tracking branch 'origin/runscript-cs-input' into runscri…
tomsonpl Dec 5, 2024
0075942
remove reduntant text
tomsonpl Dec 5, 2024
65cbd2c
Merge branch 'main' into runscript-cs-input
tomsonpl Dec 5, 2024
e0c9c44
add ra codes for runscript
tomsonpl Dec 6, 2024
e2c15b8
Merge branch 'main' into runscript-cs-input
tomsonpl Dec 9, 2024
c2c4456
revert
tomsonpl Dec 9, 2024
aed126a
Merge remote-tracking branch 'origin/runscript-cs-input' into runscri…
tomsonpl Dec 9, 2024
924ab36
fix
tomsonpl Dec 9, 2024
f3e1220
update help text
tomsonpl Dec 9, 2024
c785860
fix tests
tomsonpl Dec 9, 2024
aa60ebc
Update x-pack/plugins/security_solution/public/management/components/…
tomsonpl Dec 9, 2024
5ab705f
add note
tomsonpl Dec 9, 2024
7f87374
Merge remote-tracking branch 'origin/runscript-cs-input' into runscri…
tomsonpl Dec 9, 2024
d3c067e
fix
tomsonpl Dec 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ export const GET_FILE_ROUTE = `${BASE_ENDPOINT_ACTION_ROUTE}/get_file`;
export const EXECUTE_ROUTE = `${BASE_ENDPOINT_ACTION_ROUTE}/execute`;
export const UPLOAD_ROUTE = `${BASE_ENDPOINT_ACTION_ROUTE}/upload`;
export const SCAN_ROUTE = `${BASE_ENDPOINT_ACTION_ROUTE}/scan`;
export const RUN_SCRIPT_ROUTE = `${BASE_ENDPOINT_ACTION_ROUTE}/run_script`;

/** Endpoint Actions Routes */
export const ENDPOINT_ACTION_LOG_ROUTE = `${BASE_ENDPOINT_ROUTE}/action_log/{agent_id}`;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,17 @@ export class EndpointActionGenerator extends BaseDataGenerator {
}
}

if (command === 'runscript') {
if (!output) {
output = {
type: 'json',
content: {
code: 'ra_runscript_success_done',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you also have a list of error codes? Then you should add those below in a function as well.
randomRunscriptFailureCode()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't have a list unfortunately, I noted a few codes though so when I conitnue working on CrowdStrike connector and results - I'll adjust the CS errors list 👍

},
};
}
}

if (command === 'execute') {
if (!output) {
output = this.generateExecuteActionResponseOutput();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const RESPONSE_ACTION_API_COMMANDS_NAMES = [
'execute',
'upload',
'scan',
'runscript',
] as const;

export type ResponseActionsApiCommandNames = (typeof RESPONSE_ACTION_API_COMMANDS_NAMES)[number];
Expand All @@ -54,6 +55,7 @@ export const ENDPOINT_CAPABILITIES = [
'execute',
'upload_file',
'scan',
'runscript',
] as const;

export type EndpointCapabilities = (typeof ENDPOINT_CAPABILITIES)[number];
Expand All @@ -72,6 +74,7 @@ export const CONSOLE_RESPONSE_ACTION_COMMANDS = [
'execute',
'upload',
'scan',
'runscript',
] as const;

export type ConsoleResponseActionCommands = (typeof CONSOLE_RESPONSE_ACTION_COMMANDS)[number];
Expand Down Expand Up @@ -100,6 +103,7 @@ export const RESPONSE_CONSOLE_ACTION_COMMANDS_TO_RBAC_FEATURE_CONTROL: Record<
execute: 'writeExecuteOperations',
upload: 'writeFileOperations',
scan: 'writeScanOperations',
runscript: 'writeExecuteOperations',
});

export const RESPONSE_ACTION_API_COMMAND_TO_CONSOLE_COMMAND_MAP = Object.freeze<
Expand All @@ -114,6 +118,7 @@ export const RESPONSE_ACTION_API_COMMAND_TO_CONSOLE_COMMAND_MAP = Object.freeze<
'suspend-process': 'suspend-process',
upload: 'upload',
scan: 'scan',
runscript: 'runscript',
});

export const RESPONSE_CONSOLE_COMMAND_TO_API_COMMAND_MAP = Object.freeze<
Expand All @@ -128,6 +133,7 @@ export const RESPONSE_CONSOLE_COMMAND_TO_API_COMMAND_MAP = Object.freeze<
'suspend-process': 'suspend-process',
upload: 'upload',
scan: 'scan',
runscript: 'runscript',
});

export const RESPONSE_CONSOLE_ACTION_COMMANDS_TO_ENDPOINT_CAPABILITY = Object.freeze<
Expand All @@ -142,6 +148,7 @@ export const RESPONSE_CONSOLE_ACTION_COMMANDS_TO_ENDPOINT_CAPABILITY = Object.fr
'suspend-process': 'suspend_process',
upload: 'upload_file',
scan: 'scan',
runscript: 'runscript',
});

/**
Expand All @@ -159,6 +166,7 @@ export const RESPONSE_CONSOLE_ACTION_COMMANDS_TO_REQUIRED_AUTHZ = Object.freeze<
'kill-process': 'canKillProcess',
'suspend-process': 'canSuspendProcess',
scan: 'canWriteScanOperations',
runscript: 'canWriteExecuteOperations',
});

// 4 hrs in seconds
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,18 @@ const RESPONSE_ACTIONS_SUPPORT_MAP: SupportMap = {
crowdstrike: false,
},
},
runscript: {
automated: {
endpoint: false,
sentinel_one: false,
crowdstrike: false,
},
manual: {
endpoint: false,
sentinel_one: false,
crowdstrike: true,
},
},
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,12 @@ export const allowedExperimentalValues = Object.freeze({
* Enables the Defend Insights feature
*/
defendInsights: false,

/**
* Enables CrowdStrike's RunScript RTR command
*/

crowdstrikeRunScriptEnabled: false,
});

type ExperimentalConfigKeys = Array<keyof ExperimentalFeatures>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,66 @@ export const CONSOLE_COMMANDS = {
},
};

export const CROWDSTRIKE_CONSOLE_COMMANDS = {
runscript: {
args: {
raw: {
about: i18n.translate(
'xpack.securitySolution.crowdStrikeConsoleCommands.runscript.args.raw.about',
{
defaultMessage: 'Raw script content',
}
),
},
cloudFile: {
about: i18n.translate(
'xpack.securitySolution.crowdStrikeConsoleCommands.runscript.args.cloudFile.about',
{
defaultMessage: 'Script name in cloud storage',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Should be file name I think? Unless script name and file name are the same?

Suggested change
defaultMessage: 'Script name in cloud storage',
defaultMessage: 'Script file name in cloud storage',

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. So scripts are on the Cloud, files are on a host. Again I copied this over from CrowdStrike console. But I am happy to adjust if you prefer

}
),
},
commandLine: {
about: i18n.translate(
'xpack.securitySolution.crowdStrikeConsoleCommands.runscript.args.commandLine.about',
{
defaultMessage: 'Command line arguments',
}
),
},
hostPath: {
about: i18n.translate(
'xpack.securitySolution.crowdStrikeConsoleCommands.runscript.args.hostPath.about',
{
defaultMessage: 'Absolute or relative path of script on host machine',
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
defaultMessage: 'Absolute or relative path of script on host machine',
defaultMessage: 'Absolute or relative path of script file on host machine',

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was taken 1:1 from CrowdStrike console - although I am ok with adjusting if you prefer

}
),
},
timeout: {
about: i18n.translate(
'xpack.securitySolution.crowdStrikeConsoleCommands.runscript.args.timeout.about',
{
defaultMessage: 'Timeout in seconds',
}
),
},
},
title: i18n.translate('xpack.securitySolution.crowdStrikeConsoleCommands.runscript.title', {
defaultMessage: 'Isolate',
}),
about: i18n.translate('xpack.securitySolution.crowdStrikeConsoleCommands.runscript.about', {
defaultMessage: 'Run a script on the host',
}),
privileges: i18n.translate(
'xpack.securitySolution.crowdStrikeConsoleCommands.runscript.privileges',
{
defaultMessage:
'Insufficient privileges to run script. Contact your Kibana administrator if you think you should have this permission.',
}
),
},
};

export const CONFIRM_WARNING_MODAL_LABELS = (entryType: string) => {
return {
title: i18n.translate('xpack.securitySolution.artifacts.confirmWarningModal.title', {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ export const CommandInputUsage = memo<Pick<CommandUsageProps, 'commandDef'>>(({
});
}, [commandDef]);

const helpExample = useMemo(() => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did we need to add a helpUsage property if exampleUsage already existed? Is it because you wanted to have the input hint be different from what --help displays?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that was the reason 👍

if (commandDef.helpUsage) {
return commandDef.helpUsage;
}
return commandDef.exampleUsage;
}, [commandDef]);

return (
<>
<EuiDescriptionList
Expand All @@ -55,7 +62,7 @@ export const CommandInputUsage = memo<Pick<CommandUsageProps, 'commandDef'>>(({
titleProps={additionalProps}
/>
<EuiSpacer size="s" />
{commandDef.exampleUsage && (
{helpExample && (
<EuiDescriptionList
compressed
type="column"
Expand All @@ -69,7 +76,7 @@ export const CommandInputUsage = memo<Pick<CommandUsageProps, 'commandDef'>>(({
})}
</ConsoleCodeBlock>
),
description: <ConsoleCodeBlock>{commandDef.exampleUsage}</ConsoleCodeBlock>,
description: <ConsoleCodeBlock>{helpExample}</ConsoleCodeBlock>,
},
]}
descriptionProps={additionalProps}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,13 @@ export interface CommandDefinition<TMeta = any> {
*/
exampleUsage?: string;

/**
* Displayed in the output of this command's `--help`.
* This value will override the command usage generated by the console
* from the Command Definition.
*/
helpUsage?: string;
paul-tavares marked this conversation as resolved.
Show resolved Hide resolved

/**
* Validate the command entered by the user. This is called only after the Console has ran
* through all of its builtin validations (based on `CommandDefinition`).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import {
import { getCommandAboutInfo } from './get_command_about_info';

import { validateUnitOfTime } from './utils';
import { CONSOLE_COMMANDS } from '../../../common/translations';
import { CONSOLE_COMMANDS, CROWDSTRIKE_CONSOLE_COMMANDS } from '../../../common/translations';
import { ScanActionResult } from '../command_render_components/scan_action';

const emptyArgumentValidator = (argData: ParsedArgData): true | string => {
Expand Down Expand Up @@ -167,6 +167,7 @@ export const getEndpointConsoleCommands = ({
const featureFlags = ExperimentalFeaturesService.get();

const isUploadEnabled = featureFlags.responseActionUploadEnabled;
const crowdstrikeRunScriptEnabled = featureFlags.crowdstrikeRunScriptEnabled;

const doesEndpointSupportCommand = (commandName: ConsoleResponseActionCommands) => {
// Agent capabilities is only validated for Endpoint agent types
Expand Down Expand Up @@ -523,6 +524,75 @@ export const getEndpointConsoleCommands = ({
privileges: endpointPrivileges,
}),
});
if (crowdstrikeRunScriptEnabled) {
consoleCommands.push({
name: 'runscript',
about: getCommandAboutInfo({
aboutInfo: CROWDSTRIKE_CONSOLE_COMMANDS.runscript.about,
isSupported: doesEndpointSupportCommand('runscript'),
}),
RenderComponent: () => null,
meta: {
agentType,
endpointId: endpointAgentId,
capabilities: endpointCapabilities,
privileges: endpointPrivileges,
},
exampleUsage: `runscript -Raw=\`\`\`Get-ChildItem .\`\`\` -CommandLine=""`,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not seem correct.

  1. you seem to be using single - instead of double --
  2. Why is the example using back-tick (`) ? The helpUsage below shows the examples enclosed in double quotes image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Changing - into -- thanks!
  2. I'd say it could support both, or even more: runscript --Raw=ls | runscript --Raw="ls" | runscript --Raw='ls' | 'runscript --Raw=ls'

helpUsage: `runscript -CloudFile="CloudScript1.ps1" -CommandLine="-Verbose true"
Run a script saved to the CrowdStrike cloud with the specified command line arguments
runscript -CloudFile="CloudScript1.ps1" -CommandLine="-Verbose true" -Timeout=180
Run a script saved to the CrowdStrike cloud with the specified command line arguments and 180 seconds timeout
runscript -Raw=\`\`\`Get-ChildItem .\`\`\` -CommandLine=""
Run a raw script whose entire contents are provided in the "-Raw=" flag
runscript -HostPath="C:\\temp\\LocalScript.ps1" -CommandLine="-Verbose true"
Run a script from a path on the remote host with the specified command line arguments`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the screenshot, I notice the first line is indented separately from the rest of the lines.
Screenshot 2024-12-09 at 13 52 12

Also, I feel the set of example help text here is a bit too dense to read on the screen. Consider visually separating the help title/text from the actual example command. Why not have the help description on top of the help syntax?

Something like
-- Run a script saved to the CrowdStrike cloud with the specified command line arguments
runscript -CloudFile="CloudScript1.ps1" -CommandLine="-Verbose true"

--Run a script saved to the CrowdStrike cloud with the specified command line arguments and 180 seconds timeout
runscript -CloudFile="CloudScript1.ps1" -CommandLine="-Verbose true" -Timeout=180
...
...
etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied some changes - hope it looks better :) I might create a component to render it nicer but I'd prefer to do it at the later stage if we still have time before 8.18 👍

exampleInstruction: CROWDSTRIKE_CONSOLE_COMMANDS.runscript.about,
validate: capabilitiesAndPrivilegesValidator(agentType),
mustHaveArgs: true,
args: {
Raw: {
required: false,
allowMultiples: false,
about: CROWDSTRIKE_CONSOLE_COMMANDS.runscript.args.raw.about,
mustHaveValue: 'non-empty-string',
},
CloudFile: {
required: false,
allowMultiples: false,
about: CROWDSTRIKE_CONSOLE_COMMANDS.runscript.args.cloudFile.about,
mustHaveValue: 'non-empty-string',
},
CommandLine: {
required: false,
allowMultiples: false,
about: CROWDSTRIKE_CONSOLE_COMMANDS.runscript.args.commandLine.about,
mustHaveValue: 'non-empty-string',
},
HostPath: {
required: false,
allowMultiples: false,
about: CROWDSTRIKE_CONSOLE_COMMANDS.runscript.args.hostPath.about,
mustHaveValue: 'non-empty-string',
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought you said that 1 of these tree needed to be used... so should have the exclusiveOr property set to true, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit tricky, since CrowdStrike lets you add multiple of these arguments, and then the strange behavior I explained during the meeting happened. But I agree with you that our approach would be to use exclusiveOr and just let them use one at a time.
Added exclusiveOr 👍 Thank you, I also added a description to exclusiveOr type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok. Sorry about this - I do now remember that we discussed that they can use multiples, but at least one of them must be present. In that case, you are correct in that we can't use exclusiveOr because that limits the options for the user to having to only pick one.

The main issue I saw when testing this is that there was no validations in place. Realizing now that all three could be used, and that at least 1 must be defined, I think the perhaps the command should be setup as:

  • Remove exclusiveOr from the arguments
  • Set the command's mustHaveArgs to false
  • Add a command level validate callback and add the validation there (that at least one if being used)

Removing the mustHaveArgs (or setting it to false) will also address the visual issue where the help was showing runscript --

Timeout: {
required: false,
allowMultiples: false,
about: CROWDSTRIKE_CONSOLE_COMMANDS.runscript.args.timeout.about,
mustHaveValue: 'non-empty-string',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This setting's value (non-empty-string) correct ? I thought timeout was a number.

image

},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused on this setup for the arguments... Should at least one of these be required? if so, then all arguments configuration should have exclusiveOr: true set on them.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, I wasn't aware exclusiveOr:true existed - will adjust the code 👍 Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reading through the options again - can you detail in the issue what the input is to these arguments and how they should be used?

Example:

  • How will a user know what --CloudFile should be set to? Can this be "anything"? or does it have to match a file in the Crowdstrike system? if it has to match a file in the Crowdstrike system, do we have an API in crowdstrike that can pull that data in? because if so, then we should provide a better UI in the console for it (a popup to pick it)
  • Is CommandLine an argument that can be used with all other arguments (in combination with)? or is it only applicable to some (ex. maybe only applicable to CloudFile and HostPath?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, I understand this may be a bit unclear 👍

  • .--CloudFile you're absolutely right, there is a separate API to fetch the Cloud script details: example of usage was showed in the PoC. However, I've seen the Select component in the input that could be used for this too. But I believe it may be done as a last item on the list for runscript. For now - what the user need to know is the scripts name - probably they know it by heart by now anyway :P
Zrzut ekranu 2024-12-5 o 09 41 12
  • The --CommandLine parameter in the runscript command is used to provide arguments or parameters to the script being executed. Its functionality depends on how the script is being run (via -CloudFile, -HostPath, or -Raw):

runscript -CloudFile="example_script.ps1" -CommandLine="-param1 value1 -param2 value2"
runscript -HostPath="C:\Scripts\example_script.ps1" -CommandLine="-param1 value1"
runscript -Raw="param([string]$name) Write-Host \"Hello, $name\"" -CommandLine="John"

I'll put some info about it in the issue itself too as you suggested 👍

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also: I played with CS Console and it's possible to pass multiple arguments eg.
runscript --CloudFile='test1' --Raw='ls' --HostPath='test1' .
However no matter in which order I've put the commands -it always started with HostPath, then CloudFile and Raw as last - strange behavior.
Anyway - I think we should mark all the arguments as optional. It's how it's done in CrowdStrike, and if arguments are missing - API will return an error eg.
stderr:"runscript: Either -Raw or -HostPath must be specified\n"

What do you think?

...commandCommentArgument(),
},
helpGroupLabel: HELP_GROUPS.responseActions.label,
helpGroupPosition: HELP_GROUPS.responseActions.position,
helpCommandPosition: 9,
helpDisabled: !doesEndpointSupportCommand('runscript'),
helpHidden: !getRbacControl({
commandName: 'runscript',
privileges: endpointPrivileges,
}),
});
}

switch (agentType) {
case 'sentinel_one':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,13 @@ const CODES = Object.freeze({
'xpack.securitySolution.endpointActionResponseCodes.scan.success',
{ defaultMessage: 'Scan complete' }
),

// Dev:
// runscript success/competed
ra_runscript_success_done: i18n.translate(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should not be using these code for Crowdstrike. This are Elastic Defend specific and IMO should remain as such.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it to reflect the behavior in tests, but I am ok with removing it 👍

'xpack.securitySolution.endpointActionResponseCodes.runscript.success',
{ defaultMessage: 'Runscript complete' }
),
});

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,10 @@ describe('When displaying Endpoint Response Actions', () => {
HELP_GROUPS.responseActions.label
);

const expectedCommands: string[] = [...CONSOLE_RESPONSE_ACTION_COMMANDS];
const endpointCommands = CONSOLE_RESPONSE_ACTION_COMMANDS.filter(
(command) => command !== 'runscript'
);
const expectedCommands: string[] = [...endpointCommands];
// add status to the list of expected commands in that order
expectedCommands.splice(2, 0, 'status');

Expand Down Expand Up @@ -149,6 +152,7 @@ describe('When displaying Endpoint Response Actions', () => {
beforeEach(() => {
(ExperimentalFeaturesService.get as jest.Mock).mockReturnValue({
responseActionsCrowdstrikeManualHostIsolationEnabled: true,
crowdstrikeRunScriptEnabled: true,
});
commands = getEndpointConsoleCommands({
agentType: 'crowdstrike',
Expand Down Expand Up @@ -176,7 +180,7 @@ describe('When displaying Endpoint Response Actions', () => {
HELP_GROUPS.responseActions.label
);

expect(commandsInPanel).toEqual(['isolate', 'release']);
expect(commandsInPanel).toEqual(['isolate', 'release', 'runscript --']);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -1518,6 +1518,7 @@ describe('Response actions history', () => {
beforeEach(() => {
featureFlags = {
responseActionUploadEnabled: true,
crowdstrikeRunScriptEnabled: true,
};

mockedContext.setExperimentalFlag(featureFlags);
Expand All @@ -1544,9 +1545,9 @@ describe('Response actions history', () => {
await user.click(getByTestId(`${testPrefix}-${filterPrefix}-popoverButton`));
const filterList = getByTestId(`${testPrefix}-${filterPrefix}-popoverList`);
expect(filterList).toBeTruthy();
expect(getAllByTestId(`${filterPrefix}-option`).length).toEqual(
RESPONSE_ACTION_API_COMMANDS_NAMES.length
);
// TODO: RUNSCRIPT does not have a corresponding action in the API yet
const TEMPORARY_LENGTH = RESPONSE_ACTION_API_COMMANDS_NAMES.length - 1;
expect(getAllByTestId(`${filterPrefix}-option`).length).toEqual(TEMPORARY_LENGTH);
Copy link
Member

@ashokaditya ashokaditya Dec 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an issue with the EUI filter popover component. The popover list shows 9 items at a time on the default height. We need to collect the options using querySelectorAll or something like that. I think worth noting this glitch in a comment here 😓

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried adjusting according to your suggestions but nothing helped. I'd take a note though and try to address this in another PR if this is ok with you? :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok @ashokaditya showed me on zoom, that this was indeed the case. I was adjusting wrong components height 😅 Thanks!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found a workaround and sent you the diff.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied, thanks a lot 👍

expect(getAllByTestId(`${filterPrefix}-option`).map((option) => option.textContent)).toEqual([
'isolate. To check this option, press Enter.',
'release. To check this option, press Enter.',
Expand Down
Loading