Add support for /extensions config command (#17895)

This commit is contained in:
christine betts
2026-02-05 11:04:24 -05:00
committed by GitHub
parent e3b8490edf
commit ee58e1e3c1
8 changed files with 908 additions and 211 deletions

View File

@@ -821,5 +821,74 @@ describe('extensionSettings', () => {
);
// Should complete without error
});
it('should throw error if env var name contains invalid characters', async () => {
const securityConfig: ExtensionConfig = {
name: 'test-ext',
version: '1.0.0',
settings: [{ name: 's2', description: 'd2', envVar: 'VAR-BAD' }],
};
mockRequestSetting.mockResolvedValue('value');
await expect(
updateSetting(
securityConfig,
'12345',
'VAR-BAD',
mockRequestSetting,
ExtensionSettingScope.USER,
tempWorkspaceDir,
),
).rejects.toThrow(/Invalid environment variable name/);
});
it('should throw error if env var value contains newlines', async () => {
mockRequestSetting.mockResolvedValue('value\nwith\nnewlines');
await expect(
updateSetting(
config,
'12345',
'VAR1',
mockRequestSetting,
ExtensionSettingScope.USER,
tempWorkspaceDir,
),
).rejects.toThrow(/Invalid environment variable value/);
});
it('should quote values with spaces', async () => {
mockRequestSetting.mockResolvedValue('value with spaces');
await updateSetting(
config,
'12345',
'VAR1',
mockRequestSetting,
ExtensionSettingScope.USER,
tempWorkspaceDir,
);
const expectedEnvPath = path.join(extensionDir, '.env');
const actualContent = await fsPromises.readFile(expectedEnvPath, 'utf-8');
expect(actualContent).toContain('VAR1="value with spaces"');
});
it('should escape quotes in values', async () => {
mockRequestSetting.mockResolvedValue('value with "quotes"');
await updateSetting(
config,
'12345',
'VAR1',
mockRequestSetting,
ExtensionSettingScope.USER,
tempWorkspaceDir,
);
const expectedEnvPath = path.join(extensionDir, '.env');
const actualContent = await fsPromises.readFile(expectedEnvPath, 'utf-8');
expect(actualContent).toContain('VAR1="value with \\"quotes\\""');
});
});
});

View File

@@ -130,7 +130,19 @@ export async function maybePromptForSettings(
function formatEnvContent(settings: Record<string, string>): string {
let envContent = '';
for (const [key, value] of Object.entries(settings)) {
const formattedValue = value.includes(' ') ? `"${value}"` : value;
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(key)) {
throw new Error(
`Invalid environment variable name: "${key}". Must contain only alphanumeric characters and underscores.`,
);
}
if (value.includes('\n') || value.includes('\r')) {
throw new Error(
`Invalid environment variable value for "${key}". Values cannot contain newlines.`,
);
}
const formattedValue = value.includes(' ')
? `"${value.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`
: value;
envContent += `${key}=${formattedValue}\n`;
}
return envContent;