Merge pull request #261 from mvanhorn/fix/234-secret-env-redaction
fix(server): redact secret-sourced env vars in logs by provenance
This commit is contained in:
@@ -245,7 +245,7 @@ export function agentRoutes(db: Db) {
|
|||||||
adapterConfig: Record<string, unknown>,
|
adapterConfig: Record<string, unknown>,
|
||||||
) {
|
) {
|
||||||
if (adapterType !== "opencode_local") return;
|
if (adapterType !== "opencode_local") return;
|
||||||
const runtimeConfig = await secretsSvc.resolveAdapterConfigForRuntime(companyId, adapterConfig);
|
const { config: runtimeConfig } = await secretsSvc.resolveAdapterConfigForRuntime(companyId, adapterConfig);
|
||||||
const runtimeEnv = asRecord(runtimeConfig.env) ?? {};
|
const runtimeEnv = asRecord(runtimeConfig.env) ?? {};
|
||||||
try {
|
try {
|
||||||
await ensureOpenCodeModelConfiguredAndAvailable({
|
await ensureOpenCodeModelConfiguredAndAvailable({
|
||||||
@@ -420,7 +420,7 @@ export function agentRoutes(db: Db) {
|
|||||||
inputAdapterConfig,
|
inputAdapterConfig,
|
||||||
{ strictMode: strictSecretsMode },
|
{ strictMode: strictSecretsMode },
|
||||||
);
|
);
|
||||||
const runtimeAdapterConfig = await secretsSvc.resolveAdapterConfigForRuntime(
|
const { config: runtimeAdapterConfig } = await secretsSvc.resolveAdapterConfigForRuntime(
|
||||||
companyId,
|
companyId,
|
||||||
normalizedAdapterConfig,
|
normalizedAdapterConfig,
|
||||||
);
|
);
|
||||||
@@ -1264,7 +1264,7 @@ export function agentRoutes(db: Db) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const config = asRecord(agent.adapterConfig) ?? {};
|
const config = asRecord(agent.adapterConfig) ?? {};
|
||||||
const runtimeConfig = await secretsSvc.resolveAdapterConfigForRuntime(agent.companyId, config);
|
const { config: runtimeConfig } = await secretsSvc.resolveAdapterConfigForRuntime(agent.companyId, config);
|
||||||
const result = await runClaudeLogin({
|
const result = await runClaudeLogin({
|
||||||
runId: `claude-login-${randomUUID()}`,
|
runId: `claude-login-${randomUUID()}`,
|
||||||
agent: {
|
agent: {
|
||||||
|
|||||||
@@ -1240,11 +1240,16 @@ export function heartbeatService(db: Db) {
|
|||||||
const mergedConfig = issueAssigneeOverrides?.adapterConfig
|
const mergedConfig = issueAssigneeOverrides?.adapterConfig
|
||||||
? { ...config, ...issueAssigneeOverrides.adapterConfig }
|
? { ...config, ...issueAssigneeOverrides.adapterConfig }
|
||||||
: config;
|
: config;
|
||||||
const resolvedConfig = await secretsSvc.resolveAdapterConfigForRuntime(
|
const { config: resolvedConfig, secretKeys } = await secretsSvc.resolveAdapterConfigForRuntime(
|
||||||
agent.companyId,
|
agent.companyId,
|
||||||
mergedConfig,
|
mergedConfig,
|
||||||
);
|
);
|
||||||
const onAdapterMeta = async (meta: AdapterInvocationMeta) => {
|
const onAdapterMeta = async (meta: AdapterInvocationMeta) => {
|
||||||
|
if (meta.env && secretKeys.size > 0) {
|
||||||
|
for (const key of secretKeys) {
|
||||||
|
if (key in meta.env) meta.env[key] = "***REDACTED***";
|
||||||
|
}
|
||||||
|
}
|
||||||
await appendRunEvent(currentRun, seq++, {
|
await appendRunEvent(currentRun, seq++, {
|
||||||
eventType: "adapter.invoke",
|
eventType: "adapter.invoke",
|
||||||
stream: "system",
|
stream: "system",
|
||||||
|
|||||||
@@ -308,10 +308,11 @@ export function secretService(db: Db) {
|
|||||||
return normalized;
|
return normalized;
|
||||||
},
|
},
|
||||||
|
|
||||||
resolveEnvBindings: async (companyId: string, envValue: unknown) => {
|
resolveEnvBindings: async (companyId: string, envValue: unknown): Promise<{ env: Record<string, string>; secretKeys: Set<string> }> => {
|
||||||
const record = asRecord(envValue);
|
const record = asRecord(envValue);
|
||||||
if (!record) return {} as Record<string, string>;
|
if (!record) return { env: {} as Record<string, string>, secretKeys: new Set<string>() };
|
||||||
const resolved: Record<string, string> = {};
|
const resolved: Record<string, string> = {};
|
||||||
|
const secretKeys = new Set<string>();
|
||||||
|
|
||||||
for (const [key, rawBinding] of Object.entries(record)) {
|
for (const [key, rawBinding] of Object.entries(record)) {
|
||||||
if (!ENV_KEY_RE.test(key)) {
|
if (!ENV_KEY_RE.test(key)) {
|
||||||
@@ -326,20 +327,22 @@ export function secretService(db: Db) {
|
|||||||
resolved[key] = binding.value;
|
resolved[key] = binding.value;
|
||||||
} else {
|
} else {
|
||||||
resolved[key] = await resolveSecretValue(companyId, binding.secretId, binding.version);
|
resolved[key] = await resolveSecretValue(companyId, binding.secretId, binding.version);
|
||||||
|
secretKeys.add(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return resolved;
|
return { env: resolved, secretKeys };
|
||||||
},
|
},
|
||||||
|
|
||||||
resolveAdapterConfigForRuntime: async (companyId: string, adapterConfig: Record<string, unknown>) => {
|
resolveAdapterConfigForRuntime: async (companyId: string, adapterConfig: Record<string, unknown>): Promise<{ config: Record<string, unknown>; secretKeys: Set<string> }> => {
|
||||||
const resolved = { ...adapterConfig };
|
const resolved = { ...adapterConfig };
|
||||||
|
const secretKeys = new Set<string>();
|
||||||
if (!Object.prototype.hasOwnProperty.call(adapterConfig, "env")) {
|
if (!Object.prototype.hasOwnProperty.call(adapterConfig, "env")) {
|
||||||
return resolved;
|
return { config: resolved, secretKeys };
|
||||||
}
|
}
|
||||||
const record = asRecord(adapterConfig.env);
|
const record = asRecord(adapterConfig.env);
|
||||||
if (!record) {
|
if (!record) {
|
||||||
resolved.env = {};
|
resolved.env = {};
|
||||||
return resolved;
|
return { config: resolved, secretKeys };
|
||||||
}
|
}
|
||||||
const env: Record<string, string> = {};
|
const env: Record<string, string> = {};
|
||||||
for (const [key, rawBinding] of Object.entries(record)) {
|
for (const [key, rawBinding] of Object.entries(record)) {
|
||||||
@@ -355,10 +358,11 @@ export function secretService(db: Db) {
|
|||||||
env[key] = binding.value;
|
env[key] = binding.value;
|
||||||
} else {
|
} else {
|
||||||
env[key] = await resolveSecretValue(companyId, binding.secretId, binding.version);
|
env[key] = await resolveSecretValue(companyId, binding.secretId, binding.version);
|
||||||
|
secretKeys.add(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolved.env = env;
|
resolved.env = env;
|
||||||
return resolved;
|
return { config: resolved, secretKeys };
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user