PR #666 introduced hardcoded SAFE_COMMAND_PREFIXES and SSRF URL blocklists with no override mechanism. Users with non-standard credential tools (sops, doppler, age, infisical) or needing to fetch from internal URLs (self-hosted docs, VPN services) were silently blocked with no recourse. Add two global-only settings (ignored in project-level settings.json to preserve the security property against malicious repos): - allowedCommandPrefixes: replaces the built-in command allowlist - fetchAllowedUrls: exempts hostnames from SSRF blocking Both also support env var overrides (GSD_ALLOWED_COMMAND_PREFIXES, GSD_FETCH_ALLOWED_URLS) for CI/container environments. Env vars take precedence over settings.json. Security model: global-only keys are stripped from project settings at load time via stripGlobalOnlyKeys(), applied at all three assignment points for this.projectSettings. The merge function stays untouched — no future caller can accidentally skip stripping. 15 new tests covering override behavior, cache invalidation, allowlist exemptions, and global-only enforcement.
42 lines
1.5 KiB
TypeScript
42 lines
1.5 KiB
TypeScript
/**
|
|
* Apply user-configured security overrides from global settings.json and env vars.
|
|
*
|
|
* Both overrides are global-only (not project-level) because the threat model is
|
|
* malicious project-level config in cloned repos. Global settings and env vars
|
|
* represent the user's own authority on their machine.
|
|
*
|
|
* Precedence: env var > settings.json > built-in defaults
|
|
*/
|
|
|
|
import { type SettingsManager, setAllowedCommandPrefixes } from '@gsd/pi-coding-agent'
|
|
import { setFetchAllowedUrls } from './resources/extensions/search-the-web/url-utils.js'
|
|
|
|
export function applySecurityOverrides(settingsManager: SettingsManager): void {
|
|
// --- Command prefix allowlist ---
|
|
const envPrefixes = process.env.GSD_ALLOWED_COMMAND_PREFIXES
|
|
if (envPrefixes) {
|
|
const prefixes = envPrefixes.split(',').map(s => s.trim()).filter(Boolean)
|
|
if (prefixes.length > 0) {
|
|
setAllowedCommandPrefixes(prefixes)
|
|
}
|
|
} else {
|
|
const settingsPrefixes = settingsManager.getAllowedCommandPrefixes()
|
|
if (settingsPrefixes && settingsPrefixes.length > 0) {
|
|
setAllowedCommandPrefixes(settingsPrefixes)
|
|
}
|
|
}
|
|
|
|
// --- Fetch URL allowlist (SSRF exemptions) ---
|
|
const envUrls = process.env.GSD_FETCH_ALLOWED_URLS
|
|
if (envUrls) {
|
|
const urls = envUrls.split(',').map(s => s.trim()).filter(Boolean)
|
|
if (urls.length > 0) {
|
|
setFetchAllowedUrls(urls)
|
|
}
|
|
} else {
|
|
const settingsUrls = settingsManager.getFetchAllowedUrls()
|
|
if (settingsUrls && settingsUrls.length > 0) {
|
|
setFetchAllowedUrls(settingsUrls)
|
|
}
|
|
}
|
|
}
|