@backstage/plugin-scaffolder-backend 2.0.1-next.0 → 2.1.0-next.2
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 +52 -0
- package/dist/alpha.cjs.js +2 -0
- package/dist/alpha.cjs.js.map +1 -1
- package/dist/alpha.d.ts +17 -1
- package/dist/index.d.ts +7 -2
- package/dist/scaffolder/tasks/DatabaseTaskStore.cjs.js +63 -20
- package/dist/scaffolder/tasks/DatabaseTaskStore.cjs.js.map +1 -1
- package/dist/scaffolder/tasks/StorageTaskBroker.cjs.js.map +1 -1
- package/dist/service/alpha.cjs.js +9 -0
- package/dist/service/alpha.cjs.js.map +1 -1
- package/dist/service/permissions.cjs.js +4 -0
- package/dist/service/permissions.cjs.js.map +1 -1
- package/dist/service/router.cjs.js +53 -21
- package/dist/service/router.cjs.js.map +1 -1
- package/dist/service/rules.cjs.js +27 -0
- package/dist/service/rules.cjs.js.map +1 -1
- package/dist/util/checkPermissions.cjs.js +38 -0
- package/dist/util/checkPermissions.cjs.js.map +1 -1
- package/package.json +27 -27
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permissions.cjs.js","sources":["../../src/service/permissions.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 { PermissionRule } from '@backstage/plugin-permission-node';\nimport {\n TemplateEntityStepV1beta3,\n TemplateParametersV1beta3,\n} from '@backstage/plugin-scaffolder-common';\nimport {\n RESOURCE_TYPE_SCAFFOLDER_ACTION,\n RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n} from '@backstage/plugin-scaffolder-common/alpha';\nimport { PermissionRuleParams } from '@backstage/plugin-permission-common';\n\n/**\n * @public\n */\nexport type TemplatePermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<\n TemplateEntityStepV1beta3 | TemplateParametersV1beta3,\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n TParams\n>;\nexport function isTemplatePermissionRuleInput(\n permissionRule:
|
|
1
|
+
{"version":3,"file":"permissions.cjs.js","sources":["../../src/service/permissions.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 { PermissionRule } from '@backstage/plugin-permission-node';\nimport {\n TemplateEntityStepV1beta3,\n TemplateParametersV1beta3,\n} from '@backstage/plugin-scaffolder-common';\nimport {\n RESOURCE_TYPE_SCAFFOLDER_ACTION,\n RESOURCE_TYPE_SCAFFOLDER_TASK,\n RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n} from '@backstage/plugin-scaffolder-common/alpha';\nimport { PermissionRuleParams } from '@backstage/plugin-permission-common';\nimport { SerializedTask } from '@backstage/plugin-scaffolder-node';\n\n/**\n *\n * @public\n */\nexport type ScaffolderPermissionRuleInput =\n | TemplatePermissionRuleInput\n | ActionPermissionRuleInput\n | TaskPermissionRuleInput;\n\n/**\n * @public\n */\nexport type TemplatePermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<\n TemplateEntityStepV1beta3 | TemplateParametersV1beta3,\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n TParams\n>;\nexport function isTemplatePermissionRuleInput(\n permissionRule: ScaffolderPermissionRuleInput,\n): permissionRule is TemplatePermissionRuleInput {\n return permissionRule.resourceType === RESOURCE_TYPE_SCAFFOLDER_TEMPLATE;\n}\n\n/**\n *\n * @public\n */\nexport type ActionPermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<\n TemplateEntityStepV1beta3 | TemplateParametersV1beta3,\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_ACTION,\n TParams\n>;\nexport function isActionPermissionRuleInput(\n permissionRule: ScaffolderPermissionRuleInput,\n): permissionRule is ActionPermissionRuleInput {\n return permissionRule.resourceType === RESOURCE_TYPE_SCAFFOLDER_ACTION;\n}\n\n/**\n * @public\n */\nexport type TaskPermissionRuleInput<\n TParams extends PermissionRuleParams = PermissionRuleParams,\n> = PermissionRule<\n SerializedTask,\n {\n key: string;\n values?: string[];\n },\n typeof RESOURCE_TYPE_SCAFFOLDER_TASK,\n TParams\n>;\nexport function isTaskPermissionRuleInput(\n permissionRule: ScaffolderPermissionRuleInput,\n): permissionRule is TaskPermissionRuleInput {\n return permissionRule.resourceType === RESOURCE_TYPE_SCAFFOLDER_TASK;\n}\n"],"names":["RESOURCE_TYPE_SCAFFOLDER_TEMPLATE","RESOURCE_TYPE_SCAFFOLDER_ACTION","RESOURCE_TYPE_SCAFFOLDER_TASK"],"mappings":";;;;AAiDO,SAAS,8BACd,cAC+C,EAAA;AAC/C,EAAA,OAAO,eAAe,YAAiB,KAAAA,uCAAA;AACzC;AAcO,SAAS,4BACd,cAC6C,EAAA;AAC7C,EAAA,OAAO,eAAe,YAAiB,KAAAC,qCAAA;AACzC;AAgBO,SAAS,0BACd,cAC2C,EAAA;AAC3C,EAAA,OAAO,eAAe,YAAiB,KAAAC,mCAAA;AACzC;;;;;;"}
|
|
@@ -44,8 +44,8 @@ var TaskWorker = require('../scaffolder/tasks/TaskWorker.cjs.js');
|
|
|
44
44
|
var createDryRunner = require('../scaffolder/dryrun/createDryRunner.cjs.js');
|
|
45
45
|
var checkPermissions = require('../util/checkPermissions.cjs.js');
|
|
46
46
|
var helpers = require('./helpers.cjs.js');
|
|
47
|
-
var rules = require('./rules.cjs.js');
|
|
48
47
|
var permissions = require('./permissions.cjs.js');
|
|
48
|
+
var rules = require('./rules.cjs.js');
|
|
49
49
|
|
|
50
50
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
51
51
|
|
|
@@ -183,13 +183,19 @@ async function createRouter(options) {
|
|
|
183
183
|
const actionRules = Object.values(
|
|
184
184
|
rules.scaffolderActionRules
|
|
185
185
|
);
|
|
186
|
+
const taskRules = Object.values(rules.scaffolderTaskRules);
|
|
186
187
|
if (permissionRules) {
|
|
187
188
|
templateRules.push(
|
|
188
189
|
...permissionRules.filter(permissions.isTemplatePermissionRuleInput)
|
|
189
190
|
);
|
|
190
191
|
actionRules.push(...permissionRules.filter(permissions.isActionPermissionRuleInput));
|
|
192
|
+
taskRules.push(...permissionRules.filter(permissions.isTaskPermissionRuleInput));
|
|
191
193
|
}
|
|
192
|
-
const
|
|
194
|
+
const isTemplateAuthorized = pluginPermissionNode.createConditionAuthorizer(
|
|
195
|
+
Object.values(templateRules)
|
|
196
|
+
);
|
|
197
|
+
const isTaskAuthorized = pluginPermissionNode.createConditionAuthorizer(Object.values(taskRules));
|
|
198
|
+
const taskTransformConditions = pluginPermissionNode.createConditionTransformer(Object.values(taskRules));
|
|
193
199
|
const permissionIntegrationRouter = pluginPermissionNode.createPermissionIntegrationRouter({
|
|
194
200
|
resources: [
|
|
195
201
|
{
|
|
@@ -201,6 +207,11 @@ async function createRouter(options) {
|
|
|
201
207
|
resourceType: alpha.RESOURCE_TYPE_SCAFFOLDER_ACTION,
|
|
202
208
|
permissions: alpha.scaffolderActionPermissions,
|
|
203
209
|
rules: actionRules
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
resourceType: alpha.RESOURCE_TYPE_SCAFFOLDER_TASK,
|
|
213
|
+
permissions: alpha.scaffolderTaskPermissions,
|
|
214
|
+
rules: taskRules
|
|
204
215
|
}
|
|
205
216
|
],
|
|
206
217
|
permissions: alpha.scaffolderPermissions
|
|
@@ -359,11 +370,6 @@ async function createRouter(options) {
|
|
|
359
370
|
});
|
|
360
371
|
try {
|
|
361
372
|
const credentials = await httpAuth.credentials(req);
|
|
362
|
-
await checkPermissions.checkPermission({
|
|
363
|
-
credentials,
|
|
364
|
-
permissions: [alpha.taskReadPermission],
|
|
365
|
-
permissionService: permissions$1
|
|
366
|
-
});
|
|
367
373
|
if (!taskBroker.list) {
|
|
368
374
|
throw new Error(
|
|
369
375
|
"TaskBroker does not support listing tasks, please implement the list method on the TaskBroker."
|
|
@@ -385,6 +391,12 @@ async function createRouter(options) {
|
|
|
385
391
|
});
|
|
386
392
|
const limit = helpers.parseNumberParam(req.query.limit, "limit");
|
|
387
393
|
const offset = helpers.parseNumberParam(req.query.offset, "offset");
|
|
394
|
+
const taskPermissionFilters = await checkPermissions.getAuthorizeConditions({
|
|
395
|
+
credentials,
|
|
396
|
+
permission: alpha.taskReadPermission,
|
|
397
|
+
permissionService: permissions$1,
|
|
398
|
+
transformConditions: taskTransformConditions
|
|
399
|
+
});
|
|
388
400
|
const tasks = await taskBroker.list({
|
|
389
401
|
filters: {
|
|
390
402
|
createdBy,
|
|
@@ -394,7 +406,8 @@ async function createRouter(options) {
|
|
|
394
406
|
pagination: {
|
|
395
407
|
limit: limit ? limit[0] : void 0,
|
|
396
408
|
offset: offset ? offset[0] : void 0
|
|
397
|
-
}
|
|
409
|
+
},
|
|
410
|
+
permissionFilters: taskPermissionFilters
|
|
398
411
|
});
|
|
399
412
|
await auditorEvent?.success();
|
|
400
413
|
res.status(200).json(tasks);
|
|
@@ -414,12 +427,14 @@ async function createRouter(options) {
|
|
|
414
427
|
});
|
|
415
428
|
try {
|
|
416
429
|
const credentials = await httpAuth.credentials(req);
|
|
417
|
-
await
|
|
430
|
+
const task = await taskBroker.get(taskId);
|
|
431
|
+
await checkPermissions.checkTaskPermission({
|
|
418
432
|
credentials,
|
|
419
433
|
permissions: [alpha.taskReadPermission],
|
|
420
|
-
permissionService: permissions$1
|
|
434
|
+
permissionService: permissions$1,
|
|
435
|
+
task,
|
|
436
|
+
isTaskAuthorized
|
|
421
437
|
});
|
|
422
|
-
const task = await taskBroker.get(taskId);
|
|
423
438
|
if (!task) {
|
|
424
439
|
throw new errors.NotFoundError(`Task with id ${taskId} does not exist`);
|
|
425
440
|
}
|
|
@@ -443,10 +458,13 @@ async function createRouter(options) {
|
|
|
443
458
|
});
|
|
444
459
|
try {
|
|
445
460
|
const credentials = await httpAuth.credentials(req);
|
|
446
|
-
await
|
|
461
|
+
const task = await taskBroker.get(taskId);
|
|
462
|
+
await checkPermissions.checkTaskPermission({
|
|
447
463
|
credentials,
|
|
448
464
|
permissions: [alpha.taskCancelPermission, alpha.taskReadPermission],
|
|
449
|
-
permissionService: permissions$1
|
|
465
|
+
permissionService: permissions$1,
|
|
466
|
+
task,
|
|
467
|
+
isTaskAuthorized
|
|
450
468
|
});
|
|
451
469
|
await taskBroker.cancel?.(taskId);
|
|
452
470
|
await auditorEvent?.success();
|
|
@@ -468,11 +486,19 @@ async function createRouter(options) {
|
|
|
468
486
|
});
|
|
469
487
|
try {
|
|
470
488
|
const credentials = await httpAuth.credentials(req);
|
|
489
|
+
const task = await taskBroker.get(taskId);
|
|
471
490
|
await checkPermissions.checkPermission({
|
|
472
491
|
credentials,
|
|
473
|
-
permissions: [alpha.taskCreatePermission
|
|
492
|
+
permissions: [alpha.taskCreatePermission],
|
|
474
493
|
permissionService: permissions$1
|
|
475
494
|
});
|
|
495
|
+
await checkPermissions.checkTaskPermission({
|
|
496
|
+
credentials,
|
|
497
|
+
permissions: [alpha.taskReadPermission],
|
|
498
|
+
permissionService: permissions$1,
|
|
499
|
+
task,
|
|
500
|
+
isTaskAuthorized
|
|
501
|
+
});
|
|
476
502
|
await auditorEvent?.success();
|
|
477
503
|
const { token } = await auth.getPluginRequestToken({
|
|
478
504
|
onBehalfOf: credentials,
|
|
@@ -505,10 +531,13 @@ async function createRouter(options) {
|
|
|
505
531
|
});
|
|
506
532
|
try {
|
|
507
533
|
const credentials = await httpAuth.credentials(req);
|
|
508
|
-
await
|
|
534
|
+
const task = await taskBroker.get(taskId);
|
|
535
|
+
await checkPermissions.checkTaskPermission({
|
|
509
536
|
credentials,
|
|
510
537
|
permissions: [alpha.taskReadPermission],
|
|
511
|
-
permissionService: permissions$1
|
|
538
|
+
permissionService: permissions$1,
|
|
539
|
+
task,
|
|
540
|
+
isTaskAuthorized
|
|
512
541
|
});
|
|
513
542
|
const after = req.query.after !== void 0 ? Number(req.query.after) : void 0;
|
|
514
543
|
logger.debug(`Event stream observing taskId '${taskId}' opened`);
|
|
@@ -566,10 +595,13 @@ data: ${JSON.stringify(event)}
|
|
|
566
595
|
});
|
|
567
596
|
try {
|
|
568
597
|
const credentials = await httpAuth.credentials(req);
|
|
569
|
-
await
|
|
598
|
+
const task = await taskBroker.get(taskId);
|
|
599
|
+
await checkPermissions.checkTaskPermission({
|
|
570
600
|
credentials,
|
|
571
601
|
permissions: [alpha.taskReadPermission],
|
|
572
|
-
permissionService: permissions$1
|
|
602
|
+
permissionService: permissions$1,
|
|
603
|
+
task,
|
|
604
|
+
isTaskAuthorized
|
|
573
605
|
});
|
|
574
606
|
const after = Number(req.query.after) || void 0;
|
|
575
607
|
const timeout = setTimeout(() => {
|
|
@@ -759,13 +791,13 @@ data: ${JSON.stringify(event)}
|
|
|
759
791
|
);
|
|
760
792
|
if (Array.isArray(template.spec.parameters)) {
|
|
761
793
|
template.spec.parameters = template.spec.parameters.filter(
|
|
762
|
-
(step) =>
|
|
794
|
+
(step) => isTemplateAuthorized(parameterDecision, step)
|
|
763
795
|
);
|
|
764
|
-
} else if (template.spec.parameters && !
|
|
796
|
+
} else if (template.spec.parameters && !isTemplateAuthorized(parameterDecision, template.spec.parameters)) {
|
|
765
797
|
template.spec.parameters = void 0;
|
|
766
798
|
}
|
|
767
799
|
template.spec.steps = template.spec.steps.filter(
|
|
768
|
-
(step) =>
|
|
800
|
+
(step) => isTemplateAuthorized(stepDecision, step)
|
|
769
801
|
);
|
|
770
802
|
return template;
|
|
771
803
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.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 {\n AuditorService,\n AuthService,\n BackstageCredentials,\n DatabaseService,\n HttpAuthService,\n LifecycleService,\n LoggerService,\n PermissionsService,\n resolveSafeChildPath,\n SchedulerService,\n} from '@backstage/backend-plugin-api';\nimport {\n CompoundEntityRef,\n Entity,\n parseEntityRef,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport { ScmIntegrations } from '@backstage/integration';\n\nimport { EventsService } from '@backstage/plugin-events-node';\n\nimport {\n createConditionAuthorizer,\n createPermissionIntegrationRouter,\n} from '@backstage/plugin-permission-node';\nimport {\n TaskSpec,\n TemplateEntityV1beta3,\n templateEntityV1beta3Validator,\n} from '@backstage/plugin-scaffolder-common';\nimport {\n RESOURCE_TYPE_SCAFFOLDER_ACTION,\n RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n scaffolderActionPermissions,\n scaffolderPermissions,\n scaffolderTemplatePermissions,\n taskCancelPermission,\n taskCreatePermission,\n taskReadPermission,\n templateParameterReadPermission,\n templateStepReadPermission,\n} from '@backstage/plugin-scaffolder-common/alpha';\nimport {\n TaskBroker,\n TaskStatus,\n TemplateAction,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n AutocompleteHandler,\n CreatedTemplateFilter,\n CreatedTemplateGlobal,\n WorkspaceProvider,\n} from '@backstage/plugin-scaffolder-node/alpha';\nimport { HumanDuration, JsonObject } from '@backstage/types';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { validate } from 'jsonschema';\nimport { Duration } from 'luxon';\nimport { pathToFileURL } from 'url';\nimport { v4 as uuid } from 'uuid';\nimport { z } from 'zod';\nimport {\n DatabaseTaskStore,\n TaskWorker,\n TemplateActionRegistry,\n} from '../scaffolder';\nimport { createDryRunner } from '../scaffolder/dryrun';\nimport { StorageTaskBroker } from '../scaffolder/tasks/StorageTaskBroker';\nimport { InternalTaskSecrets } from '../scaffolder/tasks/types';\nimport { checkPermission } from '../util/checkPermissions';\nimport {\n findTemplate,\n getEntityBaseUrl,\n getWorkingDirectory,\n parseNumberParam,\n parseStringsParam,\n} from './helpers';\nimport { scaffolderActionRules, scaffolderTemplateRules } from './rules';\nimport {\n convertFiltersToRecord,\n convertGlobalsToRecord,\n extractFilterMetadata,\n extractGlobalFunctionMetadata,\n extractGlobalValueMetadata,\n} from '../util/templating';\nimport { createDefaultFilters } from '../lib/templating/filters/createDefaultFilters';\nimport {\n ActionPermissionRuleInput,\n isActionPermissionRuleInput,\n isTemplatePermissionRuleInput,\n TemplatePermissionRuleInput,\n} from './permissions';\nimport { CatalogService } from '@backstage/plugin-catalog-node';\n\n/**\n * RouterOptions\n */\nexport interface RouterOptions {\n logger: LoggerService;\n config: Config;\n lifecycle?: LifecycleService;\n database: DatabaseService;\n catalog: CatalogService;\n scheduler?: SchedulerService;\n actions?: TemplateAction<any, any, any>[];\n /**\n * Sets the number of concurrent tasks that can be run at any given time on the TaskWorker\n * @defaultValue 10\n */\n concurrentTasksLimit?: number;\n taskBroker?: TaskBroker;\n additionalTemplateFilters?:\n | Record<string, TemplateFilter>\n | CreatedTemplateFilter<any, any>[];\n additionalTemplateGlobals?:\n | Record<string, TemplateGlobal>\n | CreatedTemplateGlobal[];\n additionalWorkspaceProviders?: Record<string, WorkspaceProvider>;\n permissions?: PermissionsService;\n permissionRules?: Array<\n TemplatePermissionRuleInput | ActionPermissionRuleInput\n >;\n auth: AuthService;\n httpAuth: HttpAuthService;\n events?: EventsService;\n auditor?: AuditorService;\n autocompleteHandlers?: Record<string, AutocompleteHandler>;\n}\n\nfunction isSupportedTemplate(entity: TemplateEntityV1beta3) {\n return entity.apiVersion === 'scaffolder.backstage.io/v1beta3';\n}\n\nconst readDuration = (\n config: Config,\n key: string,\n defaultValue: HumanDuration,\n) => {\n if (config.has(key)) {\n return readDurationFromConfig(config, { key });\n }\n return defaultValue;\n};\n\n/**\n * A method to create a router for the scaffolder backend plugin.\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const router = Router();\n // Be generous in upload size to support a wide range of templates in dry-run mode.\n router.use(express.json({ limit: '10MB' }));\n\n const {\n logger: parentLogger,\n config,\n database,\n catalog,\n actions,\n scheduler,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n additionalWorkspaceProviders,\n permissions,\n permissionRules,\n autocompleteHandlers = {},\n events: eventsService,\n auth,\n httpAuth,\n auditor,\n } = options;\n\n const concurrentTasksLimit =\n options.concurrentTasksLimit ??\n options.config.getOptionalNumber('scaffolder.concurrentTasksLimit');\n\n const logger = parentLogger.child({ plugin: 'scaffolder' });\n\n const workingDirectory = await getWorkingDirectory(config, logger);\n const integrations = ScmIntegrations.fromConfig(config);\n\n let taskBroker: TaskBroker;\n if (!options.taskBroker) {\n const databaseTaskStore = await DatabaseTaskStore.create({\n database,\n events: eventsService,\n });\n taskBroker = new StorageTaskBroker(\n databaseTaskStore,\n logger,\n config,\n auth,\n additionalWorkspaceProviders,\n auditor,\n );\n\n if (scheduler && databaseTaskStore.listStaleTasks) {\n await scheduler.scheduleTask({\n id: 'close_stale_tasks',\n frequency: readDuration(\n config,\n 'scaffolder.taskTimeoutJanitorFrequency',\n {\n minutes: 5,\n },\n ),\n timeout: { minutes: 15 },\n fn: async () => {\n const { tasks } = await databaseTaskStore.listStaleTasks({\n timeoutS: Duration.fromObject(\n readDuration(config, 'scaffolder.taskTimeout', {\n hours: 24,\n }),\n ).as('seconds'),\n });\n\n for (const task of tasks) {\n await databaseTaskStore.shutdownTask(task);\n logger.info(`Successfully closed stale task ${task.taskId}`);\n }\n },\n });\n }\n } else {\n taskBroker = options.taskBroker;\n }\n\n const actionRegistry = new TemplateActionRegistry();\n\n const templateExtensions = {\n additionalTemplateFilters: convertFiltersToRecord(\n additionalTemplateFilters,\n ),\n additionalTemplateGlobals: convertGlobalsToRecord(\n additionalTemplateGlobals,\n ),\n };\n\n const workers: TaskWorker[] = [];\n if (concurrentTasksLimit !== 0) {\n const gracefulShutdown = config.getOptionalBoolean(\n 'scaffolder.EXPERIMENTAL_gracefulShutdown',\n );\n\n const worker = await TaskWorker.create({\n taskBroker,\n actionRegistry,\n integrations,\n logger,\n auditor,\n workingDirectory,\n concurrentTasksLimit,\n permissions,\n gracefulShutdown,\n ...templateExtensions,\n });\n\n workers.push(worker);\n }\n\n actions?.forEach(action => actionRegistry.register(action));\n\n const launchWorkers = () => workers.forEach(worker => worker.start());\n\n const shutdownWorkers = async () => {\n await Promise.allSettled(workers.map(worker => worker.stop()));\n };\n\n if (options.lifecycle) {\n options.lifecycle.addStartupHook(launchWorkers);\n options.lifecycle.addShutdownHook(shutdownWorkers);\n } else {\n launchWorkers();\n }\n\n const dryRunner = createDryRunner({\n actionRegistry,\n integrations,\n logger,\n auditor,\n workingDirectory,\n permissions,\n ...templateExtensions,\n });\n\n const templateRules: TemplatePermissionRuleInput[] = Object.values(\n scaffolderTemplateRules,\n );\n const actionRules: ActionPermissionRuleInput[] = Object.values(\n scaffolderActionRules,\n );\n\n if (permissionRules) {\n templateRules.push(\n ...permissionRules.filter(isTemplatePermissionRuleInput),\n );\n actionRules.push(...permissionRules.filter(isActionPermissionRuleInput));\n }\n\n const isAuthorized = createConditionAuthorizer(Object.values(templateRules));\n\n const permissionIntegrationRouter = createPermissionIntegrationRouter({\n resources: [\n {\n resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n permissions: scaffolderTemplatePermissions,\n rules: templateRules,\n },\n {\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n permissions: scaffolderActionPermissions,\n rules: actionRules,\n },\n ],\n permissions: scaffolderPermissions,\n });\n\n router.use(permissionIntegrationRouter);\n\n router\n .get(\n '/v2/templates/:namespace/:kind/:name/parameter-schema',\n async (req, res) => {\n const requestedTemplateRef = `${req.params.kind}:${req.params.namespace}/${req.params.name}`;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'template-parameter-schema',\n request: req,\n meta: { templateRef: requestedTemplateRef },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n\n const template = await authorizeTemplate(req.params, credentials);\n\n const parameters = [template.spec.parameters ?? []].flat();\n\n const presentation = template.spec.presentation;\n\n const templateRef = `${template.kind}:${\n template.metadata.namespace || 'default'\n }/${template.metadata.name}`;\n\n await auditorEvent?.success({ meta: { templateRef: templateRef } });\n\n res.json({\n title: template.metadata.title ?? template.metadata.name,\n ...(presentation ? { presentation } : {}),\n description: template.metadata.description,\n 'ui:options': template.metadata['ui:options'],\n steps: parameters.map(schema => ({\n title: schema.title ?? 'Please enter the following information',\n description: schema.description,\n schema,\n })),\n EXPERIMENTAL_formDecorators:\n template.spec.EXPERIMENTAL_formDecorators,\n });\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n },\n )\n .get('/v2/actions', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'action-fetch',\n request: req,\n });\n\n try {\n const actionsList = actionRegistry.list().map(action => {\n return {\n id: action.id,\n description: action.description,\n examples: action.examples,\n schema: action.schema,\n };\n });\n\n await auditorEvent?.success();\n\n res.json(actionsList);\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .post('/v2/tasks', async (req, res) => {\n const templateRef: string = req.body.templateRef;\n const { kind, namespace, name } = parseEntityRef(templateRef, {\n defaultKind: 'template',\n });\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n severityLevel: 'medium',\n request: req,\n meta: {\n actionType: 'create',\n templateRef: templateRef,\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission],\n permissionService: permissions,\n });\n\n const userEntityRef = auth.isPrincipal(credentials, 'user')\n ? credentials.principal.userEntityRef\n : undefined;\n\n const userEntity = userEntityRef\n ? await catalog.getEntityByRef(userEntityRef, { credentials })\n : undefined;\n\n let auditLog = `Scaffolding task for ${templateRef}`;\n if (userEntityRef) {\n auditLog += ` created by ${userEntityRef}`;\n }\n logger.info(auditLog);\n\n const values = req.body.values;\n\n const template = await authorizeTemplate(\n { kind, namespace, name },\n credentials,\n );\n\n for (const parameters of [template.spec.parameters ?? []].flat()) {\n const result = validate(values, parameters);\n\n if (!result.valid) {\n await auditorEvent?.fail({\n // TODO(Rugvip): Seems like there aren't proper types for AggregateError yet\n error: (AggregateError as any)(\n result.errors,\n 'Could not create entity',\n ),\n });\n\n res.status(400).json({ errors: result.errors });\n return;\n }\n }\n\n const baseUrl = getEntityBaseUrl(template);\n\n const taskSpec: TaskSpec = {\n apiVersion: template.apiVersion,\n steps: template.spec.steps.map((step, index) => ({\n ...step,\n id: step.id ?? `step-${index + 1}`,\n name: step.name ?? step.action,\n })),\n EXPERIMENTAL_recovery: template.spec.EXPERIMENTAL_recovery,\n output: template.spec.output ?? {},\n parameters: values,\n user: {\n entity: userEntity as UserEntity,\n ref: userEntityRef,\n },\n templateInfo: {\n entityRef: stringifyEntityRef({ kind, name, namespace }),\n baseUrl,\n entity: {\n metadata: template.metadata,\n },\n },\n };\n\n const secrets: InternalTaskSecrets = {\n ...req.body.secrets,\n backstageToken: (credentials as any).token,\n __initiatorCredentials: JSON.stringify({\n ...credentials,\n // credentials.token is nonenumerable and will not be serialized, so we need to add it explicitly\n token: (credentials as any).token,\n }),\n };\n\n const result = await taskBroker.dispatch({\n spec: taskSpec,\n createdBy: userEntityRef,\n secrets,\n });\n\n await auditorEvent?.success({ meta: { taskId: result.taskId } });\n\n res.status(201).json({ id: result.taskId });\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .get('/v2/tasks', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n request: req,\n meta: {\n actionType: 'list',\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n if (!taskBroker.list) {\n throw new Error(\n 'TaskBroker does not support listing tasks, please implement the list method on the TaskBroker.',\n );\n }\n\n const createdBy = parseStringsParam(req.query.createdBy, 'createdBy');\n const status = parseStringsParam(req.query.status, 'status');\n\n const order = parseStringsParam(req.query.order, 'order')?.map(item => {\n const match = item.match(/^(asc|desc):(.+)$/);\n if (!match) {\n throw new InputError(\n `Invalid order parameter \"${item}\", expected \"<asc or desc>:<field name>\"`,\n );\n }\n\n return {\n order: match[1] as 'asc' | 'desc',\n field: match[2],\n };\n });\n\n const limit = parseNumberParam(req.query.limit, 'limit');\n const offset = parseNumberParam(req.query.offset, 'offset');\n\n const tasks = await taskBroker.list({\n filters: {\n createdBy,\n status: status ? (status as TaskStatus[]) : undefined,\n },\n order,\n pagination: {\n limit: limit ? limit[0] : undefined,\n offset: offset ? offset[0] : undefined,\n },\n });\n\n await auditorEvent?.success();\n\n res.status(200).json(tasks);\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .get('/v2/tasks/:taskId', async (req, res) => {\n const { taskId } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n request: req,\n meta: {\n actionType: 'get',\n taskId: taskId,\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n const task = await taskBroker.get(taskId);\n if (!task) {\n throw new NotFoundError(`Task with id ${taskId} does not exist`);\n }\n\n await auditorEvent?.success();\n\n // Do not disclose secrets\n delete task.secrets;\n res.status(200).json(task);\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .post('/v2/tasks/:taskId/cancel', async (req, res) => {\n const { taskId } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n severityLevel: 'medium',\n request: req,\n meta: {\n actionType: 'cancel',\n taskId: taskId,\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n // Requires both read and cancel permissions\n await checkPermission({\n credentials,\n permissions: [taskCancelPermission, taskReadPermission],\n permissionService: permissions,\n });\n\n await taskBroker.cancel?.(taskId);\n\n await auditorEvent?.success();\n\n res.status(200).json({ status: 'cancelled' });\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .post('/v2/tasks/:taskId/retry', async (req, res) => {\n const { taskId } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n severityLevel: 'medium',\n request: req,\n meta: {\n actionType: 'retry',\n taskId: taskId,\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n // Requires both read and cancel permissions\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission, taskReadPermission],\n permissionService: permissions,\n });\n\n await auditorEvent?.success();\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const secrets: InternalTaskSecrets = {\n ...req.body.secrets,\n backstageToken: token,\n __initiatorCredentials: JSON.stringify({\n ...credentials,\n // credentials.token is nonenumerable and will not be serialized, so we need to add it explicitly\n token: (credentials as any).token,\n }),\n };\n\n await taskBroker.retry?.({ secrets, taskId });\n res.status(201).json({ id: taskId });\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .get('/v2/tasks/:taskId/eventstream', async (req, res) => {\n const { taskId } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n request: req,\n meta: {\n actionType: 'stream',\n taskId: taskId,\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n const after =\n req.query.after !== undefined ? Number(req.query.after) : undefined;\n\n logger.debug(`Event stream observing taskId '${taskId}' opened`);\n\n // Mandatory headers and http status to keep connection open\n res.writeHead(200, {\n Connection: 'keep-alive',\n 'Cache-Control': 'no-cache',\n 'Content-Type': 'text/event-stream',\n });\n\n // After client opens connection send all events as string\n const subscription = taskBroker.event$({ taskId, after }).subscribe({\n error: async error => {\n logger.error(\n `Received error from event stream when observing taskId '${taskId}', ${error}`,\n );\n await auditorEvent?.fail({ error: error });\n res.end();\n },\n next: ({ events }) => {\n let shouldUnsubscribe = false;\n for (const event of events) {\n res.write(\n `event: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`,\n );\n if (event.type === 'completion' && !event.isTaskRecoverable) {\n shouldUnsubscribe = true;\n }\n }\n // res.flush() is only available with the compression middleware\n res.flush?.();\n if (shouldUnsubscribe) {\n subscription.unsubscribe();\n res.end();\n }\n },\n });\n\n // When client closes connection we update the clients list\n // avoiding the disconnected one\n req.on('close', async () => {\n subscription.unsubscribe();\n logger.debug(`Event stream observing taskId '${taskId}' closed`);\n await auditorEvent?.success();\n });\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .get('/v2/tasks/:taskId/events', async (req, res) => {\n const { taskId } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n request: req,\n meta: {\n actionType: 'events',\n taskId: taskId,\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n });\n\n const after = Number(req.query.after) || undefined;\n\n // cancel the request after 30 seconds. this aligns with the recommendations of RFC 6202.\n const timeout = setTimeout(() => {\n res.json([]);\n }, 30_000);\n\n // Get all known events after an id (always includes the completion event) and return the first callback\n const subscription = taskBroker.event$({ taskId, after }).subscribe({\n error: async error => {\n logger.error(\n `Received error from event stream when observing taskId '${taskId}', ${error}`,\n );\n await auditorEvent?.fail({ error: error });\n },\n next: async ({ events }) => {\n clearTimeout(timeout);\n subscription.unsubscribe();\n await auditorEvent?.success();\n res.json(events);\n },\n });\n\n // When client closes connection we update the clients list\n // avoiding the disconnected one\n req.on('close', () => {\n subscription.unsubscribe();\n clearTimeout(timeout);\n });\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .post('/v2/dry-run', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n request: req,\n meta: {\n actionType: 'dry-run',\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission],\n permissionService: permissions,\n });\n\n const bodySchema = z.object({\n template: z.unknown(),\n values: z.record(z.unknown()),\n secrets: z.record(z.string()).optional(),\n directoryContents: z.array(\n z.object({ path: z.string(), base64Content: z.string() }),\n ),\n });\n const body = await bodySchema.parseAsync(req.body).catch(e => {\n throw new InputError(`Malformed request: ${e}`);\n });\n\n const template = body.template as TemplateEntityV1beta3;\n if (!(await templateEntityV1beta3Validator.check(template))) {\n throw new InputError('Input template is not a template');\n }\n\n const userEntityRef = auth.isPrincipal(credentials, 'user')\n ? credentials.principal.userEntityRef\n : undefined;\n\n const userEntity = userEntityRef\n ? await catalog.getEntityByRef(userEntityRef, { credentials })\n : undefined;\n\n const templateRef: string = `${template.kind}:${\n template.metadata.namespace || 'default'\n }/${template.metadata.name}`;\n\n for (const parameters of [template.spec.parameters ?? []].flat()) {\n const result = validate(body.values, parameters);\n if (!result.valid) {\n await auditorEvent?.fail({\n // TODO(Rugvip): Seems like there aren't proper types for AggregateError yet\n error: (AggregateError as any)(\n result.errors,\n 'Could not execute dry run',\n ),\n meta: {\n templateRef: templateRef,\n parameters: template.spec.parameters,\n },\n });\n\n res.status(400).json({ errors: result.errors });\n return;\n }\n }\n\n const steps = template.spec.steps.map((step, index) => ({\n ...step,\n id: step.id ?? `step-${index + 1}`,\n name: step.name ?? step.action,\n }));\n\n const dryRunId = uuid();\n const contentsPath = resolveSafeChildPath(\n workingDirectory,\n `dry-run-content-${dryRunId}`,\n );\n const templateInfo = {\n entityRef: 'template:default/dry-run',\n entity: {\n metadata: template.metadata,\n },\n baseUrl: pathToFileURL(\n resolveSafeChildPath(contentsPath, 'template.yaml'),\n ).toString(),\n };\n\n const result = await dryRunner({\n spec: {\n apiVersion: template.apiVersion,\n steps,\n output: template.spec.output ?? {},\n parameters: body.values as JsonObject,\n user: {\n entity: userEntity as UserEntity,\n ref: userEntityRef,\n },\n },\n templateInfo: templateInfo,\n directoryContents: (body.directoryContents ?? []).map(file => ({\n path: file.path,\n content: Buffer.from(file.base64Content, 'base64'),\n })),\n secrets: {\n ...body.secrets,\n backstageToken: (credentials as any).token,\n },\n credentials,\n });\n\n await auditorEvent?.success({\n meta: {\n templateRef: templateRef,\n parameters: template.spec.parameters,\n },\n });\n\n res.status(200).json({\n ...result,\n steps,\n directoryContents: result.directoryContents.map(file => ({\n path: file.path,\n executable: file.executable,\n base64Content: file.content.toString('base64'),\n })),\n });\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .post('/v2/autocomplete/:provider/:resource', async (req, res) => {\n const { token, context } = req.body;\n const { provider, resource } = req.params;\n\n if (!token) throw new InputError('Missing token query parameter');\n\n if (!autocompleteHandlers[provider]) {\n throw new InputError(`Unsupported provider: ${provider}`);\n }\n\n const { results } = await autocompleteHandlers[provider]({\n resource,\n token,\n context,\n });\n\n res.status(200).json({ results });\n })\n .get('/v2/templating-extensions', async (_req, res) => {\n res.status(200).json({\n filters: {\n ...extractFilterMetadata(createDefaultFilters({ integrations })),\n ...extractFilterMetadata(additionalTemplateFilters),\n },\n globals: {\n functions: extractGlobalFunctionMetadata(additionalTemplateGlobals),\n values: extractGlobalValueMetadata(additionalTemplateGlobals),\n },\n });\n });\n\n const app = express();\n app.set('logger', logger);\n app.use('/', router);\n\n async function authorizeTemplate(\n entityRef: CompoundEntityRef,\n credentials: BackstageCredentials,\n ) {\n const template = await findTemplate({\n catalog,\n entityRef,\n credentials,\n });\n\n if (!isSupportedTemplate(template)) {\n throw new InputError(\n `Unsupported apiVersion field in schema entity, ${\n (template as Entity).apiVersion\n }`,\n );\n }\n\n if (!permissions) {\n return template;\n }\n\n const [parameterDecision, stepDecision] =\n await permissions.authorizeConditional(\n [\n { permission: templateParameterReadPermission },\n { permission: templateStepReadPermission },\n ],\n { credentials },\n );\n\n // Authorize parameters\n if (Array.isArray(template.spec.parameters)) {\n template.spec.parameters = template.spec.parameters.filter(step =>\n isAuthorized(parameterDecision, step),\n );\n } else if (\n template.spec.parameters &&\n !isAuthorized(parameterDecision, template.spec.parameters)\n ) {\n template.spec.parameters = undefined;\n }\n\n // Authorize steps\n template.spec.steps = template.spec.steps.filter(step =>\n isAuthorized(stepDecision, step),\n );\n\n return template;\n }\n\n return app;\n}\n"],"names":["config","readDurationFromConfig","Router","express","permissions","getWorkingDirectory","ScmIntegrations","DatabaseTaskStore","StorageTaskBroker","Duration","TemplateActionRegistry","convertFiltersToRecord","convertGlobalsToRecord","TaskWorker","createDryRunner","scaffolderTemplateRules","scaffolderActionRules","isTemplatePermissionRuleInput","isActionPermissionRuleInput","createConditionAuthorizer","createPermissionIntegrationRouter","RESOURCE_TYPE_SCAFFOLDER_TEMPLATE","scaffolderTemplatePermissions","RESOURCE_TYPE_SCAFFOLDER_ACTION","scaffolderActionPermissions","scaffolderPermissions","parseEntityRef","checkPermission","taskCreatePermission","result","validate","getEntityBaseUrl","stringifyEntityRef","taskReadPermission","parseStringsParam","InputError","parseNumberParam","NotFoundError","taskCancelPermission","z","templateEntityV1beta3Validator","uuid","resolveSafeChildPath","pathToFileURL","extractFilterMetadata","createDefaultFilters","extractGlobalFunctionMetadata","extractGlobalValueMetadata","findTemplate","templateParameterReadPermission","templateStepReadPermission"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"router.cjs.js","sources":["../../src/service/router.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 {\n AuditorService,\n AuthService,\n BackstageCredentials,\n DatabaseService,\n HttpAuthService,\n LifecycleService,\n LoggerService,\n PermissionsService,\n resolveSafeChildPath,\n SchedulerService,\n} from '@backstage/backend-plugin-api';\nimport {\n CompoundEntityRef,\n Entity,\n parseEntityRef,\n stringifyEntityRef,\n UserEntity,\n} from '@backstage/catalog-model';\nimport { Config, readDurationFromConfig } from '@backstage/config';\nimport { InputError, NotFoundError } from '@backstage/errors';\nimport { ScmIntegrations } from '@backstage/integration';\n\nimport { EventsService } from '@backstage/plugin-events-node';\n\nimport {\n createConditionAuthorizer,\n createPermissionIntegrationRouter,\n createConditionTransformer,\n ConditionTransformer,\n} from '@backstage/plugin-permission-node';\nimport {\n TaskSpec,\n TemplateEntityV1beta3,\n templateEntityV1beta3Validator,\n} from '@backstage/plugin-scaffolder-common';\nimport {\n RESOURCE_TYPE_SCAFFOLDER_ACTION,\n RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n RESOURCE_TYPE_SCAFFOLDER_TASK,\n scaffolderActionPermissions,\n scaffolderTaskPermissions,\n scaffolderPermissions,\n scaffolderTemplatePermissions,\n taskCancelPermission,\n taskCreatePermission,\n taskReadPermission,\n templateParameterReadPermission,\n templateStepReadPermission,\n} from '@backstage/plugin-scaffolder-common/alpha';\nimport {\n TaskBroker,\n TaskStatus,\n TemplateAction,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n AutocompleteHandler,\n CreatedTemplateFilter,\n CreatedTemplateGlobal,\n WorkspaceProvider,\n} from '@backstage/plugin-scaffolder-node/alpha';\nimport { HumanDuration, JsonObject } from '@backstage/types';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { validate } from 'jsonschema';\nimport { Duration } from 'luxon';\nimport { pathToFileURL } from 'url';\nimport { v4 as uuid } from 'uuid';\nimport { z } from 'zod';\nimport {\n DatabaseTaskStore,\n TaskWorker,\n TemplateActionRegistry,\n} from '../scaffolder';\nimport { createDryRunner } from '../scaffolder/dryrun';\nimport { StorageTaskBroker } from '../scaffolder/tasks/StorageTaskBroker';\nimport { InternalTaskSecrets } from '../scaffolder/tasks/types';\nimport {\n checkPermission,\n checkTaskPermission,\n getAuthorizeConditions,\n} from '../util/checkPermissions';\nimport {\n findTemplate,\n getEntityBaseUrl,\n getWorkingDirectory,\n parseNumberParam,\n parseStringsParam,\n} from './helpers';\n\nimport {\n convertFiltersToRecord,\n convertGlobalsToRecord,\n extractFilterMetadata,\n extractGlobalFunctionMetadata,\n extractGlobalValueMetadata,\n} from '../util/templating';\nimport { createDefaultFilters } from '../lib/templating/filters/createDefaultFilters';\nimport {\n ScaffolderPermissionRuleInput,\n TaskPermissionRuleInput,\n isTaskPermissionRuleInput,\n ActionPermissionRuleInput,\n isActionPermissionRuleInput,\n isTemplatePermissionRuleInput,\n TemplatePermissionRuleInput,\n} from './permissions';\nimport { CatalogService } from '@backstage/plugin-catalog-node';\n\nimport {\n scaffolderActionRules,\n scaffolderTemplateRules,\n scaffolderTaskRules,\n} from './rules';\n\nimport { TaskFilters } from '@backstage/plugin-scaffolder-node';\n\n/**\n * RouterOptions\n */\nexport interface RouterOptions {\n logger: LoggerService;\n config: Config;\n lifecycle?: LifecycleService;\n database: DatabaseService;\n catalog: CatalogService;\n scheduler?: SchedulerService;\n actions?: TemplateAction<any, any, any>[];\n /**\n * Sets the number of concurrent tasks that can be run at any given time on the TaskWorker\n * @defaultValue 10\n */\n concurrentTasksLimit?: number;\n taskBroker?: TaskBroker;\n additionalTemplateFilters?:\n | Record<string, TemplateFilter>\n | CreatedTemplateFilter<any, any>[];\n additionalTemplateGlobals?:\n | Record<string, TemplateGlobal>\n | CreatedTemplateGlobal[];\n additionalWorkspaceProviders?: Record<string, WorkspaceProvider>;\n permissions?: PermissionsService;\n permissionRules?: Array<ScaffolderPermissionRuleInput>;\n auth: AuthService;\n httpAuth: HttpAuthService;\n events?: EventsService;\n auditor?: AuditorService;\n autocompleteHandlers?: Record<string, AutocompleteHandler>;\n}\n\nfunction isSupportedTemplate(entity: TemplateEntityV1beta3) {\n return entity.apiVersion === 'scaffolder.backstage.io/v1beta3';\n}\n\nconst readDuration = (\n config: Config,\n key: string,\n defaultValue: HumanDuration,\n) => {\n if (config.has(key)) {\n return readDurationFromConfig(config, { key });\n }\n return defaultValue;\n};\n\n/**\n * A method to create a router for the scaffolder backend plugin.\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const router = Router();\n // Be generous in upload size to support a wide range of templates in dry-run mode.\n router.use(express.json({ limit: '10MB' }));\n\n const {\n logger: parentLogger,\n config,\n database,\n catalog,\n actions,\n scheduler,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n additionalWorkspaceProviders,\n permissions,\n permissionRules,\n autocompleteHandlers = {},\n events: eventsService,\n auth,\n httpAuth,\n auditor,\n } = options;\n\n const concurrentTasksLimit =\n options.concurrentTasksLimit ??\n options.config.getOptionalNumber('scaffolder.concurrentTasksLimit');\n\n const logger = parentLogger.child({ plugin: 'scaffolder' });\n\n const workingDirectory = await getWorkingDirectory(config, logger);\n const integrations = ScmIntegrations.fromConfig(config);\n\n let taskBroker: TaskBroker;\n if (!options.taskBroker) {\n const databaseTaskStore = await DatabaseTaskStore.create({\n database,\n events: eventsService,\n });\n taskBroker = new StorageTaskBroker(\n databaseTaskStore,\n logger,\n config,\n auth,\n additionalWorkspaceProviders,\n auditor,\n );\n\n if (scheduler && databaseTaskStore.listStaleTasks) {\n await scheduler.scheduleTask({\n id: 'close_stale_tasks',\n frequency: readDuration(\n config,\n 'scaffolder.taskTimeoutJanitorFrequency',\n {\n minutes: 5,\n },\n ),\n timeout: { minutes: 15 },\n fn: async () => {\n const { tasks } = await databaseTaskStore.listStaleTasks({\n timeoutS: Duration.fromObject(\n readDuration(config, 'scaffolder.taskTimeout', {\n hours: 24,\n }),\n ).as('seconds'),\n });\n\n for (const task of tasks) {\n await databaseTaskStore.shutdownTask(task);\n logger.info(`Successfully closed stale task ${task.taskId}`);\n }\n },\n });\n }\n } else {\n taskBroker = options.taskBroker;\n }\n\n const actionRegistry = new TemplateActionRegistry();\n\n const templateExtensions = {\n additionalTemplateFilters: convertFiltersToRecord(\n additionalTemplateFilters,\n ),\n additionalTemplateGlobals: convertGlobalsToRecord(\n additionalTemplateGlobals,\n ),\n };\n\n const workers: TaskWorker[] = [];\n if (concurrentTasksLimit !== 0) {\n const gracefulShutdown = config.getOptionalBoolean(\n 'scaffolder.EXPERIMENTAL_gracefulShutdown',\n );\n\n const worker = await TaskWorker.create({\n taskBroker,\n actionRegistry,\n integrations,\n logger,\n auditor,\n workingDirectory,\n concurrentTasksLimit,\n permissions,\n gracefulShutdown,\n ...templateExtensions,\n });\n\n workers.push(worker);\n }\n\n actions?.forEach(action => actionRegistry.register(action));\n\n const launchWorkers = () => workers.forEach(worker => worker.start());\n\n const shutdownWorkers = async () => {\n await Promise.allSettled(workers.map(worker => worker.stop()));\n };\n\n if (options.lifecycle) {\n options.lifecycle.addStartupHook(launchWorkers);\n options.lifecycle.addShutdownHook(shutdownWorkers);\n } else {\n launchWorkers();\n }\n\n const dryRunner = createDryRunner({\n actionRegistry,\n integrations,\n logger,\n auditor,\n workingDirectory,\n permissions,\n ...templateExtensions,\n });\n\n const templateRules: TemplatePermissionRuleInput[] = Object.values(\n scaffolderTemplateRules,\n );\n const actionRules: ActionPermissionRuleInput[] = Object.values(\n scaffolderActionRules,\n );\n const taskRules: TaskPermissionRuleInput[] =\n Object.values(scaffolderTaskRules);\n\n if (permissionRules) {\n templateRules.push(\n ...permissionRules.filter(isTemplatePermissionRuleInput),\n );\n actionRules.push(...permissionRules.filter(isActionPermissionRuleInput));\n taskRules.push(...permissionRules.filter(isTaskPermissionRuleInput));\n }\n\n const isTemplateAuthorized = createConditionAuthorizer(\n Object.values(templateRules),\n );\n const isTaskAuthorized = createConditionAuthorizer(Object.values(taskRules));\n\n const taskTransformConditions: ConditionTransformer<TaskFilters> =\n createConditionTransformer(Object.values(taskRules));\n\n const permissionIntegrationRouter = createPermissionIntegrationRouter({\n resources: [\n {\n resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n permissions: scaffolderTemplatePermissions,\n rules: templateRules,\n },\n {\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n permissions: scaffolderActionPermissions,\n rules: actionRules,\n },\n {\n resourceType: RESOURCE_TYPE_SCAFFOLDER_TASK,\n permissions: scaffolderTaskPermissions,\n rules: taskRules,\n },\n ],\n permissions: scaffolderPermissions,\n });\n\n router.use(permissionIntegrationRouter);\n\n router\n .get(\n '/v2/templates/:namespace/:kind/:name/parameter-schema',\n async (req, res) => {\n const requestedTemplateRef = `${req.params.kind}:${req.params.namespace}/${req.params.name}`;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'template-parameter-schema',\n request: req,\n meta: { templateRef: requestedTemplateRef },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n\n const template = await authorizeTemplate(req.params, credentials);\n\n const parameters = [template.spec.parameters ?? []].flat();\n\n const presentation = template.spec.presentation;\n\n const templateRef = `${template.kind}:${\n template.metadata.namespace || 'default'\n }/${template.metadata.name}`;\n\n await auditorEvent?.success({ meta: { templateRef: templateRef } });\n\n res.json({\n title: template.metadata.title ?? template.metadata.name,\n ...(presentation ? { presentation } : {}),\n description: template.metadata.description,\n 'ui:options': template.metadata['ui:options'],\n steps: parameters.map(schema => ({\n title: schema.title ?? 'Please enter the following information',\n description: schema.description,\n schema,\n })),\n EXPERIMENTAL_formDecorators:\n template.spec.EXPERIMENTAL_formDecorators,\n });\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n },\n )\n .get('/v2/actions', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'action-fetch',\n request: req,\n });\n\n try {\n const actionsList = actionRegistry.list().map(action => {\n return {\n id: action.id,\n description: action.description,\n examples: action.examples,\n schema: action.schema,\n };\n });\n\n await auditorEvent?.success();\n\n res.json(actionsList);\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .post('/v2/tasks', async (req, res) => {\n const templateRef: string = req.body.templateRef;\n const { kind, namespace, name } = parseEntityRef(templateRef, {\n defaultKind: 'template',\n });\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n severityLevel: 'medium',\n request: req,\n meta: {\n actionType: 'create',\n templateRef: templateRef,\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission],\n permissionService: permissions,\n });\n\n const userEntityRef = auth.isPrincipal(credentials, 'user')\n ? credentials.principal.userEntityRef\n : undefined;\n\n const userEntity = userEntityRef\n ? await catalog.getEntityByRef(userEntityRef, { credentials })\n : undefined;\n\n let auditLog = `Scaffolding task for ${templateRef}`;\n if (userEntityRef) {\n auditLog += ` created by ${userEntityRef}`;\n }\n logger.info(auditLog);\n\n const values = req.body.values;\n\n const template = await authorizeTemplate(\n { kind, namespace, name },\n credentials,\n );\n\n for (const parameters of [template.spec.parameters ?? []].flat()) {\n const result = validate(values, parameters);\n\n if (!result.valid) {\n await auditorEvent?.fail({\n // TODO(Rugvip): Seems like there aren't proper types for AggregateError yet\n error: (AggregateError as any)(\n result.errors,\n 'Could not create entity',\n ),\n });\n\n res.status(400).json({ errors: result.errors });\n return;\n }\n }\n\n const baseUrl = getEntityBaseUrl(template);\n\n const taskSpec: TaskSpec = {\n apiVersion: template.apiVersion,\n steps: template.spec.steps.map((step, index) => ({\n ...step,\n id: step.id ?? `step-${index + 1}`,\n name: step.name ?? step.action,\n })),\n EXPERIMENTAL_recovery: template.spec.EXPERIMENTAL_recovery,\n output: template.spec.output ?? {},\n parameters: values,\n user: {\n entity: userEntity as UserEntity,\n ref: userEntityRef,\n },\n templateInfo: {\n entityRef: stringifyEntityRef({ kind, name, namespace }),\n baseUrl,\n entity: {\n metadata: template.metadata,\n },\n },\n };\n\n const secrets: InternalTaskSecrets = {\n ...req.body.secrets,\n backstageToken: (credentials as any).token,\n __initiatorCredentials: JSON.stringify({\n ...credentials,\n // credentials.token is nonenumerable and will not be serialized, so we need to add it explicitly\n token: (credentials as any).token,\n }),\n };\n\n const result = await taskBroker.dispatch({\n spec: taskSpec,\n createdBy: userEntityRef,\n secrets,\n });\n\n await auditorEvent?.success({ meta: { taskId: result.taskId } });\n\n res.status(201).json({ id: result.taskId });\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .get('/v2/tasks', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n request: req,\n meta: {\n actionType: 'list',\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n\n if (!taskBroker.list) {\n throw new Error(\n 'TaskBroker does not support listing tasks, please implement the list method on the TaskBroker.',\n );\n }\n\n const createdBy = parseStringsParam(req.query.createdBy, 'createdBy');\n const status = parseStringsParam(req.query.status, 'status');\n\n const order = parseStringsParam(req.query.order, 'order')?.map(item => {\n const match = item.match(/^(asc|desc):(.+)$/);\n if (!match) {\n throw new InputError(\n `Invalid order parameter \"${item}\", expected \"<asc or desc>:<field name>\"`,\n );\n }\n\n return {\n order: match[1] as 'asc' | 'desc',\n field: match[2],\n };\n });\n\n const limit = parseNumberParam(req.query.limit, 'limit');\n const offset = parseNumberParam(req.query.offset, 'offset');\n\n const taskPermissionFilters = await getAuthorizeConditions({\n credentials: credentials,\n permission: taskReadPermission,\n permissionService: permissions,\n transformConditions: taskTransformConditions,\n });\n\n const tasks = await taskBroker.list({\n filters: {\n createdBy,\n status: status ? (status as TaskStatus[]) : undefined,\n },\n order,\n pagination: {\n limit: limit ? limit[0] : undefined,\n offset: offset ? offset[0] : undefined,\n },\n permissionFilters: taskPermissionFilters,\n });\n\n await auditorEvent?.success();\n\n res.status(200).json(tasks);\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .get('/v2/tasks/:taskId', async (req, res) => {\n const { taskId } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n request: req,\n meta: {\n actionType: 'get',\n taskId: taskId,\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n\n const task = await taskBroker.get(taskId);\n\n await checkTaskPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n task: task,\n isTaskAuthorized,\n });\n\n if (!task) {\n throw new NotFoundError(`Task with id ${taskId} does not exist`);\n }\n\n await auditorEvent?.success();\n\n // Do not disclose secrets\n delete task.secrets;\n res.status(200).json(task);\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .post('/v2/tasks/:taskId/cancel', async (req, res) => {\n const { taskId } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n severityLevel: 'medium',\n request: req,\n meta: {\n actionType: 'cancel',\n taskId: taskId,\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n const task = await taskBroker.get(taskId);\n // Requires both read and cancel permissions\n await checkTaskPermission({\n credentials,\n permissions: [taskCancelPermission, taskReadPermission],\n permissionService: permissions,\n task: task,\n isTaskAuthorized,\n });\n\n await taskBroker.cancel?.(taskId);\n\n await auditorEvent?.success();\n\n res.status(200).json({ status: 'cancelled' });\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .post('/v2/tasks/:taskId/retry', async (req, res) => {\n const { taskId } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n severityLevel: 'medium',\n request: req,\n meta: {\n actionType: 'retry',\n taskId: taskId,\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n const task = await taskBroker.get(taskId);\n\n // Requires both read and create permissions\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission],\n permissionService: permissions,\n });\n\n await checkTaskPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n task: task,\n isTaskAuthorized,\n });\n\n await auditorEvent?.success();\n\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: credentials,\n targetPluginId: 'catalog',\n });\n\n const secrets: InternalTaskSecrets = {\n ...req.body.secrets,\n backstageToken: token,\n __initiatorCredentials: JSON.stringify({\n ...credentials,\n // credentials.token is nonenumerable and will not be serialized, so we need to add it explicitly\n token: (credentials as any).token,\n }),\n };\n\n await taskBroker.retry?.({ secrets, taskId });\n res.status(201).json({ id: taskId });\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .get('/v2/tasks/:taskId/eventstream', async (req, res) => {\n const { taskId } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n request: req,\n meta: {\n actionType: 'stream',\n taskId: taskId,\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n const task = await taskBroker.get(taskId);\n\n await checkTaskPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n task: task,\n isTaskAuthorized,\n });\n\n const after =\n req.query.after !== undefined ? Number(req.query.after) : undefined;\n\n logger.debug(`Event stream observing taskId '${taskId}' opened`);\n\n // Mandatory headers and http status to keep connection open\n res.writeHead(200, {\n Connection: 'keep-alive',\n 'Cache-Control': 'no-cache',\n 'Content-Type': 'text/event-stream',\n });\n\n // After client opens connection send all events as string\n const subscription = taskBroker.event$({ taskId, after }).subscribe({\n error: async error => {\n logger.error(\n `Received error from event stream when observing taskId '${taskId}', ${error}`,\n );\n await auditorEvent?.fail({ error: error });\n res.end();\n },\n next: ({ events }) => {\n let shouldUnsubscribe = false;\n for (const event of events) {\n res.write(\n `event: ${event.type}\\ndata: ${JSON.stringify(event)}\\n\\n`,\n );\n if (event.type === 'completion' && !event.isTaskRecoverable) {\n shouldUnsubscribe = true;\n }\n }\n // res.flush() is only available with the compression middleware\n res.flush?.();\n if (shouldUnsubscribe) {\n subscription.unsubscribe();\n res.end();\n }\n },\n });\n\n // When client closes connection we update the clients list\n // avoiding the disconnected one\n req.on('close', async () => {\n subscription.unsubscribe();\n logger.debug(`Event stream observing taskId '${taskId}' closed`);\n await auditorEvent?.success();\n });\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .get('/v2/tasks/:taskId/events', async (req, res) => {\n const { taskId } = req.params;\n\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n request: req,\n meta: {\n actionType: 'events',\n taskId: taskId,\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n const task = await taskBroker.get(taskId);\n\n await checkTaskPermission({\n credentials,\n permissions: [taskReadPermission],\n permissionService: permissions,\n task: task,\n isTaskAuthorized,\n });\n\n const after = Number(req.query.after) || undefined;\n\n // cancel the request after 30 seconds. this aligns with the recommendations of RFC 6202.\n const timeout = setTimeout(() => {\n res.json([]);\n }, 30_000);\n\n // Get all known events after an id (always includes the completion event) and return the first callback\n const subscription = taskBroker.event$({ taskId, after }).subscribe({\n error: async error => {\n logger.error(\n `Received error from event stream when observing taskId '${taskId}', ${error}`,\n );\n await auditorEvent?.fail({ error: error });\n },\n next: async ({ events }) => {\n clearTimeout(timeout);\n subscription.unsubscribe();\n await auditorEvent?.success();\n res.json(events);\n },\n });\n\n // When client closes connection we update the clients list\n // avoiding the disconnected one\n req.on('close', () => {\n subscription.unsubscribe();\n clearTimeout(timeout);\n });\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .post('/v2/dry-run', async (req, res) => {\n const auditorEvent = await auditor?.createEvent({\n eventId: 'task',\n request: req,\n meta: {\n actionType: 'dry-run',\n },\n });\n\n try {\n const credentials = await httpAuth.credentials(req);\n await checkPermission({\n credentials,\n permissions: [taskCreatePermission],\n permissionService: permissions,\n });\n\n const bodySchema = z.object({\n template: z.unknown(),\n values: z.record(z.unknown()),\n secrets: z.record(z.string()).optional(),\n directoryContents: z.array(\n z.object({ path: z.string(), base64Content: z.string() }),\n ),\n });\n const body = await bodySchema.parseAsync(req.body).catch(e => {\n throw new InputError(`Malformed request: ${e}`);\n });\n\n const template = body.template as TemplateEntityV1beta3;\n if (!(await templateEntityV1beta3Validator.check(template))) {\n throw new InputError('Input template is not a template');\n }\n\n const userEntityRef = auth.isPrincipal(credentials, 'user')\n ? credentials.principal.userEntityRef\n : undefined;\n\n const userEntity = userEntityRef\n ? await catalog.getEntityByRef(userEntityRef, { credentials })\n : undefined;\n\n const templateRef: string = `${template.kind}:${\n template.metadata.namespace || 'default'\n }/${template.metadata.name}`;\n\n for (const parameters of [template.spec.parameters ?? []].flat()) {\n const result = validate(body.values, parameters);\n if (!result.valid) {\n await auditorEvent?.fail({\n // TODO(Rugvip): Seems like there aren't proper types for AggregateError yet\n error: (AggregateError as any)(\n result.errors,\n 'Could not execute dry run',\n ),\n meta: {\n templateRef: templateRef,\n parameters: template.spec.parameters,\n },\n });\n\n res.status(400).json({ errors: result.errors });\n return;\n }\n }\n\n const steps = template.spec.steps.map((step, index) => ({\n ...step,\n id: step.id ?? `step-${index + 1}`,\n name: step.name ?? step.action,\n }));\n\n const dryRunId = uuid();\n const contentsPath = resolveSafeChildPath(\n workingDirectory,\n `dry-run-content-${dryRunId}`,\n );\n const templateInfo = {\n entityRef: 'template:default/dry-run',\n entity: {\n metadata: template.metadata,\n },\n baseUrl: pathToFileURL(\n resolveSafeChildPath(contentsPath, 'template.yaml'),\n ).toString(),\n };\n\n const result = await dryRunner({\n spec: {\n apiVersion: template.apiVersion,\n steps,\n output: template.spec.output ?? {},\n parameters: body.values as JsonObject,\n user: {\n entity: userEntity as UserEntity,\n ref: userEntityRef,\n },\n },\n templateInfo: templateInfo,\n directoryContents: (body.directoryContents ?? []).map(file => ({\n path: file.path,\n content: Buffer.from(file.base64Content, 'base64'),\n })),\n secrets: {\n ...body.secrets,\n backstageToken: (credentials as any).token,\n },\n credentials,\n });\n\n await auditorEvent?.success({\n meta: {\n templateRef: templateRef,\n parameters: template.spec.parameters,\n },\n });\n\n res.status(200).json({\n ...result,\n steps,\n directoryContents: result.directoryContents.map(file => ({\n path: file.path,\n executable: file.executable,\n base64Content: file.content.toString('base64'),\n })),\n });\n } catch (err) {\n await auditorEvent?.fail({ error: err });\n throw err;\n }\n })\n .post('/v2/autocomplete/:provider/:resource', async (req, res) => {\n const { token, context } = req.body;\n const { provider, resource } = req.params;\n\n if (!token) throw new InputError('Missing token query parameter');\n\n if (!autocompleteHandlers[provider]) {\n throw new InputError(`Unsupported provider: ${provider}`);\n }\n\n const { results } = await autocompleteHandlers[provider]({\n resource,\n token,\n context,\n });\n\n res.status(200).json({ results });\n })\n .get('/v2/templating-extensions', async (_req, res) => {\n res.status(200).json({\n filters: {\n ...extractFilterMetadata(createDefaultFilters({ integrations })),\n ...extractFilterMetadata(additionalTemplateFilters),\n },\n globals: {\n functions: extractGlobalFunctionMetadata(additionalTemplateGlobals),\n values: extractGlobalValueMetadata(additionalTemplateGlobals),\n },\n });\n });\n\n const app = express();\n app.set('logger', logger);\n app.use('/', router);\n\n async function authorizeTemplate(\n entityRef: CompoundEntityRef,\n credentials: BackstageCredentials,\n ) {\n const template = await findTemplate({\n catalog,\n entityRef,\n credentials,\n });\n\n if (!isSupportedTemplate(template)) {\n throw new InputError(\n `Unsupported apiVersion field in schema entity, ${\n (template as Entity).apiVersion\n }`,\n );\n }\n\n if (!permissions) {\n return template;\n }\n\n const [parameterDecision, stepDecision] =\n await permissions.authorizeConditional(\n [\n { permission: templateParameterReadPermission },\n { permission: templateStepReadPermission },\n ],\n { credentials },\n );\n\n // Authorize parameters\n if (Array.isArray(template.spec.parameters)) {\n template.spec.parameters = template.spec.parameters.filter(step =>\n isTemplateAuthorized(parameterDecision, step),\n );\n } else if (\n template.spec.parameters &&\n !isTemplateAuthorized(parameterDecision, template.spec.parameters)\n ) {\n template.spec.parameters = undefined;\n }\n\n // Authorize steps\n template.spec.steps = template.spec.steps.filter(step =>\n isTemplateAuthorized(stepDecision, step),\n );\n\n return template;\n }\n\n return app;\n}\n"],"names":["config","readDurationFromConfig","Router","express","permissions","getWorkingDirectory","ScmIntegrations","DatabaseTaskStore","StorageTaskBroker","Duration","TemplateActionRegistry","convertFiltersToRecord","convertGlobalsToRecord","TaskWorker","createDryRunner","scaffolderTemplateRules","scaffolderActionRules","scaffolderTaskRules","isTemplatePermissionRuleInput","isActionPermissionRuleInput","isTaskPermissionRuleInput","createConditionAuthorizer","createConditionTransformer","createPermissionIntegrationRouter","RESOURCE_TYPE_SCAFFOLDER_TEMPLATE","scaffolderTemplatePermissions","RESOURCE_TYPE_SCAFFOLDER_ACTION","scaffolderActionPermissions","RESOURCE_TYPE_SCAFFOLDER_TASK","scaffolderTaskPermissions","scaffolderPermissions","parseEntityRef","checkPermission","taskCreatePermission","result","validate","getEntityBaseUrl","stringifyEntityRef","parseStringsParam","InputError","parseNumberParam","getAuthorizeConditions","taskReadPermission","checkTaskPermission","NotFoundError","taskCancelPermission","z","templateEntityV1beta3Validator","uuid","resolveSafeChildPath","pathToFileURL","extractFilterMetadata","createDefaultFilters","extractGlobalFunctionMetadata","extractGlobalValueMetadata","findTemplate","templateParameterReadPermission","templateStepReadPermission"],"mappings":"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"}
|
|
@@ -77,6 +77,29 @@ function buildHasProperty({
|
|
|
77
77
|
toQuery: () => ({})
|
|
78
78
|
});
|
|
79
79
|
}
|
|
80
|
+
const createTaskPermissionRule = pluginPermissionNode.makeCreatePermissionRule();
|
|
81
|
+
const isTaskOwner = createTaskPermissionRule({
|
|
82
|
+
name: "IS_TASK_OWNER",
|
|
83
|
+
description: "Allows tasks created by certain users to be accessible",
|
|
84
|
+
resourceType: alpha.RESOURCE_TYPE_SCAFFOLDER_TASK,
|
|
85
|
+
paramsSchema: zod.z.object({
|
|
86
|
+
createdBy: zod.z.array(zod.z.string()).describe(
|
|
87
|
+
"List of creater entity refs; only tasks created by these users will be viewable"
|
|
88
|
+
)
|
|
89
|
+
}),
|
|
90
|
+
apply: (resource, { createdBy }) => {
|
|
91
|
+
if (!resource.createdBy) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
return createdBy.includes(resource.createdBy);
|
|
95
|
+
},
|
|
96
|
+
toQuery: ({ createdBy }) => {
|
|
97
|
+
return {
|
|
98
|
+
key: "created_by",
|
|
99
|
+
values: createdBy
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
});
|
|
80
103
|
const scaffolderTemplateRules = { hasTag };
|
|
81
104
|
const scaffolderActionRules = {
|
|
82
105
|
hasActionId,
|
|
@@ -84,14 +107,18 @@ const scaffolderActionRules = {
|
|
|
84
107
|
hasNumberProperty,
|
|
85
108
|
hasStringProperty
|
|
86
109
|
};
|
|
110
|
+
const scaffolderTaskRules = { isTaskOwner };
|
|
87
111
|
|
|
88
112
|
exports.createActionPermissionRule = createActionPermissionRule;
|
|
113
|
+
exports.createTaskPermissionRule = createTaskPermissionRule;
|
|
89
114
|
exports.createTemplatePermissionRule = createTemplatePermissionRule;
|
|
90
115
|
exports.hasActionId = hasActionId;
|
|
91
116
|
exports.hasBooleanProperty = hasBooleanProperty;
|
|
92
117
|
exports.hasNumberProperty = hasNumberProperty;
|
|
93
118
|
exports.hasStringProperty = hasStringProperty;
|
|
94
119
|
exports.hasTag = hasTag;
|
|
120
|
+
exports.isTaskOwner = isTaskOwner;
|
|
95
121
|
exports.scaffolderActionRules = scaffolderActionRules;
|
|
122
|
+
exports.scaffolderTaskRules = scaffolderTaskRules;
|
|
96
123
|
exports.scaffolderTemplateRules = scaffolderTemplateRules;
|
|
97
124
|
//# sourceMappingURL=rules.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rules.cjs.js","sources":["../../src/service/rules.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 { makeCreatePermissionRule } from '@backstage/plugin-permission-node';\nimport {\n RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n RESOURCE_TYPE_SCAFFOLDER_ACTION,\n} from '@backstage/plugin-scaffolder-common/alpha';\n\nimport {\n TemplateEntityStepV1beta3,\n TemplateParametersV1beta3,\n} from '@backstage/plugin-scaffolder-common';\n\nimport { z } from 'zod';\nimport { JsonObject, JsonPrimitive } from '@backstage/types';\nimport { get } from 'lodash';\n\nexport const createTemplatePermissionRule = makeCreatePermissionRule<\n TemplateEntityStepV1beta3 | TemplateParametersV1beta3,\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_TEMPLATE\n>();\n\nexport const hasTag = createTemplatePermissionRule({\n name: 'HAS_TAG',\n resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n description: `Match parameters or steps with the given tag`,\n paramsSchema: z.object({\n tag: z.string().describe('Name of the tag to match on'),\n }),\n apply: (resource, { tag }) => {\n return resource['backstage:permissions']?.tags?.includes(tag) ?? false;\n },\n toQuery: () => ({}),\n});\n\nexport const createActionPermissionRule = makeCreatePermissionRule<\n {\n action: string;\n input: JsonObject | undefined;\n },\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_ACTION\n>();\n\nexport const hasActionId = createActionPermissionRule({\n name: 'HAS_ACTION_ID',\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n description: `Match actions with the given actionId`,\n paramsSchema: z.object({\n actionId: z.string().describe('Name of the actionId to match on'),\n }),\n apply: (resource, { actionId }) => {\n return resource.action === actionId;\n },\n toQuery: () => ({}),\n});\n\nexport const hasProperty = buildHasProperty({\n name: 'HAS_PROPERTY',\n valueSchema: z.union([z.string(), z.number(), z.boolean(), z.null()]),\n validateProperty: false,\n});\n\nexport const hasBooleanProperty = buildHasProperty({\n name: 'HAS_BOOLEAN_PROPERTY',\n valueSchema: z.boolean(),\n});\nexport const hasNumberProperty = buildHasProperty({\n name: 'HAS_NUMBER_PROPERTY',\n valueSchema: z.number(),\n});\nexport const hasStringProperty = buildHasProperty({\n name: 'HAS_STRING_PROPERTY',\n valueSchema: z.string(),\n});\n\nfunction buildHasProperty<Schema extends z.ZodType<JsonPrimitive>>({\n name,\n valueSchema,\n validateProperty = true,\n}: {\n name: string;\n valueSchema: Schema;\n validateProperty?: boolean;\n}) {\n return createActionPermissionRule({\n name,\n description: `Allow actions with the specified property`,\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n paramsSchema: z.object({\n key: z\n .string()\n .describe(`Property within the action parameters to match on`),\n value: valueSchema\n .optional()\n .describe(`Value of the given property to match on`),\n }) as unknown as z.ZodType<{ key: string; value?: z.infer<Schema> }>,\n apply: (resource, { key, value }) => {\n const foundValue = get(resource.input, key);\n\n if (validateProperty && !valueSchema.safeParse(foundValue).success) {\n return false;\n }\n if (value !== undefined) {\n if (valueSchema.safeParse(value).success) {\n return value === foundValue;\n }\n return false;\n }\n\n return foundValue !== undefined;\n },\n toQuery: () => ({}),\n });\n}\n\nexport const scaffolderTemplateRules = { hasTag };\nexport const scaffolderActionRules = {\n hasActionId,\n hasBooleanProperty,\n hasNumberProperty,\n hasStringProperty,\n};\n"],"names":["makeCreatePermissionRule","RESOURCE_TYPE_SCAFFOLDER_TEMPLATE","z","RESOURCE_TYPE_SCAFFOLDER_ACTION","get"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"rules.cjs.js","sources":["../../src/service/rules.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 { makeCreatePermissionRule } from '@backstage/plugin-permission-node';\n\nimport {\n RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n RESOURCE_TYPE_SCAFFOLDER_ACTION,\n RESOURCE_TYPE_SCAFFOLDER_TASK,\n} from '@backstage/plugin-scaffolder-common/alpha';\n\nimport {\n TemplateEntityStepV1beta3,\n TemplateParametersV1beta3,\n} from '@backstage/plugin-scaffolder-common';\n\nimport { SerializedTask, TaskFilter } from '@backstage/plugin-scaffolder-node';\n\nimport { z } from 'zod';\nimport { JsonObject, JsonPrimitive } from '@backstage/types';\nimport { get } from 'lodash';\n\nexport const createTemplatePermissionRule = makeCreatePermissionRule<\n TemplateEntityStepV1beta3 | TemplateParametersV1beta3,\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_TEMPLATE\n>();\n\nexport const hasTag = createTemplatePermissionRule({\n name: 'HAS_TAG',\n resourceType: RESOURCE_TYPE_SCAFFOLDER_TEMPLATE,\n description: `Match parameters or steps with the given tag`,\n paramsSchema: z.object({\n tag: z.string().describe('Name of the tag to match on'),\n }),\n apply: (resource, { tag }) => {\n return resource['backstage:permissions']?.tags?.includes(tag) ?? false;\n },\n toQuery: () => ({}),\n});\n\nexport const createActionPermissionRule = makeCreatePermissionRule<\n {\n action: string;\n input: JsonObject | undefined;\n },\n {},\n typeof RESOURCE_TYPE_SCAFFOLDER_ACTION\n>();\n\nexport const hasActionId = createActionPermissionRule({\n name: 'HAS_ACTION_ID',\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n description: `Match actions with the given actionId`,\n paramsSchema: z.object({\n actionId: z.string().describe('Name of the actionId to match on'),\n }),\n apply: (resource, { actionId }) => {\n return resource.action === actionId;\n },\n toQuery: () => ({}),\n});\n\nexport const hasProperty = buildHasProperty({\n name: 'HAS_PROPERTY',\n valueSchema: z.union([z.string(), z.number(), z.boolean(), z.null()]),\n validateProperty: false,\n});\n\nexport const hasBooleanProperty = buildHasProperty({\n name: 'HAS_BOOLEAN_PROPERTY',\n valueSchema: z.boolean(),\n});\nexport const hasNumberProperty = buildHasProperty({\n name: 'HAS_NUMBER_PROPERTY',\n valueSchema: z.number(),\n});\nexport const hasStringProperty = buildHasProperty({\n name: 'HAS_STRING_PROPERTY',\n valueSchema: z.string(),\n});\n\nfunction buildHasProperty<Schema extends z.ZodType<JsonPrimitive>>({\n name,\n valueSchema,\n validateProperty = true,\n}: {\n name: string;\n valueSchema: Schema;\n validateProperty?: boolean;\n}) {\n return createActionPermissionRule({\n name,\n description: `Allow actions with the specified property`,\n resourceType: RESOURCE_TYPE_SCAFFOLDER_ACTION,\n paramsSchema: z.object({\n key: z\n .string()\n .describe(`Property within the action parameters to match on`),\n value: valueSchema\n .optional()\n .describe(`Value of the given property to match on`),\n }) as unknown as z.ZodType<{ key: string; value?: z.infer<Schema> }>,\n apply: (resource, { key, value }) => {\n const foundValue = get(resource.input, key);\n\n if (validateProperty && !valueSchema.safeParse(foundValue).success) {\n return false;\n }\n if (value !== undefined) {\n if (valueSchema.safeParse(value).success) {\n return value === foundValue;\n }\n return false;\n }\n\n return foundValue !== undefined;\n },\n toQuery: () => ({}),\n });\n}\n\nexport const createTaskPermissionRule = makeCreatePermissionRule<\n SerializedTask,\n TaskFilter,\n typeof RESOURCE_TYPE_SCAFFOLDER_TASK\n>();\n\nexport const isTaskOwner = createTaskPermissionRule({\n name: 'IS_TASK_OWNER',\n description: 'Allows tasks created by certain users to be accessible',\n resourceType: RESOURCE_TYPE_SCAFFOLDER_TASK,\n paramsSchema: z.object({\n createdBy: z\n .array(z.string())\n .describe(\n 'List of creater entity refs; only tasks created by these users will be viewable',\n ),\n }),\n apply: (resource, { createdBy }) => {\n if (!resource.createdBy) {\n return false;\n }\n return createdBy.includes(resource.createdBy);\n },\n toQuery: ({ createdBy }) => {\n return {\n key: 'created_by',\n values: createdBy,\n };\n },\n});\n\nexport const scaffolderTemplateRules = { hasTag };\nexport const scaffolderActionRules = {\n hasActionId,\n hasBooleanProperty,\n hasNumberProperty,\n hasStringProperty,\n};\nexport const scaffolderTaskRules = { isTaskOwner };\n"],"names":["makeCreatePermissionRule","RESOURCE_TYPE_SCAFFOLDER_TEMPLATE","z","RESOURCE_TYPE_SCAFFOLDER_ACTION","get","RESOURCE_TYPE_SCAFFOLDER_TASK"],"mappings":";;;;;;;AAmCO,MAAM,+BAA+BA,6CAI1C;AAEK,MAAM,SAAS,4BAA6B,CAAA;AAAA,EACjD,IAAM,EAAA,SAAA;AAAA,EACN,YAAc,EAAAC,uCAAA;AAAA,EACd,WAAa,EAAA,CAAA,4CAAA,CAAA;AAAA,EACb,YAAA,EAAcC,MAAE,MAAO,CAAA;AAAA,IACrB,GAAK,EAAAA,KAAA,CAAE,MAAO,EAAA,CAAE,SAAS,6BAA6B;AAAA,GACvD,CAAA;AAAA,EACD,KAAO,EAAA,CAAC,QAAU,EAAA,EAAE,KAAU,KAAA;AAC5B,IAAA,OAAO,SAAS,uBAAuB,CAAA,EAAG,IAAM,EAAA,QAAA,CAAS,GAAG,CAAK,IAAA,KAAA;AAAA,GACnE;AAAA,EACA,OAAA,EAAS,OAAO,EAAC;AACnB,CAAC;AAEM,MAAM,6BAA6BF,6CAOxC;AAEK,MAAM,cAAc,0BAA2B,CAAA;AAAA,EACpD,IAAM,EAAA,eAAA;AAAA,EACN,YAAc,EAAAG,qCAAA;AAAA,EACd,WAAa,EAAA,CAAA,qCAAA,CAAA;AAAA,EACb,YAAA,EAAcD,MAAE,MAAO,CAAA;AAAA,IACrB,QAAU,EAAAA,KAAA,CAAE,MAAO,EAAA,CAAE,SAAS,kCAAkC;AAAA,GACjE,CAAA;AAAA,EACD,KAAO,EAAA,CAAC,QAAU,EAAA,EAAE,UAAe,KAAA;AACjC,IAAA,OAAO,SAAS,MAAW,KAAA,QAAA;AAAA,GAC7B;AAAA,EACA,OAAA,EAAS,OAAO,EAAC;AACnB,CAAC;AAE0B,gBAAiB,CAAA;AAAA,EAC1C,IAAM,EAAA,cAAA;AAAA,EACN,aAAaA,KAAE,CAAA,KAAA,CAAM,CAACA,KAAA,CAAE,QAAU,EAAAA,KAAA,CAAE,MAAO,EAAA,EAAGA,MAAE,OAAQ,EAAA,EAAGA,KAAE,CAAA,IAAA,EAAM,CAAC,CAAA;AAAA,EACpE,gBAAkB,EAAA;AACpB,CAAC;AAEM,MAAM,qBAAqB,gBAAiB,CAAA;AAAA,EACjD,IAAM,EAAA,sBAAA;AAAA,EACN,WAAA,EAAaA,MAAE,OAAQ;AACzB,CAAC;AACM,MAAM,oBAAoB,gBAAiB,CAAA;AAAA,EAChD,IAAM,EAAA,qBAAA;AAAA,EACN,WAAA,EAAaA,MAAE,MAAO;AACxB,CAAC;AACM,MAAM,oBAAoB,gBAAiB,CAAA;AAAA,EAChD,IAAM,EAAA,qBAAA;AAAA,EACN,WAAA,EAAaA,MAAE,MAAO;AACxB,CAAC;AAED,SAAS,gBAA0D,CAAA;AAAA,EACjE,IAAA;AAAA,EACA,WAAA;AAAA,EACA,gBAAmB,GAAA;AACrB,CAIG,EAAA;AACD,EAAA,OAAO,0BAA2B,CAAA;AAAA,IAChC,IAAA;AAAA,IACA,WAAa,EAAA,CAAA,yCAAA,CAAA;AAAA,IACb,YAAc,EAAAC,qCAAA;AAAA,IACd,YAAA,EAAcD,MAAE,MAAO,CAAA;AAAA,MACrB,GAAK,EAAAA,KAAA,CACF,MAAO,EAAA,CACP,SAAS,CAAmD,iDAAA,CAAA,CAAA;AAAA,MAC/D,KAAO,EAAA,WAAA,CACJ,QAAS,EAAA,CACT,SAAS,CAAyC,uCAAA,CAAA;AAAA,KACtD,CAAA;AAAA,IACD,OAAO,CAAC,QAAA,EAAU,EAAE,GAAA,EAAK,OAAY,KAAA;AACnC,MAAA,MAAM,UAAa,GAAAE,UAAA,CAAI,QAAS,CAAA,KAAA,EAAO,GAAG,CAAA;AAE1C,MAAA,IAAI,oBAAoB,CAAC,WAAA,CAAY,SAAU,CAAA,UAAU,EAAE,OAAS,EAAA;AAClE,QAAO,OAAA,KAAA;AAAA;AAET,MAAA,IAAI,UAAU,KAAW,CAAA,EAAA;AACvB,QAAA,IAAI,WAAY,CAAA,SAAA,CAAU,KAAK,CAAA,CAAE,OAAS,EAAA;AACxC,UAAA,OAAO,KAAU,KAAA,UAAA;AAAA;AAEnB,QAAO,OAAA,KAAA;AAAA;AAGT,MAAA,OAAO,UAAe,KAAA,KAAA,CAAA;AAAA,KACxB;AAAA,IACA,OAAA,EAAS,OAAO,EAAC;AAAA,GAClB,CAAA;AACH;AAEO,MAAM,2BAA2BJ,6CAItC;AAEK,MAAM,cAAc,wBAAyB,CAAA;AAAA,EAClD,IAAM,EAAA,eAAA;AAAA,EACN,WAAa,EAAA,wDAAA;AAAA,EACb,YAAc,EAAAK,mCAAA;AAAA,EACd,YAAA,EAAcH,MAAE,MAAO,CAAA;AAAA,IACrB,WAAWA,KACR,CAAA,KAAA,CAAMA,KAAE,CAAA,MAAA,EAAQ,CAChB,CAAA,QAAA;AAAA,MACC;AAAA;AACF,GACH,CAAA;AAAA,EACD,KAAO,EAAA,CAAC,QAAU,EAAA,EAAE,WAAgB,KAAA;AAClC,IAAI,IAAA,CAAC,SAAS,SAAW,EAAA;AACvB,MAAO,OAAA,KAAA;AAAA;AAET,IAAO,OAAA,SAAA,CAAU,QAAS,CAAA,QAAA,CAAS,SAAS,CAAA;AAAA,GAC9C;AAAA,EACA,OAAS,EAAA,CAAC,EAAE,SAAA,EAAgB,KAAA;AAC1B,IAAO,OAAA;AAAA,MACL,GAAK,EAAA,YAAA;AAAA,MACL,MAAQ,EAAA;AAAA,KACV;AAAA;AAEJ,CAAC;AAEY,MAAA,uBAAA,GAA0B,EAAE,MAAO;AACzC,MAAM,qBAAwB,GAAA;AAAA,EACnC,WAAA;AAAA,EACA,kBAAA;AAAA,EACA,iBAAA;AAAA,EACA;AACF;AACa,MAAA,mBAAA,GAAsB,EAAE,WAAY;;;;;;;;;;;;;;;"}
|
|
@@ -20,6 +20,44 @@ async function checkPermission(options) {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
|
+
async function checkTaskPermission(options) {
|
|
24
|
+
const {
|
|
25
|
+
permissions,
|
|
26
|
+
permissionService,
|
|
27
|
+
credentials,
|
|
28
|
+
task,
|
|
29
|
+
isTaskAuthorized
|
|
30
|
+
} = options;
|
|
31
|
+
if (permissionService) {
|
|
32
|
+
const permissionRequest = permissions.map((permission) => ({
|
|
33
|
+
permission
|
|
34
|
+
}));
|
|
35
|
+
const authorizationResponses = await permissionService.authorizeConditional(
|
|
36
|
+
permissionRequest,
|
|
37
|
+
{ credentials }
|
|
38
|
+
);
|
|
39
|
+
for (const response of authorizationResponses) {
|
|
40
|
+
if (response.result === pluginPermissionCommon.AuthorizeResult.DENY || !isTaskAuthorized(response, task)) {
|
|
41
|
+
throw new errors.NotAllowedError();
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
const getAuthorizeConditions = async (options) => {
|
|
47
|
+
const { permission, permissionService, credentials, transformConditions } = options;
|
|
48
|
+
if (permissionService) {
|
|
49
|
+
const [taskDecision] = await permissionService.authorizeConditional(
|
|
50
|
+
[{ permission }],
|
|
51
|
+
{ credentials }
|
|
52
|
+
);
|
|
53
|
+
if (taskDecision.result === pluginPermissionCommon.AuthorizeResult.CONDITIONAL) {
|
|
54
|
+
return transformConditions(taskDecision.conditions);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return void 0;
|
|
58
|
+
};
|
|
23
59
|
|
|
24
60
|
exports.checkPermission = checkPermission;
|
|
61
|
+
exports.checkTaskPermission = checkTaskPermission;
|
|
62
|
+
exports.getAuthorizeConditions = getAuthorizeConditions;
|
|
25
63
|
//# sourceMappingURL=checkPermissions.cjs.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkPermissions.cjs.js","sources":["../../src/util/checkPermissions.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 */\nimport {\n BackstageCredentials,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\nimport { NotAllowedError } from '@backstage/errors';\nimport {\n AuthorizeResult,\n BasicPermission,\n} from '@backstage/plugin-permission-common';\n\nexport type checkPermissionOptions = {\n credentials: BackstageCredentials;\n permissions: BasicPermission[];\n permissionService?: PermissionsService;\n};\n\n/**\n * Does a basic check on permissions. Throws 403 error if any permission responds with AuthorizeResult.DENY\n * @public\n */\nexport async function checkPermission(options: checkPermissionOptions) {\n const { permissions, permissionService, credentials } = options;\n if (permissionService) {\n const permissionRequest = permissions.map(permission => ({\n permission,\n }));\n const authorizationResponses = await permissionService.authorize(\n permissionRequest,\n { credentials: credentials },\n );\n\n for (const response of authorizationResponses) {\n if (response.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n }\n }\n}\n"],"names":["AuthorizeResult","NotAllowedError"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"checkPermissions.cjs.js","sources":["../../src/util/checkPermissions.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 */\nimport {\n BackstageCredentials,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\nimport { NotAllowedError } from '@backstage/errors';\nimport {\n AuthorizeResult,\n BasicPermission,\n PermissionCriteria,\n PolicyDecision,\n ResourcePermission,\n} from '@backstage/plugin-permission-common';\nimport { ConditionTransformer } from '@backstage/plugin-permission-node';\nimport { SerializedTask } from '@backstage/plugin-scaffolder-node';\nimport { TaskFilters } from '@backstage/plugin-scaffolder-node';\n\nexport type checkPermissionOptions = {\n credentials: BackstageCredentials;\n permissions: BasicPermission[];\n permissionService?: PermissionsService;\n};\n\nexport type checkTaskPermissionOptions = {\n credentials: BackstageCredentials;\n permissions: ResourcePermission[];\n permissionService?: PermissionsService;\n task: SerializedTask;\n isTaskAuthorized: (\n decision: PolicyDecision,\n resource: SerializedTask | undefined,\n ) => boolean;\n};\n\nexport type authorizeConditionsOptions = {\n credentials: BackstageCredentials;\n permission: ResourcePermission;\n permissionService?: PermissionsService;\n transformConditions: ConditionTransformer<TaskFilters>;\n};\n\n/**\n * Does a basic check on permissions. Throws 403 error if any permission responds with AuthorizeResult.DENY\n * @public\n */\nexport async function checkPermission(options: checkPermissionOptions) {\n const { permissions, permissionService, credentials } = options;\n if (permissionService) {\n const permissionRequest = permissions.map(permission => ({\n permission,\n }));\n const authorizationResponses = await permissionService.authorize(\n permissionRequest,\n { credentials: credentials },\n );\n\n for (const response of authorizationResponses) {\n if (response.result === AuthorizeResult.DENY) {\n throw new NotAllowedError();\n }\n }\n }\n}\n\n/**\n * Does a conditional permission check for scaffolder task reading and cancellation.\n * Throws 403 error if permission responds with AuthorizeResult.DENY, or does not resolve to true during the conditional rule check\n * @public\n */\nexport async function checkTaskPermission(options: checkTaskPermissionOptions) {\n const {\n permissions,\n permissionService,\n credentials,\n task,\n isTaskAuthorized,\n } = options;\n if (permissionService) {\n const permissionRequest = permissions.map(permission => ({\n permission,\n }));\n const authorizationResponses = await permissionService.authorizeConditional(\n permissionRequest,\n { credentials },\n );\n for (const response of authorizationResponses) {\n if (\n response.result === AuthorizeResult.DENY ||\n !isTaskAuthorized(response, task)\n ) {\n throw new NotAllowedError();\n }\n }\n }\n}\n\n/** Fetches and transforms authorization conditions into filters, or returns `undefined` if the decision is not conditional.\n * @public\n */\nexport const getAuthorizeConditions = async (\n options: authorizeConditionsOptions,\n): Promise<PermissionCriteria<TaskFilters> | undefined> => {\n const { permission, permissionService, credentials, transformConditions } =\n options;\n if (permissionService) {\n const [taskDecision] = await permissionService.authorizeConditional(\n [{ permission: permission }],\n { credentials },\n );\n if (taskDecision.result === AuthorizeResult.CONDITIONAL) {\n return transformConditions(taskDecision.conditions);\n }\n }\n return undefined;\n};\n"],"names":["AuthorizeResult","NotAllowedError"],"mappings":";;;;;AA2DA,eAAsB,gBAAgB,OAAiC,EAAA;AACrE,EAAA,MAAM,EAAE,WAAA,EAAa,iBAAmB,EAAA,WAAA,EAAgB,GAAA,OAAA;AACxD,EAAA,IAAI,iBAAmB,EAAA;AACrB,IAAM,MAAA,iBAAA,GAAoB,WAAY,CAAA,GAAA,CAAI,CAAe,UAAA,MAAA;AAAA,MACvD;AAAA,KACA,CAAA,CAAA;AACF,IAAM,MAAA,sBAAA,GAAyB,MAAM,iBAAkB,CAAA,SAAA;AAAA,MACrD,iBAAA;AAAA,MACA,EAAE,WAAyB;AAAA,KAC7B;AAEA,IAAA,KAAA,MAAW,YAAY,sBAAwB,EAAA;AAC7C,MAAI,IAAA,QAAA,CAAS,MAAW,KAAAA,sCAAA,CAAgB,IAAM,EAAA;AAC5C,QAAA,MAAM,IAAIC,sBAAgB,EAAA;AAAA;AAC5B;AACF;AAEJ;AAOA,eAAsB,oBAAoB,OAAqC,EAAA;AAC7E,EAAM,MAAA;AAAA,IACJ,WAAA;AAAA,IACA,iBAAA;AAAA,IACA,WAAA;AAAA,IACA,IAAA;AAAA,IACA;AAAA,GACE,GAAA,OAAA;AACJ,EAAA,IAAI,iBAAmB,EAAA;AACrB,IAAM,MAAA,iBAAA,GAAoB,WAAY,CAAA,GAAA,CAAI,CAAe,UAAA,MAAA;AAAA,MACvD;AAAA,KACA,CAAA,CAAA;AACF,IAAM,MAAA,sBAAA,GAAyB,MAAM,iBAAkB,CAAA,oBAAA;AAAA,MACrD,iBAAA;AAAA,MACA,EAAE,WAAY;AAAA,KAChB;AACA,IAAA,KAAA,MAAW,YAAY,sBAAwB,EAAA;AAC7C,MACE,IAAA,QAAA,CAAS,WAAWD,sCAAgB,CAAA,IAAA,IACpC,CAAC,gBAAiB,CAAA,QAAA,EAAU,IAAI,CAChC,EAAA;AACA,QAAA,MAAM,IAAIC,sBAAgB,EAAA;AAAA;AAC5B;AACF;AAEJ;AAKa,MAAA,sBAAA,GAAyB,OACpC,OACyD,KAAA;AACzD,EAAA,MAAM,EAAE,UAAA,EAAY,iBAAmB,EAAA,WAAA,EAAa,qBAClD,GAAA,OAAA;AACF,EAAA,IAAI,iBAAmB,EAAA;AACrB,IAAA,MAAM,CAAC,YAAY,CAAI,GAAA,MAAM,iBAAkB,CAAA,oBAAA;AAAA,MAC7C,CAAC,EAAE,UAAA,EAAwB,CAAA;AAAA,MAC3B,EAAE,WAAY;AAAA,KAChB;AACA,IAAI,IAAA,YAAA,CAAa,MAAW,KAAAD,sCAAA,CAAgB,WAAa,EAAA;AACvD,MAAO,OAAA,mBAAA,CAAoB,aAAa,UAAU,CAAA;AAAA;AACpD;AAEF,EAAO,OAAA,KAAA,CAAA;AACT;;;;;;"}
|