Skip to content

Commit 2b84d3a

Browse files
[SOR] Added support for name attribute in create/update SOR functions (elastic#228464)
## Summary Added support for name attribute in create/update SOR functions. ### Checklist - [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 - [x] The PR description includes the appropriate Release Notes section, and the correct `release_note:*` label is applied per the [guidelines](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process) __Closes: https://github.com/elastic/kibana/issues/228463__ ### Release Note Added support for the `name` attribute in create and update actions for saved objects.
1 parent a48f653 commit 2b84d3a

File tree

5 files changed

+70
-1
lines changed

5 files changed

+70
-1
lines changed

src/core/packages/saved-objects/api-server-internal/src/lib/apis/create.test.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ import { loggerMock } from '@kbn/logging-mocks';
3131
import { SavedObjectsSerializer } from '@kbn/core-saved-objects-base-server-internal';
3232
import { kibanaMigratorMock } from '../../mocks';
3333
import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks';
34+
import { savedObjectsExtensionsMock } from '../../mocks/saved_objects_extensions.mock';
35+
import type { ISavedObjectsSecurityExtension } from '@kbn/core-saved-objects-server';
3436

3537
import {
3638
CUSTOM_INDEX_TYPE,
@@ -57,6 +59,7 @@ describe('#create', () => {
5759
let migrator: ReturnType<typeof kibanaMigratorMock.create>;
5860
let logger: ReturnType<typeof loggerMock.create>;
5961
let serializer: jest.Mocked<SavedObjectsSerializer>;
62+
let securityExtension: jest.Mocked<ISavedObjectsSecurityExtension>;
6063

6164
const registry = createRegistry();
6265
const documentMigrator = createDocumentMigrator(registry);
@@ -80,6 +83,7 @@ describe('#create', () => {
8083
migrator.migrateDocument = jest.fn().mockImplementation(documentMigrator.migrate);
8184
migrator.runMigrations = jest.fn().mockResolvedValue([{ status: 'skipped' }]);
8285
logger = loggerMock.create();
86+
securityExtension = savedObjectsExtensionsMock.createSecurityExtension();
8387

8488
// create a mock serializer "shim" so we can track function calls, but use the real serializer's implementation
8589
serializer = createSpySerializer(registry);
@@ -97,6 +101,9 @@ describe('#create', () => {
97101
serializer,
98102
allowedTypes,
99103
logger,
104+
extensions: {
105+
securityExtension,
106+
},
100107
});
101108

102109
mockGetCurrentTime.mockReturnValue(mockTimestamp);
@@ -829,5 +836,20 @@ describe('#create', () => {
829836
});
830837
});
831838
});
839+
840+
describe('security', () => {
841+
it('correctly passes params to securityExtension.authorizeCreate', async () => {
842+
await createSuccess(type, attributes, { overwrite: true });
843+
844+
expect(securityExtension.authorizeCreate).toHaveBeenCalledWith(
845+
expect.objectContaining({
846+
object: expect.objectContaining({
847+
name: 'Logstash',
848+
type: 'index-pattern',
849+
}),
850+
})
851+
);
852+
});
853+
});
832854
});
833855
});

src/core/packages/saved-objects/api-server-internal/src/lib/apis/create.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ export const performCreate = async <T>(
109109
id,
110110
initialNamespaces,
111111
existingNamespaces: preflightResult?.existingDocument?._source?.namespaces ?? [],
112+
name: SavedObjectsUtils.getName(registry.getNameAttribute(type), {
113+
attributes: {
114+
...(preflightResult?.existingDocument?._source?.[type] ?? {}),
115+
...attributes,
116+
},
117+
}),
112118
},
113119
});
114120

src/core/packages/saved-objects/api-server-internal/src/lib/apis/update.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ import {
2727
} from '@kbn/core-saved-objects-base-server-internal';
2828
import { elasticsearchClientMock } from '@kbn/core-elasticsearch-client-server-mocks';
2929
import { kibanaMigratorMock } from '../../mocks';
30+
import { savedObjectsExtensionsMock } from '../../mocks/saved_objects_extensions.mock';
31+
import type { ISavedObjectsSecurityExtension } from '@kbn/core-saved-objects-server';
3032
import {
3133
NAMESPACE_AGNOSTIC_TYPE,
3234
MULTI_NAMESPACE_ISOLATED_TYPE,
@@ -53,6 +55,7 @@ describe('#update', () => {
5355
let migrator: ReturnType<typeof kibanaMigratorMock.create>;
5456
let logger: ReturnType<typeof loggerMock.create>;
5557
let serializer: jest.Mocked<SavedObjectsSerializer>;
58+
let securityExtension: jest.Mocked<ISavedObjectsSecurityExtension>;
5659

5760
const registry = createRegistry();
5861
const documentMigrator = createDocumentMigrator(registry);
@@ -75,6 +78,7 @@ describe('#update', () => {
7578
migrator.migrateDocument = jest.fn().mockImplementation(documentMigrator.migrate);
7679
migrator.runMigrations = jest.fn().mockResolvedValue([{ status: 'skipped' }]);
7780
logger = loggerMock.create();
81+
securityExtension = savedObjectsExtensionsMock.createSecurityExtension();
7882

7983
// create a mock serializer "shim" so we can track function calls, but use the real serializer's implementation
8084
serializer = createSpySerializer(registry);
@@ -92,6 +96,9 @@ describe('#update', () => {
9296
serializer,
9397
allowedTypes,
9498
logger,
99+
extensions: {
100+
securityExtension,
101+
},
95102
});
96103

97104
mockGetCurrentTime.mockReturnValue(mockTimestamp);
@@ -803,5 +810,30 @@ describe('#update', () => {
803810
expect(result).toMatchObject({ originId });
804811
});
805812
});
813+
814+
describe('security', () => {
815+
it('correctly passes params to securityExtension.authorizeUpdate', async () => {
816+
await updateSuccess(
817+
client,
818+
repository,
819+
registry,
820+
MULTI_NAMESPACE_ISOLATED_TYPE,
821+
id,
822+
attributes,
823+
{ references }
824+
);
825+
826+
expect(securityExtension.authorizeUpdate).toHaveBeenCalledWith(
827+
expect.objectContaining({
828+
object: {
829+
existingNamespaces: ['default'],
830+
id: 'logstash-*',
831+
name: 'Testing',
832+
type: 'multiNamespaceIsolatedType',
833+
},
834+
})
835+
);
836+
});
837+
});
806838
});
807839
});

src/core/packages/saved-objects/api-server-internal/src/lib/apis/update.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,15 @@ export const executeUpdate = async <T>(
112112
const existingNamespaces = preflightDocNSResult.savedObjectNamespaces ?? [];
113113
const authorizationResult = await securityExtension?.authorizeUpdate({
114114
namespace,
115-
object: { type, id, existingNamespaces },
115+
object: {
116+
type,
117+
id,
118+
existingNamespaces,
119+
objectNamespace: namespace && registry.isSingleNamespace(type) ? namespace : undefined,
120+
name: SavedObjectsUtils.getName(registry.getNameAttribute(type), {
121+
attributes: { ...(preflightDocResult.rawDocSource?._source?.[type] ?? {}), ...attributes },
122+
}),
123+
},
116124
});
117125

118126
// validate if an update (directly update or create the object instead) can be done, based on if the doc exists or not

src/core/packages/saved-objects/api-server-internal/src/lib/repository.security_extension.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ describe('SavedObjectsRepository Security Extension', () => {
281281
type: 'multiNamespaceTypeCustomIndex',
282282
id: expect.objectContaining(/index-pattern:[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}/),
283283
existingNamespaces: multiNamespaceObjNamespaces,
284+
name: 'Testing',
284285
};
285286

286287
const { namespace: actualNamespace, object: actualObject } =

0 commit comments

Comments
 (0)