From 21b54689c6d54d1f560ef76ff499780782c00cec Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Fri, 19 Nov 2021 17:50:25 +0100 Subject: [PATCH] scaffolder-backend: add initial SecureTemplater implementation Co-authored-by: Johan Haals Signed-off-by: Patrik Oldsberg --- plugins/scaffolder-backend/package.json | 3 +- .../src/lib/templating/SecureTemplater.ts | 71 +++++++++++++++++++ yarn.lock | 5 ++ 3 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index 7b7407e410..d4582cfa25 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -69,7 +69,8 @@ "octokit-plugin-create-pull-request": "^3.10.0", "uuid": "^8.2.0", "winston": "^3.2.1", - "yaml": "^1.10.0" + "yaml": "^1.10.0", + "vm2": "^3.9.5" }, "devDependencies": { "@backstage/cli": "^0.9.0", diff --git a/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts b/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts new file mode 100644 index 0000000000..c6fa98de4e --- /dev/null +++ b/plugins/scaffolder-backend/src/lib/templating/SecureTemplater.ts @@ -0,0 +1,71 @@ +/* + * Copyright 2021 The Backstage Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { VM } from 'vm2'; +import { resolvePackagePath } from '@backstage/backend-common'; +import fs from 'fs-extra'; + +const mkScript = (nunjucksSource: string) => ` +const render = (() => { + const module = {}; + const require = (pkg) => { if (pkg === 'events') { return function (){}; }}; + + ${nunjucksSource} + + const env = module.exports.configure({ + autoescape: false, + tags: { + variableStart: '\${{', + variableEnd: '}}', + }, + }); + + return function render(str, values) { + return env.renderString(str, JSON.parse(values)); + } +})(); +`; + +export class SecureTemplater { + #vm?: VM; + + async render(template: string, values: unknown) { + const vm = await this.getVm(); + vm.setGlobal('templateStr', template); + vm.setGlobal('templateValues', JSON.stringify(values)); + const result = vm.run(`render(templateStr, templateValues)`); + return result; + } + + private async getVm() { + if (!this.#vm) { + this.#vm = new VM({ + timeout: 1000, + }); + + const nunjucksSource = await fs.readFile( + resolvePackagePath( + '@backstage/plugin-scaffolder-backend', + 'assets/nunjucks.js.txt', + ), + 'utf-8', + ); + + this.#vm.run(mkScript(nunjucksSource)); + } + return this.#vm; + } +} diff --git a/yarn.lock b/yarn.lock index e20a75a023..b41442f8bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -28707,6 +28707,11 @@ vm-browserify@^1.0.1: resolved "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0" integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ== +vm2@^3.9.5: + version "3.9.5" + resolved "https://registry.npmjs.org/vm2/-/vm2-3.9.5.tgz#5288044860b4bbace443101fcd3bddb2a0aa2496" + integrity sha512-LuCAHZN75H9tdrAiLFf030oW7nJV5xwNMuk1ymOZwopmuK3d2H4L1Kv4+GFHgarKiLfXXLFU+7LDABHnwOkWng== + vscode-languageserver-types@^3.15.1: version "3.15.1" resolved "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.1.tgz#17be71d78d2f6236d414f0001ce1ef4d23e6b6de"