Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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 @@ -10,10 +10,12 @@ import {
hasSimpleExecutableName,
OperatingSystem,
ConditionEntryField,
TrustedDeviceConditionEntryField,
validateWildcardInput,
validateHasWildcardWithWrongOperator,
validatePotentialWildcardInput,
validateFilePathInput,
isTrustedDeviceFieldAvailableForOs,
WILDCARD_WARNING,
FILEPATH_WARNING,
} from '.';
Expand Down Expand Up @@ -756,3 +758,86 @@ describe('hasSimpleExecutableName', () => {
).toEqual(false);
});
});

describe('isTrustedDeviceFieldAvailableForOs', () => {
describe('USERNAME field availability', () => {
it('should return true for USERNAME field when Windows OS is selected exclusively', () => {
expect(
isTrustedDeviceFieldAvailableForOs(TrustedDeviceConditionEntryField.USERNAME, [
OperatingSystem.WINDOWS,
])
).toBe(true);
});

it('should return false for USERNAME field when Mac OS is selected exclusively', () => {
expect(
isTrustedDeviceFieldAvailableForOs(TrustedDeviceConditionEntryField.USERNAME, [
OperatingSystem.MAC,
])
).toBe(false);
});

it('should return false for USERNAME field when both Windows and Mac OS are selected', () => {
expect(
isTrustedDeviceFieldAvailableForOs(TrustedDeviceConditionEntryField.USERNAME, [
OperatingSystem.WINDOWS,
OperatingSystem.MAC,
])
).toBe(false);
});

it('should return false for USERNAME field when Mac and Windows OS are selected (different order)', () => {
expect(
isTrustedDeviceFieldAvailableForOs(TrustedDeviceConditionEntryField.USERNAME, [
OperatingSystem.MAC,
OperatingSystem.WINDOWS,
])
).toBe(false);
});

it('should return false for USERNAME field when empty OS array is provided', () => {
expect(
isTrustedDeviceFieldAvailableForOs(TrustedDeviceConditionEntryField.USERNAME, [])
).toBe(false);
});
});

describe('Other fields availability', () => {
const commonFields = [
TrustedDeviceConditionEntryField.HOST,
TrustedDeviceConditionEntryField.DEVICE_ID,
TrustedDeviceConditionEntryField.MANUFACTURER,
TrustedDeviceConditionEntryField.PRODUCT_ID,
];

it.each(commonFields)(
'should return true for %s field when Windows OS is selected exclusively',
(field) => {
expect(isTrustedDeviceFieldAvailableForOs(field, [OperatingSystem.WINDOWS])).toBe(true);
}
);

it.each(commonFields)(
'should return true for %s field when Mac OS is selected exclusively',
(field) => {
expect(isTrustedDeviceFieldAvailableForOs(field, [OperatingSystem.MAC])).toBe(true);
}
);

it.each(commonFields)(
'should return true for %s field when both Windows and Mac OS are selected',
(field) => {
expect(
isTrustedDeviceFieldAvailableForOs(field, [OperatingSystem.WINDOWS, OperatingSystem.MAC])
).toBe(true);
}
);

it.each(commonFields)(
'should return true for %s field when empty OS array is provided',
(field) => {
expect(isTrustedDeviceFieldAvailableForOs(field, [])).toBe(true);
}
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,32 @@ export type EntryTypes = 'match' | 'wildcard' | 'match_any';
export type TrustedAppEntryTypes = Extract<EntryTypes, 'match' | 'wildcard'>;
export type EventFiltersTypes = EntryTypes | 'exists' | 'nested';

export const TRUSTED_DEVICE_OS_FIELD_AVAILABILITY = {
/** Fields available for all supported operating systems */
ALL_OS: [
TrustedDeviceConditionEntryField.HOST,
TrustedDeviceConditionEntryField.DEVICE_ID,
TrustedDeviceConditionEntryField.MANUFACTURER,
TrustedDeviceConditionEntryField.PRODUCT_ID,
] as const,

/** Fields available only for Windows OS exclusively */
WINDOWS_ONLY: [TrustedDeviceConditionEntryField.USERNAME] as const,
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Not used, added for clarity.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

i'd suggest to use it. it can be easily used in the function below in the same style as the ALL_OS array. therefore we would have a single source of truth, because now you need to modify the array in two places

} as const;

export function isTrustedDeviceFieldAvailableForOs(
field: TrustedDeviceConditionEntryField,
osTypes: readonly string[]
): boolean {
const { WINDOWS_ONLY, ALL_OS } = TRUSTED_DEVICE_OS_FIELD_AVAILABILITY;

if (WINDOWS_ONLY.includes(field as (typeof WINDOWS_ONLY)[number])) {
return osTypes.length === 1 && osTypes.includes(OperatingSystem.WINDOWS);
}

return ALL_OS.includes(field as (typeof ALL_OS)[number]);
}

export const validatePotentialWildcardInput = ({
field = '',
os,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -410,18 +410,22 @@ export class ExceptionsListItemGenerator extends BaseDataGenerator<ExceptionList
}

generateTrustedDevice(overrides: Partial<ExceptionListItemSchema> = {}): ExceptionListItemSchema {
// Use HOST field by default for compatibility with all OS types
// USERNAME field can only be used with Windows-only OS
const defaultEntries: ExceptionListItemSchema['entries'] = [
{
field: 'host.name',
operator: 'included' as const,
type: 'match' as const,
value: `host_${this.randomString(5)}`,
},
];

return this.generate({
name: `Trusted device (${this.randomString(5)})`,
list_id: ENDPOINT_ARTIFACT_LISTS.trustedDevices.id,
os_types: this.randomChoice([['windows'], ['macos'], ['windows', 'macos']]),
entries: [
{
field: 'user.name',
operator: 'included',
type: 'match',
value: `user_${this.randomString(5)}`,
},
],
entries: defaultEntries,
...overrides,
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,23 +72,23 @@ describe(
value: 'test-user',
},
],
os_types: ['windows', 'macos'],
os_types: ['windows'],
});

describe('Renders Trusted Devices form fields', () => {
it('Correctly renders trusted devices form for Windows and Mac', () => {
it('Correctly renders trusted devices form for Windows only with Username field', () => {
openTrustedDevices({ create: true });

selectOs('Windows and Mac');
selectOs('Windows');

selectField('Username');
selectOperator('is');
fillValue('test-user');
});

it('Renders all field options correctly', () => {
it('Renders all field options correctly for Windows only', () => {
openTrustedDevices({ create: true });
selectOs('Windows and Mac');
selectOs('Windows');

const fields: Array<'Username' | 'Host' | 'Device ID' | 'Manufacturer' | 'Product ID'> = [
'Username',
Expand All @@ -103,19 +103,39 @@ describe(
cy.getByTestSubj('trustedDevices-form-fieldSelect').should('contain', field);
});
});

it('Shows limited field options for Windows and Mac (no Username)', () => {
openTrustedDevices({ create: true });
selectOs('Windows and Mac');

cy.getByTestSubj('trustedDevices-form-fieldSelect').click();

const availableFields: Array<'Host' | 'Device ID' | 'Manufacturer' | 'Product ID'> = [
'Host',
'Device ID',
'Manufacturer',
'Product ID',
];

availableFields.forEach((field) => {
cy.get('[role="option"]').should('contain', field);
});

cy.get('[role="option"]').should('not.contain', 'Username');
});
});

describe('Handles CRUD with device fields', () => {
afterEach(() => {
removeExceptionsList(ENDPOINT_ARTIFACT_LISTS.trustedDevices.id);
});

it('Correctly creates a trusted device with a single username field on Windows and Mac', () => {
it('Correctly creates a trusted device with a single username field on Windows only', () => {
const expectedCondition = /user\.name\s*IS\s*test-user/i;

openTrustedDevices({ create: true });
fillOutTrustedDevicesFlyout();
selectOs('Windows and Mac');
selectOs('Windows');
selectField('Username');
selectOperator('is');
fillValue('test-user');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -541,18 +541,18 @@ export const getArtifactsListTestsData = (): ArtifactsFixtureType[] => [
},
{
type: 'click',
customSelector: '[role="option"]:contains("Username")',
customSelector: '[role="option"]:contains("Host")',
},
{
type: 'input',
selector: 'trustedDevices-form-valueField',
value: 'test-user',
value: 'test-host',
},
],
checkResults: [
{
selector: 'trustedDevicesList-card-criteriaConditions',
value: ' OSIS Windows, MacAND user.nameIS test-user',
value: ' OSIS Windows, MacAND host.nameIS test-host',
},
],
},
Expand Down Expand Up @@ -583,13 +583,13 @@ export const getArtifactsListTestsData = (): ArtifactsFixtureType[] => [
{
type: 'input',
selector: 'trustedDevices-form-valueField',
value: 'updated-user',
value: 'updated-host',
},
],
checkResults: [
{
selector: 'trustedDevicesList-card-criteriaConditions',
value: ' OSIS Windows, MacAND user.nameIS test-user',
value: ' OSIS Windows, MacAND host.nameIS updated-host',
},
{
selector: 'trustedDevicesList-card-header-title',
Expand All @@ -611,10 +611,10 @@ export const getArtifactsListTestsData = (): ArtifactsFixtureType[] => [
list_id: ENDPOINT_ARTIFACT_LISTS.trustedDevices.id,
entries: [
{
field: 'user.name',
field: 'host.name',
operator: 'included',
type: 'match',
value: 'test-user',
value: 'test-host',
},
],
os_types: ['windows', 'macos'],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,9 @@ export const trustedAppsFormSelectors = {
export const trustedDevicesFormSelectors = {
selectOs: (osOption: 'Windows and Mac' | 'Windows' | 'Mac') => {
cy.getByTestSubj('trustedDevices-form-osSelectField').click();
cy.get('[role="option"]').contains(osOption).click();
cy.get('[role="option"]')
.contains(new RegExp(`^${osOption}$`))
.click();
},

selectField: (field: 'Username' | 'Host' | 'Device ID' | 'Manufacturer' | 'Product ID') => {
Expand Down
Loading