renovate 40.11.1 → 40.11.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/dist/config/secrets.d.ts
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
import type { InterpolatorOptions } from '../util/interpolator';
|
1
2
|
import type { AllConfig, RenovateConfig } from './types';
|
3
|
+
export declare const options: InterpolatorOptions;
|
2
4
|
export declare function validateConfigSecrets(config: AllConfig): void;
|
3
5
|
export declare function applySecretsToConfig(config: RenovateConfig, secrets?: Record<string, string> | undefined, deleteSecrets?: boolean): RenovateConfig;
|
package/dist/config/secrets.js
CHANGED
@@ -1,97 +1,30 @@
|
|
1
1
|
"use strict";
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.options = void 0;
|
3
4
|
exports.validateConfigSecrets = validateConfigSecrets;
|
4
5
|
exports.applySecretsToConfig = applySecretsToConfig;
|
5
6
|
const tslib_1 = require("tslib");
|
6
7
|
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
|
7
|
-
const
|
8
|
-
const logger_1 = require("../logger");
|
8
|
+
const interpolator_1 = require("../util/interpolator");
|
9
9
|
const regex_1 = require("../util/regex");
|
10
10
|
const sanitize_1 = require("../util/sanitize");
|
11
11
|
const secretNamePattern = '[A-Za-z][A-Za-z0-9_]*';
|
12
12
|
const secretNameRegex = (0, regex_1.regEx)(`^${secretNamePattern}$`);
|
13
13
|
const secretTemplateRegex = (0, regex_1.regEx)(`{{ secrets\\.(${secretNamePattern}) }}`);
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
if (is_1.default.plainObject(secrets_)) {
|
20
|
-
for (const [secretName, secretValue] of Object.entries(secrets_)) {
|
21
|
-
if (!secretNameRegex.test(secretName)) {
|
22
|
-
validationErrors.push(`Invalid secret name "${secretName}"`);
|
23
|
-
}
|
24
|
-
if (!is_1.default.string(secretValue)) {
|
25
|
-
validationErrors.push(`Secret values must be strings. Found type ${typeof secretValue} for secret ${secretName}`);
|
26
|
-
}
|
27
|
-
}
|
28
|
-
}
|
29
|
-
else {
|
30
|
-
validationErrors.push(`Config secrets must be a plain object. Found: ${typeof secrets_}`);
|
31
|
-
}
|
32
|
-
if (validationErrors.length) {
|
33
|
-
logger_1.logger.error({ validationErrors }, 'Invalid secrets configured');
|
34
|
-
throw new Error(error_messages_1.CONFIG_SECRETS_INVALID);
|
35
|
-
}
|
36
|
-
}
|
14
|
+
exports.options = {
|
15
|
+
name: 'secrets',
|
16
|
+
nameRegex: secretNameRegex,
|
17
|
+
templateRegex: secretTemplateRegex,
|
18
|
+
};
|
37
19
|
function validateConfigSecrets(config) {
|
38
|
-
|
20
|
+
(0, interpolator_1.validateInterpolatedValues)(config.secrets, exports.options);
|
39
21
|
if (config.repositories) {
|
40
22
|
for (const repository of config.repositories) {
|
41
23
|
if (is_1.default.plainObject(repository)) {
|
42
|
-
|
43
|
-
}
|
44
|
-
}
|
45
|
-
}
|
46
|
-
}
|
47
|
-
function replaceSecretsInString(key, value, secrets) {
|
48
|
-
// do nothing if no secret template found
|
49
|
-
if (!secretTemplateRegex.test(value)) {
|
50
|
-
return value;
|
51
|
-
}
|
52
|
-
const disallowedPrefixes = ['branch', 'commit', 'group', 'pr', 'semantic'];
|
53
|
-
if (disallowedPrefixes.some((prefix) => key.startsWith(prefix))) {
|
54
|
-
const error = new Error(error_messages_1.CONFIG_VALIDATION);
|
55
|
-
error.validationSource = 'config';
|
56
|
-
error.validationError = 'Disallowed secret substitution';
|
57
|
-
error.validationMessage = `The field \`${key}\` may not use secret substitution`;
|
58
|
-
throw error;
|
59
|
-
}
|
60
|
-
return value.replace(secretTemplateRegex, (_, secretName) => {
|
61
|
-
if (secrets?.[secretName]) {
|
62
|
-
return secrets[secretName];
|
63
|
-
}
|
64
|
-
const error = new Error(error_messages_1.CONFIG_VALIDATION);
|
65
|
-
error.validationSource = 'config';
|
66
|
-
error.validationError = 'Unknown secret name';
|
67
|
-
error.validationMessage = `The following secret name was not found in config: ${String(secretName)}`;
|
68
|
-
throw error;
|
69
|
-
});
|
70
|
-
}
|
71
|
-
function replaceSecretsInObject(config_, secrets, deleteSecrets) {
|
72
|
-
const config = { ...config_ };
|
73
|
-
if (deleteSecrets) {
|
74
|
-
delete config.secrets;
|
75
|
-
}
|
76
|
-
for (const [key, value] of Object.entries(config)) {
|
77
|
-
if (is_1.default.plainObject(value)) {
|
78
|
-
config[key] = replaceSecretsInObject(value, secrets, deleteSecrets);
|
79
|
-
}
|
80
|
-
if (is_1.default.string(value)) {
|
81
|
-
config[key] = replaceSecretsInString(key, value, secrets);
|
82
|
-
}
|
83
|
-
if (is_1.default.array(value)) {
|
84
|
-
for (const [arrayIndex, arrayItem] of value.entries()) {
|
85
|
-
if (is_1.default.plainObject(arrayItem)) {
|
86
|
-
value[arrayIndex] = replaceSecretsInObject(arrayItem, secrets, deleteSecrets);
|
87
|
-
}
|
88
|
-
else if (is_1.default.string(arrayItem)) {
|
89
|
-
value[arrayIndex] = replaceSecretsInString(key, arrayItem, secrets);
|
90
|
-
}
|
24
|
+
(0, interpolator_1.validateInterpolatedValues)(repository.secrets, exports.options);
|
91
25
|
}
|
92
26
|
}
|
93
27
|
}
|
94
|
-
return config;
|
95
28
|
}
|
96
29
|
function applySecretsToConfig(config, secrets = config.secrets, deleteSecrets = true) {
|
97
30
|
// Add all secrets to be sanitized
|
@@ -101,6 +34,6 @@ function applySecretsToConfig(config, secrets = config.secrets, deleteSecrets =
|
|
101
34
|
}
|
102
35
|
}
|
103
36
|
// TODO: fix types (#9610)
|
104
|
-
return
|
37
|
+
return (0, interpolator_1.replaceInterpolatedValuesInObject)(config, secrets, exports.options, deleteSecrets);
|
105
38
|
}
|
106
39
|
//# sourceMappingURL=secrets.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../lib/config/secrets.ts"],"names":[],"mappings":"
|
1
|
+
{"version":3,"file":"secrets.js","sourceRoot":"","sources":["../../lib/config/secrets.ts"],"names":[],"mappings":";;;AAqBA,sDASC;AAED,oDAkBC;;AAlDD,kEAAkC;AAElC,uDAG8B;AAC9B,yCAAsC;AACtC,+CAA0D;AAG1D,MAAM,iBAAiB,GAAG,uBAAuB,CAAC;AAElD,MAAM,eAAe,GAAG,IAAA,aAAK,EAAC,IAAI,iBAAiB,GAAG,CAAC,CAAC;AACxD,MAAM,mBAAmB,GAAG,IAAA,aAAK,EAAC,iBAAiB,iBAAiB,MAAM,CAAC,CAAC;AAE/D,QAAA,OAAO,GAAwB;IAC1C,IAAI,EAAE,SAAS;IACf,SAAS,EAAE,eAAe;IAC1B,aAAa,EAAE,mBAAmB;CACnC,CAAC;AAEF,SAAgB,qBAAqB,CAAC,MAAiB;IACrD,IAAA,yCAA0B,EAAC,MAAM,CAAC,OAAO,EAAE,eAAO,CAAC,CAAC;IACpD,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;QACxB,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,YAAY,EAAE,CAAC;YAC7C,IAAI,YAAE,CAAC,WAAW,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/B,IAAA,yCAA0B,EAAC,UAAU,CAAC,OAAO,EAAE,eAAO,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAgB,oBAAoB,CAClC,MAAsB,EACtB,OAAO,GAAG,MAAM,CAAC,OAAO,EACxB,aAAa,GAAG,IAAI;IAEpB,kCAAkC;IAClC,IAAI,YAAE,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5C,IAAA,iCAAsB,EAAC,MAAM,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IACD,0BAA0B;IAC1B,OAAO,IAAA,gDAAiC,EACtC,MAAM,EACN,OAAQ,EACR,eAAO,EACP,aAAa,CACd,CAAC;AACJ,CAAC","sourcesContent":["import is from '@sindresorhus/is';\nimport type { InterpolatorOptions } from '../util/interpolator';\nimport {\n replaceInterpolatedValuesInObject,\n validateInterpolatedValues,\n} from '../util/interpolator';\nimport { regEx } from '../util/regex';\nimport { addSecretForSanitizing } from '../util/sanitize';\nimport type { AllConfig, RenovateConfig } from './types';\n\nconst secretNamePattern = '[A-Za-z][A-Za-z0-9_]*';\n\nconst secretNameRegex = regEx(`^${secretNamePattern}$`);\nconst secretTemplateRegex = regEx(`{{ secrets\\\\.(${secretNamePattern}) }}`);\n\nexport const options: InterpolatorOptions = {\n name: 'secrets',\n nameRegex: secretNameRegex,\n templateRegex: secretTemplateRegex,\n};\n\nexport function validateConfigSecrets(config: AllConfig): void {\n validateInterpolatedValues(config.secrets, options);\n if (config.repositories) {\n for (const repository of config.repositories) {\n if (is.plainObject(repository)) {\n validateInterpolatedValues(repository.secrets, options);\n }\n }\n }\n}\n\nexport function applySecretsToConfig(\n config: RenovateConfig,\n secrets = config.secrets,\n deleteSecrets = true,\n): RenovateConfig {\n // Add all secrets to be sanitized\n if (is.plainObject(secrets)) {\n for (const secret of Object.values(secrets)) {\n addSecretForSanitizing(secret);\n }\n }\n // TODO: fix types (#9610)\n return replaceInterpolatedValuesInObject(\n config,\n secrets!,\n options,\n deleteSecrets,\n );\n}\n"]}
|
@@ -0,0 +1,8 @@
|
|
1
|
+
import type { RenovateConfig } from '../config/types';
|
2
|
+
export interface InterpolatorOptions {
|
3
|
+
name: 'secrets' | 'variables';
|
4
|
+
templateRegex: RegExp;
|
5
|
+
nameRegex: RegExp;
|
6
|
+
}
|
7
|
+
export declare function validateInterpolatedValues(input: unknown, options: InterpolatorOptions): void;
|
8
|
+
export declare function replaceInterpolatedValuesInObject(config_: RenovateConfig, input: Record<string, string>, options: InterpolatorOptions, deleteValues: boolean): RenovateConfig;
|
@@ -0,0 +1,85 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.validateInterpolatedValues = validateInterpolatedValues;
|
4
|
+
exports.replaceInterpolatedValuesInObject = replaceInterpolatedValuesInObject;
|
5
|
+
const tslib_1 = require("tslib");
|
6
|
+
const is_1 = tslib_1.__importDefault(require("@sindresorhus/is"));
|
7
|
+
const error_messages_1 = require("../constants/error-messages");
|
8
|
+
const logger_1 = require("../logger");
|
9
|
+
const string_1 = require("./string");
|
10
|
+
function validateInterpolatedValues(input, options) {
|
11
|
+
if (!input) {
|
12
|
+
return;
|
13
|
+
}
|
14
|
+
const { name, nameRegex } = options;
|
15
|
+
const validationErrors = [];
|
16
|
+
if (is_1.default.plainObject(input)) {
|
17
|
+
for (const [key, value] of Object.entries(input)) {
|
18
|
+
if (!nameRegex.test(key)) {
|
19
|
+
validationErrors.push(`Invalid ${name} name "${key}"`);
|
20
|
+
}
|
21
|
+
if (!is_1.default.string(value)) {
|
22
|
+
validationErrors.push(`${(0, string_1.capitalize)(name)} values must be strings. Found type ${typeof value} for ${name} ${key}`);
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
else {
|
27
|
+
validationErrors.push(`Config ${name}s must be a plain object. Found: ${typeof input}`);
|
28
|
+
}
|
29
|
+
if (validationErrors.length) {
|
30
|
+
logger_1.logger.error({ validationErrors }, `Invalid ${name}s configured`);
|
31
|
+
throw new Error(error_messages_1.CONFIG_SECRETS_INVALID);
|
32
|
+
}
|
33
|
+
}
|
34
|
+
function replaceInterpolatedValuesInString(key, value, input, options) {
|
35
|
+
const { name, templateRegex } = options;
|
36
|
+
// do nothing if no interpolator template found
|
37
|
+
if (!templateRegex.test(value)) {
|
38
|
+
return value;
|
39
|
+
}
|
40
|
+
const disallowedPrefixes = ['branch', 'commit', 'group', 'pr', 'semantic'];
|
41
|
+
if (disallowedPrefixes.some((prefix) => key.startsWith(prefix))) {
|
42
|
+
const error = new Error(error_messages_1.CONFIG_VALIDATION);
|
43
|
+
error.validationSource = 'config';
|
44
|
+
error.validationError = `Disallowed ${name} substitution`;
|
45
|
+
error.validationMessage = `The field \`${key}\` may not use ${name} substitution`;
|
46
|
+
throw error;
|
47
|
+
}
|
48
|
+
return value.replace(templateRegex, (_, key) => {
|
49
|
+
if (input?.[key]) {
|
50
|
+
return input[key];
|
51
|
+
}
|
52
|
+
const error = new Error(error_messages_1.CONFIG_VALIDATION);
|
53
|
+
error.validationSource = 'config';
|
54
|
+
error.validationError = `Unknown ${name} name`;
|
55
|
+
error.validationMessage = `The following ${name} name was not found in config: ${String(key)}`;
|
56
|
+
throw error;
|
57
|
+
});
|
58
|
+
}
|
59
|
+
function replaceInterpolatedValuesInObject(config_, input, options, deleteValues) {
|
60
|
+
const config = { ...config_ };
|
61
|
+
const { name } = options;
|
62
|
+
if (deleteValues) {
|
63
|
+
delete config[name];
|
64
|
+
}
|
65
|
+
for (const [key, value] of Object.entries(config)) {
|
66
|
+
if (is_1.default.plainObject(value)) {
|
67
|
+
config[key] = replaceInterpolatedValuesInObject(value, input, options, deleteValues);
|
68
|
+
}
|
69
|
+
if (is_1.default.string(value)) {
|
70
|
+
config[key] = replaceInterpolatedValuesInString(key, value, input, options);
|
71
|
+
}
|
72
|
+
if (is_1.default.array(value)) {
|
73
|
+
for (const [arrayIndex, arrayItem] of value.entries()) {
|
74
|
+
if (is_1.default.plainObject(arrayItem)) {
|
75
|
+
value[arrayIndex] = replaceInterpolatedValuesInObject(arrayItem, input, options, deleteValues);
|
76
|
+
}
|
77
|
+
else if (is_1.default.string(arrayItem)) {
|
78
|
+
value[arrayIndex] = replaceInterpolatedValuesInString(key, arrayItem, input, options);
|
79
|
+
}
|
80
|
+
}
|
81
|
+
}
|
82
|
+
}
|
83
|
+
return config;
|
84
|
+
}
|
85
|
+
//# sourceMappingURL=interpolator.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"interpolator.js","sourceRoot":"","sources":["../../lib/util/interpolator.ts"],"names":[],"mappings":"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","sourcesContent":["import is from '@sindresorhus/is';\nimport type { RenovateConfig } from '../config/types';\nimport {\n CONFIG_SECRETS_INVALID,\n CONFIG_VALIDATION,\n} from '../constants/error-messages';\nimport { logger } from '../logger';\nimport { capitalize } from './string';\n\nexport interface InterpolatorOptions {\n name: 'secrets' | 'variables';\n templateRegex: RegExp;\n nameRegex: RegExp;\n}\n\nexport function validateInterpolatedValues(\n input: unknown,\n options: InterpolatorOptions,\n): void {\n if (!input) {\n return;\n }\n\n const { name, nameRegex } = options;\n\n const validationErrors: string[] = [];\n if (is.plainObject(input)) {\n for (const [key, value] of Object.entries(input)) {\n if (!nameRegex.test(key)) {\n validationErrors.push(`Invalid ${name} name \"${key}\"`);\n }\n if (!is.string(value)) {\n validationErrors.push(\n `${capitalize(name)} values must be strings. Found type ${typeof value} for ${name} ${key}`,\n );\n }\n }\n } else {\n validationErrors.push(\n `Config ${name}s must be a plain object. Found: ${typeof input}`,\n );\n }\n\n if (validationErrors.length) {\n logger.error({ validationErrors }, `Invalid ${name}s configured`);\n throw new Error(CONFIG_SECRETS_INVALID);\n }\n}\n\nfunction replaceInterpolatedValuesInString(\n key: string,\n value: string,\n input: Record<string, string>,\n options: InterpolatorOptions,\n): string {\n const { name, templateRegex } = options;\n // do nothing if no interpolator template found\n if (!templateRegex.test(value)) {\n return value;\n }\n\n const disallowedPrefixes = ['branch', 'commit', 'group', 'pr', 'semantic'];\n if (disallowedPrefixes.some((prefix) => key.startsWith(prefix))) {\n const error = new Error(CONFIG_VALIDATION);\n error.validationSource = 'config';\n error.validationError = `Disallowed ${name} substitution`;\n error.validationMessage = `The field \\`${key}\\` may not use ${name} substitution`;\n throw error;\n }\n return value.replace(templateRegex, (_, key) => {\n if (input?.[key]) {\n return input[key];\n }\n const error = new Error(CONFIG_VALIDATION);\n error.validationSource = 'config';\n error.validationError = `Unknown ${name} name`;\n error.validationMessage = `The following ${name} name was not found in config: ${String(\n key,\n )}`;\n throw error;\n });\n}\n\nexport function replaceInterpolatedValuesInObject(\n config_: RenovateConfig,\n input: Record<string, string>,\n options: InterpolatorOptions,\n deleteValues: boolean,\n): RenovateConfig {\n const config = { ...config_ };\n const { name } = options;\n if (deleteValues) {\n delete config[name];\n }\n for (const [key, value] of Object.entries(config)) {\n if (is.plainObject(value)) {\n config[key] = replaceInterpolatedValuesInObject(\n value,\n input,\n options,\n deleteValues,\n );\n }\n if (is.string(value)) {\n config[key] = replaceInterpolatedValuesInString(\n key,\n value,\n input,\n options,\n );\n }\n if (is.array(value)) {\n for (const [arrayIndex, arrayItem] of value.entries()) {\n if (is.plainObject(arrayItem)) {\n value[arrayIndex] = replaceInterpolatedValuesInObject(\n arrayItem,\n input,\n options,\n deleteValues,\n );\n } else if (is.string(arrayItem)) {\n value[arrayIndex] = replaceInterpolatedValuesInString(\n key,\n arrayItem,\n input,\n options,\n );\n }\n }\n }\n }\n return config;\n}\n"]}
|