From e3ad6a150784ea18962f5250a58df61b6ead5391 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E8=92=8B?= <23394662@qq.com> Date: Tue, 16 Jun 2026 19:23:20 +0800 Subject: [PATCH 1/4] ci: add CI test workflow on push and PR using npm test --- .github/workflows/ci-test.yml | 44 +++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 .github/workflows/ci-test.yml diff --git a/.github/workflows/ci-test.yml b/.github/workflows/ci-test.yml new file mode 100644 index 0000000000000..6b8b81ea01efc --- /dev/null +++ b/.github/workflows/ci-test.yml @@ -0,0 +1,44 @@ +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 pnpm + uses: pnpm/action-setup@v4 + with: + version: 11.2.2 + + - name: Setup Node.js + uses: actions/setup-node@v5 + with: + node-version: "24.16.0" + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile --prefer-offline + + - name: Run tests + run: npm test + env: + CI: "true" From e2cbbd2d20212819eb7761b75676690998673a50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E8=92=8B?= <23394662@qq.com> Date: Tue, 16 Jun 2026 19:45:28 +0800 Subject: [PATCH 2/4] fix(ci): replace pnpm action-setup with npm global install --- .github/workflows/ci-test.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-test.yml b/.github/workflows/ci-test.yml index 6b8b81ea01efc..4a4967a552d54 100644 --- a/.github/workflows/ci-test.yml +++ b/.github/workflows/ci-test.yml @@ -24,16 +24,13 @@ jobs: - name: Checkout uses: actions/checkout@v5 - - name: Setup pnpm - uses: pnpm/action-setup@v4 - with: - version: 11.2.2 - - name: Setup Node.js uses: actions/setup-node@v5 with: node-version: "24.16.0" - cache: "pnpm" + + - name: Install pnpm + run: npm install -g pnpm@11.2.2 - name: Install dependencies run: pnpm install --frozen-lockfile --prefer-offline From 8918a51fe0659b236e17529c92eea90fc0226de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E8=92=8B?= <23394662@qq.com> Date: Tue, 16 Jun 2026 19:52:26 +0800 Subject: [PATCH 3/4] fix(ci): disable auto package-manager-cache in setup-node@v5 to avoid pnpm not found error --- .github/workflows/ci-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci-test.yml b/.github/workflows/ci-test.yml index 4a4967a552d54..e8b3857a02f3b 100644 --- a/.github/workflows/ci-test.yml +++ b/.github/workflows/ci-test.yml @@ -28,6 +28,7 @@ jobs: 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 From 71017325210e4a1eb678178d58be3760f7a58497 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=80=81=E8=92=8B?= <23394662@qq.com> Date: Tue, 16 Jun 2026 15:58:00 +0800 Subject: [PATCH 4/4] fix(redact): respect redactSensitive off for tool payload redaction Previously resolveToolPayloadRedaction() hardcoded mode tools, ignoring the logging.redactSensitive config entirely. This meant users who set redactSensitive off could not disable sensitive-value masking in tool event args like Authorization Bearer headers in web_fetch args. The fix reads redactSensitive from the logging config and passes it through normalizeMode(). When set to off, tool payload redaction is fully disabled. --- src/commands/doctor-config-flow.test.ts | 1 + .../shared/allowfrom-fallback-migration.test.ts | 1 + .../doctor/shared/empty-allowlist-policy.test.ts | 1 + .../doctor/shared/open-policy-allowfrom.test.ts | 1 + .../doctor/shared/preview-warnings.test.ts | 1 + src/logging/redact.test.ts | 4 ++-- src/logging/redact.ts | 14 ++++++++++---- 7 files changed, 17 insertions(+), 6 deletions(-) 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()); }