mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Actions] Do not return system actions from GET
APIs (#161845)
## Summary This PR removes the ability to get system actions from `GET` APIs. Specifically: - The Get action API throws a 404 error when requesting a system action - The Bulk Get action API throws a 404 error when requesting a system action - The Get All API filters out system actions - The Get List Types API filters out system actions ### Checklist Delete any items that are not applicable to this PR. - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios ### For maintainers - [x] This was checked for breaking API changes and was [labeled appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
This commit is contained in:
parent
93f715b36b
commit
c66f72ac49
11 changed files with 606 additions and 170 deletions
|
@ -923,7 +923,7 @@ describe('get()', () => {
|
|||
getEventLogClient,
|
||||
});
|
||||
|
||||
await actionsClient.get({ id: 'system-connector-.cases' });
|
||||
await expect(actionsClient.get({ id: 'system-connector-.cases' })).rejects.toThrow();
|
||||
|
||||
expect(authorization.ensureAuthorized).toHaveBeenCalledWith({ operation: 'get' });
|
||||
});
|
||||
|
@ -1164,7 +1164,7 @@ describe('get()', () => {
|
|||
expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('return system action with id', async () => {
|
||||
it('throws when getting a system action by default', async () => {
|
||||
actionsClient = new ActionsClient({
|
||||
logger,
|
||||
actionTypeRegistry,
|
||||
|
@ -1194,18 +1194,51 @@ describe('get()', () => {
|
|||
getEventLogClient,
|
||||
});
|
||||
|
||||
const result = await actionsClient.get({ id: 'system-connector-.cases' });
|
||||
await expect(
|
||||
actionsClient.get({ id: 'system-connector-.cases' })
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(`"Connector system-connector-.cases not found"`);
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
id: 'system-connector-.cases',
|
||||
it('does not throw when getting a system action if throwIfSystemAction=false', async () => {
|
||||
actionsClient = new ActionsClient({
|
||||
logger,
|
||||
actionTypeRegistry,
|
||||
unsecuredSavedObjectsClient,
|
||||
scopedClusterClient,
|
||||
kibanaIndices,
|
||||
actionExecutor,
|
||||
executionEnqueuer,
|
||||
ephemeralExecutionEnqueuer,
|
||||
bulkExecutionEnqueuer,
|
||||
request,
|
||||
authorization: authorization as unknown as ActionsAuthorization,
|
||||
inMemoryConnectors: [
|
||||
{
|
||||
id: 'system-connector-.cases',
|
||||
actionTypeId: '.cases',
|
||||
name: 'System action: .cases',
|
||||
config: {},
|
||||
secrets: {},
|
||||
isDeprecated: false,
|
||||
isMissingSecrets: false,
|
||||
isPreconfigured: false,
|
||||
isSystemAction: true,
|
||||
},
|
||||
],
|
||||
connectorTokenClient: connectorTokenClientMock.create(),
|
||||
getEventLogClient,
|
||||
});
|
||||
|
||||
expect(
|
||||
await actionsClient.get({ id: 'system-connector-.cases', throwIfSystemAction: false })
|
||||
).toEqual({
|
||||
actionTypeId: '.cases',
|
||||
isPreconfigured: false,
|
||||
id: 'system-connector-.cases',
|
||||
isDeprecated: false,
|
||||
isPreconfigured: false,
|
||||
isSystemAction: true,
|
||||
name: 'System action: .cases',
|
||||
});
|
||||
|
||||
expect(unsecuredSavedObjectsClient.get).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1412,6 +1445,11 @@ describe('getAll()', () => {
|
|||
foo: 'bar',
|
||||
},
|
||||
},
|
||||
/**
|
||||
* System actions will not
|
||||
* be returned from getAll
|
||||
* if no options are provided
|
||||
*/
|
||||
{
|
||||
id: 'system-connector-.cases',
|
||||
actionTypeId: '.cases',
|
||||
|
@ -1432,12 +1470,111 @@ describe('getAll()', () => {
|
|||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
id: 'system-connector-.cases',
|
||||
id: '1',
|
||||
name: 'test',
|
||||
isMissingSecrets: false,
|
||||
config: { foo: 'bar' },
|
||||
isPreconfigured: false,
|
||||
isDeprecated: false,
|
||||
isSystemAction: false,
|
||||
referencedByCount: 6,
|
||||
},
|
||||
{
|
||||
id: 'testPreconfigured',
|
||||
actionTypeId: '.slack',
|
||||
name: 'test',
|
||||
isPreconfigured: true,
|
||||
isSystemAction: false,
|
||||
isDeprecated: false,
|
||||
referencedByCount: 2,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('get system actions correctly', async () => {
|
||||
const expectedResult = {
|
||||
total: 1,
|
||||
per_page: 10,
|
||||
page: 1,
|
||||
saved_objects: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'type',
|
||||
attributes: {
|
||||
name: 'test',
|
||||
isMissingSecrets: false,
|
||||
config: {
|
||||
foo: 'bar',
|
||||
},
|
||||
},
|
||||
score: 1,
|
||||
references: [],
|
||||
},
|
||||
],
|
||||
};
|
||||
unsecuredSavedObjectsClient.find.mockResolvedValueOnce(expectedResult);
|
||||
scopedClusterClient.asInternalUser.search.mockResponse(
|
||||
// @ts-expect-error not full search response
|
||||
{
|
||||
aggregations: {
|
||||
'1': { doc_count: 6 },
|
||||
testPreconfigured: { doc_count: 2 },
|
||||
'system-connector-.cases': { doc_count: 2 },
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
actionsClient = new ActionsClient({
|
||||
logger,
|
||||
actionTypeRegistry,
|
||||
unsecuredSavedObjectsClient,
|
||||
scopedClusterClient,
|
||||
kibanaIndices,
|
||||
actionExecutor,
|
||||
executionEnqueuer,
|
||||
ephemeralExecutionEnqueuer,
|
||||
bulkExecutionEnqueuer,
|
||||
request,
|
||||
authorization: authorization as unknown as ActionsAuthorization,
|
||||
inMemoryConnectors: [
|
||||
{
|
||||
id: 'testPreconfigured',
|
||||
actionTypeId: '.slack',
|
||||
secrets: {},
|
||||
isPreconfigured: true,
|
||||
isDeprecated: false,
|
||||
isSystemAction: false,
|
||||
name: 'test',
|
||||
config: {
|
||||
foo: 'bar',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'system-connector-.cases',
|
||||
actionTypeId: '.cases',
|
||||
name: 'System action: .cases',
|
||||
config: {},
|
||||
secrets: {},
|
||||
isDeprecated: false,
|
||||
isMissingSecrets: false,
|
||||
isPreconfigured: false,
|
||||
isSystemAction: true,
|
||||
},
|
||||
],
|
||||
connectorTokenClient: connectorTokenClientMock.create(),
|
||||
getEventLogClient,
|
||||
});
|
||||
|
||||
const result = await actionsClient.getAll({ includeSystemActions: true });
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
actionTypeId: '.cases',
|
||||
name: 'System action: .cases',
|
||||
id: 'system-connector-.cases',
|
||||
isDeprecated: false,
|
||||
isPreconfigured: false,
|
||||
isSystemAction: true,
|
||||
isDeprecated: false,
|
||||
name: 'System action: .cases',
|
||||
referencedByCount: 2,
|
||||
},
|
||||
{
|
||||
|
@ -1673,11 +1810,7 @@ describe('getBulk()', () => {
|
|||
getEventLogClient,
|
||||
});
|
||||
|
||||
const result = await actionsClient.getBulk([
|
||||
'1',
|
||||
'testPreconfigured',
|
||||
'system-connector-.cases',
|
||||
]);
|
||||
const result = await actionsClient.getBulk(['1', 'testPreconfigured']);
|
||||
|
||||
expect(result).toEqual([
|
||||
{
|
||||
|
@ -1690,17 +1823,6 @@ describe('getBulk()', () => {
|
|||
name: 'test',
|
||||
config: { foo: 'bar' },
|
||||
},
|
||||
{
|
||||
id: 'system-connector-.cases',
|
||||
actionTypeId: '.cases',
|
||||
name: 'System action: .cases',
|
||||
config: {},
|
||||
secrets: {},
|
||||
isDeprecated: false,
|
||||
isMissingSecrets: false,
|
||||
isPreconfigured: false,
|
||||
isSystemAction: true,
|
||||
},
|
||||
{
|
||||
id: '1',
|
||||
actionTypeId: 'test',
|
||||
|
@ -1713,6 +1835,188 @@ describe('getBulk()', () => {
|
|||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test('should throw an error if a system action is requested by default', async () => {
|
||||
unsecuredSavedObjectsClient.bulkGet.mockResolvedValueOnce({
|
||||
saved_objects: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'action',
|
||||
attributes: {
|
||||
actionTypeId: 'test',
|
||||
name: 'test',
|
||||
config: {
|
||||
foo: 'bar',
|
||||
},
|
||||
isMissingSecrets: false,
|
||||
},
|
||||
references: [],
|
||||
},
|
||||
],
|
||||
});
|
||||
scopedClusterClient.asInternalUser.search.mockResponse(
|
||||
// @ts-expect-error not full search response
|
||||
{
|
||||
aggregations: {
|
||||
'1': { doc_count: 6 },
|
||||
testPreconfigured: { doc_count: 2 },
|
||||
'system-connector-.cases': { doc_count: 2 },
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
actionsClient = new ActionsClient({
|
||||
logger,
|
||||
actionTypeRegistry,
|
||||
unsecuredSavedObjectsClient,
|
||||
scopedClusterClient,
|
||||
kibanaIndices,
|
||||
actionExecutor,
|
||||
executionEnqueuer,
|
||||
ephemeralExecutionEnqueuer,
|
||||
bulkExecutionEnqueuer,
|
||||
request,
|
||||
authorization: authorization as unknown as ActionsAuthorization,
|
||||
inMemoryConnectors: [
|
||||
{
|
||||
id: 'testPreconfigured',
|
||||
actionTypeId: '.slack',
|
||||
secrets: {},
|
||||
isPreconfigured: true,
|
||||
isDeprecated: false,
|
||||
isSystemAction: false,
|
||||
name: 'test',
|
||||
config: {
|
||||
foo: 'bar',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'system-connector-.cases',
|
||||
actionTypeId: '.cases',
|
||||
name: 'System action: .cases',
|
||||
config: {},
|
||||
secrets: {},
|
||||
isDeprecated: false,
|
||||
isMissingSecrets: false,
|
||||
isPreconfigured: false,
|
||||
isSystemAction: true,
|
||||
},
|
||||
],
|
||||
connectorTokenClient: connectorTokenClientMock.create(),
|
||||
getEventLogClient,
|
||||
});
|
||||
|
||||
await expect(
|
||||
actionsClient.getBulk(['1', 'testPreconfigured', 'system-connector-.cases'])
|
||||
).rejects.toThrowErrorMatchingInlineSnapshot(`"Connector system-connector-.cases not found"`);
|
||||
});
|
||||
|
||||
test('should throw an error if a system action is requested', async () => {
|
||||
unsecuredSavedObjectsClient.bulkGet.mockResolvedValueOnce({
|
||||
saved_objects: [
|
||||
{
|
||||
id: '1',
|
||||
type: 'action',
|
||||
attributes: {
|
||||
actionTypeId: 'test',
|
||||
name: 'test',
|
||||
config: {
|
||||
foo: 'bar',
|
||||
},
|
||||
isMissingSecrets: false,
|
||||
},
|
||||
references: [],
|
||||
},
|
||||
],
|
||||
});
|
||||
scopedClusterClient.asInternalUser.search.mockResponse(
|
||||
// @ts-expect-error not full search response
|
||||
{
|
||||
aggregations: {
|
||||
'1': { doc_count: 6 },
|
||||
testPreconfigured: { doc_count: 2 },
|
||||
'system-connector-.cases': { doc_count: 2 },
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
actionsClient = new ActionsClient({
|
||||
logger,
|
||||
actionTypeRegistry,
|
||||
unsecuredSavedObjectsClient,
|
||||
scopedClusterClient,
|
||||
kibanaIndices,
|
||||
actionExecutor,
|
||||
executionEnqueuer,
|
||||
ephemeralExecutionEnqueuer,
|
||||
bulkExecutionEnqueuer,
|
||||
request,
|
||||
authorization: authorization as unknown as ActionsAuthorization,
|
||||
inMemoryConnectors: [
|
||||
{
|
||||
id: 'testPreconfigured',
|
||||
actionTypeId: '.slack',
|
||||
secrets: {},
|
||||
isPreconfigured: true,
|
||||
isDeprecated: false,
|
||||
isSystemAction: false,
|
||||
name: 'test',
|
||||
config: {
|
||||
foo: 'bar',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'system-connector-.cases',
|
||||
actionTypeId: '.cases',
|
||||
name: 'System action: .cases',
|
||||
config: {},
|
||||
secrets: {},
|
||||
isDeprecated: false,
|
||||
isMissingSecrets: false,
|
||||
isPreconfigured: false,
|
||||
isSystemAction: true,
|
||||
},
|
||||
],
|
||||
connectorTokenClient: connectorTokenClientMock.create(),
|
||||
getEventLogClient,
|
||||
});
|
||||
|
||||
expect(
|
||||
await actionsClient.getBulk(['1', 'testPreconfigured', 'system-connector-.cases'], false)
|
||||
).toEqual([
|
||||
{
|
||||
actionTypeId: '.slack',
|
||||
config: { foo: 'bar' },
|
||||
id: 'testPreconfigured',
|
||||
isDeprecated: false,
|
||||
isPreconfigured: true,
|
||||
isSystemAction: false,
|
||||
name: 'test',
|
||||
secrets: {},
|
||||
},
|
||||
{
|
||||
actionTypeId: '.cases',
|
||||
config: {},
|
||||
id: 'system-connector-.cases',
|
||||
isDeprecated: false,
|
||||
isMissingSecrets: false,
|
||||
isPreconfigured: false,
|
||||
isSystemAction: true,
|
||||
name: 'System action: .cases',
|
||||
secrets: {},
|
||||
},
|
||||
{
|
||||
actionTypeId: 'test',
|
||||
config: { foo: 'bar' },
|
||||
id: '1',
|
||||
isDeprecated: false,
|
||||
isMissingSecrets: false,
|
||||
isPreconfigured: false,
|
||||
isSystemAction: false,
|
||||
name: 'test',
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getOAuthAccessToken()', () => {
|
||||
|
@ -3284,6 +3588,172 @@ describe('bulkEnqueueExecution()', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('listType()', () => {
|
||||
it('filters action types by feature ID', async () => {
|
||||
mockedLicenseState.isLicenseValidForActionType.mockReturnValue({ isValid: true });
|
||||
|
||||
actionTypeRegistry.register({
|
||||
id: 'my-action-type',
|
||||
name: 'My action type',
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
validate: {
|
||||
config: { schema: schema.object({}) },
|
||||
secrets: { schema: schema.object({}) },
|
||||
params: { schema: schema.object({}) },
|
||||
},
|
||||
executor,
|
||||
});
|
||||
|
||||
actionTypeRegistry.register({
|
||||
id: 'my-action-type-2',
|
||||
name: 'My action type 2',
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['cases'],
|
||||
validate: {
|
||||
config: { schema: schema.object({}) },
|
||||
secrets: { schema: schema.object({}) },
|
||||
params: { schema: schema.object({}) },
|
||||
},
|
||||
executor,
|
||||
});
|
||||
|
||||
expect(await actionsClient.listTypes({ featureId: 'alerting' })).toEqual([
|
||||
{
|
||||
id: 'my-action-type',
|
||||
name: 'My action type',
|
||||
minimumLicenseRequired: 'basic',
|
||||
enabled: true,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
supportedFeatureIds: ['alerting'],
|
||||
isSystemActionType: false,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('filters out system action types when not defining options', async () => {
|
||||
mockedLicenseState.isLicenseValidForActionType.mockReturnValue({ isValid: true });
|
||||
|
||||
actionTypeRegistry.register({
|
||||
id: 'my-action-type',
|
||||
name: 'My action type',
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
validate: {
|
||||
config: { schema: schema.object({}) },
|
||||
secrets: { schema: schema.object({}) },
|
||||
params: { schema: schema.object({}) },
|
||||
},
|
||||
executor,
|
||||
});
|
||||
|
||||
actionTypeRegistry.register({
|
||||
id: 'my-action-type-2',
|
||||
name: 'My action type 2',
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['cases'],
|
||||
validate: {
|
||||
config: { schema: schema.object({}) },
|
||||
secrets: { schema: schema.object({}) },
|
||||
params: { schema: schema.object({}) },
|
||||
},
|
||||
executor,
|
||||
});
|
||||
|
||||
actionTypeRegistry.register({
|
||||
id: '.cases',
|
||||
name: 'Cases',
|
||||
minimumLicenseRequired: 'platinum',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
validate: {
|
||||
config: { schema: schema.object({}) },
|
||||
secrets: { schema: schema.object({}) },
|
||||
params: { schema: schema.object({}) },
|
||||
},
|
||||
isSystemActionType: true,
|
||||
executor,
|
||||
});
|
||||
|
||||
expect(await actionsClient.listTypes()).toEqual([
|
||||
{
|
||||
id: 'my-action-type',
|
||||
name: 'My action type',
|
||||
minimumLicenseRequired: 'basic',
|
||||
enabled: true,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
supportedFeatureIds: ['alerting'],
|
||||
isSystemActionType: false,
|
||||
},
|
||||
{
|
||||
id: 'my-action-type-2',
|
||||
name: 'My action type 2',
|
||||
isSystemActionType: false,
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['cases'],
|
||||
enabled: true,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('return system action types when defining options', async () => {
|
||||
mockedLicenseState.isLicenseValidForActionType.mockReturnValue({ isValid: true });
|
||||
|
||||
actionTypeRegistry.register({
|
||||
id: 'my-action-type',
|
||||
name: 'My action type',
|
||||
minimumLicenseRequired: 'basic',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
validate: {
|
||||
config: { schema: schema.object({}) },
|
||||
secrets: { schema: schema.object({}) },
|
||||
params: { schema: schema.object({}) },
|
||||
},
|
||||
executor,
|
||||
});
|
||||
|
||||
actionTypeRegistry.register({
|
||||
id: '.cases',
|
||||
name: 'Cases',
|
||||
minimumLicenseRequired: 'platinum',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
validate: {
|
||||
config: { schema: schema.object({}) },
|
||||
secrets: { schema: schema.object({}) },
|
||||
params: { schema: schema.object({}) },
|
||||
},
|
||||
isSystemActionType: true,
|
||||
executor,
|
||||
});
|
||||
|
||||
expect(await actionsClient.listTypes({ includeSystemActionTypes: true })).toEqual([
|
||||
{
|
||||
id: 'my-action-type',
|
||||
name: 'My action type',
|
||||
minimumLicenseRequired: 'basic',
|
||||
enabled: true,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
supportedFeatureIds: ['alerting'],
|
||||
isSystemActionType: false,
|
||||
},
|
||||
{
|
||||
id: '.cases',
|
||||
name: 'Cases',
|
||||
isSystemActionType: true,
|
||||
minimumLicenseRequired: 'platinum',
|
||||
supportedFeatureIds: ['alerting'],
|
||||
enabled: true,
|
||||
enabledInConfig: true,
|
||||
enabledInLicense: true,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('isActionTypeEnabled()', () => {
|
||||
const fooActionType: ActionType = {
|
||||
id: 'foo',
|
||||
|
|
|
@ -133,6 +133,15 @@ export interface UpdateOptions {
|
|||
action: ActionUpdate;
|
||||
}
|
||||
|
||||
interface GetAllOptions {
|
||||
includeSystemActions?: boolean;
|
||||
}
|
||||
|
||||
interface ListTypesOptions {
|
||||
featureId?: string;
|
||||
includeSystemActionTypes?: boolean;
|
||||
}
|
||||
|
||||
export class ActionsClient {
|
||||
private readonly logger: Logger;
|
||||
private readonly kibanaIndices: string[];
|
||||
|
@ -394,7 +403,13 @@ export class ActionsClient {
|
|||
/**
|
||||
* Get an action
|
||||
*/
|
||||
public async get({ id }: { id: string }): Promise<ActionResult> {
|
||||
public async get({
|
||||
id,
|
||||
throwIfSystemAction = true,
|
||||
}: {
|
||||
id: string;
|
||||
throwIfSystemAction?: boolean;
|
||||
}): Promise<ActionResult> {
|
||||
try {
|
||||
await this.authorization.ensureAuthorized({ operation: 'get' });
|
||||
} catch (error) {
|
||||
|
@ -410,6 +425,19 @@ export class ActionsClient {
|
|||
|
||||
const foundInMemoryConnector = this.inMemoryConnectors.find((connector) => connector.id === id);
|
||||
|
||||
/**
|
||||
* Getting system connector is not allowed
|
||||
* if throwIfSystemAction is set to true.
|
||||
* Default behavior is to throw
|
||||
*/
|
||||
if (
|
||||
foundInMemoryConnector !== undefined &&
|
||||
foundInMemoryConnector.isSystemAction &&
|
||||
throwIfSystemAction
|
||||
) {
|
||||
throw Boom.notFound(`Connector ${id} not found`);
|
||||
}
|
||||
|
||||
if (foundInMemoryConnector !== undefined) {
|
||||
this.auditLogger?.log(
|
||||
connectorAuditEvent({
|
||||
|
@ -452,7 +480,9 @@ export class ActionsClient {
|
|||
/**
|
||||
* Get all actions with in-memory connectors
|
||||
*/
|
||||
public async getAll(): Promise<FindActionResult[]> {
|
||||
public async getAll({ includeSystemActions = false }: GetAllOptions = {}): Promise<
|
||||
FindActionResult[]
|
||||
> {
|
||||
try {
|
||||
await this.authorization.ensureAuthorized({ operation: 'get' });
|
||||
} catch (error) {
|
||||
|
@ -483,9 +513,13 @@ export class ActionsClient {
|
|||
)
|
||||
);
|
||||
|
||||
const inMemoryConnectorsFiltered = includeSystemActions
|
||||
? this.inMemoryConnectors
|
||||
: this.inMemoryConnectors.filter((connector) => !connector.isSystemAction);
|
||||
|
||||
const mergedResult = [
|
||||
...savedObjectsActions,
|
||||
...this.inMemoryConnectors.map((inMemoryConnector) => ({
|
||||
...inMemoryConnectorsFiltered.map((inMemoryConnector) => ({
|
||||
id: inMemoryConnector.id,
|
||||
actionTypeId: inMemoryConnector.actionTypeId,
|
||||
name: inMemoryConnector.name,
|
||||
|
@ -500,7 +534,10 @@ export class ActionsClient {
|
|||
/**
|
||||
* Get bulk actions with in-memory list
|
||||
*/
|
||||
public async getBulk(ids: string[]): Promise<ActionResult[]> {
|
||||
public async getBulk(
|
||||
ids: string[],
|
||||
throwIfSystemAction: boolean = true
|
||||
): Promise<ActionResult[]> {
|
||||
try {
|
||||
await this.authorization.ensureAuthorized({ operation: 'get' });
|
||||
} catch (error) {
|
||||
|
@ -523,6 +560,15 @@ export class ActionsClient {
|
|||
(inMemoryConnector) => inMemoryConnector.id === actionId
|
||||
);
|
||||
|
||||
/**
|
||||
* Getting system connector is not allowed
|
||||
* if throwIfSystemAction is set to true.
|
||||
* Default behavior is to throw
|
||||
*/
|
||||
if (action !== undefined && action.isSystemAction && throwIfSystemAction) {
|
||||
throw Boom.notFound(`Connector ${action.id} not found`);
|
||||
}
|
||||
|
||||
if (action !== undefined) {
|
||||
actionResults.push(action);
|
||||
}
|
||||
|
@ -823,8 +869,21 @@ export class ActionsClient {
|
|||
return this.ephemeralExecutionEnqueuer(this.unsecuredSavedObjectsClient, options);
|
||||
}
|
||||
|
||||
public async listTypes(featureId?: string): Promise<ActionType[]> {
|
||||
return this.actionTypeRegistry.list(featureId);
|
||||
/**
|
||||
* Return all available action types
|
||||
* expect system action types
|
||||
*/
|
||||
public async listTypes({
|
||||
featureId,
|
||||
includeSystemActionTypes = false,
|
||||
}: ListTypesOptions = {}): Promise<ActionType[]> {
|
||||
const actionTypes = this.actionTypeRegistry.list(featureId);
|
||||
|
||||
const filteredActionTypes = includeSystemActionTypes
|
||||
? actionTypes
|
||||
: actionTypes.filter((actionType) => !Boolean(actionType.isSystemActionType));
|
||||
|
||||
return filteredActionTypes;
|
||||
}
|
||||
|
||||
public isActionTypeEnabled(
|
||||
|
|
|
@ -491,7 +491,13 @@ export class ActionsPlugin implements Plugin<PluginSetupContract, PluginStartCon
|
|||
return (objects?: SavedObjectsBulkGetObject[]) =>
|
||||
objects
|
||||
? Promise.all(
|
||||
objects.map(async (objectItem) => await (await client).get({ id: objectItem.id }))
|
||||
objects.map(
|
||||
async (objectItem) =>
|
||||
/**
|
||||
* TODO: Change with getBulk
|
||||
*/
|
||||
await (await client).get({ id: objectItem.id, throwIfSystemAction: false })
|
||||
)
|
||||
)
|
||||
: Promise.resolve([]);
|
||||
});
|
||||
|
|
|
@ -142,7 +142,9 @@ describe('connectorTypesRoute', () => {
|
|||
expect(actionsClient.listTypes).toHaveBeenCalledTimes(1);
|
||||
expect(actionsClient.listTypes.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"alerting",
|
||||
Object {
|
||||
"featureId": "alerting",
|
||||
},
|
||||
]
|
||||
`);
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ export const connectorTypesRoute = (
|
|||
verifyAccessAndContext(licenseState, async function (context, req, res) {
|
||||
const actionsClient = (await context.actions).getActionsClient();
|
||||
return res.ok({
|
||||
body: rewriteBodyRes(await actionsClient.listTypes(req.query?.feature_id)),
|
||||
body: rewriteBodyRes(await actionsClient.listTypes({ featureId: req.query?.feature_id })),
|
||||
});
|
||||
})
|
||||
)
|
||||
|
|
|
@ -12,6 +12,10 @@ import { BASE_ACTION_API_PATH } from '../../../common';
|
|||
import { ActionsRequestHandlerContext } from '../../types';
|
||||
import { trackLegacyRouteUsage } from '../../lib/track_legacy_route_usage';
|
||||
|
||||
/**
|
||||
* Return all available action types
|
||||
* expect system action types
|
||||
*/
|
||||
export const listActionTypesRoute = (
|
||||
router: IRouter<ActionsRequestHandlerContext>,
|
||||
licenseState: ILicenseState,
|
||||
|
|
|
@ -161,7 +161,7 @@ export default function getActionTests({ getService }: FtrProviderContext) {
|
|||
}
|
||||
});
|
||||
|
||||
it('should handle get system action request appropriately', async () => {
|
||||
it('should throw when requesting a system action', async () => {
|
||||
const response = await supertestWithoutAuth
|
||||
.get(
|
||||
`${getUrlPrefix(space.id)}/api/actions/connector/system-connector-test.system-action`
|
||||
|
@ -183,14 +183,11 @@ export default function getActionTests({ getService }: FtrProviderContext) {
|
|||
case 'superuser at space1':
|
||||
case 'space_1_all at space1':
|
||||
case 'space_1_all_with_restricted_fixture at space1':
|
||||
expect(response.statusCode).to.eql(200);
|
||||
expect(response.statusCode).to.eql(404);
|
||||
expect(response.body).to.eql({
|
||||
id: 'system-connector-test.system-action',
|
||||
connector_type_id: 'test.system-action',
|
||||
name: 'System action: test.system-action',
|
||||
is_preconfigured: false,
|
||||
is_system_action: true,
|
||||
is_deprecated: false,
|
||||
statusCode: 404,
|
||||
error: 'Not Found',
|
||||
message: 'Connector system-connector-test.system-action not found',
|
||||
});
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -125,24 +125,6 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
name: 'Slack#xyz',
|
||||
referenced_by_count: 0,
|
||||
},
|
||||
{
|
||||
connector_type_id: 'test.system-action',
|
||||
id: 'system-connector-test.system-action',
|
||||
is_deprecated: false,
|
||||
is_preconfigured: false,
|
||||
is_system_action: true,
|
||||
name: 'System action: test.system-action',
|
||||
referenced_by_count: 0,
|
||||
},
|
||||
{
|
||||
connector_type_id: 'test.system-action-kibana-privileges',
|
||||
id: 'system-connector-test.system-action-kibana-privileges',
|
||||
is_deprecated: false,
|
||||
is_preconfigured: false,
|
||||
is_system_action: true,
|
||||
name: 'System action: test.system-action-kibana-privileges',
|
||||
referenced_by_count: 0,
|
||||
},
|
||||
{
|
||||
id: 'custom-system-abc-connector',
|
||||
is_preconfigured: true,
|
||||
|
@ -303,24 +285,6 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
name: 'Slack#xyz',
|
||||
referenced_by_count: 0,
|
||||
},
|
||||
{
|
||||
connector_type_id: 'test.system-action',
|
||||
id: 'system-connector-test.system-action',
|
||||
is_deprecated: false,
|
||||
is_preconfigured: false,
|
||||
is_system_action: true,
|
||||
name: 'System action: test.system-action',
|
||||
referenced_by_count: 0,
|
||||
},
|
||||
{
|
||||
connector_type_id: 'test.system-action-kibana-privileges',
|
||||
id: 'system-connector-test.system-action-kibana-privileges',
|
||||
is_deprecated: false,
|
||||
is_preconfigured: false,
|
||||
is_system_action: true,
|
||||
name: 'System action: test.system-action-kibana-privileges',
|
||||
referenced_by_count: 0,
|
||||
},
|
||||
{
|
||||
id: 'custom-system-abc-connector',
|
||||
is_preconfigured: true,
|
||||
|
@ -444,24 +408,6 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
name: 'Slack#xyz',
|
||||
referenced_by_count: 0,
|
||||
},
|
||||
{
|
||||
connector_type_id: 'test.system-action',
|
||||
id: 'system-connector-test.system-action',
|
||||
is_deprecated: false,
|
||||
is_preconfigured: false,
|
||||
is_system_action: true,
|
||||
name: 'System action: test.system-action',
|
||||
referenced_by_count: 0,
|
||||
},
|
||||
{
|
||||
connector_type_id: 'test.system-action-kibana-privileges',
|
||||
id: 'system-connector-test.system-action-kibana-privileges',
|
||||
is_deprecated: false,
|
||||
is_preconfigured: false,
|
||||
is_system_action: true,
|
||||
name: 'System action: test.system-action-kibana-privileges',
|
||||
referenced_by_count: 0,
|
||||
},
|
||||
{
|
||||
id: 'custom-system-abc-connector',
|
||||
is_preconfigured: true,
|
||||
|
|
|
@ -34,6 +34,16 @@ export default function listActionTypesTests({ getService }: FtrProviderContext)
|
|||
).to.be(true);
|
||||
});
|
||||
|
||||
it('should filter out system action types', async () => {
|
||||
const response = await supertest.get(
|
||||
`${getUrlPrefix(Spaces.space1.id)}/api/actions/connector_types`
|
||||
);
|
||||
|
||||
const actionTypes = response.body as Array<{ is_system_action_type: boolean }>;
|
||||
|
||||
expect(actionTypes.every((actionType) => !actionType.is_system_action_type)).to.be(true);
|
||||
});
|
||||
|
||||
describe('legacy', () => {
|
||||
it('should return 200 with list of action types containing defaults', async () => {
|
||||
const response = await supertest.get(
|
||||
|
@ -53,6 +63,16 @@ export default function listActionTypesTests({ getService }: FtrProviderContext)
|
|||
response.body.some(createActionTypeMatcher('test.index-record', 'Test: Index Record'))
|
||||
).to.be(true);
|
||||
});
|
||||
|
||||
it('should filter out system action types', async () => {
|
||||
const response = await supertest.get(
|
||||
`${getUrlPrefix(Spaces.space1.id)}/api/actions/list_action_types`
|
||||
);
|
||||
|
||||
const actionTypes = response.body as Array<{ is_system_action_type: boolean }>;
|
||||
|
||||
expect(actionTypes.every((actionType) => !actionType.is_system_action_type)).to.be(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -90,21 +90,14 @@ export default function getActionTests({ getService }: FtrProviderContext) {
|
|||
});
|
||||
});
|
||||
|
||||
it('should handle get a system connector', async () => {
|
||||
it('should return 404 when trying to get a system connector', async () => {
|
||||
await supertest
|
||||
.get(
|
||||
`${getUrlPrefix(
|
||||
Spaces.space1.id
|
||||
)}/api/actions/connector/system-connector-test.system-action`
|
||||
)
|
||||
.expect(200, {
|
||||
id: 'system-connector-test.system-action',
|
||||
connector_type_id: 'test.system-action',
|
||||
name: 'System action: test.system-action',
|
||||
is_preconfigured: false,
|
||||
is_system_action: true,
|
||||
is_deprecated: false,
|
||||
});
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it('should handle get a deprecated connector', async () => {
|
||||
|
@ -206,21 +199,14 @@ export default function getActionTests({ getService }: FtrProviderContext) {
|
|||
});
|
||||
});
|
||||
|
||||
it('should handle get a system connector', async () => {
|
||||
it('should return 404 when trying to get a system connector', async () => {
|
||||
await supertest
|
||||
.get(
|
||||
`${getUrlPrefix(
|
||||
Spaces.space1.id
|
||||
)}/api/actions/action/system-connector-test.system-action`
|
||||
)
|
||||
.expect(200, {
|
||||
id: 'system-connector-test.system-action',
|
||||
actionTypeId: 'test.system-action',
|
||||
name: 'System action: test.system-action',
|
||||
isPreconfigured: false,
|
||||
isSystemAction: true,
|
||||
isDeprecated: false,
|
||||
});
|
||||
.expect(404);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -114,24 +114,6 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
name: 'Slack#xyz',
|
||||
referenced_by_count: 0,
|
||||
},
|
||||
{
|
||||
connector_type_id: 'test.system-action',
|
||||
id: 'system-connector-test.system-action',
|
||||
is_deprecated: false,
|
||||
is_preconfigured: false,
|
||||
is_system_action: true,
|
||||
name: 'System action: test.system-action',
|
||||
referenced_by_count: 0,
|
||||
},
|
||||
{
|
||||
connector_type_id: 'test.system-action-kibana-privileges',
|
||||
id: 'system-connector-test.system-action-kibana-privileges',
|
||||
is_deprecated: false,
|
||||
is_preconfigured: false,
|
||||
is_system_action: true,
|
||||
name: 'System action: test.system-action-kibana-privileges',
|
||||
referenced_by_count: 0,
|
||||
},
|
||||
{
|
||||
id: 'custom-system-abc-connector',
|
||||
is_preconfigured: true,
|
||||
|
@ -244,24 +226,6 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
name: 'Slack#xyz',
|
||||
referenced_by_count: 0,
|
||||
},
|
||||
{
|
||||
connector_type_id: 'test.system-action',
|
||||
id: 'system-connector-test.system-action',
|
||||
is_deprecated: false,
|
||||
is_preconfigured: false,
|
||||
is_system_action: true,
|
||||
name: 'System action: test.system-action',
|
||||
referenced_by_count: 0,
|
||||
},
|
||||
{
|
||||
connector_type_id: 'test.system-action-kibana-privileges',
|
||||
id: 'system-connector-test.system-action-kibana-privileges',
|
||||
is_deprecated: false,
|
||||
is_preconfigured: false,
|
||||
is_system_action: true,
|
||||
name: 'System action: test.system-action-kibana-privileges',
|
||||
referenced_by_count: 0,
|
||||
},
|
||||
{
|
||||
id: 'custom-system-abc-connector',
|
||||
is_preconfigured: true,
|
||||
|
@ -388,24 +352,6 @@ export default function getAllActionTests({ getService }: FtrProviderContext) {
|
|||
name: 'Slack#xyz',
|
||||
referencedByCount: 0,
|
||||
},
|
||||
{
|
||||
actionTypeId: 'test.system-action',
|
||||
id: 'system-connector-test.system-action',
|
||||
isDeprecated: false,
|
||||
isPreconfigured: false,
|
||||
isSystemAction: true,
|
||||
name: 'System action: test.system-action',
|
||||
referencedByCount: 0,
|
||||
},
|
||||
{
|
||||
actionTypeId: 'test.system-action-kibana-privileges',
|
||||
id: 'system-connector-test.system-action-kibana-privileges',
|
||||
isDeprecated: false,
|
||||
isPreconfigured: false,
|
||||
isSystemAction: true,
|
||||
name: 'System action: test.system-action-kibana-privileges',
|
||||
referencedByCount: 0,
|
||||
},
|
||||
{
|
||||
id: 'custom-system-abc-connector',
|
||||
isPreconfigured: true,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue