diff --git a/extensions/qa-matrix/src/runners/contract/scenario-runtime-e2ee.ts b/extensions/qa-matrix/src/runners/contract/scenario-runtime-e2ee.ts index ce552fc9c88..d36bad1e646 100644 --- a/extensions/qa-matrix/src/runners/contract/scenario-runtime-e2ee.ts +++ b/extensions/qa-matrix/src/runners/contract/scenario-runtime-e2ee.ts @@ -1,5 +1,5 @@ import { randomUUID } from "node:crypto"; -import { chmod, mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; +import { chmod, mkdir, mkdtemp, rm, stat, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import path from "node:path"; import { setTimeout as sleep } from "node:timers/promises"; @@ -315,6 +315,16 @@ async function writeMatrixQaCliOutputArtifacts(params: { return { stderrPath, stdoutPath }; } +async function assertMatrixQaPrivatePathMode(pathToCheck: string, label: string) { + if (process.platform === "win32") { + return; + } + const mode = (await stat(pathToCheck)).mode & 0o777; + if ((mode & 0o077) !== 0) { + throw new Error(`${label} permissions are too broad: ${mode.toString(8)}`); + } +} + function assertMatrixQaCliSasMatches(params: { cliSas: ReturnType; owner: MatrixVerificationSummary; @@ -390,10 +400,13 @@ async function createMatrixQaCliSelfVerificationRuntime(params: { const stateDir = path.join(rootDir, "state"); const configPath = path.join(rootDir, "config.json"); await chmod(rootDir, 0o700).catch(() => undefined); + await assertMatrixQaPrivatePathMode(rootDir, "Matrix QA CLI temp directory"); await mkdir(artifactDir, { mode: 0o700, recursive: true }); await chmod(artifactDir, 0o700).catch(() => undefined); + await assertMatrixQaPrivatePathMode(artifactDir, "Matrix QA CLI artifact directory"); await mkdir(stateDir, { mode: 0o700, recursive: true }); await chmod(stateDir, 0o700).catch(() => undefined); + await assertMatrixQaPrivatePathMode(stateDir, "Matrix QA CLI state directory"); await writeFile( configPath, `${JSON.stringify( @@ -422,8 +435,9 @@ async function createMatrixQaCliSelfVerificationRuntime(params: { null, 2, )}\n`, - { mode: 0o600 }, + { flag: "wx", mode: 0o600 }, ); + await assertMatrixQaPrivatePathMode(configPath, "Matrix QA CLI config file"); const env = { ...requireMatrixQaCliRuntimeEnv(params.context), FORCE_COLOR: "0", diff --git a/src/logging/redact.ts b/src/logging/redact.ts index 3689fb6a4a4..bd27a23beed 100644 --- a/src/logging/redact.ts +++ b/src/logging/redact.ts @@ -15,9 +15,11 @@ const DEFAULT_REDACT_KEEP_END = 4; const DEFAULT_REDACT_PATTERNS: string[] = [ // ENV-style assignments. - String.raw`\b[A-Z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD)\b\s*[=:]\s*(["']?)([^\s"'\\]+)\1`, + String.raw`(?:^|\s)\b[A-Z0-9_]*(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD)\b\s*[=:]\s*(["']?)([^\s"'\\]+)\1`, // JSON fields. String.raw`"(?:apiKey|token|secret|password|passwd|accessToken|refreshToken|access_token|refresh_token)"\s*:\s*"([^"]+)"`, + // URL query parameters. + String.raw`([?&](?:access_token|refresh_token)=)([^&#\s]+)`, // CLI flags. String.raw`--(?:api[-_]?key|hook[-_]?token|token|secret|password|passwd)\s+(["']?)([^\s"']+)\1`, // Authorization headers.