mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[Fleet] Couple agent and package policies spaces (#197487)
This commit is contained in:
parent
8fc7df26a5
commit
84dc8da610
7 changed files with 346 additions and 24 deletions
|
@ -113,6 +113,7 @@ export const createAppContextStartContractMock = (
|
|||
experimentalFeatures: {
|
||||
agentTamperProtectionEnabled: true,
|
||||
diagnosticFileUploadEnabled: true,
|
||||
enableReusableIntegrationPolicies: true,
|
||||
} as ExperimentalFeatures,
|
||||
isProductionMode: true,
|
||||
configInitialValue: {
|
||||
|
|
|
@ -76,9 +76,12 @@ import { sendTelemetryEvents } from './upgrade_sender';
|
|||
import { auditLoggingService } from './audit_logging';
|
||||
import { agentPolicyService } from './agent_policy';
|
||||
import { isSpaceAwarenessEnabled } from './spaces/helpers';
|
||||
import { licenseService } from './license';
|
||||
|
||||
jest.mock('./spaces/helpers');
|
||||
|
||||
jest.mock('./license');
|
||||
|
||||
const mockedSendTelemetryEvents = sendTelemetryEvents as jest.MockedFunction<
|
||||
typeof sendTelemetryEvents
|
||||
>;
|
||||
|
@ -207,7 +210,7 @@ const mockedAuditLoggingService = auditLoggingService as jest.Mocked<typeof audi
|
|||
|
||||
type CombinedExternalCallback = PutPackagePolicyUpdateCallback | PostPackagePolicyCreateCallback;
|
||||
|
||||
const mockAgentPolicyGet = () => {
|
||||
const mockAgentPolicyGet = (spaceIds: string[] = ['default']) => {
|
||||
mockAgentPolicyService.get.mockImplementation(
|
||||
(_soClient: SavedObjectsClientContract, id: string, _force = false, _errorMessage?: string) => {
|
||||
return Promise.resolve({
|
||||
|
@ -220,9 +223,29 @@ const mockAgentPolicyGet = () => {
|
|||
updated_by: 'test',
|
||||
revision: 1,
|
||||
is_protected: false,
|
||||
space_ids: spaceIds,
|
||||
});
|
||||
}
|
||||
);
|
||||
mockAgentPolicyService.getByIDs.mockImplementation(
|
||||
// @ts-ignore
|
||||
(_soClient: SavedObjectsClientContract, ids: string[]) => {
|
||||
return Promise.resolve(
|
||||
ids.map((id) => ({
|
||||
id,
|
||||
name: 'Test Agent Policy',
|
||||
namespace: 'test',
|
||||
status: 'active',
|
||||
is_managed: false,
|
||||
updated_at: new Date().toISOString(),
|
||||
updated_by: 'test',
|
||||
revision: 1,
|
||||
is_protected: false,
|
||||
space_ids: spaceIds,
|
||||
}))
|
||||
);
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
describe('Package policy service', () => {
|
||||
|
@ -240,6 +263,9 @@ describe('Package policy service', () => {
|
|||
});
|
||||
|
||||
describe('create', () => {
|
||||
beforeEach(() => {
|
||||
jest.mocked(licenseService.hasAtLeast).mockReturnValue(true);
|
||||
});
|
||||
it('should call audit logger', async () => {
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
const soClient = savedObjectsClientMock.create();
|
||||
|
@ -279,6 +305,46 @@ describe('Package policy service', () => {
|
|||
savedObjectType: LEGACY_PACKAGE_POLICY_SAVED_OBJECT_TYPE,
|
||||
});
|
||||
});
|
||||
|
||||
it('should not allow to add a reusable integration policies to an agent policies belonging to multiple spaces', async () => {
|
||||
jest.mocked(isSpaceAwarenessEnabled).mockResolvedValue(true);
|
||||
|
||||
const esClient = elasticsearchServiceMock.createClusterClient().asInternalUser;
|
||||
const soClient = savedObjectsClientMock.create();
|
||||
|
||||
soClient.create.mockResolvedValueOnce({
|
||||
id: 'test-package-policy',
|
||||
attributes: {},
|
||||
references: [],
|
||||
type: PACKAGE_POLICY_SAVED_OBJECT_TYPE,
|
||||
});
|
||||
|
||||
mockAgentPolicyGet(['test', 'default']);
|
||||
|
||||
await expect(
|
||||
packagePolicyService.create(
|
||||
soClient,
|
||||
esClient,
|
||||
{
|
||||
name: 'Test Package Policy',
|
||||
namespace: 'test',
|
||||
enabled: true,
|
||||
policy_id: 'test',
|
||||
policy_ids: ['test1', 'test2'],
|
||||
inputs: [],
|
||||
package: {
|
||||
name: 'test',
|
||||
title: 'Test',
|
||||
version: '0.0.1',
|
||||
},
|
||||
},
|
||||
// Skipping unique name verification just means we have to less mocking/setup
|
||||
{ id: 'test-package-policy', skipUniqueNameVerification: true }
|
||||
)
|
||||
).rejects.toThrowError(
|
||||
/Reusable integration policies cannot be used with agent policies belonging to multiple spaces./
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('inspect', () => {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
/* eslint-disable max-classes-per-file */
|
||||
|
||||
import { omit, partition, isEqual, cloneDeep, without } from 'lodash';
|
||||
import { indexBy } from 'lodash/fp';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import semverLt from 'semver/functions/lt';
|
||||
import { getFlattenedObject } from '@kbn/std';
|
||||
|
@ -144,6 +145,7 @@ import { validateAgentPolicyOutputForIntegration } from './agent_policies/output
|
|||
import type { PackagePolicyClientFetchAllItemIdsOptions } from './package_policy_service';
|
||||
import { validatePolicyNamespaceForSpace } from './spaces/policy_namespaces';
|
||||
import { isSpaceAwarenessEnabled, isSpaceAwarenessMigrationPending } from './spaces/helpers';
|
||||
import { updatePackagePolicySpaces } from './spaces/package_policy';
|
||||
|
||||
export type InputsOverride = Partial<NewPackagePolicyInput> & {
|
||||
vars?: Array<NewPackagePolicyInput['vars'] & { name: string }>;
|
||||
|
@ -227,6 +229,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient {
|
|||
context?: RequestHandlerContext,
|
||||
request?: KibanaRequest
|
||||
): Promise<PackagePolicy> {
|
||||
const useSpaceAwareness = await isSpaceAwarenessEnabled();
|
||||
const packagePolicyId = options?.id || uuidv4();
|
||||
|
||||
let authorizationHeader = options.authorizationHeader;
|
||||
|
@ -274,6 +277,10 @@ class PackagePolicyClientImpl implements PackagePolicyClient {
|
|||
|
||||
for (const policyId of enrichedPackagePolicy.policy_ids) {
|
||||
const agentPolicy = await agentPolicyService.get(soClient, policyId, true);
|
||||
if (!agentPolicy) {
|
||||
throw new AgentPolicyNotFoundError('Agent policy not found');
|
||||
}
|
||||
|
||||
agentPolicies.push(agentPolicy);
|
||||
|
||||
// If package policy did not set an output_id, see if the agent policy's output is compatible
|
||||
|
@ -285,7 +292,10 @@ class PackagePolicyClientImpl implements PackagePolicyClient {
|
|||
);
|
||||
}
|
||||
|
||||
await validateIsNotHostedPolicy(soClient, policyId, options?.force);
|
||||
validateIsNotHostedPolicy(agentPolicy, options?.force);
|
||||
if (useSpaceAwareness) {
|
||||
validateReusableIntegrationsAndSpaceAwareness(enrichedPackagePolicy, agentPolicies);
|
||||
}
|
||||
}
|
||||
|
||||
// trailing whitespace causes issues creating API keys
|
||||
|
@ -413,6 +423,21 @@ class PackagePolicyClientImpl implements PackagePolicyClient {
|
|||
{ ...options, id: packagePolicyId }
|
||||
);
|
||||
|
||||
for (const agentPolicy of agentPolicies) {
|
||||
if (
|
||||
useSpaceAwareness &&
|
||||
agentPolicy &&
|
||||
agentPolicy.space_ids &&
|
||||
agentPolicy.space_ids.length > 1
|
||||
) {
|
||||
await updatePackagePolicySpaces({
|
||||
packagePolicyId: newSo.id,
|
||||
currentSpaceId: soClient.getCurrentNamespace() ?? DEFAULT_SPACE_ID,
|
||||
newSpaceIds: agentPolicy.space_ids,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (options?.bumpRevision ?? true) {
|
||||
for (const policyId of enrichedPackagePolicy.policy_ids) {
|
||||
await agentPolicyService.bumpRevision(soClient, esClient, policyId, {
|
||||
|
@ -460,6 +485,7 @@ class PackagePolicyClientImpl implements PackagePolicyClient {
|
|||
created: PackagePolicy[];
|
||||
failed: Array<{ packagePolicy: NewPackagePolicy; error?: Error | SavedObjectError }>;
|
||||
}> {
|
||||
const useSpaceAwareness = await isSpaceAwarenessEnabled();
|
||||
const savedObjectType = await getPackagePolicySavedObjectType();
|
||||
for (const packagePolicy of packagePolicies) {
|
||||
const basePkgInfo = packagePolicy.package
|
||||
|
@ -486,8 +512,20 @@ class PackagePolicyClientImpl implements PackagePolicyClient {
|
|||
|
||||
const agentPolicyIds = new Set(packagePolicies.flatMap((pkgPolicy) => pkgPolicy.policy_ids));
|
||||
|
||||
for (const agentPolicyId of agentPolicyIds) {
|
||||
await validateIsNotHostedPolicy(soClient, agentPolicyId, options?.force);
|
||||
const agentPolicies = await agentPolicyService.getByIDs(soClient, [...agentPolicyIds]);
|
||||
const agentPoliciesIndexById = indexBy('id', agentPolicies);
|
||||
for (const agentPolicy of agentPolicies) {
|
||||
validateIsNotHostedPolicy(agentPolicy, options?.force);
|
||||
}
|
||||
if (useSpaceAwareness) {
|
||||
for (const packagePolicy of packagePolicies) {
|
||||
validateReusableIntegrationsAndSpaceAwareness(
|
||||
packagePolicy,
|
||||
packagePolicy.policy_ids
|
||||
.map((policyId) => agentPoliciesIndexById[policyId])
|
||||
.filter((policy) => policy !== undefined)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const packageInfos = await getPackageInfoForPackagePolicies(packagePolicies, soClient);
|
||||
|
@ -604,6 +642,23 @@ class PackagePolicyClientImpl implements PackagePolicyClient {
|
|||
}
|
||||
});
|
||||
|
||||
if (useSpaceAwareness) {
|
||||
for (const newSo of newSos) {
|
||||
// Do not support multpile spaces for reusable integrations
|
||||
if (newSo.attributes.policy_ids.length > 1) {
|
||||
continue;
|
||||
}
|
||||
const agentPolicy = agentPoliciesIndexById[newSo.attributes.policy_ids[0]];
|
||||
if (agentPolicy && agentPolicy.space_ids && agentPolicy.space_ids.length > 1) {
|
||||
await updatePackagePolicySpaces({
|
||||
packagePolicyId: newSo.id,
|
||||
currentSpaceId: soClient.getCurrentNamespace() ?? DEFAULT_SPACE_ID,
|
||||
newSpaceIds: agentPolicy.space_ids,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Assign it to the given agent policy
|
||||
|
||||
if (options?.bumpRevision ?? true) {
|
||||
|
@ -1001,6 +1056,17 @@ class PackagePolicyClientImpl implements PackagePolicyClient {
|
|||
}
|
||||
}
|
||||
|
||||
if ((packagePolicyUpdate.policy_ids?.length ?? 0) > 1) {
|
||||
for (const policyId of packagePolicyUpdate.policy_ids) {
|
||||
const agentPolicy = await agentPolicyService.get(soClient, policyId, true);
|
||||
if ((agentPolicy?.space_ids?.length ?? 0) > 1) {
|
||||
throw new FleetError(
|
||||
'Reusable integration policies cannot be used with agent policies belonging to multiple spaces.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle component template/mappings updates for experimental features, e.g. synthetic source
|
||||
await handleExperimentalDatastreamFeatureOptIn({
|
||||
soClient,
|
||||
|
@ -1391,9 +1457,13 @@ class PackagePolicyClientImpl implements PackagePolicyClient {
|
|||
|
||||
for (const agentPolicyId of uniqueAgentPolicyIds) {
|
||||
try {
|
||||
const agentPolicy = await validateIsNotHostedPolicy(
|
||||
soClient,
|
||||
agentPolicyId,
|
||||
const agentPolicy = await agentPolicyService.get(soClient, agentPolicyId);
|
||||
if (!agentPolicy) {
|
||||
throw new AgentPolicyNotFoundError('Agent policy not found');
|
||||
}
|
||||
|
||||
validateIsNotHostedPolicy(
|
||||
agentPolicy,
|
||||
options?.force,
|
||||
'Cannot remove integrations of hosted agent policy'
|
||||
);
|
||||
|
@ -3025,27 +3095,30 @@ export function _validateRestrictedFieldsNotModifiedOrThrow(opts: {
|
|||
}
|
||||
}
|
||||
|
||||
async function validateIsNotHostedPolicy(
|
||||
soClient: SavedObjectsClientContract,
|
||||
id: string,
|
||||
force = false,
|
||||
errorMessage?: string
|
||||
): Promise<AgentPolicy> {
|
||||
const agentPolicy = await agentPolicyService.get(soClient, id, false);
|
||||
|
||||
if (!agentPolicy) {
|
||||
throw new AgentPolicyNotFoundError('Agent policy not found');
|
||||
function validateReusableIntegrationsAndSpaceAwareness(
|
||||
packagePolicy: Pick<NewPackagePolicy, 'policy_ids'>,
|
||||
agentPolicies: AgentPolicy[]
|
||||
) {
|
||||
if ((packagePolicy.policy_ids.length ?? 0) <= 1) {
|
||||
return;
|
||||
}
|
||||
for (const agentPolicy of agentPolicies) {
|
||||
if ((agentPolicy?.space_ids?.length ?? 0) > 1) {
|
||||
throw new FleetError(
|
||||
'Reusable integration policies cannot be used with agent policies belonging to multiple spaces.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function validateIsNotHostedPolicy(agentPolicy: AgentPolicy, force = false, errorMessage?: string) {
|
||||
const isManagedPolicyWithoutServerlessSupport = agentPolicy.is_managed && !force;
|
||||
|
||||
if (isManagedPolicyWithoutServerlessSupport) {
|
||||
throw new HostedAgentPolicyRestrictionRelatedError(
|
||||
errorMessage ?? `Cannot update integrations of hosted agent policy ${id}`
|
||||
errorMessage ?? `Cannot update integrations of hosted agent policy ${agentPolicy.id}`
|
||||
);
|
||||
}
|
||||
|
||||
return agentPolicy;
|
||||
}
|
||||
|
||||
export function sendUpdatePackagePolicyTelemetryEvent(
|
||||
|
|
136
x-pack/plugins/fleet/server/services/spaces/agent_policy.test.ts
Normal file
136
x-pack/plugins/fleet/server/services/spaces/agent_policy.test.ts
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* 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 { createAppContextStartContractMock } from '../../mocks';
|
||||
import { agentPolicyService } from '../agent_policy';
|
||||
import { appContextService } from '../app_context';
|
||||
import { packagePolicyService } from '../package_policy';
|
||||
|
||||
import { updateAgentPolicySpaces } from './agent_policy';
|
||||
import { isSpaceAwarenessEnabled } from './helpers';
|
||||
|
||||
jest.mock('./helpers');
|
||||
jest.mock('../agent_policy');
|
||||
jest.mock('../package_policy');
|
||||
|
||||
describe('updateAgentPolicySpaces', () => {
|
||||
beforeEach(() => {
|
||||
jest.mocked(isSpaceAwarenessEnabled).mockResolvedValue(true);
|
||||
jest.mocked(agentPolicyService.get).mockResolvedValue({
|
||||
id: 'policy1',
|
||||
space_ids: ['default'],
|
||||
} as any);
|
||||
jest.mocked(packagePolicyService.findAllForAgentPolicy).mockResolvedValue([
|
||||
{
|
||||
id: 'package-policy-1',
|
||||
policy_ids: ['policy1'],
|
||||
},
|
||||
{
|
||||
id: 'package-policy-2',
|
||||
policy_ids: ['policy1'],
|
||||
},
|
||||
] as any);
|
||||
appContextService.start(createAppContextStartContractMock());
|
||||
|
||||
jest
|
||||
.mocked(appContextService.getInternalUserSOClientWithoutSpaceExtension())
|
||||
.updateObjectsSpaces.mockResolvedValue({ objects: [] });
|
||||
});
|
||||
|
||||
it('does nothings if agent policy already in correct space', async () => {
|
||||
await updateAgentPolicySpaces({
|
||||
agentPolicyId: 'policy1',
|
||||
currentSpaceId: 'default',
|
||||
newSpaceIds: ['default'],
|
||||
authorizedSpaces: ['default'],
|
||||
});
|
||||
expect(
|
||||
appContextService.getInternalUserSOClientWithoutSpaceExtension().updateObjectsSpaces
|
||||
).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('does nothing if feature flag is not enabled', async () => {
|
||||
jest.mocked(isSpaceAwarenessEnabled).mockResolvedValue(false);
|
||||
await updateAgentPolicySpaces({
|
||||
agentPolicyId: 'policy1',
|
||||
currentSpaceId: 'default',
|
||||
newSpaceIds: ['test'],
|
||||
authorizedSpaces: ['test', 'default'],
|
||||
});
|
||||
|
||||
expect(
|
||||
appContextService.getInternalUserSOClientWithoutSpaceExtension().updateObjectsSpaces
|
||||
).not.toBeCalled();
|
||||
});
|
||||
|
||||
it('allow to change spaces', async () => {
|
||||
await updateAgentPolicySpaces({
|
||||
agentPolicyId: 'policy1',
|
||||
currentSpaceId: 'default',
|
||||
newSpaceIds: ['test'],
|
||||
authorizedSpaces: ['test', 'default'],
|
||||
});
|
||||
|
||||
expect(
|
||||
appContextService.getInternalUserSOClientWithoutSpaceExtension().updateObjectsSpaces
|
||||
).toBeCalledWith(
|
||||
[
|
||||
{ id: 'policy1', type: 'fleet-agent-policies' },
|
||||
{ id: 'package-policy-1', type: 'fleet-package-policies' },
|
||||
{ id: 'package-policy-2', type: 'fleet-package-policies' },
|
||||
],
|
||||
['test'],
|
||||
['default'],
|
||||
{ namespace: 'default', refresh: 'wait_for' }
|
||||
);
|
||||
});
|
||||
|
||||
it('throw when trying to change space to a policy with reusable package policies', async () => {
|
||||
jest.mocked(packagePolicyService.findAllForAgentPolicy).mockResolvedValue([
|
||||
{
|
||||
id: 'package-policy-1',
|
||||
policy_ids: ['policy1'],
|
||||
},
|
||||
{
|
||||
id: 'package-policy-2',
|
||||
policy_ids: ['policy1', 'policy2'],
|
||||
},
|
||||
] as any);
|
||||
await expect(
|
||||
updateAgentPolicySpaces({
|
||||
agentPolicyId: 'policy1',
|
||||
currentSpaceId: 'default',
|
||||
newSpaceIds: ['test'],
|
||||
authorizedSpaces: ['test', 'default'],
|
||||
})
|
||||
).rejects.toThrowError(
|
||||
/Agent policies using reusable integration policies cannot be moved to a different space./
|
||||
);
|
||||
});
|
||||
|
||||
it('throw when trying to add a space with missing permissions', async () => {
|
||||
await expect(
|
||||
updateAgentPolicySpaces({
|
||||
agentPolicyId: 'policy1',
|
||||
currentSpaceId: 'default',
|
||||
newSpaceIds: ['default', 'test'],
|
||||
authorizedSpaces: ['default'],
|
||||
})
|
||||
).rejects.toThrowError(/Not enough permissions to create policies in space test/);
|
||||
});
|
||||
|
||||
it('throw when trying to remove a space with missing permissions', async () => {
|
||||
await expect(
|
||||
updateAgentPolicySpaces({
|
||||
agentPolicyId: 'policy1',
|
||||
currentSpaceId: 'default',
|
||||
newSpaceIds: ['test'],
|
||||
authorizedSpaces: ['test'],
|
||||
})
|
||||
).rejects.toThrowError(/Not enough permissions to remove policies from space default/);
|
||||
});
|
||||
});
|
|
@ -54,6 +54,11 @@ export async function updateAgentPolicySpaces({
|
|||
return;
|
||||
}
|
||||
|
||||
if (existingPackagePolicies.some((packagePolicy) => packagePolicy.policy_ids.length > 1)) {
|
||||
throw new FleetError(
|
||||
'Agent policies using reusable integration policies cannot be moved to a different space.'
|
||||
);
|
||||
}
|
||||
const spacesToAdd = newSpaceIds.filter(
|
||||
(spaceId) => !existingPolicy?.space_ids?.includes(spaceId) ?? true
|
||||
);
|
||||
|
@ -63,13 +68,13 @@ export async function updateAgentPolicySpaces({
|
|||
// Privileges check
|
||||
for (const spaceId of spacesToAdd) {
|
||||
if (!authorizedSpaces.includes(spaceId)) {
|
||||
throw new FleetError(`No enough permissions to create policies in space ${spaceId}`);
|
||||
throw new FleetError(`Not enough permissions to create policies in space ${spaceId}`);
|
||||
}
|
||||
}
|
||||
|
||||
for (const spaceId of spacesToRemove) {
|
||||
if (!authorizedSpaces.includes(spaceId)) {
|
||||
throw new FleetError(`No enough permissions to remove policies from space ${spaceId}`);
|
||||
throw new FleetError(`Not enough permissions to remove policies from space ${spaceId}`);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* 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 { PACKAGE_POLICY_SAVED_OBJECT_TYPE } from '../../../common/constants';
|
||||
|
||||
import { appContextService } from '../app_context';
|
||||
|
||||
export async function updatePackagePolicySpaces({
|
||||
packagePolicyId,
|
||||
currentSpaceId,
|
||||
newSpaceIds,
|
||||
}: {
|
||||
packagePolicyId: string;
|
||||
currentSpaceId: string;
|
||||
newSpaceIds: string[];
|
||||
}) {
|
||||
const soClientWithoutSpaceExtension =
|
||||
appContextService.getInternalUserSOClientWithoutSpaceExtension();
|
||||
|
||||
const results = await soClientWithoutSpaceExtension.updateObjectsSpaces(
|
||||
[
|
||||
{
|
||||
id: packagePolicyId,
|
||||
type: PACKAGE_POLICY_SAVED_OBJECT_TYPE,
|
||||
},
|
||||
],
|
||||
newSpaceIds,
|
||||
[],
|
||||
{ refresh: 'wait_for', namespace: currentSpaceId }
|
||||
);
|
||||
|
||||
for (const soRes of results.objects) {
|
||||
if (soRes.error) {
|
||||
throw soRes.error;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -165,7 +165,7 @@ export default function (providerContext: FtrProviderContext) {
|
|||
description: 'tata',
|
||||
space_ids: ['default', TEST_SPACE_1],
|
||||
}),
|
||||
/400 Bad Request No enough permissions to create policies in space test1/
|
||||
/400 Bad Request Not enough permissions to create policies in space test1/
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -190,7 +190,7 @@ export default function (providerContext: FtrProviderContext) {
|
|||
description: 'tata',
|
||||
space_ids: ['default'],
|
||||
}),
|
||||
/400 Bad Request No enough permissions to remove policies from space test1/
|
||||
/400 Bad Request Not enough permissions to remove policies from space test1/
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue