hardening: isolate third-party paths and clean external-build metadata (#311)
* hardening: isolate third-party paths and clean external-build metadata * fix: restore external feedback flow and make privacy check portable
This commit is contained in:
63
src/tools/WebFetchTool/domainCheck.test.ts
Normal file
63
src/tools/WebFetchTool/domainCheck.test.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import { afterEach, beforeEach, describe, expect, mock, test } from 'bun:test'
|
||||
import axios from 'axios'
|
||||
|
||||
const originalEnv = { ...process.env }
|
||||
|
||||
async function importFreshModule() {
|
||||
return import(`./utils.ts?ts=${Date.now()}-${Math.random()}`)
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
process.env = { ...originalEnv }
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
process.env = { ...originalEnv }
|
||||
})
|
||||
|
||||
describe('checkDomainBlocklist', () => {
|
||||
test('returns allowed without API call in OpenAI mode', async () => {
|
||||
process.env.CLAUDE_CODE_USE_OPENAI = '1'
|
||||
const getSpy = mock(() =>
|
||||
Promise.resolve({ status: 200, data: { can_fetch: true } }),
|
||||
)
|
||||
axios.get = getSpy as typeof axios.get
|
||||
|
||||
const { checkDomainBlocklist } = await importFreshModule()
|
||||
const result = await checkDomainBlocklist('example.com')
|
||||
|
||||
expect(result.status).toBe('allowed')
|
||||
expect(getSpy).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test('returns allowed without API call in Gemini mode', async () => {
|
||||
process.env.CLAUDE_CODE_USE_GEMINI = '1'
|
||||
const getSpy = mock(() =>
|
||||
Promise.resolve({ status: 200, data: { can_fetch: true } }),
|
||||
)
|
||||
axios.get = getSpy as typeof axios.get
|
||||
|
||||
const { checkDomainBlocklist } = await importFreshModule()
|
||||
const result = await checkDomainBlocklist('example.com')
|
||||
|
||||
expect(result.status).toBe('allowed')
|
||||
expect(getSpy).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
test('calls Anthropic domain check in first-party mode', async () => {
|
||||
delete process.env.CLAUDE_CODE_USE_OPENAI
|
||||
delete process.env.CLAUDE_CODE_USE_GEMINI
|
||||
delete process.env.CLAUDE_CODE_USE_GITHUB
|
||||
|
||||
const getSpy = mock(() =>
|
||||
Promise.resolve({ status: 200, data: { can_fetch: true } }),
|
||||
)
|
||||
axios.get = getSpy as typeof axios.get
|
||||
|
||||
const { checkDomainBlocklist } = await importFreshModule()
|
||||
const result = await checkDomainBlocklist('example.com')
|
||||
|
||||
expect(result.status).toBe('allowed')
|
||||
expect(getSpy).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
@@ -8,6 +8,7 @@ import { queryHaiku } from '../../services/api/claude.js'
|
||||
import { AbortError } from '../../utils/errors.js'
|
||||
import { getWebFetchUserAgent } from '../../utils/http.js'
|
||||
import { logError } from '../../utils/log.js'
|
||||
import { getAPIProvider } from '../../utils/model/providers.js'
|
||||
import {
|
||||
isBinaryContentType,
|
||||
persistBinaryContent,
|
||||
@@ -176,6 +177,11 @@ type DomainCheckResult =
|
||||
export async function checkDomainBlocklist(
|
||||
domain: string,
|
||||
): Promise<DomainCheckResult> {
|
||||
// Third-party providers should not consult Anthropic's domain policy.
|
||||
if (getAPIProvider() !== 'firstParty') {
|
||||
return { status: 'allowed' }
|
||||
}
|
||||
|
||||
if (DOMAIN_CHECK_CACHE.has(domain)) {
|
||||
return { status: 'allowed' }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user