@vigilbase/cli
Version:
Vigilbase CLI — security scanners, agent tools, and Vigilbase One from the terminal.
81 lines (80 loc) • 4.28 kB
JavaScript
/**
* The environment every cf child process receives (spec §F3).
*
* This is the only source file that names the Cloudflare API token variable;
* everything else imports `CF_TOKEN_ENV` (enforced by the grep guard test).
* The child environment is built from an empty object: a fixed allowlist is
* copied by name without inspecting values, then fixed values are forced.
* Base-URL overrides (`CLOUDFLARE_API_BASE_URL`, `CF_API_BASE_URL`), other
* Cloudflare/Wrangler credentials, `VIGILBASE_*`, `NODE_OPTIONS`, `DEBUG`,
* npm config and agent-harness markers are therefore absent by construction.
* Scrubbing the base-URL variables is the primary control against redirecting
* the token; the dry-run preflight cannot detect it.
*/
export const CF_TOKEN_ENV = 'CLOUDFLARE_API_TOKEN';
export const CF_ACCOUNT_ENV = 'CLOUDFLARE_ACCOUNT_ID';
const PASSTHROUGH = [
'PATH', 'HOME', 'USER', 'LOGNAME', 'USERPROFILE', 'APPDATA', 'LOCALAPPDATA', 'SystemRoot', 'WINDIR',
'XDG_CONFIG_HOME', 'XDG_CACHE_HOME', 'XDG_DATA_HOME', 'XDG_STATE_HOME', 'XDG_RUNTIME_DIR',
'TMPDIR', 'TMP', 'TEMP', 'LANG', 'LC_ALL', 'LC_CTYPE', 'TZ',
'HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY', 'http_proxy', 'https_proxy', 'no_proxy',
'NODE_EXTRA_CA_CERTS', 'SSL_CERT_FILE', 'SSL_CERT_DIR', 'DBUS_SESSION_BUS_ADDRESS', 'CLOUDFLARE_AUTH_USE_KEYRING',
];
/** Telemetry off, no update checks or prompts, no project-local delegation. */
const FORCED_TELEMETRY = { CF_SEND_TELEMETRY: 'false', DO_NOT_TRACK: '1', CF_DELEGATION: '1' };
const FORCED_NON_INTERACTIVE = { CI: '1', NO_COLOR: '1', FORCE_COLOR: '0', CF_QUIET: '1' };
function lookup(parent, platform) {
if (platform !== 'win32')
return (name) => parent[name];
// Windows variable names are case-insensitive (`Path`, `SystemRoot`).
const keys = new Map(Object.keys(parent).map((key) => [key.toUpperCase(), key]));
return (name) => {
const key = keys.get(name.toUpperCase());
return key === undefined ? undefined : parent[key];
};
}
/** Presence only: the value is never read, printed or validated by the Vigilbase CLI. */
export function hasEnvToken(parent, platform = process.platform) {
const value = lookup(parent, platform)(CF_TOKEN_ENV);
return typeof value === 'string' && value.length > 0;
}
export function buildChildEnv(parent, options) {
const platform = options.platform ?? process.platform;
const get = lookup(parent, platform);
const env = {};
for (const name of PASSTHROUGH) {
const value = get(name);
if (typeof value === 'string')
env[name] = value;
}
Object.assign(env, FORCED_TELEMETRY);
if (options.purpose !== 'login')
Object.assign(env, FORCED_NON_INTERACTIVE);
if (options.accountId !== undefined) {
if (!/^[0-9a-f]{32}$/.test(options.accountId))
throw new Error('Invalid Cloudflare account ID for cf.');
env[CF_ACCOUNT_ENV] = options.accountId;
}
// Copied by name, only for authenticated reads in --cf-auth env mode. In
// profile and default modes it would outrank --profile, so it is stripped.
if (options.purpose === 'api' && options.authMode === 'env') {
const token = get(CF_TOKEN_ENV);
if (typeof token === 'string' && token.length > 0)
env[CF_TOKEN_ENV] = token;
}
return env;
}
/** Variable names (never values) a cf child would receive, for `--dry-run` output. */
export function childEnvVariableNames(parent, authMode, platform = process.platform) {
const names = Object.keys(buildChildEnv(parent, { purpose: 'api', authMode, accountId: '0'.repeat(32), platform }));
if (authMode === 'env' && !names.includes(CF_TOKEN_ENV))
names.push(CF_TOKEN_ENV);
return names.sort();
}
/** Shown in profile and default modes when the token variable is set in the parent shell. */
export function strippedTokenNotice(authMode) {
return `${CF_TOKEN_ENV} is set in this shell but is not passed to cf in --cf-auth ${authMode} mode (it would override the profile). Use --cf-auth env to collect with it.`;
}
export function missingEnvTokenMessage() {
return `--cf-auth env requires ${CF_TOKEN_ENV} in this shell. cf reads it itself; the Vigilbase CLI only passes it through by name.`;
}