From 2d4f5a7833a8a782bf8b8e7ad6bd04cdbead2250 Mon Sep 17 00:00:00 2001 From: Kiss Miklos Date: Fri, 16 Sep 2022 18:17:59 +0200 Subject: [PATCH 01/11] make nunjucks' globals configureable Signed-off-by: Kiss Miklos --- .../src/ScaffolderPlugin.ts | 10 ++++++- .../src/lib/templating/SecureTemplater.ts | 29 +++++++++++++++++-- .../actions/builtin/createBuiltinActions.ts | 3 ++ .../actions/builtin/fetch/template.ts | 9 +++++- .../src/scaffolder/dryrun/createDryRunner.ts | 1 + .../tasks/NunjucksWorkflowRunner.ts | 3 ++ .../src/scaffolder/tasks/TaskWorker.ts | 3 ++ .../scaffolder-backend/src/service/router.ts | 5 ++++ 8 files changed, 58 insertions(+), 5 deletions(-) diff --git a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts index b884802a1f..57d7971f50 100644 --- a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts +++ b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts @@ -39,6 +39,7 @@ export type ScaffolderPluginOptions = { taskWorkers?: number; taskBroker?: TaskBroker; additionalTemplateFilters?: Record; + additionalTemplateGlobals?: Record; }; /** @@ -101,7 +102,12 @@ export const scaffolderPlugin = createBackendPlugin({ httpRouter, catalogClient, }) { - const { additionalTemplateFilters, taskBroker, taskWorkers } = options; + const { + additionalTemplateFilters, + taskBroker, + taskWorkers, + additionalTemplateGlobals, + } = options; const log = loggerToWinstonLogger(logger); const actions = options.actions || [ @@ -112,6 +118,7 @@ export const scaffolderPlugin = createBackendPlugin({ reader, config, additionalTemplateFilters, + additionalTemplateGlobals, }), ]; @@ -130,6 +137,7 @@ export const scaffolderPlugin = createBackendPlugin({ taskBroker, taskWorkers, additionalTemplateFilters, + additionalTemplateGlobals, }); httpRouter.use(router); }, diff --git a/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts b/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts index e82620a90d..1b8e201845 100644 --- a/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts +++ b/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts @@ -64,6 +64,12 @@ const { render, renderCompat } = (() => { } } + if (typeof additionalTemplateGlobals !== 'undefined') { + for (const [globalName, globalFn] of Object.entries(additionalTemplateGlobals)) { + env.addGlobal(globalName, (...args) => JSON.parse(globalFn(...args))); + } + } + let uninstallCompat = undefined; function render(str, values) { @@ -107,6 +113,7 @@ export interface SecureTemplaterOptions { /* Extra user-provided nunjucks filters */ additionalTemplateFilters?: Record; + additionalTemplateGlobals?: Record; } export type SecureTemplateRenderer = ( @@ -116,8 +123,12 @@ export type SecureTemplateRenderer = ( export class SecureTemplater { static async loadRenderer(options: SecureTemplaterOptions = {}) { - const { parseRepoUrl, cookiecutterCompat, additionalTemplateFilters } = - options; + const { + parseRepoUrl, + cookiecutterCompat, + additionalTemplateFilters, + additionalTemplateGlobals, + } = options; const sandbox: Record = {}; if (parseRepoUrl) { @@ -134,7 +145,19 @@ export class SecureTemplater { ]), ); } - + if (additionalTemplateGlobals) { + console.log(additionalTemplateGlobals, '!!!!!!!!!!!'); + sandbox.additionalTemplateGlobals = Object.fromEntries( + Object.entries(additionalTemplateGlobals) + .filter(([_, filterFunction]) => !!filterFunction) + .map(([filterName, filterFunction]) => [ + filterName, + (...args: JsonValue[]) => JSON.stringify(filterFunction(...args)), + ]), + ); + } + console.log(sandbox.additionalTemplateGlobals, 'HUH?'); + console.log(sandbox.additionalTemplateFilters, 'HUH?'); const vm = new VM({ sandbox }); const nunjucksSource = await fs.readFile( diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts index fcddf127e2..7581189411 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts @@ -82,6 +82,7 @@ export interface CreateBuiltInActionsOptions { * Template Manifests and also template skeleton files when using `fetch:template`. */ additionalTemplateFilters?: Record; + additionalTemplateGlobals?: Record; } /** @@ -100,6 +101,7 @@ export const createBuiltinActions = ( catalogClient, config, additionalTemplateFilters, + additionalTemplateGlobals, } = options; const githubCredentialsProvider: GithubCredentialsProvider = @@ -114,6 +116,7 @@ export const createBuiltinActions = ( integrations, reader, additionalTemplateFilters, + additionalTemplateGlobals, }), createPublishGerritAction({ integrations, diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts index 1ead7ebcd6..47a85df9ca 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts @@ -39,8 +39,14 @@ export function createFetchTemplateAction(options: { reader: UrlReader; integrations: ScmIntegrations; additionalTemplateFilters?: Record; + additionalTemplateGlobals?: Record; }) { - const { reader, integrations, additionalTemplateFilters } = options; + const { + reader, + integrations, + additionalTemplateFilters, + additionalTemplateGlobals, + } = options; return createTemplateAction<{ url: string; @@ -218,6 +224,7 @@ export function createFetchTemplateAction(options: { const renderTemplate = await SecureTemplater.loadRenderer({ cookiecutterCompat: ctx.input.cookiecutterCompat, additionalTemplateFilters, + additionalTemplateGlobals, }); for (const location of allEntriesInTemplate) { diff --git a/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts b/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts index f2c3c13509..36a5a3728a 100644 --- a/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts @@ -52,6 +52,7 @@ export type TemplateTesterCreateOptions = { actionRegistry: TemplateActionRegistry; workingDirectory: string; additionalTemplateFilters?: Record; + additionalTemplateGlobals?: Record; }; /** diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index 009ea1357d..eb6683e32b 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -45,6 +45,7 @@ type NunjucksWorkflowRunnerOptions = { integrations: ScmIntegrations; logger: winston.Logger; additionalTemplateFilters?: Record; + additionalTemplateGlobals?: Record; }; type TemplateContext = { @@ -188,6 +189,7 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { ); const { integrations } = this.options; + console.log(this.options.additionalTemplateGlobals, '@@@%%%%%%%%%%@@@'); const renderTemplate = await SecureTemplater.loadRenderer({ // TODO(blam): let's work out how we can deprecate this. // We shouldn't really need to be exposing these now we can deal with @@ -197,6 +199,7 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { return parseRepoUrl(url, integrations); }, additionalTemplateFilters: this.options.additionalTemplateFilters, + additionalTemplateGlobals: this.options.additionalTemplateGlobals, }); try { diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts index 9defd71c49..bd0e6a6dd4 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts @@ -46,6 +46,7 @@ export type CreateWorkerOptions = { workingDirectory: string; logger: Logger; additionalTemplateFilters?: Record; + additionalTemplateGlobals?: Record; }; /** @@ -64,6 +65,7 @@ export class TaskWorker { integrations, workingDirectory, additionalTemplateFilters, + additionalTemplateGlobals, } = options; const workflowRunner = new NunjucksWorkflowRunner({ @@ -72,6 +74,7 @@ export class TaskWorker { logger, workingDirectory, additionalTemplateFilters, + additionalTemplateGlobals, }); return new TaskWorker({ diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 28dd1ca413..592e0be79d 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -70,6 +70,7 @@ export interface RouterOptions { taskWorkers?: number; taskBroker?: TaskBroker; additionalTemplateFilters?: Record; + additionalTemplateGlobals?: Record; identity?: IdentityApi; } @@ -160,6 +161,7 @@ export async function createRouter( taskWorkers, scheduler, additionalTemplateFilters, + additionalTemplateGlobals, } = options; const logger = parentLogger.child({ plugin: 'scaffolder' }); @@ -207,6 +209,7 @@ export async function createRouter( logger, workingDirectory, additionalTemplateFilters, + additionalTemplateGlobals, }); workers.push(worker); } @@ -219,6 +222,7 @@ export async function createRouter( reader, config, additionalTemplateFilters, + additionalTemplateGlobals, }); actionsToRegister.forEach(action => actionRegistry.register(action)); @@ -230,6 +234,7 @@ export async function createRouter( logger, workingDirectory, additionalTemplateFilters, + additionalTemplateGlobals, }); router From 155b46255d2bd3a224e4f791c7ef37d13a4b525c Mon Sep 17 00:00:00 2001 From: Kiss Miklos Date: Fri, 16 Sep 2022 18:25:46 +0200 Subject: [PATCH 02/11] remove console.logs Signed-off-by: Kiss Miklos --- .../scaffolder-backend/src/lib/templating/SecureTemplater.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts b/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts index 1b8e201845..ebe32a8c11 100644 --- a/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts +++ b/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts @@ -156,8 +156,6 @@ export class SecureTemplater { ]), ); } - console.log(sandbox.additionalTemplateGlobals, 'HUH?'); - console.log(sandbox.additionalTemplateFilters, 'HUH?'); const vm = new VM({ sandbox }); const nunjucksSource = await fs.readFile( From 4c571c6f1975b956f2fe266ffd13295cd648c69f Mon Sep 17 00:00:00 2001 From: Kiss Miklos Date: Thu, 22 Sep 2022 01:15:05 +0200 Subject: [PATCH 03/11] remove console.log Signed-off-by: Kiss Miklos --- plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts b/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts index ebe32a8c11..575eae1887 100644 --- a/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts +++ b/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts @@ -146,7 +146,6 @@ export class SecureTemplater { ); } if (additionalTemplateGlobals) { - console.log(additionalTemplateGlobals, '!!!!!!!!!!!'); sandbox.additionalTemplateGlobals = Object.fromEntries( Object.entries(additionalTemplateGlobals) .filter(([_, filterFunction]) => !!filterFunction) From e640515640701e596033e485dae7d9babea19329 Mon Sep 17 00:00:00 2001 From: Kiss Miklos Date: Thu, 22 Sep 2022 01:21:37 +0200 Subject: [PATCH 04/11] api-report.md Signed-off-by: Kiss Miklos --- plugins/scaffolder-backend/api-report.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 35e3dab0b5..17b119e17b 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -60,6 +60,8 @@ export const createBuiltinActions: ( // @public export interface CreateBuiltInActionsOptions { additionalTemplateFilters?: Record; + // (undocumented) + additionalTemplateGlobals?: Record; catalogClient: CatalogApi; config: Config; integrations: ScmIntegrations; @@ -108,6 +110,7 @@ export function createFetchTemplateAction(options: { reader: UrlReader; integrations: ScmIntegrations; additionalTemplateFilters?: Record; + additionalTemplateGlobals?: Record; }): TemplateAction<{ url: string; targetPath?: string | undefined; @@ -448,6 +451,7 @@ export type CreateWorkerOptions = { workingDirectory: string; logger: Logger; additionalTemplateFilters?: Record; + additionalTemplateGlobals?: Record; }; // @public @@ -538,6 +542,8 @@ export interface RouterOptions { // (undocumented) additionalTemplateFilters?: Record; // (undocumented) + additionalTemplateGlobals?: Record; + // (undocumented) catalogClient: CatalogApi; // (undocumented) config: Config; @@ -593,6 +599,7 @@ export type ScaffolderPluginOptions = { taskWorkers?: number; taskBroker?: TaskBroker; additionalTemplateFilters?: Record; + additionalTemplateGlobals?: Record; }; // @public From 253453fa1434ab7e235cbe3028f4472d81110195 Mon Sep 17 00:00:00 2001 From: Kiss Miklos Date: Thu, 22 Sep 2022 01:23:41 +0200 Subject: [PATCH 05/11] add changeset Signed-off-by: Kiss Miklos --- .changeset/dull-rocks-warn.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/dull-rocks-warn.md diff --git a/.changeset/dull-rocks-warn.md b/.changeset/dull-rocks-warn.md new file mode 100644 index 0000000000..7bd13ae6a1 --- /dev/null +++ b/.changeset/dull-rocks-warn.md @@ -0,0 +1,5 @@ +--- +'@backstage/plugin-scaffolder-backend': minor +--- + +Added a new property called `additionalTemplateGlobals` which allowes you to add global functions to the scaffolder nunjucks templates. From 5ca599b381d94d558c96c94bc878783c3f7cfb6e Mon Sep 17 00:00:00 2001 From: Kiss Miklos Date: Sat, 24 Sep 2022 17:55:39 +0200 Subject: [PATCH 06/11] fix lint stuff Signed-off-by: Kiss Miklos --- .changeset/dull-rocks-warn.md | 2 +- .../src/scaffolder/tasks/NunjucksWorkflowRunner.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.changeset/dull-rocks-warn.md b/.changeset/dull-rocks-warn.md index 7bd13ae6a1..0ccf4f20cb 100644 --- a/.changeset/dull-rocks-warn.md +++ b/.changeset/dull-rocks-warn.md @@ -2,4 +2,4 @@ '@backstage/plugin-scaffolder-backend': minor --- -Added a new property called `additionalTemplateGlobals` which allowes you to add global functions to the scaffolder nunjucks templates. +Added a new property called `additionalTemplateGlobals` which allows you to add global functions to the scaffolder nunjucks templates. diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index eb6683e32b..a9ed5bab8a 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -189,7 +189,6 @@ export class NunjucksWorkflowRunner implements WorkflowRunner { ); const { integrations } = this.options; - console.log(this.options.additionalTemplateGlobals, '@@@%%%%%%%%%%@@@'); const renderTemplate = await SecureTemplater.loadRenderer({ // TODO(blam): let's work out how we can deprecate this. // We shouldn't really need to be exposing these now we can deal with From bd8ab057dc286eaf9b4ee89550d4c36ebd05d767 Mon Sep 17 00:00:00 2001 From: Kiss Miklos Date: Mon, 26 Sep 2022 01:35:21 +0200 Subject: [PATCH 07/11] add option to add any JsonValue for globals Signed-off-by: Kiss Miklos --- packages/backend/src/plugins/scaffolder.ts | 6 ++++ plugins/scaffolder-backend/api-report.md | 17 ++++++---- .../src/ScaffolderPlugin.ts | 4 +-- .../src/lib/templating/SecureTemplater.ts | 31 ++++++++++++++----- .../src/lib/templating/index.ts | 2 +- .../actions/builtin/createBuiltinActions.ts | 4 +-- .../actions/builtin/fetch/template.ts | 3 +- .../src/scaffolder/dryrun/createDryRunner.ts | 4 +-- .../tasks/NunjucksWorkflowRunner.ts | 3 +- .../src/scaffolder/tasks/TaskWorker.ts | 7 +++-- .../scaffolder-backend/src/service/router.ts | 4 +-- 11 files changed, 58 insertions(+), 27 deletions(-) diff --git a/packages/backend/src/plugins/scaffolder.ts b/packages/backend/src/plugins/scaffolder.ts index d079b64c28..eff781cdb7 100644 --- a/packages/backend/src/plugins/scaffolder.ts +++ b/packages/backend/src/plugins/scaffolder.ts @@ -34,5 +34,11 @@ export default async function createPlugin( reader: env.reader, identity: env.identity, scheduler: env.scheduler, + additionalTemplateGlobals: { + company: 'RoadieHQ', + now: () => { + return 'NOW !!!!'; + }, + }, }); } diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 17b119e17b..9dcc45f91b 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -61,7 +61,7 @@ export const createBuiltinActions: ( export interface CreateBuiltInActionsOptions { additionalTemplateFilters?: Record; // (undocumented) - additionalTemplateGlobals?: Record; + additionalTemplateGlobals?: Record; catalogClient: CatalogApi; config: Config; integrations: ScmIntegrations; @@ -110,7 +110,7 @@ export function createFetchTemplateAction(options: { reader: UrlReader; integrations: ScmIntegrations; additionalTemplateFilters?: Record; - additionalTemplateGlobals?: Record; + additionalTemplateGlobals?: Record; }): TemplateAction<{ url: string; targetPath?: string | undefined; @@ -429,7 +429,7 @@ export const createPublishGitlabMergeRequestAction: (options: { branchName: string; targetPath: string; token?: string | undefined; - commitAction?: 'update' | 'create' | 'delete' | undefined; + commitAction?: 'update' | 'delete' | 'create' | undefined; projectid?: string | undefined; removeSourceBranch?: boolean | undefined; assignee?: string | undefined; @@ -451,7 +451,7 @@ export type CreateWorkerOptions = { workingDirectory: string; logger: Logger; additionalTemplateFilters?: Record; - additionalTemplateGlobals?: Record; + additionalTemplateGlobals?: Record; }; // @public @@ -542,7 +542,7 @@ export interface RouterOptions { // (undocumented) additionalTemplateFilters?: Record; // (undocumented) - additionalTemplateGlobals?: Record; + additionalTemplateGlobals?: Record; // (undocumented) catalogClient: CatalogApi; // (undocumented) @@ -599,7 +599,7 @@ export type ScaffolderPluginOptions = { taskWorkers?: number; taskBroker?: TaskBroker; additionalTemplateFilters?: Record; - additionalTemplateGlobals?: Record; + additionalTemplateGlobals?: Record; }; // @public @@ -820,4 +820,9 @@ export class TemplateActionRegistry { // @public (undocumented) export type TemplateFilter = (...args: JsonValue[]) => JsonValue | undefined; + +// @public (undocumented) +export type TemplateGlobal = + | ((...args: JsonValue[]) => JsonValue | undefined) + | JsonValue; ``` diff --git a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts index 57d7971f50..09d7bdcbb2 100644 --- a/plugins/scaffolder-backend/src/ScaffolderPlugin.ts +++ b/plugins/scaffolder-backend/src/ScaffolderPlugin.ts @@ -26,7 +26,7 @@ import { } from '@backstage/backend-plugin-api'; import { ScmIntegrations } from '@backstage/integration'; import { catalogServiceRef } from '@backstage/plugin-catalog-node'; -import { TemplateFilter } from './lib'; +import { TemplateFilter, TemplateGlobal } from './lib'; import { createBuiltinActions, TaskBroker, TemplateAction } from './scaffolder'; import { createRouter } from './service/router'; @@ -39,7 +39,7 @@ export type ScaffolderPluginOptions = { taskWorkers?: number; taskBroker?: TaskBroker; additionalTemplateFilters?: Record; - additionalTemplateGlobals?: Record; + additionalTemplateGlobals?: Record; }; /** diff --git a/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts b/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts index 575eae1887..2a16ff96c1 100644 --- a/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts +++ b/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts @@ -65,8 +65,12 @@ const { render, renderCompat } = (() => { } if (typeof additionalTemplateGlobals !== 'undefined') { - for (const [globalName, globalFn] of Object.entries(additionalTemplateGlobals)) { - env.addGlobal(globalName, (...args) => JSON.parse(globalFn(...args))); + for (const [globalName, global] of Object.entries(additionalTemplateGlobals)) { + if (typeof global === 'function') { + env.addGlobal(globalName, (...args) => JSON.parse(global(...args))); + } else { + env.addGlobal(globalName, global); + } } } @@ -104,6 +108,11 @@ const { render, renderCompat } = (() => { /** @public */ export type TemplateFilter = (...args: JsonValue[]) => JsonValue | undefined; +/** @public */ +export type TemplateGlobal = + | ((...args: JsonValue[]) => JsonValue | undefined) + | JsonValue; + export interface SecureTemplaterOptions { /* Optional implementation of the parseRepoUrl filter */ parseRepoUrl?(repoUrl: string): RepoSpec; @@ -113,7 +122,8 @@ export interface SecureTemplaterOptions { /* Extra user-provided nunjucks filters */ additionalTemplateFilters?: Record; - additionalTemplateGlobals?: Record; + /* Extra user-provided nunjucks globals */ + additionalTemplateGlobals?: Record; } export type SecureTemplateRenderer = ( @@ -148,11 +158,16 @@ export class SecureTemplater { if (additionalTemplateGlobals) { sandbox.additionalTemplateGlobals = Object.fromEntries( Object.entries(additionalTemplateGlobals) - .filter(([_, filterFunction]) => !!filterFunction) - .map(([filterName, filterFunction]) => [ - filterName, - (...args: JsonValue[]) => JSON.stringify(filterFunction(...args)), - ]), + .filter(([_, global]) => !!global) + .map(([globalName, global]) => { + if (typeof global === 'function') { + return [ + globalName, + (...args: JsonValue[]) => JSON.stringify(global(...args)), + ]; + } + return [globalName, global]; + }), ); } const vm = new VM({ sandbox }); diff --git a/plugins/scaffolder-backend/src/lib/templating/index.ts b/plugins/scaffolder-backend/src/lib/templating/index.ts index 29d77291a1..1f9e5eb855 100644 --- a/plugins/scaffolder-backend/src/lib/templating/index.ts +++ b/plugins/scaffolder-backend/src/lib/templating/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -export type { TemplateFilter } from './SecureTemplater'; +export type { TemplateFilter, TemplateGlobal } from './SecureTemplater'; diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts index 7581189411..e388a70f00 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/createBuiltinActions.ts @@ -28,7 +28,7 @@ import { createCatalogWriteAction, } from './catalog'; -import { TemplateFilter } from '../../../lib'; +import { TemplateFilter, TemplateGlobal } from '../../../lib'; import { TemplateAction } from '../types'; import { createDebugLogAction } from './debug'; import { createFetchPlainAction, createFetchTemplateAction } from './fetch'; @@ -82,7 +82,7 @@ export interface CreateBuiltInActionsOptions { * Template Manifests and also template skeleton files when using `fetch:template`. */ additionalTemplateFilters?: Record; - additionalTemplateGlobals?: Record; + additionalTemplateGlobals?: Record; } /** diff --git a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts index 47a85df9ca..d71997d496 100644 --- a/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts +++ b/plugins/scaffolder-backend/src/scaffolder/actions/builtin/fetch/template.ts @@ -26,6 +26,7 @@ import { isBinaryFile } from 'isbinaryfile'; import { TemplateFilter, SecureTemplater, + TemplateGlobal, } from '../../../../lib/templating/SecureTemplater'; /** @@ -39,7 +40,7 @@ export function createFetchTemplateAction(options: { reader: UrlReader; integrations: ScmIntegrations; additionalTemplateFilters?: Record; - additionalTemplateGlobals?: Record; + additionalTemplateGlobals?: Record; }) { const { reader, diff --git a/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts b/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts index 36a5a3728a..17f9092bff 100644 --- a/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/dryrun/createDryRunner.ts @@ -25,7 +25,7 @@ import { SerializedFile, serializeDirectoryContents, } from '../../lib/files'; -import { TemplateFilter } from '../../lib/templating'; +import { TemplateFilter, TemplateGlobal } from '../../lib/templating'; import { createTemplateAction, TemplateActionRegistry } from '../actions'; import { NunjucksWorkflowRunner } from '../tasks/NunjucksWorkflowRunner'; import { TaskSecrets } from '../tasks/types'; @@ -52,7 +52,7 @@ export type TemplateTesterCreateOptions = { actionRegistry: TemplateActionRegistry; workingDirectory: string; additionalTemplateFilters?: Record; - additionalTemplateGlobals?: Record; + additionalTemplateGlobals?: Record; }; /** diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts index a9ed5bab8a..298ea16484 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/NunjucksWorkflowRunner.ts @@ -31,6 +31,7 @@ import { TemplateFilter, SecureTemplater, SecureTemplateRenderer, + TemplateGlobal, } from '../../lib/templating/SecureTemplater'; import { TaskSpec, @@ -45,7 +46,7 @@ type NunjucksWorkflowRunnerOptions = { integrations: ScmIntegrations; logger: winston.Logger; additionalTemplateFilters?: Record; - additionalTemplateGlobals?: Record; + additionalTemplateGlobals?: Record; }; type TemplateContext = { diff --git a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts index bd0e6a6dd4..52ecd1a4dc 100644 --- a/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts +++ b/plugins/scaffolder-backend/src/scaffolder/tasks/TaskWorker.ts @@ -20,7 +20,10 @@ import { Logger } from 'winston'; import { TemplateActionRegistry } from '../actions'; import { ScmIntegrations } from '@backstage/integration'; import { assertError } from '@backstage/errors'; -import { TemplateFilter } from '../../lib/templating/SecureTemplater'; +import { + TemplateFilter, + TemplateGlobal, +} from '../../lib/templating/SecureTemplater'; /** * TaskWorkerOptions @@ -46,7 +49,7 @@ export type CreateWorkerOptions = { workingDirectory: string; logger: Logger; additionalTemplateFilters?: Record; - additionalTemplateGlobals?: Record; + additionalTemplateGlobals?: Record; }; /** diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 592e0be79d..a36ea3c769 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -36,7 +36,7 @@ import Router from 'express-promise-router'; import { validate } from 'jsonschema'; import { Logger } from 'winston'; import { z } from 'zod'; -import { TemplateFilter } from '../lib'; +import { TemplateFilter, TemplateGlobal } from '../lib'; import { createBuiltinActions, DatabaseTaskStore, @@ -70,7 +70,7 @@ export interface RouterOptions { taskWorkers?: number; taskBroker?: TaskBroker; additionalTemplateFilters?: Record; - additionalTemplateGlobals?: Record; + additionalTemplateGlobals?: Record; identity?: IdentityApi; } From 12e7d7d535a32e8d3c5d744faf30c81c7279a081 Mon Sep 17 00:00:00 2001 From: Kiss Miklos Date: Mon, 26 Sep 2022 11:03:31 +0200 Subject: [PATCH 08/11] api-report all Signed-off-by: Kiss Miklos --- plugins/scaffolder-backend/api-report.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/scaffolder-backend/api-report.md b/plugins/scaffolder-backend/api-report.md index 9dcc45f91b..a5f4db22d2 100644 --- a/plugins/scaffolder-backend/api-report.md +++ b/plugins/scaffolder-backend/api-report.md @@ -429,7 +429,7 @@ export const createPublishGitlabMergeRequestAction: (options: { branchName: string; targetPath: string; token?: string | undefined; - commitAction?: 'update' | 'delete' | 'create' | undefined; + commitAction?: 'update' | 'create' | 'delete' | undefined; projectid?: string | undefined; removeSourceBranch?: boolean | undefined; assignee?: string | undefined; From 40cde40308ddc9149c1a5f1f93f2f504d6e6b803 Mon Sep 17 00:00:00 2001 From: Kiss Miklos Date: Mon, 26 Sep 2022 11:17:37 +0200 Subject: [PATCH 09/11] remove temp props Signed-off-by: Kiss Miklos --- packages/backend/src/plugins/scaffolder.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/packages/backend/src/plugins/scaffolder.ts b/packages/backend/src/plugins/scaffolder.ts index eff781cdb7..d079b64c28 100644 --- a/packages/backend/src/plugins/scaffolder.ts +++ b/packages/backend/src/plugins/scaffolder.ts @@ -34,11 +34,5 @@ export default async function createPlugin( reader: env.reader, identity: env.identity, scheduler: env.scheduler, - additionalTemplateGlobals: { - company: 'RoadieHQ', - now: () => { - return 'NOW !!!!'; - }, - }, }); } From 42a7e89b06ddbcaaf00d238128946503efeb5608 Mon Sep 17 00:00:00 2001 From: Kiss Miklos Date: Mon, 26 Sep 2022 11:40:18 +0200 Subject: [PATCH 10/11] add test for global addition Signed-off-by: Kiss Miklos --- .../lib/templating/SecureTemplater.test.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.test.ts b/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.test.ts index 8b8d7847ac..76643131f5 100644 --- a/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.test.ts +++ b/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.test.ts @@ -144,6 +144,27 @@ describe('SecureTemplater', () => { ['the input value', 'another extra arg'], ]); }); + it('should make additional globals available when requested', async () => { + const mockGlobal1 = jest.fn(() => 'awesome global function'); + const mockGlobal2 = 'foo'; + const mockGlobal3 = 123456; + const renderWith = await SecureTemplater.loadRenderer({ + additionalTemplateGlobals: { mockGlobal1, mockGlobal2, mockGlobal3 }, + }); + const renderWithout = await SecureTemplater.loadRenderer(); + + const ctx = {}; + + expect(renderWith('${{ mockGlobal1() }}', ctx)).toBe( + 'awesome global function', + ); + expect(renderWith('${{ mockGlobal2 }}', ctx)).toBe('foo'); + expect(renderWith('${{ mockGlobal3 }}', ctx)).toBe('123456'); + + expect(() => renderWithout('${{ mockGlobal1() }}', ctx)).toThrow( + /Error: Unable to call `mockGlobal1`/, + ); + }); it('should not allow helpers to be rewritten', async () => { const render = await SecureTemplater.loadRenderer({ From 074def89aa5bf38c8881fd6fbd809c86b641114a Mon Sep 17 00:00:00 2001 From: Kiss Miklos Date: Tue, 27 Sep 2022 12:03:07 +0200 Subject: [PATCH 11/11] stringify globals Signed-off-by: Kiss Miklos --- .../scaffolder-backend/src/lib/templating/SecureTemplater.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts b/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts index 2a16ff96c1..7dc42658be 100644 --- a/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts +++ b/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts @@ -69,7 +69,7 @@ const { render, renderCompat } = (() => { if (typeof global === 'function') { env.addGlobal(globalName, (...args) => JSON.parse(global(...args))); } else { - env.addGlobal(globalName, global); + env.addGlobal(globalName, JSON.parse(global)); } } } @@ -166,7 +166,7 @@ export class SecureTemplater { (...args: JsonValue[]) => JSON.stringify(global(...args)), ]; } - return [globalName, global]; + return [globalName, JSON.stringify(global)]; }), ); }