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

[Security Solution] Put Artifacts by Policy feature behind a feature flag #95284

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
2330c33
Added sync_master file for tracking/triggering PRs for merging master…
paul-tavares Jan 14, 2021
d3e1952
removed unnecessary (temporary) markdown file
paul-tavares Jan 14, 2021
b3b63ea
Trusted apps by policy api (#88025)
efreeti Jan 15, 2021
d93198d
[SECURITY_SOLUTION][ENDPOINT] Ability to create a Trusted App as eith…
paul-tavares Jan 28, 2021
00932d4
[SECURITY SOLUTION][ENDPOINT] UI for editing Trusted Application item…
paul-tavares Feb 5, 2021
318f6cf
[SECURITY SOLUTION][ENDPOINT] API (`PUT`) for Trusted Apps Edit flow …
paul-tavares Feb 10, 2021
a894195
[SECURITY SOLUTION][ENDPOINT] Trusted Apps API to retrieve a single T…
paul-tavares Feb 16, 2021
edd0f1d
[Security Solution][Endpoint] Multiple misc. updates/fixes for Edit T…
paul-tavares Feb 19, 2021
8b3bbf1
Fix failing server tests
paul-tavares Feb 22, 2021
1d23186
[Security Solution][Endpoint] Trusted Apps list API KQL filtering sup…
paul-tavares Feb 24, 2021
c6d59e1
Refactor schema with Put method after merging changes with master
dasansol92 Mar 22, 2021
a3aba39
WIP: allow effectScope only when feature flag is enabled
dasansol92 Mar 22, 2021
f4f3c89
Fixes errors with non declared logger
dasansol92 Mar 22, 2021
f5305af
Uses experimental features module to allow or not effectScope on crea…
dasansol92 Mar 22, 2021
e9f0bd4
Set default value for effectScope when feature flag is disabled
dasansol92 Mar 23, 2021
cf74b2b
Adds experimentals into redux store. Also creates hook to retrieve a …
dasansol92 Mar 23, 2021
0e86279
Hides effectPolicy when feature flag is not enabled
dasansol92 Mar 23, 2021
530db6d
Fixes unit test mocking hook and adds new test case
dasansol92 Mar 23, 2021
99565d8
Changes file extension for custom hook
dasansol92 Mar 24, 2021
4a4cafc
Adds new unit test for custom hook
dasansol92 Mar 24, 2021
de7c045
Hides horizontal bar with feature flag
dasansol92 Mar 24, 2021
9599891
Compress text area depending on feature flag
dasansol92 Mar 24, 2021
722da21
Fixes failing test because feature flag
dasansol92 Mar 24, 2021
a2c8e63
Fixes wrong import and unit test
dasansol92 Mar 24, 2021
d0d92d2
Thwrows error if invalid feature flag check
dasansol92 Mar 25, 2021
78e8a44
Adds snapshoot checks with feature flag enabled/disabled
dasansol92 Mar 25, 2021
f6b1f41
Test snapshots
dasansol92 Mar 25, 2021
7f6381a
Changes type name
dasansol92 Mar 25, 2021
a8817fe
Add experimentalFeatures in app context
dasansol92 Mar 25, 2021
647e7af
Fixes type checks due AppContext changes
dasansol92 Mar 25, 2021
5dadf5e
Fixes test due changes on custom hook
dasansol92 Mar 25, 2021
a640dfc
Merge branch 'master' into feature/olm-endpoint_artifacts_by_policy_f…
kibanamachine Mar 25, 2021
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
5 changes: 4 additions & 1 deletion x-pack/plugins/lists/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import { ListPlugin } from './plugin';

// exporting these since its required at top level in siem plugin
export { ListClient } from './services/lists/list_client';
export { CreateExceptionListItemOptions } from './services/exception_lists/exception_list_client_types';
export {
CreateExceptionListItemOptions,
UpdateExceptionListItemOptions,
} from './services/exception_lists/exception_list_client_types';
export { ExceptionListClient } from './services/exception_lists/exception_list_client';
export type { ListPluginSetup, ListsApiRequestHandlerContext } from './types';

Expand Down
2 changes: 2 additions & 0 deletions x-pack/plugins/security_solution/common/endpoint/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ export const telemetryIndexPattern = 'metrics-endpoint.telemetry-*';
export const LIMITED_CONCURRENCY_ENDPOINT_ROUTE_TAG = 'endpoint:limited-concurrency';
export const LIMITED_CONCURRENCY_ENDPOINT_COUNT = 100;

export const TRUSTED_APPS_GET_API = '/api/endpoint/trusted_apps/{id}';
export const TRUSTED_APPS_LIST_API = '/api/endpoint/trusted_apps';
export const TRUSTED_APPS_CREATE_API = '/api/endpoint/trusted_apps';
export const TRUSTED_APPS_UPDATE_API = '/api/endpoint/trusted_apps/{id}';
export const TRUSTED_APPS_DELETE_API = '/api/endpoint/trusted_apps/{id}';
export const TRUSTED_APPS_SUMMARY_API = '/api/endpoint/trusted_apps/summary';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,18 @@
* 2.0.
*/

import { GetTrustedAppsRequestSchema, PostTrustedAppCreateRequestSchema } from './trusted_apps';
import { ConditionEntryField, OperatingSystem } from '../types';
import {
GetTrustedAppsRequestSchema,
PostTrustedAppCreateRequestSchema,
PutTrustedAppUpdateRequestSchema,
} from './trusted_apps';
import {
ConditionEntry,
ConditionEntryField,
NewTrustedApp,
OperatingSystem,
PutTrustedAppsRequestParams,
} from '../types';

describe('When invoking Trusted Apps Schema', () => {
describe('for GET List', () => {
Expand Down Expand Up @@ -72,17 +82,18 @@ describe('When invoking Trusted Apps Schema', () => {
});

describe('for POST Create', () => {
const createConditionEntry = <T>(data?: T) => ({
const createConditionEntry = <T>(data?: T): ConditionEntry => ({
field: ConditionEntryField.PATH,
type: 'match',
operator: 'included',
value: 'c:/programs files/Anti-Virus',
...(data || {}),
});
const createNewTrustedApp = <T>(data?: T) => ({
const createNewTrustedApp = <T>(data?: T): NewTrustedApp => ({
name: 'Some Anti-Virus App',
description: 'this one is ok',
os: 'windows',
os: OperatingSystem.WINDOWS,
effectScope: { type: 'global' },
entries: [createConditionEntry()],
...(data || {}),
});
Expand Down Expand Up @@ -329,4 +340,55 @@ describe('When invoking Trusted Apps Schema', () => {
});
});
});

describe('for PUT Update', () => {
const createConditionEntry = <T>(data?: T): ConditionEntry => ({
field: ConditionEntryField.PATH,
type: 'match',
operator: 'included',
value: 'c:/programs files/Anti-Virus',
...(data || {}),
});
const createNewTrustedApp = <T>(data?: T): NewTrustedApp => ({
name: 'Some Anti-Virus App',
description: 'this one is ok',
os: OperatingSystem.WINDOWS,
effectScope: { type: 'global' },
entries: [createConditionEntry()],
...(data || {}),
});

const updateParams = <T>(data?: T): PutTrustedAppsRequestParams => ({
id: 'validId',
...(data || {}),
});

const body = PutTrustedAppUpdateRequestSchema.body;
const params = PutTrustedAppUpdateRequestSchema.params;

it('should not error on a valid message', () => {
const bodyMsg = createNewTrustedApp();
const paramsMsg = updateParams();
expect(body.validate(bodyMsg)).toStrictEqual(bodyMsg);
expect(params.validate(paramsMsg)).toStrictEqual(paramsMsg);
});

it('should validate `id` params is required', () => {
expect(() => params.validate(updateParams({ id: undefined }))).toThrow();
});

it('should validate `id` params to be string', () => {
expect(() => params.validate(updateParams({ id: 1 }))).toThrow();
});

it('should validate `version`', () => {
const bodyMsg = createNewTrustedApp({ version: 'v1' });
expect(body.validate(bodyMsg)).toStrictEqual(bodyMsg);
});

it('should validate `version` must be string', () => {
const bodyMsg = createNewTrustedApp({ version: 1 });
expect(() => body.validate(bodyMsg)).toThrow();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,26 @@
*/

import { schema } from '@kbn/config-schema';
import { ConditionEntryField, OperatingSystem } from '../types';
import { getDuplicateFields, isValidHash } from '../validation/trusted_apps';
import { ConditionEntry, ConditionEntryField, OperatingSystem } from '../types';
import { getDuplicateFields, isValidHash } from '../service/trusted_apps/validations';

export const DeleteTrustedAppsRequestSchema = {
params: schema.object({
id: schema.string(),
}),
};

export const GetOneTrustedAppRequestSchema = {
params: schema.object({
id: schema.string(),
}),
};

export const GetTrustedAppsRequestSchema = {
query: schema.object({
page: schema.maybe(schema.number({ defaultValue: 1, min: 1 })),
per_page: schema.maybe(schema.number({ defaultValue: 20, min: 1 })),
kuery: schema.maybe(schema.string()),
}),
};

Expand All @@ -40,18 +47,18 @@ const CommonEntrySchema = {
schema.siblingRef('field'),
ConditionEntryField.HASH,
schema.string({
validate: (hash) =>
validate: (hash: string) =>
isValidHash(hash) ? undefined : `invalidField.${ConditionEntryField.HASH}`,
}),
schema.conditional(
schema.siblingRef('field'),
ConditionEntryField.PATH,
schema.string({
validate: (field) =>
validate: (field: string) =>
field.length > 0 ? undefined : `invalidField.${ConditionEntryField.PATH}`,
}),
schema.string({
validate: (field) =>
validate: (field: string) =>
field.length > 0 ? undefined : `invalidField.${ConditionEntryField.SIGNER}`,
})
)
Expand Down Expand Up @@ -99,7 +106,7 @@ const EntrySchemaDependingOnOS = schema.conditional(
*/
const EntriesSchema = schema.arrayOf(EntrySchemaDependingOnOS, {
minSize: 1,
validate(entries) {
validate(entries: ConditionEntry[]) {
return (
getDuplicateFields(entries)
.map((field) => `duplicatedEntry.${field}`)
Expand All @@ -108,15 +115,35 @@ const EntriesSchema = schema.arrayOf(EntrySchemaDependingOnOS, {
},
});

export const PostTrustedAppCreateRequestSchema = {
body: schema.object({
const getTrustedAppForOsScheme = (forUpdateFlow: boolean = false) =>
schema.object({
name: schema.string({ minLength: 1, maxLength: 256 }),
description: schema.maybe(schema.string({ minLength: 0, maxLength: 256, defaultValue: '' })),
os: schema.oneOf([
schema.literal(OperatingSystem.WINDOWS),
schema.literal(OperatingSystem.LINUX),
schema.literal(OperatingSystem.MAC),
]),
effectScope: schema.oneOf([
schema.object({
type: schema.literal('global'),
}),
schema.object({
type: schema.literal('policy'),
policies: schema.arrayOf(schema.string({ minLength: 1 })),
}),
]),
entries: EntriesSchema,
...(forUpdateFlow ? { version: schema.maybe(schema.string()) } : {}),
});

export const PostTrustedAppCreateRequestSchema = {
body: getTrustedAppForOsScheme(),
};

export const PutTrustedAppUpdateRequestSchema = {
params: schema.object({
id: schema.string(),
}),
body: getTrustedAppForOsScheme(true),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import { MaybeImmutable, NewTrustedApp, UpdateTrustedApp } from '../../types';

const NEW_TRUSTED_APP_KEYS: Array<keyof UpdateTrustedApp> = [
'name',
'effectScope',
'entries',
'description',
'os',
'version',
];

export const toUpdateTrustedApp = <T extends NewTrustedApp>(
trustedApp: MaybeImmutable<T>
): UpdateTrustedApp => {
const trustedAppForUpdate: UpdateTrustedApp = {} as UpdateTrustedApp;

for (const key of NEW_TRUSTED_APP_KEYS) {
// This should be safe. Its needed due to the inter-dependency on property values (`os` <=> `entries`)
// @ts-expect-error
trustedAppForUpdate[key] = trustedApp[key];
}
return trustedAppForUpdate;
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* 2.0.
*/

import { ConditionEntry, ConditionEntryField } from '../types';
import { ConditionEntry, ConditionEntryField } from '../../types';

const HASH_LENGTHS: readonly number[] = [
32, // MD5
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ type ImmutableMap<K, V> = ReadonlyMap<Immutable<K>, Immutable<V>>;
type ImmutableSet<T> = ReadonlySet<Immutable<T>>;
type ImmutableObject<T> = { readonly [K in keyof T]: Immutable<T[K]> };

/**
* Utility type that will return back a union of the given [T]ype and an Immutable version of it
*/
export type MaybeImmutable<T> = T | Immutable<T>;

/**
* Stats for related events for a particular node in a resolver graph.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,22 @@ import { TypeOf } from '@kbn/config-schema';
import { ApplicationStart } from 'kibana/public';
import {
DeleteTrustedAppsRequestSchema,
GetOneTrustedAppRequestSchema,
GetTrustedAppsRequestSchema,
PostTrustedAppCreateRequestSchema,
PutTrustedAppUpdateRequestSchema,
} from '../schema/trusted_apps';
import { OperatingSystem } from './os';

/** API request params for deleting Trusted App entry */
export type DeleteTrustedAppsRequestParams = TypeOf<typeof DeleteTrustedAppsRequestSchema.params>;

export type GetOneTrustedAppRequestParams = TypeOf<typeof GetOneTrustedAppRequestSchema.params>;

export interface GetOneTrustedAppResponse {
data: TrustedApp;
}

/** API request params for retrieving a list of Trusted Apps */
export type GetTrustedAppsListRequest = TypeOf<typeof GetTrustedAppsRequestSchema.query>;

Expand All @@ -39,6 +47,15 @@ export interface PostTrustedAppCreateResponse {
data: TrustedApp;
}

/** API request params for updating a Trusted App */
export type PutTrustedAppsRequestParams = TypeOf<typeof PutTrustedAppUpdateRequestSchema.params>;

/** API Request body for Updating a new Trusted App entry */
export type PutTrustedAppUpdateRequest = TypeOf<typeof PutTrustedAppUpdateRequestSchema.body> &
(MacosLinuxConditionEntries | WindowsConditionEntries);

export type PutTrustedAppUpdateResponse = PostTrustedAppCreateResponse;

export interface GetTrustedAppsSummaryResponse {
total: number;
windows: number;
Expand Down Expand Up @@ -76,17 +93,38 @@ export interface WindowsConditionEntries {
entries: WindowsConditionEntry[];
}

export interface GlobalEffectScope {
type: 'global';
}

export interface PolicyEffectScope {
type: 'policy';
/** An array of Endpoint Integration Policy UUIDs */
policies: string[];
}

export type EffectScope = GlobalEffectScope | PolicyEffectScope;

/** Type for a new Trusted App Entry */
export type NewTrustedApp = {
name: string;
description?: string;
effectScope: EffectScope;
} & (MacosLinuxConditionEntries | WindowsConditionEntries);

/** An Update to a Trusted App Entry */
export type UpdateTrustedApp = NewTrustedApp & {
version?: string;
};

/** A trusted app entry */
export type TrustedApp = NewTrustedApp & {
version: string;
id: string;
created_at: string;
created_by: string;
updated_at: string;
updated_by: string;
};

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export type ExperimentalFeatures = typeof allowedExperimentalValues;
*/
const allowedExperimentalValues = Object.freeze({
fleetServerEnabled: false,
trustedAppsByPolicyEnabled: false,
});

type ExperimentalConfigKeys = Array<keyof ExperimentalFeatures>;
Expand Down
Loading