@backstage/plugin-scaffolder-backend 4.0.3-next.1 → 4.0.3
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 +28 -0
- package/dist/ScaffolderPlugin.cjs.js +1 -1
- package/dist/scaffolder/actions/builtin/fetch/template.cjs.js +3 -1
- package/dist/scaffolder/actions/builtin/fetch/template.cjs.js.map +1 -1
- package/dist/scaffolder/actions/builtin/fetch/templateActionHandler.cjs.js +70 -68
- package/dist/scaffolder/actions/builtin/fetch/templateActionHandler.cjs.js.map +1 -1
- package/dist/scaffolder/actions/builtin/fetch/templateFile.cjs.js +4 -1
- package/dist/scaffolder/actions/builtin/fetch/templateFile.cjs.js.map +1 -1
- package/dist/scaffolder/actions/builtin/fetch/templateFileActionHandler.cjs.js +14 -30
- package/dist/scaffolder/actions/builtin/fetch/templateFileActionHandler.cjs.js.map +1 -1
- package/dist/scaffolder/dryrun/createDryRunner.cjs.js +6 -0
- package/dist/scaffolder/dryrun/createDryRunner.cjs.js.map +1 -1
- package/dist/scaffolder/tasks/NunjucksWorkflowRunner.cjs.js +103 -109
- package/dist/scaffolder/tasks/NunjucksWorkflowRunner.cjs.js.map +1 -1
- package/dist/scaffolder/tasks/TaskWorker.cjs.js +5 -2
- package/dist/scaffolder/tasks/TaskWorker.cjs.js.map +1 -1
- package/dist/service/router.cjs.js +1 -1
- package/dist/util/templating.cjs.js +12 -0
- package/dist/util/templating.cjs.js.map +1 -1
- package/package.json +21 -26
- package/assets/nunjucks.js.txt +0 -10385
- package/dist/lib/templating/SecureTemplater.cjs.js +0 -188
- package/dist/lib/templating/SecureTemplater.cjs.js.map +0 -1
- package/dist/lib/templating/helpers.cjs.js +0 -13
- package/dist/lib/templating/helpers.cjs.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"NunjucksWorkflowRunner.cjs.js","sources":["../../../src/scaffolder/tasks/NunjucksWorkflowRunner.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { InputError, NotAllowedError, stringifyError } from '@backstage/errors';\nimport { ScmIntegrations } from '@backstage/integration';\nimport {\n TaskRecovery,\n TaskSpec,\n TaskSpecV1beta3,\n TaskStep,\n} from '@backstage/plugin-scaffolder-common';\nimport { JsonArray, JsonObject, JsonValue } from '@backstage/types';\nimport fs from 'fs-extra';\nimport { validate as validateJsonSchema } from 'jsonschema';\nimport path from 'node:path';\nimport nunjucks from 'nunjucks';\nimport * as winston from 'winston';\nimport {\n SecureTemplater,\n SecureTemplateRenderer,\n} from '../../lib/templating/SecureTemplater';\nimport { TemplateActionRegistry } from '../actions/TemplateActionRegistry';\nimport {\n filterConditionalItems,\n generateExampleOutput,\n isTruthy,\n} from './helper';\nimport { TaskTrackType, WorkflowResponse, WorkflowRunner } from './types';\n\nimport type {\n AuditorService,\n LoggerService,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\nimport type { MetricsService } from '@backstage/backend-plugin-api/alpha';\nimport { UserEntity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n AuthorizeResult,\n PolicyDecision,\n} from '@backstage/plugin-permission-common';\nimport { createConditionAuthorizer } from '@backstage/plugin-permission-node';\nimport { actionExecutePermission } from '@backstage/plugin-scaffolder-common/alpha';\nimport {\n TaskContext,\n TaskSecrets,\n TemplateAction,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n CheckpointContext,\n CheckpointState,\n} from '@backstage/plugin-scaffolder-node/alpha';\nimport { resolveDefaultEnvironment } from '../../lib/defaultEnvironment';\nimport { createDefaultFilters } from '../../lib/templating/filters/createDefaultFilters';\nimport { scaffolderActionRules } from '../../service/rules';\nimport { createCounterMetric, createHistogramMetric } from '../../util/metrics';\nimport { convertFiltersToRecord } from '../../util/templating';\nimport { BackstageLoggerTransport, WinstonLogger } from './logger';\n\ntype NunjucksWorkflowRunnerOptions = {\n workingDirectory: string;\n actionRegistry: TemplateActionRegistry;\n integrations: ScmIntegrations;\n logger: LoggerService;\n auditor?: AuditorService;\n additionalTemplateFilters?: Record<string, TemplateFilter>;\n additionalTemplateGlobals?: Record<string, TemplateGlobal>;\n permissions?: PermissionsService;\n config?: Config;\n metrics: MetricsService;\n};\n\ntype TemplateContext = {\n parameters: JsonObject;\n environment: JsonObject;\n EXPERIMENTAL_recovery?: TaskRecovery;\n steps: {\n [stepName: string]: { output: { [outputName: string]: JsonValue } };\n };\n secrets?: Record<string, string>;\n user?: {\n entity?: UserEntity;\n ref?: string;\n };\n each?: JsonValue;\n context: {\n task: {\n id: string;\n };\n };\n};\n\nconst isValidTaskSpec = (taskSpec: TaskSpec): taskSpec is TaskSpecV1beta3 => {\n return taskSpec.apiVersion === 'scaffolder.backstage.io/v1beta3';\n};\n\nconst createStepLogger = ({\n task,\n step,\n rootLogger,\n redactions,\n}: {\n task: TaskContext;\n step: TaskStep;\n rootLogger: LoggerService;\n redactions?: Record<string, string>;\n}) => {\n const taskLogger = WinstonLogger.create({\n level: process.env.LOG_LEVEL || 'info',\n format: winston.format.combine(\n winston.format.colorize(),\n winston.format.simple(),\n ),\n transports: [new BackstageLoggerTransport(rootLogger, task, step.id)],\n });\n\n taskLogger.addRedactions(Object.values(redactions ?? {}));\n\n return { taskLogger };\n};\n\n/**\n * Recursively compares two rendered objects and returns string values from\n * `withSecrets` that differ from their counterpart in `withoutSecrets`.\n * These are values that were influenced by secret interpolation and should\n * be added as log redactions.\n */\nfunction collectSecretRedactions(\n withSecrets: unknown,\n withoutSecrets: unknown,\n): string[] {\n if (typeof withSecrets === 'string') {\n return withSecrets !== withoutSecrets ? [withSecrets] : [];\n }\n if (Array.isArray(withSecrets)) {\n const other = Array.isArray(withoutSecrets) ? withoutSecrets : [];\n return withSecrets.flatMap((val, i) =>\n collectSecretRedactions(val, other[i]),\n );\n }\n if (withSecrets && typeof withSecrets === 'object') {\n const other =\n withoutSecrets && typeof withoutSecrets === 'object'\n ? (withoutSecrets as Record<string, unknown>)\n : {};\n return Object.entries(withSecrets as Record<string, unknown>).flatMap(\n ([key, val]) => collectSecretRedactions(val, other[key]),\n );\n }\n return [];\n}\n\n/**\n * Extracts all string values from a nested object structure.\n * Used as a fallback when the comparison render fails.\n */\nfunction extractStringValues(obj: unknown): string[] {\n if (typeof obj === 'string') return [obj];\n if (Array.isArray(obj)) return obj.flatMap(extractStringValues);\n if (obj && typeof obj === 'object') {\n return Object.entries(obj).flatMap(([key, val]) => [\n key,\n ...extractStringValues(val),\n ]);\n }\n return [];\n}\n\nconst isActionAuthorized = createConditionAuthorizer(\n Object.values(scaffolderActionRules),\n);\n\nexport class NunjucksWorkflowRunner implements WorkflowRunner {\n private readonly defaultTemplateFilters: Record<string, TemplateFilter>;\n private readonly options: NunjucksWorkflowRunnerOptions;\n private environment: {\n parameters: JsonObject;\n secrets?: Record<string, string>;\n } = { parameters: {}, secrets: {} };\n\n private readonly tracker: ReturnType<typeof scaffoldingTracker>;\n\n constructor(options: NunjucksWorkflowRunnerOptions) {\n this.options = options;\n this.defaultTemplateFilters = convertFiltersToRecord(\n createDefaultFilters({\n integrations: this.options.integrations,\n }),\n );\n this.tracker = scaffoldingTracker(options.metrics);\n }\n\n async getEnvironmentConfig(): Promise<{\n parameters: JsonObject;\n secrets?: TaskSecrets;\n }> {\n if (this.options.config) {\n const defaultEnvironment = resolveDefaultEnvironment(this.options.config);\n return {\n parameters: defaultEnvironment.parameters,\n secrets: defaultEnvironment.secrets,\n };\n }\n\n return {\n parameters: {},\n secrets: {},\n };\n }\n\n private isSingleTemplateString(input: string) {\n const { parser, nodes } = nunjucks as unknown as {\n parser: {\n parse(\n template: string,\n ctx: object,\n options: nunjucks.ConfigureOptions,\n ): { children: { children?: unknown[] }[] };\n };\n nodes: { TemplateData: Function };\n };\n\n const parsed = parser.parse(\n input,\n {},\n {\n autoescape: false,\n tags: {\n variableStart: '${{',\n variableEnd: '}}',\n },\n },\n );\n\n return (\n parsed.children.length === 1 &&\n !(parsed.children[0]?.children?.[0] instanceof nodes.TemplateData)\n );\n }\n\n private render<T>(\n input: T,\n context: TemplateContext,\n renderTemplate: SecureTemplateRenderer,\n ): T {\n return JSON.parse(JSON.stringify(input), (_key, value) => {\n try {\n if (typeof value === 'string') {\n try {\n if (this.isSingleTemplateString(value)) {\n // Lets convert ${{ parameters.bob }} to ${{ (parameters.bob) | dump }} so we can keep the input type\n const wrappedDumped = value.replace(\n /\\${{(.+)}}/g,\n '${{ ( $1 ) | dump }}',\n );\n\n // Run the templating\n const templated = renderTemplate(wrappedDumped, context);\n\n // If there's an empty string returned, then it's undefined\n if (templated === '') {\n return undefined;\n }\n\n // Reparse the dumped string\n return JSON.parse(templated);\n }\n } catch (ex) {\n this.options.logger.error(\n `Failed to parse template string: ${value} with error ${ex.message}`,\n );\n }\n\n // Fallback to default behaviour\n const templated = renderTemplate(value, context);\n\n if (templated === '') {\n return undefined;\n }\n\n return templated;\n }\n } catch {\n return value;\n }\n return value;\n });\n }\n\n async executeStep(\n task: TaskContext,\n step: TaskStep,\n context: TemplateContext,\n renderTemplate: (template: string, values: unknown) => string,\n taskTrack: TaskTrackType,\n workspacePath: string,\n decision: PolicyDecision,\n ) {\n const stepTrack = await this.tracker.stepStart(task, step);\n\n if (task.cancelSignal.aborted) {\n throw new Error(\n `Step ${step.id} (${step.name}) of task ${task.taskId} has been cancelled.`,\n );\n }\n\n try {\n if (\n step.if === false ||\n (typeof step.if === 'string' &&\n step.each === undefined &&\n !isTruthy(this.render(step.if, context, renderTemplate)))\n ) {\n await stepTrack.skipFalsy();\n return;\n }\n const action: TemplateAction<JsonObject> =\n await this.options.actionRegistry.get(step.action, {\n credentials: await task.getInitiatorCredentials(),\n });\n const { taskLogger } = createStepLogger({\n task,\n step,\n rootLogger: this.options.logger,\n redactions: {\n ...task.secrets,\n ...this.environment?.secrets,\n },\n });\n\n if (task.isDryRun) {\n const redactedSecrets = Object.fromEntries(\n Object.entries(task.secrets ?? {}).map(secret => [secret[0], '***']),\n );\n\n const redactedEnvironmentSecrets = Object.fromEntries(\n Object.entries(this.environment?.secrets ?? {}).map(secret => [\n secret[0],\n '***',\n ]),\n );\n const debugInput =\n (step.input &&\n this.render(\n step.input,\n {\n ...context,\n environment: {\n parameters: this.environment?.parameters || {},\n secrets: redactedEnvironmentSecrets,\n },\n secrets: redactedSecrets,\n },\n renderTemplate,\n )) ??\n {};\n taskLogger.info(\n `Running ${\n action.id\n } in dry-run mode with inputs (secrets redacted): ${JSON.stringify(\n debugInput,\n undefined,\n 2,\n )}`,\n );\n if (!action.supportsDryRun) {\n await taskTrack.skipDryRun(step, action);\n const outputSchema = action.schema?.output;\n if (outputSchema) {\n context.steps[step.id] = {\n output: generateExampleOutput(outputSchema) as {\n [name in string]: JsonValue;\n },\n };\n } else {\n context.steps[step.id] = { output: {} };\n }\n return;\n }\n }\n\n const preIterationContext = {\n ...context,\n environment: {\n parameters: this.environment?.parameters ?? {},\n secrets: task.isDryRun ? {} : this.environment?.secrets ?? {},\n },\n secrets: task.secrets ?? {},\n };\n\n const resolvedEach =\n step.each &&\n this.render(step.each, preIterationContext, renderTemplate);\n\n if (step.each && !resolvedEach) {\n throw new InputError(\n `Invalid value on action ${action.id}.each parameter, \"${step.each}\" cannot be resolved to a value`,\n );\n }\n\n const iterations = (\n resolvedEach\n ? Object.entries(resolvedEach).map(([key, value]) => ({\n each: { key, value },\n }))\n : [{}]\n ).map(i => {\n const fullContext = { ...preIterationContext, ...i };\n // Evaluate if condition once per iteration, only when using 'each'\n const shouldRun =\n !('each' in i) ||\n !step.if ||\n isTruthy(this.render(step.if, fullContext, renderTemplate));\n\n return {\n ...i,\n shouldRun,\n // Secrets are only passed when templating the input to actions for security reasons\n input: step.input\n ? this.render(step.input, fullContext, renderTemplate)\n : {},\n };\n });\n for (const iteration of iterations) {\n if (!iteration.shouldRun) {\n // No need to check schema or authorization for iterations that will not run\n continue;\n }\n\n const actionId = `${action.id}${\n iteration.each ? `[${iteration.each.key}]` : ''\n }`;\n\n if (action.schema?.input) {\n const validateResult = validateJsonSchema(\n iteration.input,\n action.schema.input,\n );\n if (!validateResult.valid) {\n const errors = validateResult.errors.join(', ');\n throw new InputError(\n `Invalid input passed to action ${actionId}, ${errors}`,\n );\n }\n }\n if (\n !isActionAuthorized(decision, {\n action: action.id,\n input: iteration.input,\n })\n ) {\n throw new NotAllowedError(\n `Unauthorized action: ${actionId}. The action is not allowed. Input: ${JSON.stringify(\n iteration.input,\n null,\n 2,\n )}`,\n );\n }\n }\n const tmpDirs = new Array<string>();\n const stepOutput: { [outputName: string]: JsonValue } = {};\n const prevTaskState = await task.getTaskState?.();\n\n for (const iteration of iterations) {\n if (iteration.each) {\n if (!iteration.shouldRun) {\n taskLogger.info(\n `Skipping step each: ${JSON.stringify(\n iteration.each,\n (k, v) => (k ? String(v) : v),\n 0,\n )}`,\n );\n continue;\n }\n taskLogger.info(\n `Running step each: ${JSON.stringify(\n iteration.each,\n (k, v) => (k ? String(v) : v),\n 0,\n )}`,\n );\n }\n\n // Redact any rendered values that were influenced by secrets.\n // Re-render the input without secrets and diff against the real render\n // to find values that changed due to secret interpolation.\n if (step.input) {\n const hasSecrets =\n Object.keys(task.secrets ?? {}).length > 0 ||\n Object.keys(this.environment?.secrets ?? {}).length > 0;\n\n if (hasSecrets) {\n try {\n const contextNoSecrets = {\n ...preIterationContext,\n ...(iteration.each ? { each: iteration.each } : {}),\n secrets: {},\n environment: {\n ...preIterationContext.environment,\n secrets: {},\n },\n };\n const inputWithoutSecrets = this.render(\n step.input,\n contextNoSecrets,\n renderTemplate,\n );\n taskLogger.addRedactions(\n collectSecretRedactions(iteration.input, inputWithoutSecrets),\n );\n } catch {\n taskLogger.addRedactions(extractStringValues(iteration.input));\n }\n }\n }\n\n await action.handler({\n input: iteration.input,\n task: {\n id: await task.getWorkspaceName(),\n },\n secrets: task.secrets ?? {},\n logger: taskLogger,\n workspacePath,\n async checkpoint<T extends JsonValue | void>(\n opts: CheckpointContext<T>,\n ) {\n const { key: checkpointKey, fn } = opts;\n const key = `v1.task.checkpoint.${step.id}.${checkpointKey}`;\n\n try {\n let prevValue: T | undefined;\n\n if (prevTaskState) {\n const prevState = (\n prevTaskState.state?.checkpoints as CheckpointState\n )?.[key];\n\n if (prevState && prevState.status === 'success') {\n prevValue = prevState.value as T;\n }\n }\n\n const value = prevValue ? prevValue : await fn();\n\n if (!prevValue) {\n task.updateCheckpoint?.({\n key,\n status: 'success',\n value: value ?? {},\n });\n }\n return value;\n } catch (err) {\n task.updateCheckpoint?.({\n key,\n status: 'failed',\n reason: stringifyError(err),\n });\n throw err;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n },\n createTemporaryDirectory: async () => {\n const tmpDir = await fs.mkdtemp(\n `${workspacePath}_step-${step.id}-`,\n );\n tmpDirs.push(tmpDir);\n return tmpDir;\n },\n output(name: string, value: JsonValue) {\n if (step.each) {\n stepOutput[name] = stepOutput[name] || [];\n (stepOutput[name] as JsonArray).push(value);\n } else {\n stepOutput[name] = value;\n }\n },\n templateInfo: task.spec.templateInfo,\n user: task.spec.user,\n isDryRun: task.isDryRun,\n signal: task.cancelSignal,\n getInitiatorCredentials: () => task.getInitiatorCredentials(),\n step: {\n id: step.id,\n name: step.name,\n },\n });\n }\n\n // Remove all temporary directories that were created when executing the action\n for (const tmpDir of tmpDirs) {\n await fs.remove(tmpDir);\n }\n\n context.steps[step.id] = { output: stepOutput };\n\n if (task.cancelSignal.aborted) {\n throw new Error(\n `Step ${step.id} (${step.name}) of task ${task.taskId} has been cancelled.`,\n );\n }\n\n await stepTrack.markSuccessful();\n } catch (err) {\n await taskTrack.markFailed(step, err);\n await stepTrack.markFailed();\n throw err;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n }\n\n async execute(task: TaskContext): Promise<WorkflowResponse> {\n if (!isValidTaskSpec(task.spec)) {\n throw new InputError(\n 'Wrong template version executed with the workflow engine',\n );\n }\n const taskId = await task.getWorkspaceName();\n\n const workspacePath = path.join(this.options.workingDirectory, taskId);\n\n const { additionalTemplateFilters, additionalTemplateGlobals } =\n this.options;\n\n this.environment = await this.getEnvironmentConfig();\n\n // Track whether any step has failed, used by status check functions\n const taskState = { failed: false };\n\n // Track whether a status check global (always/failure) was invoked during rendering\n const statusCheckInvoked = { value: false };\n\n const { render: renderTemplate, dispose } =\n await SecureTemplater.loadRenderer({\n templateFilters: {\n ...this.defaultTemplateFilters,\n ...additionalTemplateFilters,\n },\n templateGlobals: {\n ...additionalTemplateGlobals,\n always: () => {\n statusCheckInvoked.value = true;\n return true;\n },\n failure: () => {\n statusCheckInvoked.value = true;\n return taskState.failed;\n },\n },\n });\n\n try {\n await task.rehydrateWorkspace?.({ taskId, targetPath: workspacePath });\n\n const taskTrack = await this.tracker.taskStart(task);\n await fs.ensureDir(workspacePath);\n\n const context: TemplateContext = {\n parameters: task.spec.parameters,\n environment: {\n parameters: this.environment?.parameters || {},\n secrets: {},\n },\n steps: {},\n user: task.spec.user,\n context: {\n task: {\n id: taskId,\n },\n },\n };\n\n const [decision]: PolicyDecision[] =\n this.options.permissions && task.spec.steps.length\n ? await this.options.permissions.authorizeConditional(\n [{ permission: actionExecutePermission }],\n { credentials: await task.getInitiatorCredentials() },\n )\n : [{ result: AuthorizeResult.ALLOW }];\n\n let firstError: Error | undefined;\n const allErrors: Array<{ step: TaskStep; error: Error }> = [];\n\n for (const step of task.spec.steps) {\n // If a previous step failed, only run steps whose `if` condition\n // invokes a status check global (${{ always() }} or ${{ failure() }})\n if (taskState.failed) {\n if (typeof step.if !== 'string') {\n await task.emitLog(\n `Skipping step ${step.id} because a previous step failed`,\n { stepId: step.id, status: 'skipped' },\n );\n continue;\n }\n\n // Render the if condition to detect status check function usage\n statusCheckInvoked.value = false;\n this.render(step.if, context, renderTemplate);\n\n if (!statusCheckInvoked.value) {\n await task.emitLog(\n `Skipping step ${step.id} because a previous step failed`,\n { stepId: step.id, status: 'skipped' },\n );\n continue;\n }\n }\n\n try {\n await this.executeStep(\n task,\n step,\n context,\n renderTemplate,\n taskTrack,\n workspacePath,\n decision,\n );\n } catch (err) {\n const error = err as Error;\n allErrors.push({ step, error });\n\n if (!firstError) {\n firstError = error;\n } else {\n // Log subsequent errors to preserve debugging information\n this.options.logger.error(\n `Additional error in step ${step.id} (${step.name}): ${error.message}`,\n error,\n );\n await task.emitLog(\n `Additional error occurred: ${error.message}\\n${error.stack}`,\n { stepId: step.id, status: 'failed' },\n );\n }\n taskState.failed = true;\n }\n }\n\n if (firstError) {\n // If there were multiple errors, add context to the first error\n if (allErrors.length > 1) {\n const additionalErrorSummary = allErrors\n .slice(1)\n .map(({ step }) => `${step.id} (${step.name})`)\n .join(', ');\n this.options.logger.warn(\n `Task failed with ${allErrors.length} errors. First error from step ${allErrors[0].step.id}. Additional failures in: ${additionalErrorSummary}`,\n );\n }\n throw firstError;\n }\n\n const output = this.render(task.spec.output, context, renderTemplate);\n\n // Filter output links and text items based on their `if` condition\n if (Array.isArray(output?.links)) {\n output.links = filterConditionalItems(output.links);\n }\n if (Array.isArray(output?.text)) {\n output.text = filterConditionalItems(output.text);\n }\n\n await taskTrack.markSuccessful();\n await task.cleanWorkspace?.();\n\n return { output };\n } finally {\n try {\n dispose();\n } catch {\n // Ignore disposal errors so they don't mask the original failure.\n }\n if (workspacePath) {\n await fs.remove(workspacePath);\n }\n }\n }\n}\n\nfunction scaffoldingTracker(metrics: MetricsService) {\n // prom-client metrics are deprecated in favour of OpenTelemetry metrics.\n const promTaskCount = createCounterMetric({\n name: 'scaffolder_task_count',\n help: 'Count of task runs',\n labelNames: ['template', 'user', 'result'],\n });\n const promTaskDuration = createHistogramMetric({\n name: 'scaffolder_task_duration',\n help: 'Duration of a task run',\n labelNames: ['template', 'result'],\n });\n const promStepCount = createCounterMetric({\n name: 'scaffolder_step_count',\n help: 'Count of step runs',\n labelNames: ['template', 'step', 'result'],\n });\n const promStepDuration = createHistogramMetric({\n name: 'scaffolder_step_duration',\n help: 'Duration of a step runs',\n labelNames: ['template', 'step', 'result'],\n });\n\n const taskCount = metrics.createCounter('scaffolder.task.count', {\n description: 'Total number of scaffolder tasks executed',\n });\n\n const taskDuration = metrics.createHistogram('scaffolder.task.duration', {\n description: 'Time taken to complete a scaffolder task end-to-end',\n unit: 's',\n });\n\n const stepCount = metrics.createCounter('scaffolder.step.count', {\n description: 'Total number of individual scaffolder action steps executed',\n });\n\n const stepDuration = metrics.createHistogram('scaffolder.step.duration', {\n description: 'Time taken to complete a single scaffolder action step',\n unit: 's',\n });\n\n async function taskStart(task: TaskContext) {\n await task.emitLog(`Starting up task with ${task.spec.steps.length} steps`);\n const template = task.spec.templateInfo?.entityRef || '';\n const user = task.spec.user?.ref || '';\n\n const startTime = process.hrtime();\n const taskTimer = promTaskDuration.startTimer({\n template,\n });\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n async function skipDryRun(\n step: TaskStep,\n action: TemplateAction<JsonObject>,\n ) {\n task.emitLog(`Skipping because ${action.id} does not support dry-run`, {\n stepId: step.id,\n status: 'skipped',\n });\n }\n\n async function markSuccessful() {\n promTaskCount.inc({\n template,\n user,\n result: 'ok',\n });\n taskTimer({ result: 'ok' });\n\n taskCount.add(1, { template, user, result: 'ok' });\n taskDuration.record(endTime(), {\n template,\n result: 'ok',\n });\n }\n\n async function markFailed(step: TaskStep, err: Error) {\n await task.emitLog(String(err.stack), {\n stepId: step.id,\n status: 'failed',\n });\n promTaskCount.inc({\n template,\n user,\n result: 'failed',\n });\n taskTimer({ result: 'failed' });\n\n taskCount.add(1, { template, user, result: 'failed' });\n taskDuration.record(endTime(), {\n template,\n result: 'failed',\n });\n }\n\n async function markCancelled(step: TaskStep) {\n await task.emitLog(`Step ${step.id} has been cancelled.`, {\n stepId: step.id,\n status: 'cancelled',\n });\n promTaskCount.inc({\n template,\n user,\n result: 'cancelled',\n });\n taskTimer({ result: 'cancelled' });\n\n taskCount.add(1, { template, user, result: 'cancelled' });\n taskDuration.record(endTime(), {\n template,\n result: 'cancelled',\n });\n }\n\n return {\n skipDryRun,\n markCancelled,\n markSuccessful,\n markFailed,\n };\n }\n\n async function stepStart(task: TaskContext, step: TaskStep) {\n await task.emitLog(`Beginning step ${step.name}`, {\n stepId: step.id,\n status: 'processing',\n });\n const template = task.spec.templateInfo?.entityRef || '';\n\n const startTime = process.hrtime();\n const stepTimer = promStepDuration.startTimer({\n template,\n step: step.name,\n });\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n async function markSuccessful() {\n await task.emitLog(`Finished step ${step.name}`, {\n stepId: step.id,\n status: 'completed',\n });\n promStepCount.inc({\n template,\n step: step.name,\n result: 'ok',\n });\n stepTimer({ result: 'ok' });\n\n stepCount.add(1, { template, step: step.name, result: 'ok' });\n stepDuration.record(endTime(), {\n template,\n step: step.name,\n result: 'ok',\n });\n }\n\n async function markCancelled() {\n promStepCount.inc({\n template,\n step: step.name,\n result: 'cancelled',\n });\n stepTimer({ result: 'cancelled' });\n\n stepCount.add(1, { template, step: step.name, result: 'cancelled' });\n stepDuration.record(endTime(), {\n template,\n step: step.name,\n result: 'cancelled',\n });\n }\n\n async function markFailed() {\n promStepCount.inc({\n template,\n step: step.name,\n result: 'failed',\n });\n stepTimer({ result: 'failed' });\n\n stepCount.add(1, { template, step: step.name, result: 'failed' });\n stepDuration.record(endTime(), {\n template,\n step: step.name,\n result: 'failed',\n });\n }\n\n async function skipFalsy() {\n await task.emitLog(\n `Skipping step ${step.id} because its if condition was false`,\n { stepId: step.id, status: 'skipped' },\n );\n stepTimer({ result: 'skipped' });\n\n stepCount.add(1, { template, step: step.name, result: 'skipped' });\n stepDuration.record(endTime(), {\n template,\n step: step.name,\n result: 'skipped',\n });\n }\n\n return {\n markCancelled,\n markFailed,\n markSuccessful,\n skipFalsy,\n };\n }\n\n return {\n taskStart,\n stepStart,\n };\n}\n"],"names":["WinstonLogger","winston","BackstageLoggerTransport","createConditionAuthorizer","scaffolderActionRules","convertFiltersToRecord","createDefaultFilters","defaultEnvironment","resolveDefaultEnvironment","nunjucks","templated","isTruthy","generateExampleOutput","InputError","validateJsonSchema","errors","NotAllowedError","stringifyError","fs","path","SecureTemplater","actionExecutePermission","AuthorizeResult","filterConditionalItems","metrics","createCounterMetric","createHistogramMetric"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"NunjucksWorkflowRunner.cjs.js","sources":["../../../src/scaffolder/tasks/NunjucksWorkflowRunner.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { InputError, NotAllowedError, stringifyError } from '@backstage/errors';\nimport { ScmIntegrations } from '@backstage/integration';\nimport {\n TaskRecovery,\n TaskSpec,\n TaskSpecV1beta3,\n TaskStep,\n} from '@backstage/plugin-scaffolder-common';\nimport { JsonArray, JsonObject, JsonValue } from '@backstage/types';\nimport fs from 'fs-extra';\nimport { validate as validateJsonSchema } from 'jsonschema';\nimport path from 'node:path';\nimport {\n createTemplateRenderer,\n PreparedTemplateContext,\n TemplateCapabilities,\n TemplateContext as NunjitsuTemplateContext,\n TemplateRenderer,\n TemplateValue as NunjitsuTemplateValue,\n} from 'nunjitsu';\nimport * as winston from 'winston';\nimport { TemplateActionRegistry } from '../actions/TemplateActionRegistry';\nimport {\n filterConditionalItems,\n generateExampleOutput,\n isTruthy,\n} from './helper';\nimport { TaskTrackType, WorkflowResponse, WorkflowRunner } from './types';\n\nimport type {\n AuditorService,\n LoggerService,\n PermissionsService,\n} from '@backstage/backend-plugin-api';\nimport type { MetricsService } from '@backstage/backend-plugin-api/alpha';\nimport { UserEntity } from '@backstage/catalog-model';\nimport { Config } from '@backstage/config';\nimport {\n AuthorizeResult,\n PolicyDecision,\n} from '@backstage/plugin-permission-common';\nimport { createConditionAuthorizer } from '@backstage/plugin-permission-node';\nimport { actionExecutePermission } from '@backstage/plugin-scaffolder-common/alpha';\nimport {\n TaskContext,\n TaskSecrets,\n TemplateAction,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n CheckpointContext,\n CheckpointState,\n} from '@backstage/plugin-scaffolder-node/alpha';\nimport { resolveDefaultEnvironment } from '../../lib/defaultEnvironment';\nimport { createDefaultFilters } from '../../lib/templating/filters/createDefaultFilters';\nimport { scaffolderActionRules } from '../../service/rules';\nimport { createCounterMetric, createHistogramMetric } from '../../util/metrics';\nimport {\n collectTemplateCapabilities,\n convertFiltersToRecord,\n} from '../../util/templating';\nimport { BackstageLoggerTransport, WinstonLogger } from './logger';\n\ntype NunjucksWorkflowRunnerOptions = {\n workingDirectory: string;\n actionRegistry: TemplateActionRegistry;\n integrations: ScmIntegrations;\n logger: LoggerService;\n auditor?: AuditorService;\n templateCapabilities?: TemplateCapabilities;\n permissions?: PermissionsService;\n config?: Config;\n metrics: MetricsService;\n};\n\ntype TemplateContext = {\n parameters: JsonObject;\n environment: JsonObject;\n EXPERIMENTAL_recovery?: TaskRecovery;\n steps: {\n [stepName: string]: { output: { [outputName: string]: JsonValue } };\n };\n secrets?: Record<string, string>;\n user?: {\n entity?: UserEntity;\n ref?: string;\n };\n each?: JsonValue;\n context: {\n task: {\n id: string;\n };\n };\n};\n\nconst isValidTaskSpec = (taskSpec: TaskSpec): taskSpec is TaskSpecV1beta3 => {\n return taskSpec.apiVersion === 'scaffolder.backstage.io/v1beta3';\n};\n\nfunction stringifyEachLogValue(value: unknown): string {\n if (Array.isArray(value)) {\n return value\n .map(item =>\n item === null || item === undefined ? '' : stringifyEachLogValue(item),\n )\n .join(',');\n }\n if (value !== null && typeof value === 'object') {\n return '[object Object]';\n }\n return String(value);\n}\n\nconst createStepLogger = ({\n task,\n step,\n rootLogger,\n redactions,\n}: {\n task: TaskContext;\n step: TaskStep;\n rootLogger: LoggerService;\n redactions?: Record<string, string>;\n}) => {\n const taskLogger = WinstonLogger.create({\n level: process.env.LOG_LEVEL || 'info',\n format: winston.format.combine(\n winston.format.colorize(),\n winston.format.simple(),\n ),\n transports: [new BackstageLoggerTransport(rootLogger, task, step.id)],\n });\n\n taskLogger.addRedactions(Object.values(redactions ?? {}));\n\n return { taskLogger };\n};\n\n/**\n * Recursively compares two rendered objects and returns string values from\n * `withSecrets` that differ from their counterpart in `withoutSecrets`.\n * These are values that were influenced by secret interpolation and should\n * be added as log redactions.\n */\nfunction collectSecretRedactions(\n withSecrets: unknown,\n withoutSecrets: unknown,\n): string[] {\n if (typeof withSecrets === 'string') {\n return withSecrets !== withoutSecrets ? [withSecrets] : [];\n }\n if (Array.isArray(withSecrets)) {\n const other = Array.isArray(withoutSecrets) ? withoutSecrets : [];\n return withSecrets.flatMap((val, i) =>\n collectSecretRedactions(val, other[i]),\n );\n }\n if (withSecrets && typeof withSecrets === 'object') {\n const other =\n withoutSecrets && typeof withoutSecrets === 'object'\n ? (withoutSecrets as Record<string, unknown>)\n : {};\n return Object.entries(withSecrets as Record<string, unknown>).flatMap(\n ([key, val]) => collectSecretRedactions(val, other[key]),\n );\n }\n return [];\n}\n\n/**\n * Extracts all string values from a nested object structure.\n * Used as a fallback when the comparison render fails.\n */\nfunction extractStringValues(obj: unknown): string[] {\n if (typeof obj === 'string') return [obj];\n if (Array.isArray(obj)) return obj.flatMap(extractStringValues);\n if (obj && typeof obj === 'object') {\n return Object.entries(obj).flatMap(([key, val]) => [\n key,\n ...extractStringValues(val),\n ]);\n }\n return [];\n}\n\nconst isActionAuthorized = createConditionAuthorizer(\n Object.values(scaffolderActionRules),\n);\n\nexport class NunjucksWorkflowRunner implements WorkflowRunner {\n private readonly defaultTemplateCapabilities: TemplateCapabilities;\n private readonly options: NunjucksWorkflowRunnerOptions;\n private environment: {\n parameters: JsonObject;\n secrets?: Record<string, string>;\n } = { parameters: {}, secrets: {} };\n\n private readonly tracker: ReturnType<typeof scaffoldingTracker>;\n\n constructor(options: NunjucksWorkflowRunnerOptions) {\n this.options = options;\n this.defaultTemplateCapabilities = collectTemplateCapabilities({\n filters: convertFiltersToRecord(\n createDefaultFilters({\n integrations: this.options.integrations,\n }),\n ),\n });\n this.tracker = scaffoldingTracker(options.metrics);\n }\n\n async getEnvironmentConfig(): Promise<{\n parameters: JsonObject;\n secrets?: TaskSecrets;\n }> {\n if (this.options.config) {\n const defaultEnvironment = resolveDefaultEnvironment(this.options.config);\n return {\n parameters: defaultEnvironment.parameters,\n secrets: defaultEnvironment.secrets,\n };\n }\n\n return {\n parameters: {},\n secrets: {},\n };\n }\n\n private render<T>(\n input: T,\n context: PreparedTemplateContext,\n templateRenderer: TemplateRenderer,\n ): T {\n return JSON.parse(JSON.stringify(input), (_key, value) => {\n try {\n if (typeof value === 'string') {\n return templateRenderer.renderValue(value, context);\n }\n } catch {\n return value;\n }\n return value;\n });\n }\n\n async executeStep(\n task: TaskContext,\n step: TaskStep,\n context: TemplateContext,\n preparedContext: PreparedTemplateContext,\n templateRenderer: TemplateRenderer,\n taskTrack: TaskTrackType,\n workspacePath: string,\n decision: PolicyDecision,\n ) {\n const stepTrack = await this.tracker.stepStart(task, step);\n\n if (task.cancelSignal.aborted) {\n throw new Error(\n `Step ${step.id} (${step.name}) of task ${task.taskId} has been cancelled.`,\n );\n }\n\n try {\n if (\n step.if === false ||\n (typeof step.if === 'string' &&\n step.each === undefined &&\n !isTruthy(this.render(step.if, preparedContext, templateRenderer)))\n ) {\n await stepTrack.skipFalsy();\n return preparedContext;\n }\n const action: TemplateAction<JsonObject> =\n await this.options.actionRegistry.get(step.action, {\n credentials: await task.getInitiatorCredentials(),\n });\n const { taskLogger } = createStepLogger({\n task,\n step,\n rootLogger: this.options.logger,\n redactions: {\n ...task.secrets,\n ...this.environment?.secrets,\n },\n });\n\n if (task.isDryRun) {\n const redactedSecrets = Object.fromEntries(\n Object.entries(task.secrets ?? {}).map(secret => [secret[0], '***']),\n );\n\n const redactedEnvironmentSecrets = Object.fromEntries(\n Object.entries(this.environment?.secrets ?? {}).map(secret => [\n secret[0],\n '***',\n ]),\n );\n const dryRunContext = preparedContext\n .withValue(['environment'], {\n parameters: this.environment?.parameters || {},\n secrets: redactedEnvironmentSecrets,\n } as NunjitsuTemplateValue)\n .withValue(['secrets'], redactedSecrets);\n const debugInput =\n (step.input &&\n this.render(step.input, dryRunContext, templateRenderer)) ??\n {};\n taskLogger.info(\n `Running ${\n action.id\n } in dry-run mode with inputs (secrets redacted): ${JSON.stringify(\n debugInput,\n undefined,\n 2,\n )}`,\n );\n if (!action.supportsDryRun) {\n await taskTrack.skipDryRun(step, action);\n const outputSchema = action.schema?.output;\n if (outputSchema) {\n context.steps[step.id] = {\n output: generateExampleOutput(outputSchema) as {\n [name in string]: JsonValue;\n },\n };\n } else {\n context.steps[step.id] = { output: {} };\n }\n return preparedContext.withValue(\n ['steps', step.id],\n context.steps[step.id] as unknown as NunjitsuTemplateValue,\n );\n }\n }\n\n const preIterationContext = {\n ...context,\n environment: {\n parameters: this.environment?.parameters ?? {},\n secrets: task.isDryRun ? {} : this.environment?.secrets ?? {},\n },\n secrets: task.secrets ?? {},\n };\n const preparedPreIterationContext = preparedContext\n .withValue(\n ['environment'],\n preIterationContext.environment as NunjitsuTemplateValue,\n )\n .withValue(\n ['secrets'],\n preIterationContext.secrets as NunjitsuTemplateValue,\n );\n\n const resolvedEach =\n step.each &&\n this.render(step.each, preparedPreIterationContext, templateRenderer);\n\n if (step.each && !resolvedEach) {\n throw new InputError(\n `Invalid value on action ${action.id}.each parameter, \"${step.each}\" cannot be resolved to a value`,\n );\n }\n\n const iterations = (\n resolvedEach\n ? Object.entries(resolvedEach).map(([key, value]) => ({\n each: { key, value },\n }))\n : [{}]\n ).map(i => {\n const preparedFullContext =\n 'each' in i\n ? preparedPreIterationContext.withValue(\n ['each'],\n i.each as NunjitsuTemplateValue,\n )\n : preparedPreIterationContext;\n // Evaluate if condition once per iteration, only when using 'each'\n const shouldRun =\n !('each' in i) ||\n !step.if ||\n isTruthy(this.render(step.if, preparedFullContext, templateRenderer));\n\n return {\n ...i,\n preparedContext: preparedFullContext,\n shouldRun,\n // Secrets are only passed when templating the input to actions for security reasons\n input: step.input\n ? this.render(step.input, preparedFullContext, templateRenderer)\n : {},\n };\n });\n for (const iteration of iterations) {\n if (!iteration.shouldRun) {\n // No need to check schema or authorization for iterations that will not run\n continue;\n }\n\n const actionId = `${action.id}${\n iteration.each ? `[${iteration.each.key}]` : ''\n }`;\n\n if (action.schema?.input) {\n const validateResult = validateJsonSchema(\n iteration.input,\n action.schema.input,\n );\n if (!validateResult.valid) {\n const errors = validateResult.errors.join(', ');\n throw new InputError(\n `Invalid input passed to action ${actionId}, ${errors}`,\n );\n }\n }\n if (\n !isActionAuthorized(decision, {\n action: action.id,\n input: iteration.input,\n })\n ) {\n throw new NotAllowedError(\n `Unauthorized action: ${actionId}. The action is not allowed. Input: ${JSON.stringify(\n iteration.input,\n null,\n 2,\n )}`,\n );\n }\n }\n const tmpDirs = new Array<string>();\n const stepOutput: { [outputName: string]: JsonValue } = {};\n const prevTaskState = await task.getTaskState?.();\n\n for (const iteration of iterations) {\n if (iteration.each) {\n if (!iteration.shouldRun) {\n taskLogger.info(\n `Skipping step each: ${JSON.stringify(\n iteration.each,\n (key, value) => (key ? stringifyEachLogValue(value) : value),\n 0,\n )}`,\n );\n continue;\n }\n taskLogger.info(\n `Running step each: ${JSON.stringify(\n iteration.each,\n (key, value) => (key ? stringifyEachLogValue(value) : value),\n 0,\n )}`,\n );\n }\n\n // Redact any rendered values that were influenced by secrets.\n // Re-render the input without secrets and diff against the real render\n // to find values that changed due to secret interpolation.\n if (step.input) {\n const hasSecrets =\n Object.keys(task.secrets ?? {}).length > 0 ||\n Object.keys(this.environment?.secrets ?? {}).length > 0;\n\n if (hasSecrets) {\n try {\n const preparedContextNoSecrets = iteration.preparedContext\n .withValue(['secrets'], {})\n .withValue(['environment', 'secrets'], {});\n const inputWithoutSecrets = this.render(\n step.input,\n preparedContextNoSecrets,\n templateRenderer,\n );\n taskLogger.addRedactions(\n collectSecretRedactions(iteration.input, inputWithoutSecrets),\n );\n } catch {\n taskLogger.addRedactions(extractStringValues(iteration.input));\n }\n }\n }\n\n await action.handler({\n input: iteration.input,\n task: {\n id: await task.getWorkspaceName(),\n },\n secrets: task.secrets ?? {},\n logger: taskLogger,\n workspacePath,\n async checkpoint<T extends JsonValue | void>(\n opts: CheckpointContext<T>,\n ) {\n const { key: checkpointKey, fn } = opts;\n const key = `v1.task.checkpoint.${step.id}.${checkpointKey}`;\n\n try {\n let prevValue: T | undefined;\n let value: T;\n\n try {\n if (prevTaskState) {\n const prevState = (\n prevTaskState.state?.checkpoints as CheckpointState\n )?.[key];\n\n if (prevState && prevState.status === 'success') {\n prevValue = prevState.value as T;\n }\n }\n\n value = prevValue !== undefined ? prevValue : await fn();\n } catch (err) {\n try {\n await task.updateCheckpoint?.({\n key,\n status: 'failed',\n reason: stringifyError(err),\n });\n } catch (persistenceError) {\n throw new AggregateError(\n [err, persistenceError],\n `Checkpoint '${checkpointKey}' failed and its failure state could not be persisted`,\n );\n }\n throw err;\n }\n\n if (prevValue === undefined) {\n await task.updateCheckpoint?.({\n key,\n status: 'success',\n value: value ?? {},\n });\n }\n return value;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n },\n createTemporaryDirectory: async () => {\n const tmpDir = await fs.mkdtemp(\n `${workspacePath}_step-${step.id}-`,\n );\n tmpDirs.push(tmpDir);\n return tmpDir;\n },\n output(name: string, value: JsonValue) {\n if (step.each) {\n stepOutput[name] = stepOutput[name] || [];\n (stepOutput[name] as JsonArray).push(value);\n } else {\n stepOutput[name] = value;\n }\n },\n templateInfo: task.spec.templateInfo,\n user: task.spec.user,\n isDryRun: task.isDryRun,\n signal: task.cancelSignal,\n getInitiatorCredentials: () => task.getInitiatorCredentials(),\n step: {\n id: step.id,\n name: step.name,\n },\n });\n }\n\n // Remove all temporary directories that were created when executing the action\n for (const tmpDir of tmpDirs) {\n await fs.remove(tmpDir);\n }\n\n context.steps[step.id] = { output: stepOutput };\n const updatedPreparedContext = preparedContext.withValue(\n ['steps', step.id],\n context.steps[step.id] as unknown as NunjitsuTemplateValue,\n );\n\n if (task.cancelSignal.aborted) {\n throw new Error(\n `Step ${step.id} (${step.name}) of task ${task.taskId} has been cancelled.`,\n );\n }\n\n await stepTrack.markSuccessful();\n return updatedPreparedContext;\n } catch (err) {\n await taskTrack.markFailed(step, err);\n await stepTrack.markFailed();\n throw err;\n } finally {\n await task.serializeWorkspace?.({ path: workspacePath });\n }\n }\n\n async execute(task: TaskContext): Promise<WorkflowResponse> {\n if (!isValidTaskSpec(task.spec)) {\n throw new InputError(\n 'Wrong template version executed with the workflow engine',\n );\n }\n const taskId = await task.getWorkspaceName();\n\n const workspacePath = path.join(this.options.workingDirectory, taskId);\n\n const { templateCapabilities } = this.options;\n\n this.environment = await this.getEnvironmentConfig();\n\n // Track whether any step has failed, used by status check functions\n const taskState = { failed: false };\n\n // Track whether a status check global (always/failure) was invoked during rendering\n const statusCheckInvoked = { value: false };\n\n const templateRenderer = createTemplateRenderer({\n allowRegexExecution: true,\n filters: {\n ...this.defaultTemplateCapabilities.filters,\n ...templateCapabilities?.filters,\n },\n globals: {\n ...templateCapabilities?.globals,\n always: () => {\n statusCheckInvoked.value = true;\n return true;\n },\n failure: () => {\n statusCheckInvoked.value = true;\n return taskState.failed;\n },\n },\n });\n try {\n await task.rehydrateWorkspace?.({ taskId, targetPath: workspacePath });\n\n const taskTrack = await this.tracker.taskStart(task);\n await fs.ensureDir(workspacePath);\n\n const context: TemplateContext = {\n parameters: task.spec.parameters,\n environment: {\n parameters: this.environment?.parameters || {},\n secrets: {},\n },\n steps: {},\n user: task.spec.user,\n context: {\n task: {\n id: taskId,\n },\n },\n };\n let preparedContext = templateRenderer.prepareContext(\n context as unknown as NunjitsuTemplateContext,\n );\n\n const [decision]: PolicyDecision[] =\n this.options.permissions && task.spec.steps.length\n ? await this.options.permissions.authorizeConditional(\n [{ permission: actionExecutePermission }],\n { credentials: await task.getInitiatorCredentials() },\n )\n : [{ result: AuthorizeResult.ALLOW }];\n\n let firstError: Error | undefined;\n const allErrors: Array<{ step: TaskStep; error: Error }> = [];\n\n for (const step of task.spec.steps) {\n // If a previous step failed, only run steps whose `if` condition\n // invokes a status check global (${{ always() }} or ${{ failure() }})\n if (taskState.failed) {\n if (typeof step.if !== 'string') {\n await task.emitLog(\n `Skipping step ${step.id} because a previous step failed`,\n { stepId: step.id, status: 'skipped' },\n );\n continue;\n }\n\n // Render the if condition to detect status check function usage\n statusCheckInvoked.value = false;\n this.render(step.if, preparedContext, templateRenderer);\n\n if (!statusCheckInvoked.value) {\n await task.emitLog(\n `Skipping step ${step.id} because a previous step failed`,\n { stepId: step.id, status: 'skipped' },\n );\n continue;\n }\n }\n\n try {\n preparedContext = await this.executeStep(\n task,\n step,\n context,\n preparedContext,\n templateRenderer,\n taskTrack,\n workspacePath,\n decision,\n );\n } catch (err) {\n const error = err as Error;\n allErrors.push({ step, error });\n\n if (!firstError) {\n firstError = error;\n } else {\n // Log subsequent errors to preserve debugging information\n this.options.logger.error(\n `Additional error in step ${step.id} (${step.name}): ${error.message}`,\n error,\n );\n await task.emitLog(\n `Additional error occurred: ${error.message}\\n${error.stack}`,\n { stepId: step.id, status: 'failed' },\n );\n }\n taskState.failed = true;\n }\n }\n\n if (firstError) {\n // If there were multiple errors, add context to the first error\n if (allErrors.length > 1) {\n const additionalErrorSummary = allErrors\n .slice(1)\n .map(({ step }) => `${step.id} (${step.name})`)\n .join(', ');\n this.options.logger.warn(\n `Task failed with ${allErrors.length} errors. First error from step ${allErrors[0].step.id}. Additional failures in: ${additionalErrorSummary}`,\n );\n }\n throw firstError;\n }\n\n const output = this.render(\n task.spec.output,\n preparedContext,\n templateRenderer,\n );\n\n // Filter output links and text items based on their `if` condition\n if (Array.isArray(output?.links)) {\n output.links = filterConditionalItems(output.links);\n }\n if (Array.isArray(output?.text)) {\n output.text = filterConditionalItems(output.text);\n }\n\n await taskTrack.markSuccessful();\n await task.cleanWorkspace?.();\n\n return { output };\n } finally {\n if (workspacePath) {\n await fs.remove(workspacePath);\n }\n }\n }\n}\n\nfunction scaffoldingTracker(metrics: MetricsService) {\n // prom-client metrics are deprecated in favour of OpenTelemetry metrics.\n const promTaskCount = createCounterMetric({\n name: 'scaffolder_task_count',\n help: 'Count of task runs',\n labelNames: ['template', 'user', 'result'],\n });\n const promTaskDuration = createHistogramMetric({\n name: 'scaffolder_task_duration',\n help: 'Duration of a task run',\n labelNames: ['template', 'result'],\n });\n const promStepCount = createCounterMetric({\n name: 'scaffolder_step_count',\n help: 'Count of step runs',\n labelNames: ['template', 'step', 'result'],\n });\n const promStepDuration = createHistogramMetric({\n name: 'scaffolder_step_duration',\n help: 'Duration of a step runs',\n labelNames: ['template', 'step', 'result'],\n });\n\n const taskCount = metrics.createCounter('scaffolder.task.count', {\n description: 'Total number of scaffolder tasks executed',\n });\n\n const taskDuration = metrics.createHistogram('scaffolder.task.duration', {\n description: 'Time taken to complete a scaffolder task end-to-end',\n unit: 's',\n });\n\n const stepCount = metrics.createCounter('scaffolder.step.count', {\n description: 'Total number of individual scaffolder action steps executed',\n });\n\n const stepDuration = metrics.createHistogram('scaffolder.step.duration', {\n description: 'Time taken to complete a single scaffolder action step',\n unit: 's',\n });\n\n async function taskStart(task: TaskContext) {\n await task.emitLog(`Starting up task with ${task.spec.steps.length} steps`);\n const template = task.spec.templateInfo?.entityRef || '';\n const user = task.spec.user?.ref || '';\n\n const startTime = process.hrtime();\n const taskTimer = promTaskDuration.startTimer({\n template,\n });\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n async function skipDryRun(\n step: TaskStep,\n action: TemplateAction<JsonObject>,\n ) {\n task.emitLog(`Skipping because ${action.id} does not support dry-run`, {\n stepId: step.id,\n status: 'skipped',\n });\n }\n\n async function markSuccessful() {\n promTaskCount.inc({\n template,\n user,\n result: 'ok',\n });\n taskTimer({ result: 'ok' });\n\n taskCount.add(1, { template, user, result: 'ok' });\n taskDuration.record(endTime(), {\n template,\n result: 'ok',\n });\n }\n\n async function markFailed(step: TaskStep, err: Error) {\n await task.emitLog(String(err.stack), {\n stepId: step.id,\n status: 'failed',\n });\n promTaskCount.inc({\n template,\n user,\n result: 'failed',\n });\n taskTimer({ result: 'failed' });\n\n taskCount.add(1, { template, user, result: 'failed' });\n taskDuration.record(endTime(), {\n template,\n result: 'failed',\n });\n }\n\n async function markCancelled(step: TaskStep) {\n await task.emitLog(`Step ${step.id} has been cancelled.`, {\n stepId: step.id,\n status: 'cancelled',\n });\n promTaskCount.inc({\n template,\n user,\n result: 'cancelled',\n });\n taskTimer({ result: 'cancelled' });\n\n taskCount.add(1, { template, user, result: 'cancelled' });\n taskDuration.record(endTime(), {\n template,\n result: 'cancelled',\n });\n }\n\n return {\n skipDryRun,\n markCancelled,\n markSuccessful,\n markFailed,\n };\n }\n\n async function stepStart(task: TaskContext, step: TaskStep) {\n await task.emitLog(`Beginning step ${step.name}`, {\n stepId: step.id,\n status: 'processing',\n });\n const template = task.spec.templateInfo?.entityRef || '';\n\n const startTime = process.hrtime();\n const stepTimer = promStepDuration.startTimer({\n template,\n step: step.name,\n });\n\n function endTime() {\n const delta = process.hrtime(startTime);\n return delta[0] + delta[1] / 1e9;\n }\n\n async function markSuccessful() {\n await task.emitLog(`Finished step ${step.name}`, {\n stepId: step.id,\n status: 'completed',\n });\n promStepCount.inc({\n template,\n step: step.name,\n result: 'ok',\n });\n stepTimer({ result: 'ok' });\n\n stepCount.add(1, { template, step: step.name, result: 'ok' });\n stepDuration.record(endTime(), {\n template,\n step: step.name,\n result: 'ok',\n });\n }\n\n async function markCancelled() {\n promStepCount.inc({\n template,\n step: step.name,\n result: 'cancelled',\n });\n stepTimer({ result: 'cancelled' });\n\n stepCount.add(1, { template, step: step.name, result: 'cancelled' });\n stepDuration.record(endTime(), {\n template,\n step: step.name,\n result: 'cancelled',\n });\n }\n\n async function markFailed() {\n promStepCount.inc({\n template,\n step: step.name,\n result: 'failed',\n });\n stepTimer({ result: 'failed' });\n\n stepCount.add(1, { template, step: step.name, result: 'failed' });\n stepDuration.record(endTime(), {\n template,\n step: step.name,\n result: 'failed',\n });\n }\n\n async function skipFalsy() {\n await task.emitLog(\n `Skipping step ${step.id} because its if condition was false`,\n { stepId: step.id, status: 'skipped' },\n );\n stepTimer({ result: 'skipped' });\n\n stepCount.add(1, { template, step: step.name, result: 'skipped' });\n stepDuration.record(endTime(), {\n template,\n step: step.name,\n result: 'skipped',\n });\n }\n\n return {\n markCancelled,\n markFailed,\n markSuccessful,\n skipFalsy,\n };\n }\n\n return {\n taskStart,\n stepStart,\n };\n}\n"],"names":["WinstonLogger","winston","BackstageLoggerTransport","createConditionAuthorizer","scaffolderActionRules","collectTemplateCapabilities","convertFiltersToRecord","createDefaultFilters","defaultEnvironment","resolveDefaultEnvironment","isTruthy","generateExampleOutput","InputError","validateJsonSchema","errors","NotAllowedError","stringifyError","fs","path","createTemplateRenderer","actionExecutePermission","AuthorizeResult","filterConditionalItems","metrics","createCounterMetric","createHistogramMetric"],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@ var errors = require('@backstage/errors');
|
|
|
4
4
|
var PQueue = require('p-queue');
|
|
5
5
|
var NunjucksWorkflowRunner = require('./NunjucksWorkflowRunner.cjs.js');
|
|
6
6
|
var promises = require('node:timers/promises');
|
|
7
|
+
var templating = require('../../util/templating.cjs.js');
|
|
7
8
|
|
|
8
9
|
function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
|
|
9
10
|
|
|
@@ -50,8 +51,10 @@ class TaskWorker {
|
|
|
50
51
|
logger,
|
|
51
52
|
auditor,
|
|
52
53
|
workingDirectory,
|
|
53
|
-
|
|
54
|
-
|
|
54
|
+
templateCapabilities: templating.collectTemplateCapabilities({
|
|
55
|
+
filters: additionalTemplateFilters,
|
|
56
|
+
globals: additionalTemplateGlobals
|
|
57
|
+
}),
|
|
55
58
|
permissions,
|
|
56
59
|
config,
|
|
57
60
|
metrics
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TaskWorker.cjs.js","sources":["../../../src/scaffolder/tasks/TaskWorker.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { AuditorService, LoggerService } from '@backstage/backend-plugin-api';\nimport type { MetricsService } from '@backstage/backend-plugin-api/alpha';\nimport { InputError, stringifyError, toError } from '@backstage/errors';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\nimport {\n TaskBroker,\n TaskContext,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport PQueue from 'p-queue';\nimport { TemplateActionRegistry } from '../actions/TemplateActionRegistry';\nimport { NunjucksWorkflowRunner } from './NunjucksWorkflowRunner';\nimport { WorkflowRunner } from './types';\nimport { setTimeout } from 'node:timers/promises';\nimport { JsonObject } from '@backstage/types';\nimport { Config } from '@backstage/config';\n\nconst DEFAULT_TASK_PARAMETER_MAX_LENGTH = 256;\n\n/**\n * TaskWorkerOptions\n */\nexport type TaskWorkerOptions = {\n taskBroker: TaskBroker;\n runners: {\n workflowRunner: WorkflowRunner;\n };\n concurrentTasksLimit: number;\n permissions?: PermissionEvaluator;\n logger?: LoggerService;\n auditor?: AuditorService;\n config?: Config;\n gracefulShutdown?: boolean;\n};\n\n/**\n * CreateWorkerOptions\n */\nexport type CreateWorkerOptions = {\n taskBroker: TaskBroker;\n actionRegistry: TemplateActionRegistry;\n integrations: ScmIntegrations;\n workingDirectory: string;\n logger: LoggerService;\n auditor?: AuditorService;\n config?: Config;\n additionalTemplateFilters?: Record<string, TemplateFilter>;\n /**\n * The number of tasks that can be executed at the same time by the worker\n * @defaultValue 10\n * @example\n * ```\n * {\n * concurrentTasksLimit: 1,\n * // OR\n * concurrentTasksLimit: Infinity\n * }\n * ```\n */\n concurrentTasksLimit?: number;\n additionalTemplateGlobals?: Record<string, TemplateGlobal>;\n permissions?: PermissionEvaluator;\n gracefulShutdown?: boolean;\n metrics: MetricsService;\n};\n\n/**\n * TaskWorker\n */\nexport class TaskWorker {\n private taskQueue: PQueue;\n private logger: LoggerService | undefined;\n private auditor: AuditorService | undefined;\n private parameterAuditTransform: ParameterAuditTransform;\n private stopWorkers: boolean;\n\n private readonly options: TaskWorkerOptions & {\n parameterAuditTransform: ParameterAuditTransform;\n };\n\n private constructor(\n options: TaskWorkerOptions & {\n parameterAuditTransform: ParameterAuditTransform;\n },\n ) {\n this.options = options;\n this.stopWorkers = false;\n this.logger = options.logger;\n this.auditor = options.auditor;\n this.taskQueue = new PQueue({\n concurrency: options.concurrentTasksLimit,\n });\n this.parameterAuditTransform = options.parameterAuditTransform;\n }\n\n static async create(options: CreateWorkerOptions): Promise<TaskWorker> {\n const {\n taskBroker,\n logger,\n auditor,\n config,\n actionRegistry,\n integrations,\n workingDirectory,\n additionalTemplateFilters,\n concurrentTasksLimit = 10, // from 1 to Infinity\n additionalTemplateGlobals,\n permissions,\n gracefulShutdown,\n metrics,\n } = options;\n\n const workflowRunner = new NunjucksWorkflowRunner({\n actionRegistry,\n integrations,\n logger,\n auditor,\n workingDirectory,\n additionalTemplateFilters,\n additionalTemplateGlobals,\n permissions,\n config,\n metrics,\n });\n\n return new TaskWorker({\n taskBroker: taskBroker,\n runners: { workflowRunner },\n concurrentTasksLimit,\n permissions,\n auditor,\n config,\n gracefulShutdown,\n parameterAuditTransform: createParameterTruncator(config),\n });\n }\n\n async recoverTasks() {\n try {\n await this.options.taskBroker.recoverTasks?.();\n } catch (err) {\n this.logger?.error(stringifyError(err));\n }\n }\n\n start() {\n (async () => {\n while (!this.stopWorkers) {\n await setTimeout(10000);\n await this.recoverTasks();\n }\n })();\n (async () => {\n while (!this.stopWorkers) {\n await this.onReadyToClaimTask();\n if (!this.stopWorkers) {\n const task = await this.options.taskBroker.claim();\n void this.taskQueue.add(() => this.runOneTask(task));\n }\n }\n })();\n }\n\n async stop() {\n this.stopWorkers = true;\n if (this.options?.gracefulShutdown) {\n while (this.taskQueue.size > 0) {\n await setTimeout(1000);\n }\n }\n }\n\n protected onReadyToClaimTask(): Promise<void> {\n if (this.taskQueue.pending < this.options.concurrentTasksLimit) {\n return Promise.resolve();\n }\n return new Promise(resolve => {\n // \"next\" event emits when a task completes\n // https://github.com/sindresorhus/p-queue#next\n this.taskQueue.once('next', () => {\n resolve();\n });\n });\n }\n\n async runOneTask(task: TaskContext) {\n const auditorEvent = await this.auditor?.createEvent({\n eventId: 'task',\n severityLevel: 'medium',\n meta: {\n actionType: 'execution',\n createdBy: task.createdBy,\n taskId: task.taskId,\n taskParameters: this.parameterAuditTransform(task.spec.parameters),\n templateRef: task.spec.templateInfo?.entityRef,\n },\n });\n\n try {\n if (task.spec.apiVersion !== 'scaffolder.backstage.io/v1beta3') {\n throw new Error(\n `Unsupported Template apiVersion ${task.spec.apiVersion}`,\n );\n }\n\n const { output } = await this.options.runners.workflowRunner.execute(\n task,\n );\n\n await task.complete('completed', { output });\n await auditorEvent?.success();\n } catch (error) {\n const err = toError(error);\n await auditorEvent?.fail({\n error: err,\n });\n await task.complete('failed', {\n error: { name: err.name, message: err.message },\n });\n }\n }\n}\n\ntype ParameterAuditTransform = (parameters: JsonObject) => JsonObject;\n\n/**\n * Truncates task parameters for audit logging using the configured max length.\n * @internal\n */\nexport function createParameterTruncator(\n config?: Config,\n): ParameterAuditTransform {\n const maxLength =\n config?.getOptionalNumber('scaffolder.auditor.taskParameterMaxLength') ??\n DEFAULT_TASK_PARAMETER_MAX_LENGTH;\n\n if (!Number.isSafeInteger(maxLength) || maxLength < -1) {\n throw new InputError(\n `Invalid configuration for 'scaffolder.auditor.taskParameterMaxLength', got ${maxLength}. Must be a positive integer or -1 to disable truncation.`,\n );\n }\n\n if (maxLength === -1) {\n return (parameters: JsonObject) => parameters;\n }\n\n return (parameters: JsonObject) => {\n function truncate(value: unknown): unknown {\n if (typeof value === 'string') {\n if (value.length > maxLength) {\n return value.slice(0, maxLength).concat('...<truncated>');\n }\n return value;\n }\n if (Array.isArray(value)) {\n return value.map(truncate);\n }\n if (value && typeof value === 'object') {\n const result: Record<string, unknown> = {};\n for (const k in value as object) {\n if (Object.hasOwn(value, k)) {\n result[k] = truncate((value as any)[k]);\n }\n }\n return result;\n }\n return value;\n }\n\n return truncate(parameters) as JsonObject;\n };\n}\n"],"names":["PQueue","NunjucksWorkflowRunner","stringifyError","setTimeout","toError","InputError"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TaskWorker.cjs.js","sources":["../../../src/scaffolder/tasks/TaskWorker.ts"],"sourcesContent":["/*\n * Copyright 2021 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 { AuditorService, LoggerService } from '@backstage/backend-plugin-api';\nimport type { MetricsService } from '@backstage/backend-plugin-api/alpha';\nimport { InputError, stringifyError, toError } from '@backstage/errors';\nimport { ScmIntegrations } from '@backstage/integration';\nimport { PermissionEvaluator } from '@backstage/plugin-permission-common';\nimport {\n TaskBroker,\n TaskContext,\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport PQueue from 'p-queue';\nimport { TemplateActionRegistry } from '../actions/TemplateActionRegistry';\nimport { NunjucksWorkflowRunner } from './NunjucksWorkflowRunner';\nimport { WorkflowRunner } from './types';\nimport { setTimeout } from 'node:timers/promises';\nimport { JsonObject } from '@backstage/types';\nimport { Config } from '@backstage/config';\nimport { collectTemplateCapabilities } from '../../util/templating';\n\nconst DEFAULT_TASK_PARAMETER_MAX_LENGTH = 256;\n\n/**\n * TaskWorkerOptions\n */\nexport type TaskWorkerOptions = {\n taskBroker: TaskBroker;\n runners: {\n workflowRunner: WorkflowRunner;\n };\n concurrentTasksLimit: number;\n permissions?: PermissionEvaluator;\n logger?: LoggerService;\n auditor?: AuditorService;\n config?: Config;\n gracefulShutdown?: boolean;\n};\n\n/**\n * CreateWorkerOptions\n */\nexport type CreateWorkerOptions = {\n taskBroker: TaskBroker;\n actionRegistry: TemplateActionRegistry;\n integrations: ScmIntegrations;\n workingDirectory: string;\n logger: LoggerService;\n auditor?: AuditorService;\n config?: Config;\n additionalTemplateFilters?: Record<string, TemplateFilter>;\n /**\n * The number of tasks that can be executed at the same time by the worker\n * @defaultValue 10\n * @example\n * ```\n * {\n * concurrentTasksLimit: 1,\n * // OR\n * concurrentTasksLimit: Infinity\n * }\n * ```\n */\n concurrentTasksLimit?: number;\n additionalTemplateGlobals?: Record<string, TemplateGlobal>;\n permissions?: PermissionEvaluator;\n gracefulShutdown?: boolean;\n metrics: MetricsService;\n};\n\n/**\n * TaskWorker\n */\nexport class TaskWorker {\n private taskQueue: PQueue;\n private logger: LoggerService | undefined;\n private auditor: AuditorService | undefined;\n private parameterAuditTransform: ParameterAuditTransform;\n private stopWorkers: boolean;\n\n private readonly options: TaskWorkerOptions & {\n parameterAuditTransform: ParameterAuditTransform;\n };\n\n private constructor(\n options: TaskWorkerOptions & {\n parameterAuditTransform: ParameterAuditTransform;\n },\n ) {\n this.options = options;\n this.stopWorkers = false;\n this.logger = options.logger;\n this.auditor = options.auditor;\n this.taskQueue = new PQueue({\n concurrency: options.concurrentTasksLimit,\n });\n this.parameterAuditTransform = options.parameterAuditTransform;\n }\n\n static async create(options: CreateWorkerOptions): Promise<TaskWorker> {\n const {\n taskBroker,\n logger,\n auditor,\n config,\n actionRegistry,\n integrations,\n workingDirectory,\n additionalTemplateFilters,\n concurrentTasksLimit = 10, // from 1 to Infinity\n additionalTemplateGlobals,\n permissions,\n gracefulShutdown,\n metrics,\n } = options;\n\n const workflowRunner = new NunjucksWorkflowRunner({\n actionRegistry,\n integrations,\n logger,\n auditor,\n workingDirectory,\n templateCapabilities: collectTemplateCapabilities({\n filters: additionalTemplateFilters,\n globals: additionalTemplateGlobals,\n }),\n permissions,\n config,\n metrics,\n });\n\n return new TaskWorker({\n taskBroker: taskBroker,\n runners: { workflowRunner },\n concurrentTasksLimit,\n permissions,\n auditor,\n config,\n gracefulShutdown,\n parameterAuditTransform: createParameterTruncator(config),\n });\n }\n\n async recoverTasks() {\n try {\n await this.options.taskBroker.recoverTasks?.();\n } catch (err) {\n this.logger?.error(stringifyError(err));\n }\n }\n\n start() {\n (async () => {\n while (!this.stopWorkers) {\n await setTimeout(10000);\n await this.recoverTasks();\n }\n })();\n (async () => {\n while (!this.stopWorkers) {\n await this.onReadyToClaimTask();\n if (!this.stopWorkers) {\n const task = await this.options.taskBroker.claim();\n void this.taskQueue.add(() => this.runOneTask(task));\n }\n }\n })();\n }\n\n async stop() {\n this.stopWorkers = true;\n if (this.options?.gracefulShutdown) {\n while (this.taskQueue.size > 0) {\n await setTimeout(1000);\n }\n }\n }\n\n protected onReadyToClaimTask(): Promise<void> {\n if (this.taskQueue.pending < this.options.concurrentTasksLimit) {\n return Promise.resolve();\n }\n return new Promise(resolve => {\n // \"next\" event emits when a task completes\n // https://github.com/sindresorhus/p-queue#next\n this.taskQueue.once('next', () => {\n resolve();\n });\n });\n }\n\n async runOneTask(task: TaskContext) {\n const auditorEvent = await this.auditor?.createEvent({\n eventId: 'task',\n severityLevel: 'medium',\n meta: {\n actionType: 'execution',\n createdBy: task.createdBy,\n taskId: task.taskId,\n taskParameters: this.parameterAuditTransform(task.spec.parameters),\n templateRef: task.spec.templateInfo?.entityRef,\n },\n });\n\n try {\n if (task.spec.apiVersion !== 'scaffolder.backstage.io/v1beta3') {\n throw new Error(\n `Unsupported Template apiVersion ${task.spec.apiVersion}`,\n );\n }\n\n const { output } = await this.options.runners.workflowRunner.execute(\n task,\n );\n\n await task.complete('completed', { output });\n await auditorEvent?.success();\n } catch (error) {\n const err = toError(error);\n await auditorEvent?.fail({\n error: err,\n });\n await task.complete('failed', {\n error: { name: err.name, message: err.message },\n });\n }\n }\n}\n\ntype ParameterAuditTransform = (parameters: JsonObject) => JsonObject;\n\n/**\n * Truncates task parameters for audit logging using the configured max length.\n * @internal\n */\nexport function createParameterTruncator(\n config?: Config,\n): ParameterAuditTransform {\n const maxLength =\n config?.getOptionalNumber('scaffolder.auditor.taskParameterMaxLength') ??\n DEFAULT_TASK_PARAMETER_MAX_LENGTH;\n\n if (!Number.isSafeInteger(maxLength) || maxLength < -1) {\n throw new InputError(\n `Invalid configuration for 'scaffolder.auditor.taskParameterMaxLength', got ${maxLength}. Must be a positive integer or -1 to disable truncation.`,\n );\n }\n\n if (maxLength === -1) {\n return (parameters: JsonObject) => parameters;\n }\n\n return (parameters: JsonObject) => {\n function truncate(value: unknown): unknown {\n if (typeof value === 'string') {\n if (value.length > maxLength) {\n return value.slice(0, maxLength).concat('...<truncated>');\n }\n return value;\n }\n if (Array.isArray(value)) {\n return value.map(truncate);\n }\n if (value && typeof value === 'object') {\n const result: Record<string, unknown> = {};\n for (const k in value as object) {\n if (Object.hasOwn(value, k)) {\n result[k] = truncate((value as any)[k]);\n }\n }\n return result;\n }\n return value;\n }\n\n return truncate(parameters) as JsonObject;\n };\n}\n"],"names":["PQueue","NunjucksWorkflowRunner","collectTemplateCapabilities","stringifyError","setTimeout","toError","InputError"],"mappings":"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"}
|
|
@@ -30,9 +30,9 @@ require('../scaffolder/actions/builtin/fetch/plainFile.examples.cjs.js');
|
|
|
30
30
|
require('../scaffolder/actions/builtin/fetch/template.examples.cjs.js');
|
|
31
31
|
require('globby');
|
|
32
32
|
require('isbinaryfile');
|
|
33
|
+
require('nunjitsu');
|
|
33
34
|
var createDefaultFilters = require('../lib/templating/filters/createDefaultFilters.cjs.js');
|
|
34
35
|
var templating = require('../util/templating.cjs.js');
|
|
35
|
-
require('isolated-vm');
|
|
36
36
|
require('../scaffolder/actions/builtin/fetch/templateFile.examples.cjs.js');
|
|
37
37
|
require('../scaffolder/actions/builtin/filesystem/delete.examples.cjs.js');
|
|
38
38
|
require('../scaffolder/actions/builtin/filesystem/rename.examples.cjs.js');
|
|
@@ -159,7 +159,19 @@ function convertGlobalsToRecord(globals) {
|
|
|
159
159
|
}
|
|
160
160
|
return result;
|
|
161
161
|
}
|
|
162
|
+
function collectTemplateCapabilities(options) {
|
|
163
|
+
const filters = {};
|
|
164
|
+
for (const [name, filter] of Object.entries(options.filters ?? {})) {
|
|
165
|
+
filters[name] = (input, ...args) => filter(input, ...args);
|
|
166
|
+
}
|
|
167
|
+
const globals = {};
|
|
168
|
+
for (const [name, global] of Object.entries(options.globals ?? {})) {
|
|
169
|
+
globals[name] = typeof global === "function" ? (...args) => global(...args) : global;
|
|
170
|
+
}
|
|
171
|
+
return { filters, globals };
|
|
172
|
+
}
|
|
162
173
|
|
|
174
|
+
exports.collectTemplateCapabilities = collectTemplateCapabilities;
|
|
163
175
|
exports.convertFiltersToRecord = convertFiltersToRecord;
|
|
164
176
|
exports.convertGlobalsToRecord = convertGlobalsToRecord;
|
|
165
177
|
exports.extractFilterMetadata = extractFilterMetadata;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"templating.cjs.js","sources":["../../src/util/templating.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 */\nimport {\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n CreatedTemplateFilter,\n CreatedTemplateGlobal,\n CreatedTemplateGlobalFunction,\n CreatedTemplateGlobalValue,\n ZodFunctionSchema,\n} from '@backstage/plugin-scaffolder-node/alpha';\nimport { JsonValue } from '@backstage/types';\nimport { Schema } from 'jsonschema';\nimport { ZodType, z } from 'zod/v3';\nimport zodToJsonSchema from 'zod-to-json-schema';\n\n/**\n * Converts template filters to a record of filter functions\n */\nexport function convertFiltersToRecord(\n filters?: Record<string, TemplateFilter> | CreatedTemplateFilter<any, any>[],\n): Record<string, TemplateFilter> {\n if (!filters) {\n return {};\n }\n\n if (Array.isArray(filters)) {\n const result: Record<string, TemplateFilter> = {};\n for (const filter of filters) {\n result[filter.id] = filter.filter as TemplateFilter;\n }\n return result;\n }\n\n return filters;\n}\n\ntype ExportFunctionSchema = {\n arguments?: Schema[];\n output?: Schema;\n};\n\ntype ExportFilterSchema = {\n input?: Schema;\n} & ExportFunctionSchema;\n\n/**\n * Converts a Zod function schema to JSON schema\n */\nfunction convertZodFunctionToJsonSchema(\n t: ReturnType<ZodFunctionSchema<any, any>>,\n): ExportFunctionSchema {\n if (!('parameters' in t) || !('returnType' in t)) {\n throw new Error('Invalid Zod function schema');\n }\n\n const args = (t.parameters().items as ZodType[]).map(\n zt => zodToJsonSchema(zt) as Schema,\n );\n\n let output: Schema | undefined = undefined;\n const returnType = t.returnType();\n if (!returnType._unknown) {\n output = zodToJsonSchema(returnType) as Schema;\n }\n\n const result: ExportFunctionSchema = {};\n if (args.length > 0) {\n result.arguments = args;\n }\n if (output) {\n result.output = output;\n }\n\n return result;\n}\n\n/**\n * Converts a function schema to a filter schema\n */\nfunction convertToFilterSchema(\n fnSchema: ExportFunctionSchema,\n): ExportFilterSchema {\n if (fnSchema.arguments?.length) {\n const [input, ...rest] = fnSchema.arguments;\n const result: ExportFilterSchema = { input };\n\n if (rest.length > 0) {\n result.arguments = rest;\n }\n\n if (fnSchema.output) {\n result.output = fnSchema.output;\n }\n\n return result;\n }\n return fnSchema;\n}\n\ntype ExportFilter = Pick<\n CreatedTemplateFilter<any, any>,\n 'description' | 'examples'\n> & {\n schema?: ExportFilterSchema;\n};\n\n/**\n * Extracts metadata from template filters\n */\nexport function extractFilterMetadata(\n filters?: Record<string, TemplateFilter> | CreatedTemplateFilter<any, any>[],\n): Record<string, ExportFilter> {\n if (!filters) {\n return {};\n }\n\n if (Array.isArray(filters)) {\n const result: Record<string, ExportFilter> = {};\n\n for (const filter of filters) {\n const metadata: ExportFilter = {};\n\n if (filter.description) {\n metadata.description = filter.description;\n }\n\n if (filter.examples) {\n metadata.examples = filter.examples;\n }\n\n if (filter.schema) {\n metadata.schema = convertToFilterSchema(\n convertZodFunctionToJsonSchema(\n filter.schema(z) as z.ZodFunction<any, any>,\n ),\n );\n }\n\n result[filter.id] = metadata;\n }\n\n return result;\n }\n\n // For non-array filters, return empty metadata\n const result: Record<string, ExportFilter> = {};\n for (const key in filters) {\n if (filters.hasOwnProperty(key)) {\n result[key] = {};\n }\n }\n return result;\n}\n\n/**\n * Checks if a global is a function\n */\nfunction isGlobalFunction(\n global: CreatedTemplateGlobal,\n): global is CreatedTemplateGlobalFunction<any, any> {\n return 'fn' in global;\n}\n\n/**\n * Extracts metadata from template global functions\n */\nexport function extractGlobalFunctionMetadata(\n globals?: Record<string, TemplateGlobal> | CreatedTemplateGlobal[],\n): Record<\n string,\n Pick<CreatedTemplateGlobalFunction<any, any>, 'description' | 'examples'> & {\n schema?: ExportFunctionSchema;\n }\n> {\n if (!globals) {\n return {};\n }\n\n if (Array.isArray(globals)) {\n const result: Record<string, any> = {};\n\n for (const global of globals) {\n if (isGlobalFunction(global)) {\n const metadata: any = {};\n\n if (global.description) {\n metadata.description = global.description;\n }\n\n if (global.examples) {\n metadata.examples = global.examples;\n }\n\n if (global.schema) {\n metadata.schema = convertZodFunctionToJsonSchema(global.schema(z));\n }\n\n result[global.id] = metadata;\n }\n }\n\n return result;\n }\n\n // For non-array globals, extract function metadata\n const result: Record<string, any> = {};\n for (const key in globals) {\n if (typeof globals[key] === 'function') {\n result[key] = {};\n }\n }\n return result;\n}\n\n/**\n * Extracts metadata from template global values\n */\nexport function extractGlobalValueMetadata(\n globals?: Record<string, TemplateGlobal> | CreatedTemplateGlobal[],\n): Record<string, Omit<CreatedTemplateGlobalValue, 'id'>> {\n if (!globals) {\n return {};\n }\n\n if (Array.isArray(globals)) {\n const result: Record<string, Omit<CreatedTemplateGlobalValue, 'id'>> = {};\n\n for (const global of globals) {\n if (!isGlobalFunction(global)) {\n result[global.id] = {\n value: (global as CreatedTemplateGlobalValue).value,\n description: global.description,\n };\n }\n }\n\n return result;\n }\n\n // For non-array globals, extract value metadata\n const result: Record<string, Omit<CreatedTemplateGlobalValue, 'id'>> = {};\n for (const key in globals) {\n if (typeof globals[key] !== 'function') {\n result[key] = { value: globals[key] as JsonValue };\n }\n }\n return result;\n}\n\n/**\n * Converts template globals to a record of global values and functions\n */\nexport function convertGlobalsToRecord(\n globals?: Record<string, TemplateGlobal> | CreatedTemplateGlobal[],\n): Record<string, TemplateGlobal> {\n if (!globals) {\n return {};\n }\n\n if (!Array.isArray(globals)) {\n return globals;\n }\n\n const result: Record<string, TemplateGlobal> = {};\n for (const global of globals) {\n result[global.id] = isGlobalFunction(global)\n ? (global.fn as TemplateGlobal)\n : (global as CreatedTemplateGlobalValue).value;\n }\n return result;\n}\n"],"names":["zodToJsonSchema","result","z"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"templating.cjs.js","sources":["../../src/util/templating.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 */\nimport {\n TemplateFilter,\n TemplateGlobal,\n} from '@backstage/plugin-scaffolder-node';\nimport {\n CreatedTemplateFilter,\n CreatedTemplateGlobal,\n CreatedTemplateGlobalFunction,\n CreatedTemplateGlobalValue,\n ZodFunctionSchema,\n} from '@backstage/plugin-scaffolder-node/alpha';\nimport { JsonValue } from '@backstage/types';\nimport { Schema } from 'jsonschema';\nimport {\n TemplateCapabilities,\n TemplateFilter as NunjitsuTemplateFilter,\n TemplateGlobal as NunjitsuTemplateGlobal,\n TemplateValue as NunjitsuTemplateValue,\n} from 'nunjitsu';\nimport { ZodType, z } from 'zod/v3';\nimport zodToJsonSchema from 'zod-to-json-schema';\n\n/**\n * Converts template filters to a record of filter functions\n */\nexport function convertFiltersToRecord(\n filters?: Record<string, TemplateFilter> | CreatedTemplateFilter<any, any>[],\n): Record<string, TemplateFilter> {\n if (!filters) {\n return {};\n }\n\n if (Array.isArray(filters)) {\n const result: Record<string, TemplateFilter> = {};\n for (const filter of filters) {\n result[filter.id] = filter.filter as TemplateFilter;\n }\n return result;\n }\n\n return filters;\n}\n\ntype ExportFunctionSchema = {\n arguments?: Schema[];\n output?: Schema;\n};\n\ntype ExportFilterSchema = {\n input?: Schema;\n} & ExportFunctionSchema;\n\n/**\n * Converts a Zod function schema to JSON schema\n */\nfunction convertZodFunctionToJsonSchema(\n t: ReturnType<ZodFunctionSchema<any, any>>,\n): ExportFunctionSchema {\n if (!('parameters' in t) || !('returnType' in t)) {\n throw new Error('Invalid Zod function schema');\n }\n\n const args = (t.parameters().items as ZodType[]).map(\n zt => zodToJsonSchema(zt) as Schema,\n );\n\n let output: Schema | undefined = undefined;\n const returnType = t.returnType();\n if (!returnType._unknown) {\n output = zodToJsonSchema(returnType) as Schema;\n }\n\n const result: ExportFunctionSchema = {};\n if (args.length > 0) {\n result.arguments = args;\n }\n if (output) {\n result.output = output;\n }\n\n return result;\n}\n\n/**\n * Converts a function schema to a filter schema\n */\nfunction convertToFilterSchema(\n fnSchema: ExportFunctionSchema,\n): ExportFilterSchema {\n if (fnSchema.arguments?.length) {\n const [input, ...rest] = fnSchema.arguments;\n const result: ExportFilterSchema = { input };\n\n if (rest.length > 0) {\n result.arguments = rest;\n }\n\n if (fnSchema.output) {\n result.output = fnSchema.output;\n }\n\n return result;\n }\n return fnSchema;\n}\n\ntype ExportFilter = Pick<\n CreatedTemplateFilter<any, any>,\n 'description' | 'examples'\n> & {\n schema?: ExportFilterSchema;\n};\n\n/**\n * Extracts metadata from template filters\n */\nexport function extractFilterMetadata(\n filters?: Record<string, TemplateFilter> | CreatedTemplateFilter<any, any>[],\n): Record<string, ExportFilter> {\n if (!filters) {\n return {};\n }\n\n if (Array.isArray(filters)) {\n const result: Record<string, ExportFilter> = {};\n\n for (const filter of filters) {\n const metadata: ExportFilter = {};\n\n if (filter.description) {\n metadata.description = filter.description;\n }\n\n if (filter.examples) {\n metadata.examples = filter.examples;\n }\n\n if (filter.schema) {\n metadata.schema = convertToFilterSchema(\n convertZodFunctionToJsonSchema(\n filter.schema(z) as z.ZodFunction<any, any>,\n ),\n );\n }\n\n result[filter.id] = metadata;\n }\n\n return result;\n }\n\n // For non-array filters, return empty metadata\n const result: Record<string, ExportFilter> = {};\n for (const key in filters) {\n if (filters.hasOwnProperty(key)) {\n result[key] = {};\n }\n }\n return result;\n}\n\n/**\n * Checks if a global is a function\n */\nfunction isGlobalFunction(\n global: CreatedTemplateGlobal,\n): global is CreatedTemplateGlobalFunction<any, any> {\n return 'fn' in global;\n}\n\n/**\n * Extracts metadata from template global functions\n */\nexport function extractGlobalFunctionMetadata(\n globals?: Record<string, TemplateGlobal> | CreatedTemplateGlobal[],\n): Record<\n string,\n Pick<CreatedTemplateGlobalFunction<any, any>, 'description' | 'examples'> & {\n schema?: ExportFunctionSchema;\n }\n> {\n if (!globals) {\n return {};\n }\n\n if (Array.isArray(globals)) {\n const result: Record<string, any> = {};\n\n for (const global of globals) {\n if (isGlobalFunction(global)) {\n const metadata: any = {};\n\n if (global.description) {\n metadata.description = global.description;\n }\n\n if (global.examples) {\n metadata.examples = global.examples;\n }\n\n if (global.schema) {\n metadata.schema = convertZodFunctionToJsonSchema(global.schema(z));\n }\n\n result[global.id] = metadata;\n }\n }\n\n return result;\n }\n\n // For non-array globals, extract function metadata\n const result: Record<string, any> = {};\n for (const key in globals) {\n if (typeof globals[key] === 'function') {\n result[key] = {};\n }\n }\n return result;\n}\n\n/**\n * Extracts metadata from template global values\n */\nexport function extractGlobalValueMetadata(\n globals?: Record<string, TemplateGlobal> | CreatedTemplateGlobal[],\n): Record<string, Omit<CreatedTemplateGlobalValue, 'id'>> {\n if (!globals) {\n return {};\n }\n\n if (Array.isArray(globals)) {\n const result: Record<string, Omit<CreatedTemplateGlobalValue, 'id'>> = {};\n\n for (const global of globals) {\n if (!isGlobalFunction(global)) {\n result[global.id] = {\n value: (global as CreatedTemplateGlobalValue).value,\n description: global.description,\n };\n }\n }\n\n return result;\n }\n\n // For non-array globals, extract value metadata\n const result: Record<string, Omit<CreatedTemplateGlobalValue, 'id'>> = {};\n for (const key in globals) {\n if (typeof globals[key] !== 'function') {\n result[key] = { value: globals[key] as JsonValue };\n }\n }\n return result;\n}\n\n/**\n * Converts template globals to a record of global values and functions\n */\nexport function convertGlobalsToRecord(\n globals?: Record<string, TemplateGlobal> | CreatedTemplateGlobal[],\n): Record<string, TemplateGlobal> {\n if (!globals) {\n return {};\n }\n\n if (!Array.isArray(globals)) {\n return globals;\n }\n\n const result: Record<string, TemplateGlobal> = {};\n for (const global of globals) {\n result[global.id] = isGlobalFunction(global)\n ? (global.fn as TemplateGlobal)\n : (global as CreatedTemplateGlobalValue).value;\n }\n return result;\n}\n\n/** Adapts registered Backstage capabilities for reuse by Nunjitsu renderers. */\nexport function collectTemplateCapabilities(options: {\n filters?: Record<string, TemplateFilter>;\n globals?: Record<string, TemplateGlobal>;\n}): TemplateCapabilities {\n const filters: Record<string, NunjitsuTemplateFilter> = {};\n for (const [name, filter] of Object.entries(options.filters ?? {})) {\n filters[name] = (input, ...args) =>\n filter(input as JsonValue, ...(args as JsonValue[])) as\n | NunjitsuTemplateValue\n | undefined;\n }\n\n const globals: Record<string, NunjitsuTemplateGlobal> = {};\n for (const [name, global] of Object.entries(options.globals ?? {})) {\n globals[name] =\n typeof global === 'function'\n ? (...args) =>\n global(...(args as JsonValue[])) as\n | NunjitsuTemplateValue\n | undefined\n : (global as NunjitsuTemplateGlobal);\n }\n\n return { filters, globals };\n}\n"],"names":["zodToJsonSchema","result","z"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/plugin-scaffolder-backend",
|
|
3
|
-
"version": "4.0.3
|
|
3
|
+
"version": "4.0.3",
|
|
4
4
|
"description": "The Backstage backend plugin that helps you create new things",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "backend-plugin",
|
|
@@ -62,12 +62,10 @@
|
|
|
62
62
|
"files": [
|
|
63
63
|
"dist",
|
|
64
64
|
"migrations",
|
|
65
|
-
"config.schema.json"
|
|
66
|
-
"assets"
|
|
65
|
+
"config.schema.json"
|
|
67
66
|
],
|
|
68
67
|
"scripts": {
|
|
69
68
|
"build": "backstage-cli package build",
|
|
70
|
-
"build:assets": "node scripts/build-nunjucks.js",
|
|
71
69
|
"clean": "backstage-cli package clean",
|
|
72
70
|
"generate": "backstage-repo-tools package schema openapi generate --server --client-package plugins/scaffolder-common",
|
|
73
71
|
"lint": "backstage-cli package lint",
|
|
@@ -77,31 +75,30 @@
|
|
|
77
75
|
"test": "backstage-cli package test"
|
|
78
76
|
},
|
|
79
77
|
"dependencies": {
|
|
80
|
-
"@backstage/backend-openapi-utils": "0.7.1
|
|
81
|
-
"@backstage/backend-plugin-api": "1.10.0
|
|
82
|
-
"@backstage/catalog-model": "1.
|
|
83
|
-
"@backstage/config": "1.3.8",
|
|
84
|
-
"@backstage/errors": "1.3.1",
|
|
85
|
-
"@backstage/integration": "2.1.0
|
|
86
|
-
"@backstage/plugin-catalog-node": "2.2.4
|
|
87
|
-
"@backstage/plugin-events-node": "0.4.25
|
|
88
|
-
"@backstage/plugin-permission-common": "0.9.
|
|
89
|
-
"@backstage/plugin-permission-node": "0.11.3
|
|
90
|
-
"@backstage/plugin-scaffolder-common": "2.2.2
|
|
91
|
-
"@backstage/plugin-scaffolder-node": "0.13.6
|
|
92
|
-
"@backstage/types": "1.2.2",
|
|
78
|
+
"@backstage/backend-openapi-utils": "^0.7.1",
|
|
79
|
+
"@backstage/backend-plugin-api": "^1.10.0",
|
|
80
|
+
"@backstage/catalog-model": "^1.10.0",
|
|
81
|
+
"@backstage/config": "^1.3.8",
|
|
82
|
+
"@backstage/errors": "^1.3.1",
|
|
83
|
+
"@backstage/integration": "^2.1.0",
|
|
84
|
+
"@backstage/plugin-catalog-node": "^2.2.4",
|
|
85
|
+
"@backstage/plugin-events-node": "^0.4.25",
|
|
86
|
+
"@backstage/plugin-permission-common": "^0.9.10",
|
|
87
|
+
"@backstage/plugin-permission-node": "^0.11.3",
|
|
88
|
+
"@backstage/plugin-scaffolder-common": "^2.2.2",
|
|
89
|
+
"@backstage/plugin-scaffolder-node": "^0.13.6",
|
|
90
|
+
"@backstage/types": "^1.2.2",
|
|
93
91
|
"@types/luxon": "^3.0.0",
|
|
94
92
|
"express": "^4.22.0",
|
|
95
93
|
"fs-extra": "^11.2.0",
|
|
96
94
|
"globby": "^11.0.0",
|
|
97
95
|
"isbinaryfile": "^5.0.0",
|
|
98
|
-
"isolated-vm": "^6.0.1",
|
|
99
96
|
"jsonschema": "^1.5.0",
|
|
100
97
|
"knex": "^3.0.0",
|
|
101
98
|
"lodash": "^4.17.21",
|
|
102
99
|
"logform": "^2.3.2",
|
|
103
100
|
"luxon": "^3.0.0",
|
|
104
|
-
"
|
|
101
|
+
"nunjitsu": "^0.5.0",
|
|
105
102
|
"p-queue": "^6.6.2",
|
|
106
103
|
"prom-client": "^15.0.0",
|
|
107
104
|
"triple-beam": "^1.4.1",
|
|
@@ -113,17 +110,15 @@
|
|
|
113
110
|
"zod-to-json-schema": "^3.25.1"
|
|
114
111
|
},
|
|
115
112
|
"devDependencies": {
|
|
116
|
-
"@backstage/backend-defaults": "0.17.
|
|
117
|
-
"@backstage/backend-test-utils": "1.11.6
|
|
118
|
-
"@backstage/cli": "0.36.5
|
|
119
|
-
"@backstage/plugin-scaffolder-node-test-utils": "0.3.14
|
|
120
|
-
"@backstage/repo-tools": "0.
|
|
113
|
+
"@backstage/backend-defaults": "^0.17.7",
|
|
114
|
+
"@backstage/backend-test-utils": "^1.11.6",
|
|
115
|
+
"@backstage/cli": "^0.36.5",
|
|
116
|
+
"@backstage/plugin-scaffolder-node-test-utils": "^0.3.14",
|
|
117
|
+
"@backstage/repo-tools": "^0.19.0",
|
|
121
118
|
"@types/express": "^4.17.6",
|
|
122
119
|
"@types/fs-extra": "^11.0.0",
|
|
123
|
-
"@types/nunjucks": "^3.1.4",
|
|
124
120
|
"@types/supertest": "^2.0.8",
|
|
125
121
|
"@types/zen-observable": "^0.8.0",
|
|
126
|
-
"esbuild": "^0.27.0",
|
|
127
122
|
"strip-ansi": "^7.1.0",
|
|
128
123
|
"supertest": "^7.0.0",
|
|
129
124
|
"wait-for-expect": "^4.0.0"
|