Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(config): encrypted field validation #33382

Merged
merged 15 commits into from
Jan 6, 2025
6 changes: 6 additions & 0 deletions lib/config/presets/internal/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { resolveConfigPresets } from '../';
import { CONFIG_VALIDATION } from '../../../constants/error-messages';
import { GlobalConfig } from '../../global';
import { massageConfig } from '../../massage';
import { validateConfig } from '../../validation';
import * as npm from '../npm';
Expand Down Expand Up @@ -27,6 +28,11 @@ describe('config/presets/internal/index', () => {
if (presetName !== 'description' && !ignoredPresets.includes(preset)) {
it(`${preset} validates`, async () => {
try {
if (preset === 'default:githubComToken') {
GlobalConfig.set({
privateKey: 'some-private-key',
});
}
const config = await resolveConfigPresets(
massageConfig(presetConfig),
);
Expand Down
61 changes: 61 additions & 0 deletions lib/config/validation.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,47 @@ describe('config/validation', () => {
expect(errors).toHaveLength(0);
});

it('errors if encrypted object found without privateKey', async () => {
const config = {
encrypted: {
npmToken:
'xxT19RIdhAh09lkhdrK39HzKNBn3etoLZAwHdeJ25cX+5y52a9kAC7flXmdw5JrkciN08aQuRNqDaKxp53IVptB5AYOnQPrt8MCT+x0zHgp4A1zv1QOV84I6uugdWpFSjPUkmLGMgULudEZJMlY/dAn/IVwf/IImqwazY8eHyJAA4vyUqKkL9SXzHjvS+OBonQ/9/AHYYKmDJwT8vLSRCKrXxJCdUfH7ZnikZbFqjnURJ9nGUHP44rlYJ7PFl05RZ+X5WuZG/A27S5LuBvguyQGcw8A2AZilHSDta9S/4eG6kb22jX87jXTrT6orUkxh2WHI/xvNUEout0gxwWMDkA==',
},
};
const { warnings, errors } = await configValidation.validateConfig(
'repo',
config,
);
expect(warnings).toHaveLength(0);
expect(errors).toMatchObject([
{
topic: 'Configuration Error',
message: `No privateKey found in hosted config. \`encrypted\` object cannot be used without a privateKey.`,
},
]);
});

it('errors if invalid encrypted object', async () => {
GlobalConfig.set({ privateKey: 'some-private-key' });
const config = {
encrypted: {
npmToken: 1,
},
};
const { warnings, errors } = await configValidation.validateConfig(
'repo',
config,
);
expect(warnings).toHaveLength(0);
expect(errors).toMatchObject([
{
topic: 'Configuration Error',
message:
'Invalid `encrypted.encrypted.npmToken` configuration: value is not a string',
},
]);
});

it('errors if registryAliases depth is more than 1', async () => {
const config = {
registryAliases: {
Expand Down Expand Up @@ -1426,6 +1467,26 @@ describe('config/validation', () => {
]);
});

it('errors if encrypted object found without privateKey', async () => {
const config = {
encrypted: {
npmToken:
'xxT19RIdhAh09lkhdrK39HzKNBn3etoLZAwHdeJ25cX+5y52a9kAC7flXmdw5JrkciN08aQuRNqDaKxp53IVptB5AYOnQPrt8MCT+x0zHgp4A1zv1QOV84I6uugdWpFSjPUkmLGMgULudEZJMlY/dAn/IVwf/IImqwazY8eHyJAA4vyUqKkL9SXzHjvS+OBonQ/9/AHYYKmDJwT8vLSRCKrXxJCdUfH7ZnikZbFqjnURJ9nGUHP44rlYJ7PFl05RZ+X5WuZG/A27S5LuBvguyQGcw8A2AZilHSDta9S/4eG6kb22jX87jXTrT6orUkxh2WHI/xvNUEout0gxwWMDkA==',
},
};
const { warnings, errors } = await configValidation.validateConfig(
'global',
config,
);
expect(warnings).toHaveLength(0);
expect(errors).toMatchObject([
{
topic: 'Configuration Error',
message: `No privateKey found in hosted config. \`encrypted\` object cannot be used without a privateKey.`,
},
]);
});

it('validates hostRules.headers', async () => {
const config = {
hostRules: [
Expand Down
19 changes: 19 additions & 0 deletions lib/config/validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -634,6 +634,25 @@ export async function validateConfig(
message: `Invalid \`${currentPath}.${key}.${res}\` configuration: value is not a string`,
});
}
} else if (key === 'encrypted') {
const res = validatePlainObject(val);
if (res !== true) {
errors.push({
topic: 'Configuration Error',
message: `Invalid \`${currentPath}.${key}.${res}\` configuration: value is not a string`,
});
}

const privateKey =
configType === 'global'
? config.privateKey
: GlobalConfig.get('privateKey');
if (!is.nonEmptyString(privateKey)) {
errors.push({
topic: 'Configuration Error',
message: `No privateKey found in hosted config. \`encrypted\` object cannot be used without a privateKey.`,
RahulGautamSingh marked this conversation as resolved.
Show resolved Hide resolved
});
}
} else if (key === 'env') {
const allowedEnvVars =
configType === 'global'
Expand Down
Loading