@backstage/backend-defaults 0.7.0 → 0.8.0-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +46 -0
- package/dist/CreateBackend.cjs.js +4 -0
- package/dist/CreateBackend.cjs.js.map +1 -1
- package/dist/auditor.cjs.js +12 -0
- package/dist/auditor.cjs.js.map +1 -0
- package/dist/auditor.d.ts +166 -0
- package/dist/entrypoints/auditor/DefaultAuditorService.cjs.js +83 -0
- package/dist/entrypoints/auditor/DefaultAuditorService.cjs.js.map +1 -0
- package/dist/entrypoints/auditor/WinstonRootAuditorService.cjs.js +74 -0
- package/dist/entrypoints/auditor/WinstonRootAuditorService.cjs.js.map +1 -0
- package/dist/entrypoints/auditor/auditorServiceFactory.cjs.js +24 -0
- package/dist/entrypoints/auditor/auditorServiceFactory.cjs.js.map +1 -0
- package/dist/entrypoints/database/connectors/postgres.cjs.js +1 -1
- package/dist/entrypoints/database/connectors/postgres.cjs.js.map +1 -1
- package/dist/entrypoints/permissionsRegistry/permissionsRegistryServiceFactory.cjs.js +49 -0
- package/dist/entrypoints/permissionsRegistry/permissionsRegistryServiceFactory.cjs.js.map +1 -0
- package/dist/package.json.cjs.js +18 -10
- package/dist/package.json.cjs.js.map +1 -1
- package/dist/permissionsRegistry.cjs.js +8 -0
- package/dist/permissionsRegistry.cjs.js.map +1 -0
- package/dist/permissionsRegistry.d.ts +14 -0
- package/package.json +42 -26
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,51 @@
|
|
|
1
1
|
# @backstage/backend-defaults
|
|
2
2
|
|
|
3
|
+
## 0.8.0-next.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies
|
|
8
|
+
- @backstage/backend-app-api@1.1.2-next.1
|
|
9
|
+
- @backstage/backend-dev-utils@0.1.5
|
|
10
|
+
- @backstage/backend-plugin-api@1.2.0-next.0
|
|
11
|
+
- @backstage/cli-common@0.1.15
|
|
12
|
+
- @backstage/cli-node@0.2.13-next.0
|
|
13
|
+
- @backstage/config@1.3.2
|
|
14
|
+
- @backstage/config-loader@1.9.6-next.0
|
|
15
|
+
- @backstage/errors@1.2.7
|
|
16
|
+
- @backstage/integration@1.16.1
|
|
17
|
+
- @backstage/integration-aws-node@0.1.15
|
|
18
|
+
- @backstage/types@1.2.1
|
|
19
|
+
- @backstage/plugin-auth-node@0.5.7-next.0
|
|
20
|
+
- @backstage/plugin-events-node@0.4.8-next.0
|
|
21
|
+
- @backstage/plugin-permission-node@0.8.8-next.0
|
|
22
|
+
|
|
23
|
+
## 0.8.0-next.0
|
|
24
|
+
|
|
25
|
+
### Minor Changes
|
|
26
|
+
|
|
27
|
+
- a4aa244: This change introduces the `auditor` service implementation details.
|
|
28
|
+
|
|
29
|
+
### Patch Changes
|
|
30
|
+
|
|
31
|
+
- f866b86: Internal refactor to use explicit `require` for lazy-loading dependency.
|
|
32
|
+
- a19cb2b: Added default implementation for the new `PermissionsRegistryService`.
|
|
33
|
+
- Updated dependencies
|
|
34
|
+
- @backstage/cli-node@0.2.13-next.0
|
|
35
|
+
- @backstage/plugin-permission-node@0.8.8-next.0
|
|
36
|
+
- @backstage/config-loader@1.9.6-next.0
|
|
37
|
+
- @backstage/backend-plugin-api@1.2.0-next.0
|
|
38
|
+
- @backstage/backend-app-api@1.1.2-next.0
|
|
39
|
+
- @backstage/backend-dev-utils@0.1.5
|
|
40
|
+
- @backstage/cli-common@0.1.15
|
|
41
|
+
- @backstage/config@1.3.2
|
|
42
|
+
- @backstage/errors@1.2.7
|
|
43
|
+
- @backstage/integration@1.16.1
|
|
44
|
+
- @backstage/integration-aws-node@0.1.15
|
|
45
|
+
- @backstage/types@1.2.1
|
|
46
|
+
- @backstage/plugin-auth-node@0.5.7-next.0
|
|
47
|
+
- @backstage/plugin-events-node@0.4.8-next.0
|
|
48
|
+
|
|
3
49
|
## 0.7.0
|
|
4
50
|
|
|
5
51
|
### Minor Changes
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var backendAppApi = require('@backstage/backend-app-api');
|
|
4
|
+
var auditor = require('@backstage/backend-defaults/auditor');
|
|
4
5
|
var auth = require('@backstage/backend-defaults/auth');
|
|
5
6
|
var cache = require('@backstage/backend-defaults/cache');
|
|
6
7
|
var database = require('@backstage/backend-defaults/database');
|
|
@@ -10,6 +11,7 @@ var httpRouter = require('@backstage/backend-defaults/httpRouter');
|
|
|
10
11
|
var lifecycle = require('@backstage/backend-defaults/lifecycle');
|
|
11
12
|
var logger = require('@backstage/backend-defaults/logger');
|
|
12
13
|
var permissions = require('@backstage/backend-defaults/permissions');
|
|
14
|
+
var permissionsRegistry = require('@backstage/backend-defaults/permissionsRegistry');
|
|
13
15
|
var rootConfig = require('@backstage/backend-defaults/rootConfig');
|
|
14
16
|
var rootHealth = require('@backstage/backend-defaults/rootHealth');
|
|
15
17
|
var rootHttpRouter = require('@backstage/backend-defaults/rootHttpRouter');
|
|
@@ -21,6 +23,7 @@ var userInfo = require('@backstage/backend-defaults/userInfo');
|
|
|
21
23
|
var pluginEventsNode = require('@backstage/plugin-events-node');
|
|
22
24
|
|
|
23
25
|
const defaultServiceFactories = [
|
|
26
|
+
auditor.auditorServiceFactory,
|
|
24
27
|
auth.authServiceFactory,
|
|
25
28
|
cache.cacheServiceFactory,
|
|
26
29
|
rootConfig.rootConfigServiceFactory,
|
|
@@ -31,6 +34,7 @@ const defaultServiceFactories = [
|
|
|
31
34
|
lifecycle.lifecycleServiceFactory,
|
|
32
35
|
logger.loggerServiceFactory,
|
|
33
36
|
permissions.permissionsServiceFactory,
|
|
37
|
+
permissionsRegistry.permissionsRegistryServiceFactory,
|
|
34
38
|
rootHealth.rootHealthServiceFactory,
|
|
35
39
|
rootHttpRouter.rootHttpRouterServiceFactory,
|
|
36
40
|
rootLifecycle.rootLifecycleServiceFactory,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateBackend.cjs.js","sources":["../src/CreateBackend.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Backend, createSpecializedBackend } from '@backstage/backend-app-api';\nimport { authServiceFactory } from '@backstage/backend-defaults/auth';\nimport { cacheServiceFactory } from '@backstage/backend-defaults/cache';\nimport { databaseServiceFactory } from '@backstage/backend-defaults/database';\nimport { discoveryServiceFactory } from '@backstage/backend-defaults/discovery';\nimport { httpAuthServiceFactory } from '@backstage/backend-defaults/httpAuth';\nimport { httpRouterServiceFactory } from '@backstage/backend-defaults/httpRouter';\nimport { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle';\nimport { loggerServiceFactory } from '@backstage/backend-defaults/logger';\nimport { permissionsServiceFactory } from '@backstage/backend-defaults/permissions';\nimport { rootConfigServiceFactory } from '@backstage/backend-defaults/rootConfig';\nimport { rootHealthServiceFactory } from '@backstage/backend-defaults/rootHealth';\nimport { rootHttpRouterServiceFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle';\nimport { rootLoggerServiceFactory } from '@backstage/backend-defaults/rootLogger';\nimport { schedulerServiceFactory } from '@backstage/backend-defaults/scheduler';\nimport { urlReaderServiceFactory } from '@backstage/backend-defaults/urlReader';\nimport { userInfoServiceFactory } from '@backstage/backend-defaults/userInfo';\nimport { eventsServiceFactory } from '@backstage/plugin-events-node';\n\nexport const defaultServiceFactories = [\n authServiceFactory,\n cacheServiceFactory,\n rootConfigServiceFactory,\n databaseServiceFactory,\n discoveryServiceFactory,\n httpAuthServiceFactory,\n httpRouterServiceFactory,\n lifecycleServiceFactory,\n loggerServiceFactory,\n permissionsServiceFactory,\n rootHealthServiceFactory,\n rootHttpRouterServiceFactory,\n rootLifecycleServiceFactory,\n rootLoggerServiceFactory,\n schedulerServiceFactory,\n userInfoServiceFactory,\n urlReaderServiceFactory,\n eventsServiceFactory,\n];\n\n/**\n * @public\n */\nexport function createBackend(): Backend {\n return createSpecializedBackend({ defaultServiceFactories });\n}\n"],"names":["authServiceFactory","cacheServiceFactory","rootConfigServiceFactory","databaseServiceFactory","discoveryServiceFactory","httpAuthServiceFactory","httpRouterServiceFactory","lifecycleServiceFactory","loggerServiceFactory","permissionsServiceFactory","rootHealthServiceFactory","rootHttpRouterServiceFactory","rootLifecycleServiceFactory","rootLoggerServiceFactory","schedulerServiceFactory","userInfoServiceFactory","urlReaderServiceFactory","eventsServiceFactory","createSpecializedBackend"],"mappings":"
|
|
1
|
+
{"version":3,"file":"CreateBackend.cjs.js","sources":["../src/CreateBackend.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { Backend, createSpecializedBackend } from '@backstage/backend-app-api';\nimport { auditorServiceFactory } from '@backstage/backend-defaults/auditor';\nimport { authServiceFactory } from '@backstage/backend-defaults/auth';\nimport { cacheServiceFactory } from '@backstage/backend-defaults/cache';\nimport { databaseServiceFactory } from '@backstage/backend-defaults/database';\nimport { discoveryServiceFactory } from '@backstage/backend-defaults/discovery';\nimport { httpAuthServiceFactory } from '@backstage/backend-defaults/httpAuth';\nimport { httpRouterServiceFactory } from '@backstage/backend-defaults/httpRouter';\nimport { lifecycleServiceFactory } from '@backstage/backend-defaults/lifecycle';\nimport { loggerServiceFactory } from '@backstage/backend-defaults/logger';\nimport { permissionsServiceFactory } from '@backstage/backend-defaults/permissions';\nimport { permissionsRegistryServiceFactory } from '@backstage/backend-defaults/permissionsRegistry';\nimport { rootConfigServiceFactory } from '@backstage/backend-defaults/rootConfig';\nimport { rootHealthServiceFactory } from '@backstage/backend-defaults/rootHealth';\nimport { rootHttpRouterServiceFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport { rootLifecycleServiceFactory } from '@backstage/backend-defaults/rootLifecycle';\nimport { rootLoggerServiceFactory } from '@backstage/backend-defaults/rootLogger';\nimport { schedulerServiceFactory } from '@backstage/backend-defaults/scheduler';\nimport { urlReaderServiceFactory } from '@backstage/backend-defaults/urlReader';\nimport { userInfoServiceFactory } from '@backstage/backend-defaults/userInfo';\nimport { eventsServiceFactory } from '@backstage/plugin-events-node';\n\nexport const defaultServiceFactories = [\n auditorServiceFactory,\n authServiceFactory,\n cacheServiceFactory,\n rootConfigServiceFactory,\n databaseServiceFactory,\n discoveryServiceFactory,\n httpAuthServiceFactory,\n httpRouterServiceFactory,\n lifecycleServiceFactory,\n loggerServiceFactory,\n permissionsServiceFactory,\n permissionsRegistryServiceFactory,\n rootHealthServiceFactory,\n rootHttpRouterServiceFactory,\n rootLifecycleServiceFactory,\n rootLoggerServiceFactory,\n schedulerServiceFactory,\n userInfoServiceFactory,\n urlReaderServiceFactory,\n eventsServiceFactory,\n];\n\n/**\n * @public\n */\nexport function createBackend(): Backend {\n return createSpecializedBackend({ defaultServiceFactories });\n}\n"],"names":["auditorServiceFactory","authServiceFactory","cacheServiceFactory","rootConfigServiceFactory","databaseServiceFactory","discoveryServiceFactory","httpAuthServiceFactory","httpRouterServiceFactory","lifecycleServiceFactory","loggerServiceFactory","permissionsServiceFactory","permissionsRegistryServiceFactory","rootHealthServiceFactory","rootHttpRouterServiceFactory","rootLifecycleServiceFactory","rootLoggerServiceFactory","schedulerServiceFactory","userInfoServiceFactory","urlReaderServiceFactory","eventsServiceFactory","createSpecializedBackend"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAsCO,MAAM,uBAA0B,GAAA;AAAA,EACrCA,6BAAA;AAAA,EACAC,uBAAA;AAAA,EACAC,yBAAA;AAAA,EACAC,mCAAA;AAAA,EACAC,+BAAA;AAAA,EACAC,iCAAA;AAAA,EACAC,+BAAA;AAAA,EACAC,mCAAA;AAAA,EACAC,iCAAA;AAAA,EACAC,2BAAA;AAAA,EACAC,qCAAA;AAAA,EACAC,qDAAA;AAAA,EACAC,mCAAA;AAAA,EACAC,2CAAA;AAAA,EACAC,yCAAA;AAAA,EACAC,mCAAA;AAAA,EACAC,iCAAA;AAAA,EACAC,+BAAA;AAAA,EACAC,iCAAA;AAAA,EACAC;AACF;AAKO,SAAS,aAAyB,GAAA;AACvC,EAAO,OAAAC,sCAAA,CAAyB,EAAE,uBAAA,EAAyB,CAAA;AAC7D;;;;;"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var DefaultAuditorService = require('./entrypoints/auditor/DefaultAuditorService.cjs.js');
|
|
4
|
+
var auditorServiceFactory = require('./entrypoints/auditor/auditorServiceFactory.cjs.js');
|
|
5
|
+
var WinstonRootAuditorService = require('./entrypoints/auditor/WinstonRootAuditorService.cjs.js');
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
exports.DefaultAuditorService = DefaultAuditorService.DefaultAuditorService;
|
|
10
|
+
exports.auditorServiceFactory = auditorServiceFactory.auditorServiceFactory;
|
|
11
|
+
exports.WinstonRootAuditorService = WinstonRootAuditorService.WinstonRootAuditorService;
|
|
12
|
+
//# sourceMappingURL=auditor.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auditor.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
|
+
import { AuditorServiceEventSeverityLevel, AuditorService, AuthService, HttpAuthService, PluginMetadataService, AuditorServiceCreateEventOptions, AuditorServiceEvent } from '@backstage/backend-plugin-api';
|
|
3
|
+
import { JsonObject } from '@backstage/types';
|
|
4
|
+
import { Request } from 'express';
|
|
5
|
+
import { Format } from 'logform';
|
|
6
|
+
import * as winston from 'winston';
|
|
7
|
+
|
|
8
|
+
/** @public */
|
|
9
|
+
type AuditorEventActorDetails = {
|
|
10
|
+
actorId?: string;
|
|
11
|
+
ip?: string;
|
|
12
|
+
hostname?: string;
|
|
13
|
+
userAgent?: string;
|
|
14
|
+
};
|
|
15
|
+
/** @public */
|
|
16
|
+
type AuditorEventRequest = {
|
|
17
|
+
url: string;
|
|
18
|
+
method: string;
|
|
19
|
+
};
|
|
20
|
+
/** @public */
|
|
21
|
+
type AuditorEventStatus = {
|
|
22
|
+
status: 'initiated';
|
|
23
|
+
} | {
|
|
24
|
+
status: 'succeeded';
|
|
25
|
+
} | {
|
|
26
|
+
status: 'failed';
|
|
27
|
+
error: string;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Options for creating an auditor event.
|
|
31
|
+
*
|
|
32
|
+
* @public
|
|
33
|
+
*/
|
|
34
|
+
type AuditorEventOptions<TMeta extends JsonObject> = {
|
|
35
|
+
/**
|
|
36
|
+
* Use kebab-case to name audit events (e.g., "user-login", "file-download").
|
|
37
|
+
*
|
|
38
|
+
* The `pluginId` already provides plugin/module context, so avoid redundant prefixes in the `eventId`.
|
|
39
|
+
*/
|
|
40
|
+
eventId: string;
|
|
41
|
+
severityLevel?: AuditorServiceEventSeverityLevel;
|
|
42
|
+
/** (Optional) The associated HTTP request, if applicable. */
|
|
43
|
+
request?: Request<any, any, any, any, any>;
|
|
44
|
+
/** (Optional) Additional metadata relevant to the event, structured as a JSON object. */
|
|
45
|
+
meta?: TMeta;
|
|
46
|
+
} & AuditorEventStatus;
|
|
47
|
+
/**
|
|
48
|
+
* Common fields of an audit event.
|
|
49
|
+
*
|
|
50
|
+
* @public
|
|
51
|
+
*/
|
|
52
|
+
type AuditorEvent = {
|
|
53
|
+
plugin: string;
|
|
54
|
+
eventId: string;
|
|
55
|
+
severityLevel: AuditorServiceEventSeverityLevel;
|
|
56
|
+
actor: AuditorEventActorDetails;
|
|
57
|
+
meta?: JsonObject;
|
|
58
|
+
request?: AuditorEventRequest;
|
|
59
|
+
} & AuditorEventStatus;
|
|
60
|
+
/**
|
|
61
|
+
* Logging function used by the auditor.
|
|
62
|
+
* @public
|
|
63
|
+
*/
|
|
64
|
+
type AuditorLogFunction = (event: AuditorEvent) => void | Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* A {@link @backstage/backend-plugin-api#AuditorService} implementation that logs events using a provided callback.
|
|
67
|
+
*
|
|
68
|
+
* @public
|
|
69
|
+
*
|
|
70
|
+
* @example
|
|
71
|
+
* ```ts
|
|
72
|
+
* export const auditorServiceFactory = createServiceFactory({
|
|
73
|
+
* service: coreServices.auditor,
|
|
74
|
+
* deps: {
|
|
75
|
+
* logger: coreServices.logger,
|
|
76
|
+
* auth: coreServices.auth,
|
|
77
|
+
* httpAuth: coreServices.httpAuth,
|
|
78
|
+
* plugin: coreServices.pluginMetadata,
|
|
79
|
+
* },
|
|
80
|
+
* factory({ logger, plugin, auth, httpAuth }) {
|
|
81
|
+
* const auditLogger = logger.child({ isAuditEvent: true });
|
|
82
|
+
* return DefaultAuditorService.create(
|
|
83
|
+
* event => auditLogger.info(`${event.plugin}.${event.eventId}`, event),
|
|
84
|
+
* { plugin, auth, httpAuth },
|
|
85
|
+
* );
|
|
86
|
+
* },
|
|
87
|
+
* });
|
|
88
|
+
* ```
|
|
89
|
+
*/
|
|
90
|
+
declare class DefaultAuditorService implements AuditorService {
|
|
91
|
+
private readonly logFn;
|
|
92
|
+
private readonly auth;
|
|
93
|
+
private readonly httpAuth;
|
|
94
|
+
private readonly plugin;
|
|
95
|
+
private constructor();
|
|
96
|
+
/**
|
|
97
|
+
* Creates a {@link DefaultAuditorService} instance.
|
|
98
|
+
*/
|
|
99
|
+
static create(logFn: AuditorLogFunction, deps: {
|
|
100
|
+
auth: AuthService;
|
|
101
|
+
httpAuth: HttpAuthService;
|
|
102
|
+
plugin: PluginMetadataService;
|
|
103
|
+
}): DefaultAuditorService;
|
|
104
|
+
private log;
|
|
105
|
+
createEvent(options: AuditorServiceCreateEventOptions): Promise<AuditorServiceEvent>;
|
|
106
|
+
private getActorId;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Plugin-level auditing.
|
|
111
|
+
*
|
|
112
|
+
* See {@link @backstage/code-plugin-api#AuditorService}
|
|
113
|
+
* and {@link https://backstage.io/docs/backend-system/core-services/auditor | the service docs}
|
|
114
|
+
* for more information.
|
|
115
|
+
*
|
|
116
|
+
* @public
|
|
117
|
+
*/
|
|
118
|
+
declare const auditorServiceFactory: _backstage_backend_plugin_api.ServiceFactory<_backstage_backend_plugin_api.AuditorService, "plugin", "singleton">;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Options for creating a {@link WinstonRootAuditorService}.
|
|
122
|
+
* @public
|
|
123
|
+
*/
|
|
124
|
+
type WinstonRootAuditorServiceOptions = {
|
|
125
|
+
meta?: JsonObject;
|
|
126
|
+
format?: Format;
|
|
127
|
+
transports?: winston.transport[];
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* An implementation of the {@link @backstage/backend-plugin-api#AuditorService} that logs events using a separate winston logger.
|
|
131
|
+
*
|
|
132
|
+
* @public
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```ts
|
|
136
|
+
* export const auditorServiceFactory = createServiceFactory({
|
|
137
|
+
* service: coreServices.auditor,
|
|
138
|
+
* deps: {
|
|
139
|
+
* auth: coreServices.auth,
|
|
140
|
+
* httpAuth: coreServices.httpAuth,
|
|
141
|
+
* plugin: coreServices.pluginMetadata,
|
|
142
|
+
* },
|
|
143
|
+
* createRootContext() {
|
|
144
|
+
* return WinstonRootAuditorService.create();
|
|
145
|
+
* },
|
|
146
|
+
* factory({ plugin, auth, httpAuth }, root) {
|
|
147
|
+
* return root.forPlugin({ plugin, auth, httpAuth });
|
|
148
|
+
* },
|
|
149
|
+
* });
|
|
150
|
+
* ```
|
|
151
|
+
*/
|
|
152
|
+
declare class WinstonRootAuditorService {
|
|
153
|
+
private readonly winstonLogger;
|
|
154
|
+
private constructor();
|
|
155
|
+
/**
|
|
156
|
+
* Creates a {@link WinstonRootAuditorService} instance.
|
|
157
|
+
*/
|
|
158
|
+
static create(options?: WinstonRootAuditorServiceOptions): WinstonRootAuditorService;
|
|
159
|
+
forPlugin(deps: {
|
|
160
|
+
auth: AuthService;
|
|
161
|
+
httpAuth: HttpAuthService;
|
|
162
|
+
plugin: PluginMetadataService;
|
|
163
|
+
}): AuditorService;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
export { type AuditorEvent, type AuditorEventActorDetails, type AuditorEventOptions, type AuditorEventRequest, type AuditorEventStatus, type AuditorLogFunction, DefaultAuditorService, WinstonRootAuditorService, type WinstonRootAuditorServiceOptions, auditorServiceFactory };
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var errors = require('@backstage/errors');
|
|
4
|
+
|
|
5
|
+
class DefaultAuditorService {
|
|
6
|
+
logFn;
|
|
7
|
+
auth;
|
|
8
|
+
httpAuth;
|
|
9
|
+
plugin;
|
|
10
|
+
constructor(logFn, deps) {
|
|
11
|
+
this.logFn = logFn;
|
|
12
|
+
this.auth = deps.auth;
|
|
13
|
+
this.httpAuth = deps.httpAuth;
|
|
14
|
+
this.plugin = deps.plugin;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Creates a {@link DefaultAuditorService} instance.
|
|
18
|
+
*/
|
|
19
|
+
static create(logFn, deps) {
|
|
20
|
+
return new DefaultAuditorService(logFn, deps);
|
|
21
|
+
}
|
|
22
|
+
async log(options) {
|
|
23
|
+
const { eventId, severityLevel = "low", request, meta, ...rest } = options;
|
|
24
|
+
await this.logFn({
|
|
25
|
+
plugin: this.plugin.getId(),
|
|
26
|
+
eventId,
|
|
27
|
+
severityLevel,
|
|
28
|
+
actor: {
|
|
29
|
+
actorId: await this.getActorId(request),
|
|
30
|
+
ip: request?.ip,
|
|
31
|
+
hostname: request?.hostname,
|
|
32
|
+
userAgent: request?.get("user-agent")
|
|
33
|
+
},
|
|
34
|
+
request: request ? {
|
|
35
|
+
url: request?.originalUrl,
|
|
36
|
+
method: request?.method
|
|
37
|
+
} : void 0,
|
|
38
|
+
meta: Object.keys(meta ?? {}).length === 0 ? void 0 : meta,
|
|
39
|
+
...rest
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
async createEvent(options) {
|
|
43
|
+
await this.log({ ...options, status: "initiated" });
|
|
44
|
+
return {
|
|
45
|
+
success: async (params) => {
|
|
46
|
+
await this.log({
|
|
47
|
+
...options,
|
|
48
|
+
meta: { ...options.meta, ...params?.meta },
|
|
49
|
+
status: "succeeded"
|
|
50
|
+
});
|
|
51
|
+
},
|
|
52
|
+
fail: async (params) => {
|
|
53
|
+
await this.log({
|
|
54
|
+
...options,
|
|
55
|
+
...params,
|
|
56
|
+
error: String(params.error),
|
|
57
|
+
meta: { ...options.meta, ...params?.meta },
|
|
58
|
+
status: "failed"
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async getActorId(request) {
|
|
64
|
+
let credentials = await this.auth.getOwnServiceCredentials();
|
|
65
|
+
if (request) {
|
|
66
|
+
try {
|
|
67
|
+
credentials = await this.httpAuth.credentials(request);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
throw new errors.ForwardedError("Could not resolve credentials", error);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (this.auth.isPrincipal(credentials, "user")) {
|
|
73
|
+
return credentials.principal.userEntityRef;
|
|
74
|
+
}
|
|
75
|
+
if (this.auth.isPrincipal(credentials, "service")) {
|
|
76
|
+
return credentials.principal.subject;
|
|
77
|
+
}
|
|
78
|
+
return void 0;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
exports.DefaultAuditorService = DefaultAuditorService;
|
|
83
|
+
//# sourceMappingURL=DefaultAuditorService.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DefaultAuditorService.cjs.js","sources":["../../../src/entrypoints/auditor/DefaultAuditorService.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AuditorService,\n AuditorServiceCreateEventOptions,\n AuditorServiceEvent,\n AuditorServiceEventSeverityLevel,\n AuthService,\n BackstageCredentials,\n HttpAuthService,\n PluginMetadataService,\n} from '@backstage/backend-plugin-api';\nimport { ForwardedError } from '@backstage/errors';\nimport type { JsonObject } from '@backstage/types';\nimport type { Request } from 'express';\n\n/** @public */\nexport type AuditorEventActorDetails = {\n actorId?: string;\n ip?: string;\n hostname?: string;\n userAgent?: string;\n};\n\n/** @public */\nexport type AuditorEventRequest = {\n url: string;\n method: string;\n};\n\n/** @public */\nexport type AuditorEventStatus =\n | { status: 'initiated' }\n | { status: 'succeeded' }\n | {\n status: 'failed';\n error: string;\n };\n\n/**\n * Options for creating an auditor event.\n *\n * @public\n */\nexport type AuditorEventOptions<TMeta extends JsonObject> = {\n /**\n * Use kebab-case to name audit events (e.g., \"user-login\", \"file-download\").\n *\n * The `pluginId` already provides plugin/module context, so avoid redundant prefixes in the `eventId`.\n */\n eventId: string;\n\n severityLevel?: AuditorServiceEventSeverityLevel;\n\n /** (Optional) The associated HTTP request, if applicable. */\n request?: Request<any, any, any, any, any>;\n\n /** (Optional) Additional metadata relevant to the event, structured as a JSON object. */\n meta?: TMeta;\n} & AuditorEventStatus;\n\n/**\n * Common fields of an audit event.\n *\n * @public\n */\nexport type AuditorEvent = {\n plugin: string;\n eventId: string;\n severityLevel: AuditorServiceEventSeverityLevel;\n actor: AuditorEventActorDetails;\n meta?: JsonObject;\n request?: AuditorEventRequest;\n} & AuditorEventStatus;\n\n/**\n * Logging function used by the auditor.\n * @public\n */\nexport type AuditorLogFunction = (event: AuditorEvent) => void | Promise<void>;\n\n/**\n * A {@link @backstage/backend-plugin-api#AuditorService} implementation that logs events using a provided callback.\n *\n * @public\n *\n * @example\n * ```ts\n * export const auditorServiceFactory = createServiceFactory({\n * service: coreServices.auditor,\n * deps: {\n * logger: coreServices.logger,\n * auth: coreServices.auth,\n * httpAuth: coreServices.httpAuth,\n * plugin: coreServices.pluginMetadata,\n * },\n * factory({ logger, plugin, auth, httpAuth }) {\n * const auditLogger = logger.child({ isAuditEvent: true });\n * return DefaultAuditorService.create(\n * event => auditLogger.info(`${event.plugin}.${event.eventId}`, event),\n * { plugin, auth, httpAuth },\n * );\n * },\n * });\n * ```\n */\nexport class DefaultAuditorService implements AuditorService {\n private readonly logFn: AuditorLogFunction;\n private readonly auth: AuthService;\n private readonly httpAuth: HttpAuthService;\n private readonly plugin: PluginMetadataService;\n\n private constructor(\n logFn: AuditorLogFunction,\n deps: {\n auth: AuthService;\n httpAuth: HttpAuthService;\n plugin: PluginMetadataService;\n },\n ) {\n this.logFn = logFn;\n this.auth = deps.auth;\n this.httpAuth = deps.httpAuth;\n this.plugin = deps.plugin;\n }\n\n /**\n * Creates a {@link DefaultAuditorService} instance.\n */\n static create(\n logFn: AuditorLogFunction,\n deps: {\n auth: AuthService;\n httpAuth: HttpAuthService;\n plugin: PluginMetadataService;\n },\n ): DefaultAuditorService {\n return new DefaultAuditorService(logFn, deps);\n }\n\n private async log<TMeta extends JsonObject>(\n options: AuditorEventOptions<TMeta>,\n ): Promise<void> {\n const { eventId, severityLevel = 'low', request, meta, ...rest } = options;\n\n await this.logFn({\n plugin: this.plugin.getId(),\n eventId,\n severityLevel,\n actor: {\n actorId: await this.getActorId(request),\n ip: request?.ip,\n hostname: request?.hostname,\n userAgent: request?.get('user-agent'),\n },\n request: request\n ? {\n url: request?.originalUrl,\n method: request?.method,\n }\n : undefined,\n meta: Object.keys(meta ?? {}).length === 0 ? undefined : meta,\n ...rest,\n });\n }\n\n async createEvent(\n options: AuditorServiceCreateEventOptions,\n ): Promise<AuditorServiceEvent> {\n await this.log({ ...options, status: 'initiated' });\n\n return {\n success: async params => {\n await this.log({\n ...options,\n meta: { ...options.meta, ...params?.meta },\n status: 'succeeded',\n });\n },\n fail: async params => {\n await this.log({\n ...options,\n ...params,\n error: String(params.error),\n meta: { ...options.meta, ...params?.meta },\n status: 'failed',\n });\n },\n };\n }\n\n private async getActorId(\n request?: Request<any, any, any, any, any>,\n ): Promise<string | undefined> {\n let credentials: BackstageCredentials =\n await this.auth.getOwnServiceCredentials();\n\n if (request) {\n try {\n credentials = await this.httpAuth.credentials(request);\n } catch (error) {\n throw new ForwardedError('Could not resolve credentials', error);\n }\n }\n\n if (this.auth.isPrincipal(credentials, 'user')) {\n return credentials.principal.userEntityRef;\n }\n\n if (this.auth.isPrincipal(credentials, 'service')) {\n return credentials.principal.subject;\n }\n\n return undefined;\n }\n}\n"],"names":["ForwardedError"],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var winston = require('winston');
|
|
4
|
+
require('../rootLogger/rootLoggerServiceFactory.cjs.js');
|
|
5
|
+
var WinstonLogger = require('../rootLogger/WinstonLogger.cjs.js');
|
|
6
|
+
var DefaultAuditorService = require('./DefaultAuditorService.cjs.js');
|
|
7
|
+
|
|
8
|
+
function _interopNamespaceCompat(e) {
|
|
9
|
+
if (e && typeof e === 'object' && 'default' in e) return e;
|
|
10
|
+
var n = Object.create(null);
|
|
11
|
+
if (e) {
|
|
12
|
+
Object.keys(e).forEach(function (k) {
|
|
13
|
+
if (k !== 'default') {
|
|
14
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
15
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return e[k]; }
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
n.default = e;
|
|
23
|
+
return Object.freeze(n);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
var winston__namespace = /*#__PURE__*/_interopNamespaceCompat(winston);
|
|
27
|
+
|
|
28
|
+
const defaultFormatter = winston__namespace.format.combine(
|
|
29
|
+
winston__namespace.format.timestamp({
|
|
30
|
+
format: "YYYY-MM-DD HH:mm:ss"
|
|
31
|
+
}),
|
|
32
|
+
winston__namespace.format.errors({ stack: true }),
|
|
33
|
+
winston__namespace.format.splat(),
|
|
34
|
+
winston__namespace.format.json()
|
|
35
|
+
);
|
|
36
|
+
const auditorFieldFormat = winston__namespace.format((info) => {
|
|
37
|
+
return { ...info, isAuditEvent: true };
|
|
38
|
+
})();
|
|
39
|
+
class WinstonRootAuditorService {
|
|
40
|
+
constructor(winstonLogger) {
|
|
41
|
+
this.winstonLogger = winstonLogger;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Creates a {@link WinstonRootAuditorService} instance.
|
|
45
|
+
*/
|
|
46
|
+
static create(options) {
|
|
47
|
+
let winstonLogger = WinstonLogger.WinstonLogger.create({
|
|
48
|
+
meta: {
|
|
49
|
+
service: "backstage"
|
|
50
|
+
},
|
|
51
|
+
level: "info",
|
|
52
|
+
format: winston__namespace.format.combine(
|
|
53
|
+
auditorFieldFormat,
|
|
54
|
+
options?.format ?? defaultFormatter
|
|
55
|
+
),
|
|
56
|
+
transports: options?.transports
|
|
57
|
+
});
|
|
58
|
+
if (options?.meta) {
|
|
59
|
+
winstonLogger = winstonLogger.child(options.meta);
|
|
60
|
+
}
|
|
61
|
+
return new WinstonRootAuditorService(winstonLogger);
|
|
62
|
+
}
|
|
63
|
+
forPlugin(deps) {
|
|
64
|
+
return DefaultAuditorService.DefaultAuditorService.create(
|
|
65
|
+
(e) => this.winstonLogger.info(`${e.plugin}.${e.eventId}`, e),
|
|
66
|
+
deps
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
exports.WinstonRootAuditorService = WinstonRootAuditorService;
|
|
72
|
+
exports.auditorFieldFormat = auditorFieldFormat;
|
|
73
|
+
exports.defaultFormatter = defaultFormatter;
|
|
74
|
+
//# sourceMappingURL=WinstonRootAuditorService.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WinstonRootAuditorService.cjs.js","sources":["../../../src/entrypoints/auditor/WinstonRootAuditorService.ts"],"sourcesContent":["/*\n * Copyright 2025 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport type {\n AuditorService,\n AuthService,\n HttpAuthService,\n PluginMetadataService,\n} from '@backstage/backend-plugin-api';\nimport type { JsonObject } from '@backstage/types';\nimport type { Format } from 'logform';\nimport * as winston from 'winston';\nimport { WinstonLogger } from '../rootLogger';\nimport { DefaultAuditorService } from './DefaultAuditorService';\n\n/** @public */\nexport const defaultFormatter = winston.format.combine(\n winston.format.timestamp({\n format: 'YYYY-MM-DD HH:mm:ss',\n }),\n winston.format.errors({ stack: true }),\n winston.format.splat(),\n winston.format.json(),\n);\n\n/**\n * Adds `isAuditEvent` field\n *\n * @public\n */\nexport const auditorFieldFormat = winston.format(info => {\n return { ...info, isAuditEvent: true };\n})();\n\n/**\n * Options for creating a {@link WinstonRootAuditorService}.\n * @public\n */\nexport type WinstonRootAuditorServiceOptions = {\n meta?: JsonObject;\n format?: Format;\n transports?: winston.transport[];\n};\n\n/**\n * An implementation of the {@link @backstage/backend-plugin-api#AuditorService} that logs events using a separate winston logger.\n *\n * @public\n *\n * @example\n * ```ts\n * export const auditorServiceFactory = createServiceFactory({\n * service: coreServices.auditor,\n * deps: {\n * auth: coreServices.auth,\n * httpAuth: coreServices.httpAuth,\n * plugin: coreServices.pluginMetadata,\n * },\n * createRootContext() {\n * return WinstonRootAuditorService.create();\n * },\n * factory({ plugin, auth, httpAuth }, root) {\n * return root.forPlugin({ plugin, auth, httpAuth });\n * },\n * });\n * ```\n */\nexport class WinstonRootAuditorService {\n private constructor(private readonly winstonLogger: WinstonLogger) {}\n\n /**\n * Creates a {@link WinstonRootAuditorService} instance.\n */\n static create(\n options?: WinstonRootAuditorServiceOptions,\n ): WinstonRootAuditorService {\n let winstonLogger = WinstonLogger.create({\n meta: {\n service: 'backstage',\n },\n level: 'info',\n format: winston.format.combine(\n auditorFieldFormat,\n options?.format ?? defaultFormatter,\n ),\n transports: options?.transports,\n });\n\n if (options?.meta) {\n winstonLogger = winstonLogger.child(options.meta) as WinstonLogger;\n }\n\n return new WinstonRootAuditorService(winstonLogger);\n }\n\n forPlugin(deps: {\n auth: AuthService;\n httpAuth: HttpAuthService;\n plugin: PluginMetadataService;\n }): AuditorService {\n return DefaultAuditorService.create(\n e => this.winstonLogger.info(`${e.plugin}.${e.eventId}`, e),\n deps,\n );\n }\n}\n"],"names":["winston","WinstonLogger","DefaultAuditorService"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA6Ba,MAAA,gBAAA,GAAmBA,mBAAQ,MAAO,CAAA,OAAA;AAAA,EAC7CA,kBAAA,CAAQ,OAAO,SAAU,CAAA;AAAA,IACvB,MAAQ,EAAA;AAAA,GACT,CAAA;AAAA,EACDA,mBAAQ,MAAO,CAAA,MAAA,CAAO,EAAE,KAAA,EAAO,MAAM,CAAA;AAAA,EACrCA,kBAAA,CAAQ,OAAO,KAAM,EAAA;AAAA,EACrBA,kBAAA,CAAQ,OAAO,IAAK;AACtB;AAOa,MAAA,kBAAA,GAAqBA,kBAAQ,CAAA,MAAA,CAAO,CAAQ,IAAA,KAAA;AACvD,EAAA,OAAO,EAAE,GAAG,IAAM,EAAA,YAAA,EAAc,IAAK,EAAA;AACvC,CAAC,CAAE;AAmCI,MAAM,yBAA0B,CAAA;AAAA,EAC7B,YAA6B,aAA8B,EAAA;AAA9B,IAAA,IAAA,CAAA,aAAA,GAAA,aAAA;AAAA;AAA+B;AAAA;AAAA;AAAA,EAKpE,OAAO,OACL,OAC2B,EAAA;AAC3B,IAAI,IAAA,aAAA,GAAgBC,4BAAc,MAAO,CAAA;AAAA,MACvC,IAAM,EAAA;AAAA,QACJ,OAAS,EAAA;AAAA,OACX;AAAA,MACA,KAAO,EAAA,MAAA;AAAA,MACP,MAAA,EAAQD,mBAAQ,MAAO,CAAA,OAAA;AAAA,QACrB,kBAAA;AAAA,QACA,SAAS,MAAU,IAAA;AAAA,OACrB;AAAA,MACA,YAAY,OAAS,EAAA;AAAA,KACtB,CAAA;AAED,IAAA,IAAI,SAAS,IAAM,EAAA;AACjB,MAAgB,aAAA,GAAA,aAAA,CAAc,KAAM,CAAA,OAAA,CAAQ,IAAI,CAAA;AAAA;AAGlD,IAAO,OAAA,IAAI,0BAA0B,aAAa,CAAA;AAAA;AACpD,EAEA,UAAU,IAIS,EAAA;AACjB,IAAA,OAAOE,2CAAsB,CAAA,MAAA;AAAA,MAC3B,CAAA,CAAA,KAAK,IAAK,CAAA,aAAA,CAAc,IAAK,CAAA,CAAA,EAAG,CAAE,CAAA,MAAM,CAAI,CAAA,EAAA,CAAA,CAAE,OAAO,CAAA,CAAA,EAAI,CAAC,CAAA;AAAA,MAC1D;AAAA,KACF;AAAA;AAEJ;;;;;;"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
+
var DefaultAuditorService = require('./DefaultAuditorService.cjs.js');
|
|
5
|
+
|
|
6
|
+
const auditorServiceFactory = backendPluginApi.createServiceFactory({
|
|
7
|
+
service: backendPluginApi.coreServices.auditor,
|
|
8
|
+
deps: {
|
|
9
|
+
logger: backendPluginApi.coreServices.logger,
|
|
10
|
+
auth: backendPluginApi.coreServices.auth,
|
|
11
|
+
httpAuth: backendPluginApi.coreServices.httpAuth,
|
|
12
|
+
plugin: backendPluginApi.coreServices.pluginMetadata
|
|
13
|
+
},
|
|
14
|
+
factory({ logger, plugin, auth, httpAuth }) {
|
|
15
|
+
const auditLogger = logger.child({ isAuditEvent: true });
|
|
16
|
+
return DefaultAuditorService.DefaultAuditorService.create(
|
|
17
|
+
(event) => auditLogger.info(`${event.plugin}.${event.eventId}`, event),
|
|
18
|
+
{ plugin, auth, httpAuth }
|
|
19
|
+
);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
exports.auditorServiceFactory = auditorServiceFactory;
|
|
24
|
+
//# sourceMappingURL=auditorServiceFactory.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auditorServiceFactory.cjs.js","sources":["../../../src/entrypoints/auditor/auditorServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2024 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { DefaultAuditorService } from './DefaultAuditorService';\n\n/**\n * Plugin-level auditing.\n *\n * See {@link @backstage/code-plugin-api#AuditorService}\n * and {@link https://backstage.io/docs/backend-system/core-services/auditor | the service docs}\n * for more information.\n *\n * @public\n */\nexport const auditorServiceFactory = createServiceFactory({\n service: coreServices.auditor,\n deps: {\n logger: coreServices.logger,\n auth: coreServices.auth,\n httpAuth: coreServices.httpAuth,\n plugin: coreServices.pluginMetadata,\n },\n factory({ logger, plugin, auth, httpAuth }) {\n const auditLogger = logger.child({ isAuditEvent: true });\n return DefaultAuditorService.create(\n event => auditLogger.info(`${event.plugin}.${event.eventId}`, event),\n { plugin, auth, httpAuth },\n );\n },\n});\n"],"names":["createServiceFactory","coreServices","DefaultAuditorService"],"mappings":";;;;;AA+BO,MAAM,wBAAwBA,qCAAqB,CAAA;AAAA,EACxD,SAASC,6BAAa,CAAA,OAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACJ,QAAQA,6BAAa,CAAA,MAAA;AAAA,IACrB,MAAMA,6BAAa,CAAA,IAAA;AAAA,IACnB,UAAUA,6BAAa,CAAA,QAAA;AAAA,IACvB,QAAQA,6BAAa,CAAA;AAAA,GACvB;AAAA,EACA,QAAQ,EAAE,MAAA,EAAQ,MAAQ,EAAA,IAAA,EAAM,UAAY,EAAA;AAC1C,IAAA,MAAM,cAAc,MAAO,CAAA,KAAA,CAAM,EAAE,YAAA,EAAc,MAAM,CAAA;AACvD,IAAA,OAAOC,2CAAsB,CAAA,MAAA;AAAA,MAC3B,CAAA,KAAA,KAAS,WAAY,CAAA,IAAA,CAAK,CAAG,EAAA,KAAA,CAAM,MAAM,CAAI,CAAA,EAAA,KAAA,CAAM,OAAO,CAAA,CAAA,EAAI,KAAK,CAAA;AAAA,MACnE,EAAE,MAAQ,EAAA,IAAA,EAAM,QAAS;AAAA,KAC3B;AAAA;AAEJ,CAAC;;;;"}
|
|
@@ -60,7 +60,7 @@ async function buildPgDatabaseConfig(dbConfig, overrides) {
|
|
|
60
60
|
Connector: CloudSqlConnector,
|
|
61
61
|
IpAddressTypes,
|
|
62
62
|
AuthTypes
|
|
63
|
-
} =
|
|
63
|
+
} = require("@google-cloud/cloud-sql-connector");
|
|
64
64
|
const connector = new CloudSqlConnector();
|
|
65
65
|
const clientOpts = await connector.getOptions({
|
|
66
66
|
instanceConnectionName: config.connection.instance,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"postgres.cjs.js","sources":["../../../../src/entrypoints/database/connectors/postgres.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LifecycleService, LoggerService } from '@backstage/backend-plugin-api';\nimport { Config, ConfigReader } from '@backstage/config';\nimport { ForwardedError } from '@backstage/errors';\nimport { JsonObject } from '@backstage/types';\nimport knexFactory, { Knex } from 'knex';\nimport { merge, omit } from 'lodash';\nimport limiterFactory from 'p-limit';\nimport { Client } from 'pg';\nimport { Connector } from '../types';\nimport defaultNameOverride from './defaultNameOverride';\nimport defaultSchemaOverride from './defaultSchemaOverride';\nimport { mergeDatabaseConfig } from './mergeDatabaseConfig';\nimport format from 'pg-format';\n\n// Limits the number of concurrent DDL operations to 1\nconst ddlLimiter = limiterFactory(1);\n\n/**\n * Creates a knex postgres database connection\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport async function createPgDatabaseClient(\n dbConfig: Config,\n overrides?: Knex.Config,\n) {\n const knexConfig = await buildPgDatabaseConfig(dbConfig, overrides);\n const database = knexFactory(knexConfig);\n\n const role = dbConfig.getOptionalString('role');\n\n if (role) {\n database.client.pool.on(\n 'createSuccess',\n async (_event: number, pgClient: Client) => {\n const query = format('SET ROLE %I', role);\n await pgClient.query(query);\n },\n );\n }\n return database;\n}\n\n/**\n * Builds a knex postgres database connection\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport async function buildPgDatabaseConfig(\n dbConfig: Config,\n overrides?: Knex.Config,\n) {\n const config = mergeDatabaseConfig(\n dbConfig.get(),\n {\n connection: getPgConnectionConfig(dbConfig, !!overrides),\n useNullAsDefault: true,\n },\n overrides,\n );\n\n const sanitizedConfig = JSON.parse(JSON.stringify(config));\n\n // Trim additional properties from the connection object passed to knex\n delete sanitizedConfig.connection.type;\n delete sanitizedConfig.connection.instance;\n\n if (config.connection.type === 'default' || !config.connection.type) {\n return sanitizedConfig;\n }\n\n if (config.connection.type !== 'cloudsql') {\n throw new Error(`Unknown connection type: ${config.connection.type}`);\n }\n\n if (config.client !== 'pg') {\n throw new Error('Cloud SQL only supports the pg client');\n }\n\n if (!config.connection.instance) {\n throw new Error('Missing instance connection name for Cloud SQL');\n }\n\n const {\n Connector: CloudSqlConnector,\n IpAddressTypes,\n AuthTypes,\n } = await import('@google-cloud/cloud-sql-connector');\n const connector = new CloudSqlConnector();\n const clientOpts = await connector.getOptions({\n instanceConnectionName: config.connection.instance,\n ipType: IpAddressTypes.PUBLIC,\n authType: AuthTypes.IAM,\n });\n\n return {\n ...sanitizedConfig,\n client: 'pg',\n connection: {\n ...sanitizedConfig.connection,\n ...clientOpts,\n },\n };\n}\n\n/**\n * Gets the postgres connection config\n *\n * @param dbConfig - The database config\n * @param parseConnectionString - Flag to explicitly control connection string parsing\n */\nexport function getPgConnectionConfig(\n dbConfig: Config,\n parseConnectionString?: boolean,\n): Knex.PgConnectionConfig | string {\n const connection = dbConfig.get('connection') as any;\n const isConnectionString =\n typeof connection === 'string' || connection instanceof String;\n const autoParse = typeof parseConnectionString !== 'boolean';\n\n const shouldParseConnectionString = autoParse\n ? isConnectionString\n : parseConnectionString && isConnectionString;\n\n return shouldParseConnectionString\n ? parsePgConnectionString(connection as string)\n : connection;\n}\n\n/**\n * Parses a connection string using pg-connection-string\n *\n * @param connectionString - The postgres connection string\n */\nexport function parsePgConnectionString(connectionString: string) {\n const parse = requirePgConnectionString();\n return parse(connectionString);\n}\n\nfunction requirePgConnectionString() {\n try {\n return require('pg-connection-string').parse;\n } catch (e) {\n throw new ForwardedError(\"Postgres: Install 'pg-connection-string'\", e);\n }\n}\n\n/**\n * Creates the missing Postgres database if it does not exist\n *\n * @param dbConfig - The database config\n * @param databases - The name of the databases to create\n */\nexport async function ensurePgDatabaseExists(\n dbConfig: Config,\n ...databases: Array<string>\n) {\n const admin = await createPgDatabaseClient(dbConfig, {\n connection: {\n database: 'postgres',\n },\n pool: {\n min: 0,\n acquireTimeoutMillis: 10000,\n },\n });\n\n try {\n const ensureDatabase = async (database: string) => {\n const result = await admin\n .from('pg_database')\n .where('datname', database)\n .count<Record<string, { count: string }>>();\n\n if (parseInt(result[0].count, 10) > 0) {\n return;\n }\n\n await admin.raw(`CREATE DATABASE ??`, [database]);\n };\n\n await Promise.all(\n databases.map(async database => {\n // For initial setup we use a smaller timeout but several retries. Given that this\n // is a separate connection pool we should never really run into issues with connection\n // acquisition timeouts, but we do anyway. This might be a bug in knex or some other dependency.\n let lastErr: Error | undefined = undefined;\n for (let i = 0; i < 3; i++) {\n try {\n return await ddlLimiter(() => ensureDatabase(database));\n } catch (err) {\n lastErr = err;\n }\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n throw lastErr;\n }),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Creates the missing Postgres schema if it does not exist\n *\n * @param dbConfig - The database config\n * @param schemas - The name of the schemas to create\n */\nexport async function ensurePgSchemaExists(\n dbConfig: Config,\n ...schemas: Array<string>\n): Promise<void> {\n const admin = await createPgDatabaseClient(dbConfig);\n const role = dbConfig.getOptionalString('role');\n\n try {\n const ensureSchema = async (database: string) => {\n if (role) {\n await admin.raw(`CREATE SCHEMA IF NOT EXISTS ?? AUTHORIZATION ??`, [\n database,\n role,\n ]);\n } else {\n await admin.raw(`CREATE SCHEMA IF NOT EXISTS ??`, [database]);\n }\n };\n\n await Promise.all(\n schemas.map(database => ddlLimiter(() => ensureSchema(database))),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Drops the Postgres databases.\n *\n * @param dbConfig - The database config\n * @param databases - The name of the databases to drop\n */\nexport async function dropPgDatabase(\n dbConfig: Config,\n ...databases: Array<string>\n) {\n const admin = await createPgDatabaseClient(dbConfig);\n try {\n await Promise.all(\n databases.map(async database => {\n await ddlLimiter(() => admin.raw(`DROP DATABASE ??`, [database]));\n }),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Provides a config lookup path for a plugin's config block.\n */\nfunction pluginPath(pluginId: string): string {\n return `plugin.${pluginId}`;\n}\n\nfunction normalizeConnection(\n connection: Knex.StaticConnectionConfig | JsonObject | string | undefined,\n): Partial<Knex.StaticConnectionConfig> {\n if (typeof connection === 'undefined' || connection === null) {\n return {};\n }\n\n return typeof connection === 'string' || connection instanceof String\n ? parsePgConnectionString(connection as string)\n : connection;\n}\n\nexport class PgConnector implements Connector {\n constructor(\n private readonly config: Config,\n private readonly prefix: string,\n ) {}\n\n async getClient(\n pluginId: string,\n _deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n ): Promise<Knex> {\n const pluginConfig = new ConfigReader(\n this.getConfigForPlugin(pluginId) as JsonObject,\n );\n\n const databaseName = this.getDatabaseName(pluginId);\n if (databaseName && this.getEnsureExistsConfig(pluginId)) {\n try {\n await ensurePgDatabaseExists(pluginConfig, databaseName);\n } catch (error) {\n throw new Error(\n `Failed to connect to the database to make sure that '${databaseName}' exists, ${error}`,\n );\n }\n }\n\n let schemaOverrides;\n if (this.getPluginDivisionModeConfig() === 'schema') {\n schemaOverrides = defaultSchemaOverride(pluginId);\n if (\n this.getEnsureSchemaExistsConfig(pluginId) ||\n this.getEnsureExistsConfig(pluginId)\n ) {\n try {\n await ensurePgSchemaExists(pluginConfig, pluginId);\n } catch (error) {\n throw new Error(\n `Failed to connect to the database to make sure that schema for plugin '${pluginId}' exists, ${error}`,\n );\n }\n }\n }\n\n const databaseClientOverrides = mergeDatabaseConfig(\n {},\n this.getDatabaseOverrides(pluginId),\n schemaOverrides,\n );\n\n const client = createPgDatabaseClient(\n pluginConfig,\n databaseClientOverrides,\n );\n\n return client;\n }\n\n /**\n * Provides the canonical database name for a given plugin.\n *\n * This method provides the effective database name which is determined using global\n * and plugin specific database config. If no explicit database name is configured\n * and `pluginDivisionMode` is not `schema`, this method will provide a generated name\n * which is the pluginId prefixed with 'backstage_plugin_'. If `pluginDivisionMode` is\n * `schema`, it will fallback to using the default database for the knex instance.\n *\n * @param pluginId - Lookup the database name for given plugin\n * @returns String representing the plugin's database name\n */\n private getDatabaseName(pluginId: string): string | undefined {\n const connection = this.getConnectionConfig(pluginId);\n\n const databaseName = (connection as Knex.ConnectionConfig)?.database;\n\n // `pluginDivisionMode` as `schema` should use overridden databaseName if supplied or fallback to default knex database\n if (this.getPluginDivisionModeConfig() === 'schema') {\n return databaseName;\n }\n\n // all other supported databases should fallback to an auto-prefixed name\n return databaseName ?? `${this.prefix}${pluginId}`;\n }\n\n /**\n * Provides the client type which should be used for a given plugin.\n *\n * The client type is determined by plugin specific config if present.\n * Otherwise the base client is used as the fallback.\n *\n * @param pluginId - Plugin to get the client type for\n * @returns Object with client type returned as `client` and boolean\n * representing whether or not the client was overridden as\n * `overridden`\n */\n private getClientType(pluginId: string): {\n client: string;\n overridden: boolean;\n } {\n const pluginClient = this.config.getOptionalString(\n `${pluginPath(pluginId)}.client`,\n );\n\n const baseClient = this.config.getString('client');\n const client = pluginClient ?? baseClient;\n return {\n client,\n overridden: client !== baseClient,\n };\n }\n\n private getRoleConfig(pluginId: string): string | undefined {\n return (\n this.config.getOptionalString(`${pluginPath(pluginId)}.role`) ??\n this.config.getOptionalString('role')\n );\n }\n\n /**\n * Provides the knexConfig which should be used for a given plugin.\n *\n * @param pluginId - Plugin to get the knexConfig for\n * @returns The merged knexConfig value or undefined if it isn't specified\n */\n private getAdditionalKnexConfig(pluginId: string): JsonObject | undefined {\n const pluginConfig = this.config\n .getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`)\n ?.get<JsonObject>();\n\n const baseConfig = this.config\n .getOptionalConfig('knexConfig')\n ?.get<JsonObject>();\n\n return merge(baseConfig, pluginConfig);\n }\n\n private getEnsureExistsConfig(pluginId: string): boolean {\n const baseConfig = this.config.getOptionalBoolean('ensureExists') ?? true;\n return (\n this.config.getOptionalBoolean(`${pluginPath(pluginId)}.ensureExists`) ??\n baseConfig\n );\n }\n\n private getEnsureSchemaExistsConfig(pluginId: string): boolean {\n const baseConfig =\n this.config.getOptionalBoolean('ensureSchemaExists') ?? false;\n return (\n this.config.getOptionalBoolean(\n `${pluginPath(pluginId)}.getEnsureSchemaExistsConfig`,\n ) ?? baseConfig\n );\n }\n\n private getPluginDivisionModeConfig(): string {\n return this.config.getOptionalString('pluginDivisionMode') ?? 'database';\n }\n\n /**\n * Provides a Knex connection plugin config by combining base and plugin\n * config.\n *\n * This method provides a baseConfig for a plugin database connector. If the\n * client type has not been overridden, the global connection config will be\n * included with plugin specific config as the base. Values from the plugin\n * connection take precedence over the base. Base database name is omitted\n * unless `pluginDivisionMode` is set to `schema`.\n */\n private getConnectionConfig(pluginId: string): Knex.StaticConnectionConfig {\n const { overridden } = this.getClientType(pluginId);\n\n let baseConnection = normalizeConnection(this.config.get('connection'));\n\n // Databases cannot be shared unless the `pluginDivisionMode` is set to `schema`. The\n // `database` property from the base connection is omitted unless `pluginDivisionMode`\n // is set to `schema`.\n if (this.getPluginDivisionModeConfig() !== 'schema') {\n baseConnection = omit(baseConnection, 'database');\n }\n\n // get and normalize optional plugin specific database connection\n const connection = normalizeConnection(\n this.config.getOptional(`${pluginPath(pluginId)}.connection`),\n );\n\n (\n baseConnection as Knex.PgConnectionConfig\n ).application_name ||= `backstage_plugin_${pluginId}`;\n\n return {\n // include base connection if client type has not been overridden\n ...(overridden ? {} : baseConnection),\n ...connection,\n } as Knex.StaticConnectionConfig;\n }\n\n /**\n * Provides a Knex database config for a given plugin.\n *\n * This method provides a Knex configuration object along with the plugin's\n * client type.\n *\n * @param pluginId - The plugin that the database config should correspond with\n */\n private getConfigForPlugin(pluginId: string): Knex.Config {\n const { client } = this.getClientType(pluginId);\n const role = this.getRoleConfig(pluginId);\n\n return {\n ...this.getAdditionalKnexConfig(pluginId),\n client,\n connection: this.getConnectionConfig(pluginId),\n ...(role && { role }),\n };\n }\n\n /**\n * Provides a partial `Knex.Config`• database name override for a given plugin.\n *\n * @param pluginId - Target plugin to get database name override\n * @returns Partial `Knex.Config` with database name override\n */\n private getDatabaseOverrides(pluginId: string): Knex.Config {\n const databaseName = this.getDatabaseName(pluginId);\n return databaseName ? defaultNameOverride(databaseName) : {};\n }\n}\n"],"names":["limiterFactory","knexFactory","format","mergeDatabaseConfig","ForwardedError","ConfigReader","defaultSchemaOverride","merge","omit","defaultNameOverride"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"postgres.cjs.js","sources":["../../../../src/entrypoints/database/connectors/postgres.ts"],"sourcesContent":["/*\n * Copyright 2020 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { LifecycleService, LoggerService } from '@backstage/backend-plugin-api';\nimport { Config, ConfigReader } from '@backstage/config';\nimport { ForwardedError } from '@backstage/errors';\nimport { JsonObject } from '@backstage/types';\nimport knexFactory, { Knex } from 'knex';\nimport { merge, omit } from 'lodash';\nimport limiterFactory from 'p-limit';\nimport { Client } from 'pg';\nimport { Connector } from '../types';\nimport defaultNameOverride from './defaultNameOverride';\nimport defaultSchemaOverride from './defaultSchemaOverride';\nimport { mergeDatabaseConfig } from './mergeDatabaseConfig';\nimport format from 'pg-format';\n\n// Limits the number of concurrent DDL operations to 1\nconst ddlLimiter = limiterFactory(1);\n\n/**\n * Creates a knex postgres database connection\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport async function createPgDatabaseClient(\n dbConfig: Config,\n overrides?: Knex.Config,\n) {\n const knexConfig = await buildPgDatabaseConfig(dbConfig, overrides);\n const database = knexFactory(knexConfig);\n\n const role = dbConfig.getOptionalString('role');\n\n if (role) {\n database.client.pool.on(\n 'createSuccess',\n async (_event: number, pgClient: Client) => {\n const query = format('SET ROLE %I', role);\n await pgClient.query(query);\n },\n );\n }\n return database;\n}\n\n/**\n * Builds a knex postgres database connection\n *\n * @param dbConfig - The database config\n * @param overrides - Additional options to merge with the config\n */\nexport async function buildPgDatabaseConfig(\n dbConfig: Config,\n overrides?: Knex.Config,\n) {\n const config = mergeDatabaseConfig(\n dbConfig.get(),\n {\n connection: getPgConnectionConfig(dbConfig, !!overrides),\n useNullAsDefault: true,\n },\n overrides,\n );\n\n const sanitizedConfig = JSON.parse(JSON.stringify(config));\n\n // Trim additional properties from the connection object passed to knex\n delete sanitizedConfig.connection.type;\n delete sanitizedConfig.connection.instance;\n\n if (config.connection.type === 'default' || !config.connection.type) {\n return sanitizedConfig;\n }\n\n if (config.connection.type !== 'cloudsql') {\n throw new Error(`Unknown connection type: ${config.connection.type}`);\n }\n\n if (config.client !== 'pg') {\n throw new Error('Cloud SQL only supports the pg client');\n }\n\n if (!config.connection.instance) {\n throw new Error('Missing instance connection name for Cloud SQL');\n }\n\n const {\n Connector: CloudSqlConnector,\n IpAddressTypes,\n AuthTypes,\n } = require('@google-cloud/cloud-sql-connector') as typeof import('@google-cloud/cloud-sql-connector');\n const connector = new CloudSqlConnector();\n const clientOpts = await connector.getOptions({\n instanceConnectionName: config.connection.instance,\n ipType: IpAddressTypes.PUBLIC,\n authType: AuthTypes.IAM,\n });\n\n return {\n ...sanitizedConfig,\n client: 'pg',\n connection: {\n ...sanitizedConfig.connection,\n ...clientOpts,\n },\n };\n}\n\n/**\n * Gets the postgres connection config\n *\n * @param dbConfig - The database config\n * @param parseConnectionString - Flag to explicitly control connection string parsing\n */\nexport function getPgConnectionConfig(\n dbConfig: Config,\n parseConnectionString?: boolean,\n): Knex.PgConnectionConfig | string {\n const connection = dbConfig.get('connection') as any;\n const isConnectionString =\n typeof connection === 'string' || connection instanceof String;\n const autoParse = typeof parseConnectionString !== 'boolean';\n\n const shouldParseConnectionString = autoParse\n ? isConnectionString\n : parseConnectionString && isConnectionString;\n\n return shouldParseConnectionString\n ? parsePgConnectionString(connection as string)\n : connection;\n}\n\n/**\n * Parses a connection string using pg-connection-string\n *\n * @param connectionString - The postgres connection string\n */\nexport function parsePgConnectionString(connectionString: string) {\n const parse = requirePgConnectionString();\n return parse(connectionString);\n}\n\nfunction requirePgConnectionString() {\n try {\n return require('pg-connection-string').parse;\n } catch (e) {\n throw new ForwardedError(\"Postgres: Install 'pg-connection-string'\", e);\n }\n}\n\n/**\n * Creates the missing Postgres database if it does not exist\n *\n * @param dbConfig - The database config\n * @param databases - The name of the databases to create\n */\nexport async function ensurePgDatabaseExists(\n dbConfig: Config,\n ...databases: Array<string>\n) {\n const admin = await createPgDatabaseClient(dbConfig, {\n connection: {\n database: 'postgres',\n },\n pool: {\n min: 0,\n acquireTimeoutMillis: 10000,\n },\n });\n\n try {\n const ensureDatabase = async (database: string) => {\n const result = await admin\n .from('pg_database')\n .where('datname', database)\n .count<Record<string, { count: string }>>();\n\n if (parseInt(result[0].count, 10) > 0) {\n return;\n }\n\n await admin.raw(`CREATE DATABASE ??`, [database]);\n };\n\n await Promise.all(\n databases.map(async database => {\n // For initial setup we use a smaller timeout but several retries. Given that this\n // is a separate connection pool we should never really run into issues with connection\n // acquisition timeouts, but we do anyway. This might be a bug in knex or some other dependency.\n let lastErr: Error | undefined = undefined;\n for (let i = 0; i < 3; i++) {\n try {\n return await ddlLimiter(() => ensureDatabase(database));\n } catch (err) {\n lastErr = err;\n }\n await new Promise(resolve => setTimeout(resolve, 100));\n }\n throw lastErr;\n }),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Creates the missing Postgres schema if it does not exist\n *\n * @param dbConfig - The database config\n * @param schemas - The name of the schemas to create\n */\nexport async function ensurePgSchemaExists(\n dbConfig: Config,\n ...schemas: Array<string>\n): Promise<void> {\n const admin = await createPgDatabaseClient(dbConfig);\n const role = dbConfig.getOptionalString('role');\n\n try {\n const ensureSchema = async (database: string) => {\n if (role) {\n await admin.raw(`CREATE SCHEMA IF NOT EXISTS ?? AUTHORIZATION ??`, [\n database,\n role,\n ]);\n } else {\n await admin.raw(`CREATE SCHEMA IF NOT EXISTS ??`, [database]);\n }\n };\n\n await Promise.all(\n schemas.map(database => ddlLimiter(() => ensureSchema(database))),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Drops the Postgres databases.\n *\n * @param dbConfig - The database config\n * @param databases - The name of the databases to drop\n */\nexport async function dropPgDatabase(\n dbConfig: Config,\n ...databases: Array<string>\n) {\n const admin = await createPgDatabaseClient(dbConfig);\n try {\n await Promise.all(\n databases.map(async database => {\n await ddlLimiter(() => admin.raw(`DROP DATABASE ??`, [database]));\n }),\n );\n } finally {\n await admin.destroy();\n }\n}\n\n/**\n * Provides a config lookup path for a plugin's config block.\n */\nfunction pluginPath(pluginId: string): string {\n return `plugin.${pluginId}`;\n}\n\nfunction normalizeConnection(\n connection: Knex.StaticConnectionConfig | JsonObject | string | undefined,\n): Partial<Knex.StaticConnectionConfig> {\n if (typeof connection === 'undefined' || connection === null) {\n return {};\n }\n\n return typeof connection === 'string' || connection instanceof String\n ? parsePgConnectionString(connection as string)\n : connection;\n}\n\nexport class PgConnector implements Connector {\n constructor(\n private readonly config: Config,\n private readonly prefix: string,\n ) {}\n\n async getClient(\n pluginId: string,\n _deps: {\n logger: LoggerService;\n lifecycle: LifecycleService;\n },\n ): Promise<Knex> {\n const pluginConfig = new ConfigReader(\n this.getConfigForPlugin(pluginId) as JsonObject,\n );\n\n const databaseName = this.getDatabaseName(pluginId);\n if (databaseName && this.getEnsureExistsConfig(pluginId)) {\n try {\n await ensurePgDatabaseExists(pluginConfig, databaseName);\n } catch (error) {\n throw new Error(\n `Failed to connect to the database to make sure that '${databaseName}' exists, ${error}`,\n );\n }\n }\n\n let schemaOverrides;\n if (this.getPluginDivisionModeConfig() === 'schema') {\n schemaOverrides = defaultSchemaOverride(pluginId);\n if (\n this.getEnsureSchemaExistsConfig(pluginId) ||\n this.getEnsureExistsConfig(pluginId)\n ) {\n try {\n await ensurePgSchemaExists(pluginConfig, pluginId);\n } catch (error) {\n throw new Error(\n `Failed to connect to the database to make sure that schema for plugin '${pluginId}' exists, ${error}`,\n );\n }\n }\n }\n\n const databaseClientOverrides = mergeDatabaseConfig(\n {},\n this.getDatabaseOverrides(pluginId),\n schemaOverrides,\n );\n\n const client = createPgDatabaseClient(\n pluginConfig,\n databaseClientOverrides,\n );\n\n return client;\n }\n\n /**\n * Provides the canonical database name for a given plugin.\n *\n * This method provides the effective database name which is determined using global\n * and plugin specific database config. If no explicit database name is configured\n * and `pluginDivisionMode` is not `schema`, this method will provide a generated name\n * which is the pluginId prefixed with 'backstage_plugin_'. If `pluginDivisionMode` is\n * `schema`, it will fallback to using the default database for the knex instance.\n *\n * @param pluginId - Lookup the database name for given plugin\n * @returns String representing the plugin's database name\n */\n private getDatabaseName(pluginId: string): string | undefined {\n const connection = this.getConnectionConfig(pluginId);\n\n const databaseName = (connection as Knex.ConnectionConfig)?.database;\n\n // `pluginDivisionMode` as `schema` should use overridden databaseName if supplied or fallback to default knex database\n if (this.getPluginDivisionModeConfig() === 'schema') {\n return databaseName;\n }\n\n // all other supported databases should fallback to an auto-prefixed name\n return databaseName ?? `${this.prefix}${pluginId}`;\n }\n\n /**\n * Provides the client type which should be used for a given plugin.\n *\n * The client type is determined by plugin specific config if present.\n * Otherwise the base client is used as the fallback.\n *\n * @param pluginId - Plugin to get the client type for\n * @returns Object with client type returned as `client` and boolean\n * representing whether or not the client was overridden as\n * `overridden`\n */\n private getClientType(pluginId: string): {\n client: string;\n overridden: boolean;\n } {\n const pluginClient = this.config.getOptionalString(\n `${pluginPath(pluginId)}.client`,\n );\n\n const baseClient = this.config.getString('client');\n const client = pluginClient ?? baseClient;\n return {\n client,\n overridden: client !== baseClient,\n };\n }\n\n private getRoleConfig(pluginId: string): string | undefined {\n return (\n this.config.getOptionalString(`${pluginPath(pluginId)}.role`) ??\n this.config.getOptionalString('role')\n );\n }\n\n /**\n * Provides the knexConfig which should be used for a given plugin.\n *\n * @param pluginId - Plugin to get the knexConfig for\n * @returns The merged knexConfig value or undefined if it isn't specified\n */\n private getAdditionalKnexConfig(pluginId: string): JsonObject | undefined {\n const pluginConfig = this.config\n .getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`)\n ?.get<JsonObject>();\n\n const baseConfig = this.config\n .getOptionalConfig('knexConfig')\n ?.get<JsonObject>();\n\n return merge(baseConfig, pluginConfig);\n }\n\n private getEnsureExistsConfig(pluginId: string): boolean {\n const baseConfig = this.config.getOptionalBoolean('ensureExists') ?? true;\n return (\n this.config.getOptionalBoolean(`${pluginPath(pluginId)}.ensureExists`) ??\n baseConfig\n );\n }\n\n private getEnsureSchemaExistsConfig(pluginId: string): boolean {\n const baseConfig =\n this.config.getOptionalBoolean('ensureSchemaExists') ?? false;\n return (\n this.config.getOptionalBoolean(\n `${pluginPath(pluginId)}.getEnsureSchemaExistsConfig`,\n ) ?? baseConfig\n );\n }\n\n private getPluginDivisionModeConfig(): string {\n return this.config.getOptionalString('pluginDivisionMode') ?? 'database';\n }\n\n /**\n * Provides a Knex connection plugin config by combining base and plugin\n * config.\n *\n * This method provides a baseConfig for a plugin database connector. If the\n * client type has not been overridden, the global connection config will be\n * included with plugin specific config as the base. Values from the plugin\n * connection take precedence over the base. Base database name is omitted\n * unless `pluginDivisionMode` is set to `schema`.\n */\n private getConnectionConfig(pluginId: string): Knex.StaticConnectionConfig {\n const { overridden } = this.getClientType(pluginId);\n\n let baseConnection = normalizeConnection(this.config.get('connection'));\n\n // Databases cannot be shared unless the `pluginDivisionMode` is set to `schema`. The\n // `database` property from the base connection is omitted unless `pluginDivisionMode`\n // is set to `schema`.\n if (this.getPluginDivisionModeConfig() !== 'schema') {\n baseConnection = omit(baseConnection, 'database');\n }\n\n // get and normalize optional plugin specific database connection\n const connection = normalizeConnection(\n this.config.getOptional(`${pluginPath(pluginId)}.connection`),\n );\n\n (\n baseConnection as Knex.PgConnectionConfig\n ).application_name ||= `backstage_plugin_${pluginId}`;\n\n return {\n // include base connection if client type has not been overridden\n ...(overridden ? {} : baseConnection),\n ...connection,\n } as Knex.StaticConnectionConfig;\n }\n\n /**\n * Provides a Knex database config for a given plugin.\n *\n * This method provides a Knex configuration object along with the plugin's\n * client type.\n *\n * @param pluginId - The plugin that the database config should correspond with\n */\n private getConfigForPlugin(pluginId: string): Knex.Config {\n const { client } = this.getClientType(pluginId);\n const role = this.getRoleConfig(pluginId);\n\n return {\n ...this.getAdditionalKnexConfig(pluginId),\n client,\n connection: this.getConnectionConfig(pluginId),\n ...(role && { role }),\n };\n }\n\n /**\n * Provides a partial `Knex.Config`• database name override for a given plugin.\n *\n * @param pluginId - Target plugin to get database name override\n * @returns Partial `Knex.Config` with database name override\n */\n private getDatabaseOverrides(pluginId: string): Knex.Config {\n const databaseName = this.getDatabaseName(pluginId);\n return databaseName ? defaultNameOverride(databaseName) : {};\n }\n}\n"],"names":["limiterFactory","knexFactory","format","mergeDatabaseConfig","ForwardedError","ConfigReader","defaultSchemaOverride","merge","omit","defaultNameOverride"],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var backendPluginApi = require('@backstage/backend-plugin-api');
|
|
4
|
+
var pluginPermissionNode = require('@backstage/plugin-permission-node');
|
|
5
|
+
|
|
6
|
+
const permissionsRegistryServiceFactory = backendPluginApi.createServiceFactory({
|
|
7
|
+
service: backendPluginApi.coreServices.permissionsRegistry,
|
|
8
|
+
deps: {
|
|
9
|
+
lifecycle: backendPluginApi.coreServices.lifecycle,
|
|
10
|
+
httpRouter: backendPluginApi.coreServices.httpRouter
|
|
11
|
+
},
|
|
12
|
+
async factory({ httpRouter, lifecycle }) {
|
|
13
|
+
const router = pluginPermissionNode.createPermissionIntegrationRouter();
|
|
14
|
+
httpRouter.use(router);
|
|
15
|
+
let started = false;
|
|
16
|
+
lifecycle.addStartupHook(() => {
|
|
17
|
+
started = true;
|
|
18
|
+
});
|
|
19
|
+
return {
|
|
20
|
+
addResourceType(resource) {
|
|
21
|
+
if (started) {
|
|
22
|
+
throw new Error(
|
|
23
|
+
"Cannot add permission resource types after the plugin has started"
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
router.addResourceType(resource);
|
|
27
|
+
},
|
|
28
|
+
addPermissions(permissions) {
|
|
29
|
+
if (started) {
|
|
30
|
+
throw new Error(
|
|
31
|
+
"Cannot add permissions after the plugin has started"
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
router.addPermissions(permissions);
|
|
35
|
+
},
|
|
36
|
+
addPermissionRules(rules) {
|
|
37
|
+
if (started) {
|
|
38
|
+
throw new Error(
|
|
39
|
+
"Cannot add permission rules after the plugin has started"
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
router.addPermissionRules(rules);
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
exports.permissionsRegistryServiceFactory = permissionsRegistryServiceFactory;
|
|
49
|
+
//# sourceMappingURL=permissionsRegistryServiceFactory.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissionsRegistryServiceFactory.cjs.js","sources":["../../../src/entrypoints/permissionsRegistry/permissionsRegistryServiceFactory.ts"],"sourcesContent":["/*\n * Copyright 2022 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n coreServices,\n createServiceFactory,\n} from '@backstage/backend-plugin-api';\nimport { createPermissionIntegrationRouter } from '@backstage/plugin-permission-node';\n\n/**\n * Permission system integration for registering resources and permissions.\n *\n * See {@link @backstage/core-plugin-api#PermissionsRegistryService}\n * and {@link https://backstage.io/docs/backend-system/core-services/permission-integrations | the service docs}\n * for more information.\n *\n * @public\n */\nexport const permissionsRegistryServiceFactory = createServiceFactory({\n service: coreServices.permissionsRegistry,\n deps: {\n lifecycle: coreServices.lifecycle,\n httpRouter: coreServices.httpRouter,\n },\n async factory({ httpRouter, lifecycle }) {\n const router = createPermissionIntegrationRouter();\n\n httpRouter.use(router);\n\n let started = false;\n lifecycle.addStartupHook(() => {\n started = true;\n });\n\n return {\n addResourceType(resource) {\n if (started) {\n throw new Error(\n 'Cannot add permission resource types after the plugin has started',\n );\n }\n router.addResourceType(resource);\n },\n addPermissions(permissions) {\n if (started) {\n throw new Error(\n 'Cannot add permissions after the plugin has started',\n );\n }\n router.addPermissions(permissions);\n },\n addPermissionRules(rules) {\n if (started) {\n throw new Error(\n 'Cannot add permission rules after the plugin has started',\n );\n }\n router.addPermissionRules(rules);\n },\n };\n },\n});\n"],"names":["createServiceFactory","coreServices","createPermissionIntegrationRouter"],"mappings":";;;;;AA+BO,MAAM,oCAAoCA,qCAAqB,CAAA;AAAA,EACpE,SAASC,6BAAa,CAAA,mBAAA;AAAA,EACtB,IAAM,EAAA;AAAA,IACJ,WAAWA,6BAAa,CAAA,SAAA;AAAA,IACxB,YAAYA,6BAAa,CAAA;AAAA,GAC3B;AAAA,EACA,MAAM,OAAA,CAAQ,EAAE,UAAA,EAAY,WAAa,EAAA;AACvC,IAAA,MAAM,SAASC,sDAAkC,EAAA;AAEjD,IAAA,UAAA,CAAW,IAAI,MAAM,CAAA;AAErB,IAAA,IAAI,OAAU,GAAA,KAAA;AACd,IAAA,SAAA,CAAU,eAAe,MAAM;AAC7B,MAAU,OAAA,GAAA,IAAA;AAAA,KACX,CAAA;AAED,IAAO,OAAA;AAAA,MACL,gBAAgB,QAAU,EAAA;AACxB,QAAA,IAAI,OAAS,EAAA;AACX,UAAA,MAAM,IAAI,KAAA;AAAA,YACR;AAAA,WACF;AAAA;AAEF,QAAA,MAAA,CAAO,gBAAgB,QAAQ,CAAA;AAAA,OACjC;AAAA,MACA,eAAe,WAAa,EAAA;AAC1B,QAAA,IAAI,OAAS,EAAA;AACX,UAAA,MAAM,IAAI,KAAA;AAAA,YACR;AAAA,WACF;AAAA;AAEF,QAAA,MAAA,CAAO,eAAe,WAAW,CAAA;AAAA,OACnC;AAAA,MACA,mBAAmB,KAAO,EAAA;AACxB,QAAA,IAAI,OAAS,EAAA;AACX,UAAA,MAAM,IAAI,KAAA;AAAA,YACR;AAAA,WACF;AAAA;AAEF,QAAA,MAAA,CAAO,mBAAmB,KAAK,CAAA;AAAA;AACjC,KACF;AAAA;AAEJ,CAAC;;;;"}
|
package/dist/package.json.cjs.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
5
|
var name = "@backstage/backend-defaults";
|
|
6
|
-
var version = "0.
|
|
6
|
+
var version = "0.8.0-next.1";
|
|
7
7
|
var description = "Backend defaults used by Backstage backend apps";
|
|
8
8
|
var backstage = {
|
|
9
9
|
role: "node-library"
|
|
@@ -23,6 +23,7 @@ var repository = {
|
|
|
23
23
|
var license = "Apache-2.0";
|
|
24
24
|
var exports$1 = {
|
|
25
25
|
".": "./src/index.ts",
|
|
26
|
+
"./auditor": "./src/entrypoints/auditor/index.ts",
|
|
26
27
|
"./auth": "./src/entrypoints/auth/index.ts",
|
|
27
28
|
"./cache": "./src/entrypoints/cache/index.ts",
|
|
28
29
|
"./database": "./src/entrypoints/database/index.ts",
|
|
@@ -31,6 +32,7 @@ var exports$1 = {
|
|
|
31
32
|
"./httpRouter": "./src/entrypoints/httpRouter/index.ts",
|
|
32
33
|
"./lifecycle": "./src/entrypoints/lifecycle/index.ts",
|
|
33
34
|
"./logger": "./src/entrypoints/logger/index.ts",
|
|
35
|
+
"./permissionsRegistry": "./src/entrypoints/permissionsRegistry/index.ts",
|
|
34
36
|
"./permissions": "./src/entrypoints/permissions/index.ts",
|
|
35
37
|
"./rootConfig": "./src/entrypoints/rootConfig/index.ts",
|
|
36
38
|
"./rootHealth": "./src/entrypoints/rootHealth/index.ts",
|
|
@@ -46,6 +48,9 @@ var main = "src/index.ts";
|
|
|
46
48
|
var types = "src/index.ts";
|
|
47
49
|
var typesVersions = {
|
|
48
50
|
"*": {
|
|
51
|
+
auditor: [
|
|
52
|
+
"src/entrypoints/auditor/index.ts"
|
|
53
|
+
],
|
|
49
54
|
auth: [
|
|
50
55
|
"src/entrypoints/auth/index.ts"
|
|
51
56
|
],
|
|
@@ -70,6 +75,9 @@ var typesVersions = {
|
|
|
70
75
|
logger: [
|
|
71
76
|
"src/entrypoints/logger/index.ts"
|
|
72
77
|
],
|
|
78
|
+
permissionsRegistry: [
|
|
79
|
+
"src/entrypoints/permissionsRegistry/index.ts"
|
|
80
|
+
],
|
|
73
81
|
permissions: [
|
|
74
82
|
"src/entrypoints/permissions/index.ts"
|
|
75
83
|
],
|
|
@@ -188,14 +196,6 @@ var dependencies = {
|
|
|
188
196
|
yn: "^4.0.0",
|
|
189
197
|
zod: "^3.22.4"
|
|
190
198
|
};
|
|
191
|
-
var peerDependencies = {
|
|
192
|
-
"@google-cloud/cloud-sql-connector": "^1.4.0"
|
|
193
|
-
};
|
|
194
|
-
var peerDependenciesMeta = {
|
|
195
|
-
"@google-cloud/cloud-sql-connector": {
|
|
196
|
-
optional: true
|
|
197
|
-
}
|
|
198
|
-
};
|
|
199
199
|
var devDependencies = {
|
|
200
200
|
"@aws-sdk/util-stream-node": "^3.350.0",
|
|
201
201
|
"@backstage/backend-plugin-api": "workspace:^",
|
|
@@ -217,6 +217,14 @@ var devDependencies = {
|
|
|
217
217
|
supertest: "^7.0.0",
|
|
218
218
|
"wait-for-expect": "^3.0.2"
|
|
219
219
|
};
|
|
220
|
+
var peerDependencies = {
|
|
221
|
+
"@google-cloud/cloud-sql-connector": "^1.4.0"
|
|
222
|
+
};
|
|
223
|
+
var peerDependenciesMeta = {
|
|
224
|
+
"@google-cloud/cloud-sql-connector": {
|
|
225
|
+
optional: true
|
|
226
|
+
}
|
|
227
|
+
};
|
|
220
228
|
var configSchema = "config.d.ts";
|
|
221
229
|
var packageinfo = {
|
|
222
230
|
name: name,
|
|
@@ -235,9 +243,9 @@ var packageinfo = {
|
|
|
235
243
|
files: files,
|
|
236
244
|
scripts: scripts,
|
|
237
245
|
dependencies: dependencies,
|
|
246
|
+
devDependencies: devDependencies,
|
|
238
247
|
peerDependencies: peerDependencies,
|
|
239
248
|
peerDependenciesMeta: peerDependenciesMeta,
|
|
240
|
-
devDependencies: devDependencies,
|
|
241
249
|
configSchema: configSchema
|
|
242
250
|
};
|
|
243
251
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"package.json.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"package.json.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var permissionsRegistryServiceFactory = require('./entrypoints/permissionsRegistry/permissionsRegistryServiceFactory.cjs.js');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
exports.permissionsRegistryServiceFactory = permissionsRegistryServiceFactory.permissionsRegistryServiceFactory;
|
|
8
|
+
//# sourceMappingURL=permissionsRegistry.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permissionsRegistry.cjs.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Permission system integration for registering resources and permissions.
|
|
5
|
+
*
|
|
6
|
+
* See {@link @backstage/core-plugin-api#PermissionsRegistryService}
|
|
7
|
+
* and {@link https://backstage.io/docs/backend-system/core-services/permission-integrations | the service docs}
|
|
8
|
+
* for more information.
|
|
9
|
+
*
|
|
10
|
+
* @public
|
|
11
|
+
*/
|
|
12
|
+
declare const permissionsRegistryServiceFactory: _backstage_backend_plugin_api.ServiceFactory<_backstage_backend_plugin_api.PermissionsRegistryService, "plugin", "singleton">;
|
|
13
|
+
|
|
14
|
+
export { permissionsRegistryServiceFactory };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/backend-defaults",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0-next.1",
|
|
4
4
|
"description": "Backend defaults used by Backstage backend apps",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "node-library"
|
|
@@ -24,6 +24,11 @@
|
|
|
24
24
|
"types": "./dist/index.d.ts",
|
|
25
25
|
"default": "./dist/index.cjs.js"
|
|
26
26
|
},
|
|
27
|
+
"./auditor": {
|
|
28
|
+
"require": "./dist/auditor.cjs.js",
|
|
29
|
+
"types": "./dist/auditor.d.ts",
|
|
30
|
+
"default": "./dist/auditor.cjs.js"
|
|
31
|
+
},
|
|
27
32
|
"./auth": {
|
|
28
33
|
"require": "./dist/auth.cjs.js",
|
|
29
34
|
"types": "./dist/auth.d.ts",
|
|
@@ -64,6 +69,11 @@
|
|
|
64
69
|
"types": "./dist/logger.d.ts",
|
|
65
70
|
"default": "./dist/logger.cjs.js"
|
|
66
71
|
},
|
|
72
|
+
"./permissionsRegistry": {
|
|
73
|
+
"require": "./dist/permissionsRegistry.cjs.js",
|
|
74
|
+
"types": "./dist/permissionsRegistry.d.ts",
|
|
75
|
+
"default": "./dist/permissionsRegistry.cjs.js"
|
|
76
|
+
},
|
|
67
77
|
"./permissions": {
|
|
68
78
|
"require": "./dist/permissions.cjs.js",
|
|
69
79
|
"types": "./dist/permissions.d.ts",
|
|
@@ -118,6 +128,9 @@
|
|
|
118
128
|
"index": [
|
|
119
129
|
"dist/index.d.ts"
|
|
120
130
|
],
|
|
131
|
+
"auditor": [
|
|
132
|
+
"dist/auditor.d.ts"
|
|
133
|
+
],
|
|
121
134
|
"auth": [
|
|
122
135
|
"dist/auth.d.ts"
|
|
123
136
|
],
|
|
@@ -142,6 +155,9 @@
|
|
|
142
155
|
"logger": [
|
|
143
156
|
"dist/logger.d.ts"
|
|
144
157
|
],
|
|
158
|
+
"permissionsRegistry": [
|
|
159
|
+
"dist/permissionsRegistry.d.ts"
|
|
160
|
+
],
|
|
145
161
|
"permissions": [
|
|
146
162
|
"dist/permissions.d.ts"
|
|
147
163
|
],
|
|
@@ -193,20 +209,20 @@
|
|
|
193
209
|
"@aws-sdk/types": "^3.347.0",
|
|
194
210
|
"@azure/identity": "^4.0.0",
|
|
195
211
|
"@azure/storage-blob": "^12.5.0",
|
|
196
|
-
"@backstage/backend-app-api": "
|
|
197
|
-
"@backstage/backend-dev-utils": "
|
|
198
|
-
"@backstage/backend-plugin-api": "
|
|
199
|
-
"@backstage/cli-common": "
|
|
200
|
-
"@backstage/cli-node": "
|
|
201
|
-
"@backstage/config": "
|
|
202
|
-
"@backstage/config-loader": "
|
|
203
|
-
"@backstage/errors": "
|
|
204
|
-
"@backstage/integration": "
|
|
205
|
-
"@backstage/integration-aws-node": "
|
|
206
|
-
"@backstage/plugin-auth-node": "
|
|
207
|
-
"@backstage/plugin-events-node": "
|
|
208
|
-
"@backstage/plugin-permission-node": "
|
|
209
|
-
"@backstage/types": "
|
|
212
|
+
"@backstage/backend-app-api": "1.1.2-next.1",
|
|
213
|
+
"@backstage/backend-dev-utils": "0.1.5",
|
|
214
|
+
"@backstage/backend-plugin-api": "1.2.0-next.0",
|
|
215
|
+
"@backstage/cli-common": "0.1.15",
|
|
216
|
+
"@backstage/cli-node": "0.2.13-next.0",
|
|
217
|
+
"@backstage/config": "1.3.2",
|
|
218
|
+
"@backstage/config-loader": "1.9.6-next.0",
|
|
219
|
+
"@backstage/errors": "1.2.7",
|
|
220
|
+
"@backstage/integration": "1.16.1",
|
|
221
|
+
"@backstage/integration-aws-node": "0.1.15",
|
|
222
|
+
"@backstage/plugin-auth-node": "0.5.7-next.0",
|
|
223
|
+
"@backstage/plugin-events-node": "0.4.8-next.0",
|
|
224
|
+
"@backstage/plugin-permission-node": "0.8.8-next.0",
|
|
225
|
+
"@backstage/types": "1.2.1",
|
|
210
226
|
"@google-cloud/storage": "^7.0.0",
|
|
211
227
|
"@keyv/memcache": "^2.0.1",
|
|
212
228
|
"@keyv/redis": "^4.0.1",
|
|
@@ -257,19 +273,11 @@
|
|
|
257
273
|
"yn": "^4.0.0",
|
|
258
274
|
"zod": "^3.22.4"
|
|
259
275
|
},
|
|
260
|
-
"peerDependencies": {
|
|
261
|
-
"@google-cloud/cloud-sql-connector": "^1.4.0"
|
|
262
|
-
},
|
|
263
|
-
"peerDependenciesMeta": {
|
|
264
|
-
"@google-cloud/cloud-sql-connector": {
|
|
265
|
-
"optional": true
|
|
266
|
-
}
|
|
267
|
-
},
|
|
268
276
|
"devDependencies": {
|
|
269
277
|
"@aws-sdk/util-stream-node": "^3.350.0",
|
|
270
|
-
"@backstage/backend-plugin-api": "
|
|
271
|
-
"@backstage/backend-test-utils": "
|
|
272
|
-
"@backstage/cli": "
|
|
278
|
+
"@backstage/backend-plugin-api": "1.2.0-next.0",
|
|
279
|
+
"@backstage/backend-test-utils": "1.3.0-next.1",
|
|
280
|
+
"@backstage/cli": "0.30.0-next.1",
|
|
273
281
|
"@google-cloud/cloud-sql-connector": "^1.4.0",
|
|
274
282
|
"@types/archiver": "^6.0.0",
|
|
275
283
|
"@types/base64-stream": "^1.0.2",
|
|
@@ -286,5 +294,13 @@
|
|
|
286
294
|
"supertest": "^7.0.0",
|
|
287
295
|
"wait-for-expect": "^3.0.2"
|
|
288
296
|
},
|
|
297
|
+
"peerDependencies": {
|
|
298
|
+
"@google-cloud/cloud-sql-connector": "^1.4.0"
|
|
299
|
+
},
|
|
300
|
+
"peerDependenciesMeta": {
|
|
301
|
+
"@google-cloud/cloud-sql-connector": {
|
|
302
|
+
"optional": true
|
|
303
|
+
}
|
|
304
|
+
},
|
|
289
305
|
"configSchema": "config.d.ts"
|
|
290
306
|
}
|