diff --git a/lib/util/template/index.spec.ts b/lib/util/template/index.spec.ts index 3b65b478bfe48a314e4b5274967f1473cc0f5a2f..9bf157e90756d2e3ba0c91e2627cbb3df495f59e 100644 --- a/lib/util/template/index.spec.ts +++ b/lib/util/template/index.spec.ts @@ -208,33 +208,48 @@ describe('util/template/index', () => { }; it('accessing allowed fields', () => { - const p = template.proxyCompileInput(compileInput); + const warnVariables = new Set<string>(); + const p = template.proxyCompileInput(compileInput, warnVariables); expect(p[allowedField]).toBe('allowed'); expect(p[allowedArrayField]).toStrictEqual(['allowed']); + expect(warnVariables).toBeEmpty(); expect(p[forbiddenField]).toBeUndefined(); + expect(warnVariables).toEqual(new Set<string>([forbiddenField])); }); it('supports object nesting', () => { - const proxy = template.proxyCompileInput({ - [allowedField]: compileInput, - }); + const warnVariables = new Set<string>(); + const proxy = template.proxyCompileInput( + { + [allowedField]: compileInput, + }, + warnVariables, + ); const obj = proxy[allowedField] as TestCompileInput; expect(obj[allowedField]).toBe('allowed'); + expect(warnVariables).toBeEmpty(); expect(obj[forbiddenField]).toBeUndefined(); + expect(warnVariables).toEqual(new Set<string>([forbiddenField])); }); it('supports array nesting', () => { - const proxy = template.proxyCompileInput({ - [allowedField]: [compileInput], - }); + const warnVariables = new Set<string>(); + const proxy = template.proxyCompileInput( + { + [allowedField]: [compileInput], + }, + warnVariables, + ); const arr = proxy[allowedField] as TestCompileInput[]; const obj = arr[0]; expect(obj[allowedField]).toBe('allowed'); expect(obj[allowedArrayField]).toStrictEqual(['allowed']); + expect(warnVariables).toBeEmpty(); expect(obj[forbiddenField]).toBeUndefined(); + expect(warnVariables).toEqual(new Set<string>([forbiddenField])); }); }); diff --git a/lib/util/template/index.ts b/lib/util/template/index.ts index c7dbc6dc88c888eb9eef198e2ce5c009ec6deef6..9a347b9132c510d5edc881ef3a7e1242e093ea6e 100644 --- a/lib/util/template/index.ts +++ b/lib/util/template/index.ts @@ -238,26 +238,6 @@ export const allowedFields = { 'The severity for a vulnerability alert upgrade (LOW, MEDIUM, MODERATE, HIGH, CRITICAL, UNKNOWN)', }; -const prBodyFields = [ - 'header', - 'table', - 'notes', - 'changelogs', - 'hasWarningsErrors', - 'errors', - 'warnings', - 'configDescription', - 'controls', - 'footer', -]; - -const handlebarsUtilityFields = ['else']; - -const allowedFieldsList = Object.keys(allowedFields) - .concat(exposedConfigOptions) - .concat(prBodyFields) - .concat(handlebarsUtilityFields); - type CompileInput = Record<string, unknown>; const allowedTemplateFields = new Set([ @@ -265,13 +245,16 @@ const allowedTemplateFields = new Set([ ...exposedConfigOptions, ]); -const compileInputProxyHandler: ProxyHandler<CompileInput> = { +class CompileInputProxyHandler implements ProxyHandler<CompileInput> { + constructor(private warnVariables: Set<string>) {} + get(target: CompileInput, prop: keyof CompileInput): unknown { if (prop === 'env') { return target[prop]; } if (!allowedTemplateFields.has(prop)) { + this.warnVariables.add(prop); return undefined; } @@ -286,20 +269,26 @@ const compileInputProxyHandler: ProxyHandler<CompileInput> = { return value.map((element) => is.primitive(element) ? element - : proxyCompileInput(element as CompileInput), + : proxyCompileInput(element as CompileInput, this.warnVariables), ); } if (is.plainObject(value)) { - return proxyCompileInput(value); + return proxyCompileInput(value, this.warnVariables); } return value; - }, -}; + } +} -export function proxyCompileInput(input: CompileInput): CompileInput { - return new Proxy<CompileInput>(input, compileInputProxyHandler); +export function proxyCompileInput( + input: CompileInput, + warnVariables: Set<string>, +): CompileInput { + return new Proxy<CompileInput>( + input, + new CompileInputProxyHandler(warnVariables), + ); } const templateRegex = regEx( @@ -313,30 +302,22 @@ export function compile( ): string { const env = getChildEnv({}); const data = { ...GlobalConfig.get(), ...input, env }; - const filteredInput = filterFields ? proxyCompileInput(data) : data; + const warnVariables = new Set<string>(); + const filteredInput = filterFields + ? proxyCompileInput(data, warnVariables) + : data; + logger.trace({ template, filteredInput }, 'Compiling template'); - if (filterFields) { - const matches = template.matchAll(templateRegex); - for (const match of matches) { - const varNames = match[1].split('.'); - if (varNames[0] === 'env') { - continue; - } - for (const varName of varNames) { - if (varName === 'prBodyDefinitions') { - // Allow all prBodyDefinitions.* - break; - } - if (!allowedFieldsList.includes(varName)) { - logger.info( - { varName, template }, - 'Disallowed variable name in template', - ); - } - } - } + const result = handlebars.compile(template)(filteredInput); + + if (warnVariables.size > 0) { + logger.info( + { varNames: Array.from(warnVariables), template }, + 'Disallowed variable names in template', + ); } - return handlebars.compile(template)(filteredInput); + + return result; } export function safeCompile(