diff --git a/.github/workflows/ci-test.yml b/.github/workflows/ci-test.yml new file mode 100644 index 0000000000000..e8b3857a02f3b --- /dev/null +++ b/.github/workflows/ci-test.yml @@ -0,0 +1,42 @@ +name: CI Test + +on: + push: + branches: [main] + pull_request: + types: [opened, reopened, synchronize, ready_for_review] + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + test: + name: "npm test" + runs-on: ubuntu-24.04 + timeout-minutes: 30 + if: github.event_name != 'pull_request' || !github.event.pull_request.draft + + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version: "24.16.0" + package-manager-cache: false + + - name: Install pnpm + run: npm install -g pnpm@11.2.2 + + - name: Install dependencies + run: pnpm install --frozen-lockfile --prefer-offline + + - name: Run tests + run: npm test + env: + CI: "true" diff --git a/src/commands/doctor-config-flow.test.ts b/src/commands/doctor-config-flow.test.ts index 4bdafafc3b1e3..18e402ab43a8d 100644 --- a/src/commands/doctor-config-flow.test.ts +++ b/src/commands/doctor-config-flow.test.ts @@ -753,6 +753,7 @@ vi.mock("./doctor/channel-capabilities.js", () => { ? byChannel[channelName as keyof typeof byChannel] : fallback, }; + resolveDoctorChannelAccountIds: () => undefined, }); vi.mock("../plugins/doctor-contract-registry.js", () => { diff --git a/src/commands/doctor/shared/allowfrom-fallback-migration.test.ts b/src/commands/doctor/shared/allowfrom-fallback-migration.test.ts index a6d2b0a908d95..0bc7c1abfe951 100644 --- a/src/commands/doctor/shared/allowfrom-fallback-migration.test.ts +++ b/src/commands/doctor/shared/allowfrom-fallback-migration.test.ts @@ -9,6 +9,7 @@ vi.mock("../channel-capabilities.js", () => ({ groupAllowFromFallbackToAllowFrom: channelName !== "discord", warnOnEmptyGroupSenderAllowlist: true, }), + resolveDoctorChannelAccountIds: () => undefined, })); describe("doctor group allowFrom fallback migration", () => { diff --git a/src/commands/doctor/shared/empty-allowlist-policy.test.ts b/src/commands/doctor/shared/empty-allowlist-policy.test.ts index a2f1863d10946..77a56c1342ce7 100644 --- a/src/commands/doctor/shared/empty-allowlist-policy.test.ts +++ b/src/commands/doctor/shared/empty-allowlist-policy.test.ts @@ -9,6 +9,7 @@ vi.mock("../channel-capabilities.js", () => ({ groupAllowFromFallbackToAllowFrom: channelName !== "imessage", warnOnEmptyGroupSenderAllowlist: channelName !== "discord", }), + resolveDoctorChannelAccountIds: () => undefined, })); vi.mock("./channel-doctor.js", () => ({ diff --git a/src/commands/doctor/shared/open-policy-allowfrom.test.ts b/src/commands/doctor/shared/open-policy-allowfrom.test.ts index 2b664a7e3e0f9..ee7219b7e8116 100644 --- a/src/commands/doctor/shared/open-policy-allowfrom.test.ts +++ b/src/commands/doctor/shared/open-policy-allowfrom.test.ts @@ -13,6 +13,7 @@ vi.mock("../channel-capabilities.js", () => ({ groupAllowFromFallbackToAllowFrom: true, warnOnEmptyGroupSenderAllowlist: true, }), + resolveDoctorChannelAccountIds: () => undefined, })); describe("doctor open-policy allowFrom repair", () => { diff --git a/src/commands/doctor/shared/preview-warnings.test.ts b/src/commands/doctor/shared/preview-warnings.test.ts index 1cf67ebad2213..660a3dfc1e672 100644 --- a/src/commands/doctor/shared/preview-warnings.test.ts +++ b/src/commands/doctor/shared/preview-warnings.test.ts @@ -68,6 +68,7 @@ vi.mock("../channel-capabilities.js", () => { return { getDoctorChannelCapabilities: () => fallback, }; + resolveDoctorChannelAccountIds: () => undefined, }); vi.mock("./channel-doctor.js", () => ({ diff --git a/src/logging/redact.test.ts b/src/logging/redact.test.ts index 0162c3ac00177..0c301a4bd8f70 100644 --- a/src/logging/redact.test.ts +++ b/src/logging/redact.test.ts @@ -986,7 +986,7 @@ describe("redactSensitiveText", () => { ); }); - it("forces redaction for tool details even when log redaction is disabled", () => { + it("respects redactSensitive off for tool details", () => { writeConfig(`{ logging: { redactSensitive: "off", @@ -994,7 +994,7 @@ describe("redactSensitiveText", () => { }`); expect(redactToolDetail("OPENAI_API_KEY=sk-1234567890abcdef")).toBe( - "OPENAI_API_KEY=sk-123…cdef", + "OPENAI_API_KEY=sk-1234567890abcdef", ); }); diff --git a/src/logging/redact.ts b/src/logging/redact.ts index b41198d43fcd1..ccfb20ae7aa2f 100644 --- a/src/logging/redact.ts +++ b/src/logging/redact.ts @@ -999,16 +999,22 @@ function resolveToolPayloadRedaction( loggingConfig: LoggingConfig | undefined = readLoggingConfig(), ): RedactOptions { const userPatterns = loggingConfig?.redactPatterns; + const mode = normalizeMode(loggingConfig?.redactSensitive); + if (mode === "off") { + return { mode: "off", patterns: [] }; + } const patterns = userPatterns && userPatterns.length > 0 ? [...userPatterns, ...DEFAULT_REDACT_PATTERNS] : undefined; - return { mode: "tools", patterns }; + return { mode, patterns }; } -// Forces tools-mode regardless of `logging.redactSensitive` (which governs log -// output, not UI surfaces), and merges user `logging.redactPatterns` with the -// built-in defaults so both apply. +// Resolves tool payload redaction, respecting `logging.redactSensitive` when +// set, and merges user `logging.redactPatterns` with the built-in defaults +// so both apply. When `redactSensitive` is "off", all tool payload redaction +// is disabled, matching the user's intent to disable sensitive-value masking +// (including in tool event args such as `Authorization: Bearer` headers). export function redactToolPayloadText(text: string): string { return redactToolPayloadTextWithConfig(text, readLoggingConfig()); }