mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-26 09:52:11 +03:00
fix(backend): compute AgentBridge diagnose DNS check per-agent instead of hard-coded Antigravity (#8466) (#8502)
getMitmStatus() hard-wired dnsConfigured to a single Antigravity hostname regex regardless of which agent was being diagnosed, and the diagnose route never accepted an agentId to check against. Add checkDNSEntryForAgent() reusing resolveHostsForAgent()'s existing per-target host resolution, thread an optional agentId through getMitmStatus(), and have the diagnose route parse ?agentId= and pass it through. Callers that omit agentId keep the legacy Antigravity-only behavior unchanged. Co-authored-by: ikelvingo <im.kelvinwong@gmail.com>
This commit is contained in:
committed by
GitHub
parent
13cc128dae
commit
61277813b2
1
changelog.d/fixes/8466-agentbridge-dns-per-agent.md
Normal file
1
changelog.d/fixes/8466-agentbridge-dns-per-agent.md
Normal file
@@ -0,0 +1 @@
|
||||
- fix(backend): compute AgentBridge diagnose `dnsConfigured` per-agent instead of hard-coded to Antigravity hosts (#8466)
|
||||
@@ -37,9 +37,10 @@ function probeTcp(port: number, host = "127.0.0.1", timeoutMs = 1500): Promise<b
|
||||
});
|
||||
}
|
||||
|
||||
export async function GET(): Promise<Response> {
|
||||
export async function GET(request: Request): Promise<Response> {
|
||||
try {
|
||||
const status = await getMitmStatus();
|
||||
const agentId = new URL(request.url).searchParams.get("agentId") ?? undefined;
|
||||
const status = await getMitmStatus(agentId);
|
||||
const certPath = path.join(resolveMitmDataDir(), "mitm", "server.crt");
|
||||
const certExists = fs.existsSync(certPath);
|
||||
const certTrusted = certExists ? await checkCertInstalled(certPath) : false;
|
||||
|
||||
@@ -256,6 +256,19 @@ export function checkDNSEntry(): boolean {
|
||||
return ANTIGRAVITY_HOSTS.every((h) => hasHostEntry(hostsContent, h));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether ALL hosts for the given agent are present in /etc/hosts.
|
||||
* Falls back to the Antigravity legacy hosts when `agentId` is omitted or
|
||||
* unknown, via `resolveHostsForAgent()` — so callers get the same host set
|
||||
* that `addDNSEntry`/`removeDNSEntry` already use for that agent. Used by
|
||||
* `getMitmStatus()` to answer "are THIS agent's hosts spoofed?" instead of
|
||||
* always checking the Antigravity-only set (#8466).
|
||||
*/
|
||||
export function checkDNSEntryForAgent(agentId?: string): boolean {
|
||||
const hostsContent = readHostsFile();
|
||||
return resolveHostsForAgent(agentId).every((h) => hasHostEntry(hostsContent, h));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add DNS entries for the Antigravity default hosts, or for a specific agent
|
||||
* when `agentId` is provided.
|
||||
|
||||
@@ -2,7 +2,7 @@ import { spawn, type ChildProcess } from "child_process";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import { resolveMitmDataDir } from "./dataDir.ts";
|
||||
import { removeDNSEntry, removeDNSEntries } from "./dns/dnsConfig.ts";
|
||||
import { removeDNSEntry, removeDNSEntries, checkDNSEntryForAgent } from "./dns/dnsConfig.ts";
|
||||
import { provisionDnsEntries } from "./dns/provision.ts";
|
||||
import { generateCert } from "./cert/generate.ts";
|
||||
import { installCertResult, installCaCert } from "./cert/install.ts";
|
||||
@@ -353,9 +353,16 @@ export async function handleExitCleanup(
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MITM status
|
||||
* Get MITM status.
|
||||
*
|
||||
* @param agentId - Optional agent whose hosts should be checked in DNS. When
|
||||
* omitted, preserves the legacy Antigravity-only check (unchanged behavior
|
||||
* for the existing no-agentId call sites: state/route.ts, server/route.ts,
|
||||
* settings/mitm/route.ts, cli-tools/antigravity-mitm/route.ts). When
|
||||
* provided (e.g. by the diagnose route), checks that agent's own hosts
|
||||
* instead of always checking the Antigravity host set (#8466).
|
||||
*/
|
||||
export async function getMitmStatus(): Promise<{
|
||||
export async function getMitmStatus(agentId?: string): Promise<{
|
||||
running: boolean;
|
||||
pid: number | null;
|
||||
dnsConfigured: boolean;
|
||||
@@ -387,11 +394,17 @@ export async function getMitmStatus(): Promise<{
|
||||
}
|
||||
}
|
||||
|
||||
// Check DNS configuration
|
||||
// Check DNS configuration. When an agentId is provided, check THAT agent's
|
||||
// own hosts (#8466) instead of always checking the Antigravity host set —
|
||||
// callers that don't pass agentId keep the legacy Antigravity-only check.
|
||||
let dnsConfigured = false;
|
||||
try {
|
||||
const hostsContent = fs.readFileSync("/etc/hosts", "utf-8");
|
||||
dnsConfigured = /\bdaily-cloudcode-pa\.googleapis\.com\b/.test(hostsContent);
|
||||
if (agentId) {
|
||||
dnsConfigured = checkDNSEntryForAgent(agentId);
|
||||
} else {
|
||||
const hostsContent = fs.readFileSync("/etc/hosts", "utf-8");
|
||||
dnsConfigured = /\bdaily-cloudcode-pa\.googleapis\.com\b/.test(hostsContent);
|
||||
}
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
111
tests/unit/agent-bridge-dns-per-agent-8466.test.ts
Normal file
111
tests/unit/agent-bridge-dns-per-agent-8466.test.ts
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Regression test for issue #8466: AgentBridge diagnostics `dnsConfigured`
|
||||
* was hard-wired to the Antigravity host regex (src/mitm/manager.ts) instead
|
||||
* of being computed per-agent via `resolveHostsForAgent(agentId)`
|
||||
* (src/mitm/dns/dnsConfig.ts).
|
||||
*
|
||||
* We mock fs.readFileSync so the real /etc/hosts is never touched, then
|
||||
* exercise getMitmStatus() -- the exact function named in the issue -- with
|
||||
* hosts-file contents representing each failure direction, plus the
|
||||
* diagnose route to prove the agentId query param is threaded through.
|
||||
*/
|
||||
import { test, mock, afterEach } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import fs from "node:fs";
|
||||
|
||||
afterEach(() => {
|
||||
mock.restoreAll();
|
||||
});
|
||||
|
||||
test("FALSE NEGATIVE: Claude Code host correctly spoofed, no Antigravity host present -> dnsConfigured should be true when checked for claude-code", async () => {
|
||||
const realReadFileSync = fs.readFileSync.bind(fs);
|
||||
mock.method(fs, "readFileSync", (p: string, enc?: BufferEncoding) => {
|
||||
if (p === "/etc/hosts") {
|
||||
// Claude Code target hosts = ["api.anthropic.com"] (src/mitm/targets/claudeCode.ts).
|
||||
// The user correctly spoofed it. No Antigravity host present at all.
|
||||
return "127.0.0.1 localhost\n127.0.0.1 api.anthropic.com\n::1 api.anthropic.com\n";
|
||||
}
|
||||
return realReadFileSync(p, enc);
|
||||
});
|
||||
|
||||
const { getMitmStatus } = await import("../../src/mitm/manager.ts?probe=8466-negative");
|
||||
const status = await getMitmStatus("claude-code");
|
||||
|
||||
assert.equal(
|
||||
status.dnsConfigured,
|
||||
true,
|
||||
"dnsConfigured must be true when the agent being diagnosed (Claude Code) has its own host spoofed"
|
||||
);
|
||||
});
|
||||
|
||||
test("FALSE POSITIVE: only a leftover Antigravity host is present, Claude Code host is missing -> dnsConfigured should be false when checked for claude-code", async () => {
|
||||
const realReadFileSync = fs.readFileSync.bind(fs);
|
||||
mock.method(fs, "readFileSync", (p: string, enc?: BufferEncoding) => {
|
||||
if (p === "/etc/hosts") {
|
||||
// Leftover Antigravity entry from a previous setup. Claude Code's host
|
||||
// (api.anthropic.com) is NOT present.
|
||||
return "127.0.0.1 localhost\n127.0.0.1 daily-cloudcode-pa.googleapis.com\n";
|
||||
}
|
||||
return realReadFileSync(p, enc);
|
||||
});
|
||||
|
||||
const { getMitmStatus } = await import("../../src/mitm/manager.ts?probe=8466-positive");
|
||||
const status = await getMitmStatus("claude-code");
|
||||
|
||||
assert.equal(
|
||||
status.dnsConfigured,
|
||||
false,
|
||||
"dnsConfigured must be false when the agent being diagnosed (Claude Code) has no host spoofed, even if a leftover Antigravity host is present"
|
||||
);
|
||||
});
|
||||
|
||||
test("no-agentId call sites keep legacy Antigravity-only behavior unchanged", async () => {
|
||||
const realReadFileSync = fs.readFileSync.bind(fs);
|
||||
mock.method(fs, "readFileSync", (p: string, enc?: BufferEncoding) => {
|
||||
if (p === "/etc/hosts") {
|
||||
// Claude Code host spoofed, but NO Antigravity host present. A caller
|
||||
// that omits agentId (state/route.ts, server/route.ts, settings/mitm,
|
||||
// cli-tools/antigravity-mitm) must still evaluate the legacy
|
||||
// Antigravity-only regex, so this should remain false.
|
||||
return "127.0.0.1 localhost\n127.0.0.1 api.anthropic.com\n::1 api.anthropic.com\n";
|
||||
}
|
||||
return realReadFileSync(p, enc);
|
||||
});
|
||||
|
||||
const { getMitmStatus } = await import("../../src/mitm/manager.ts?probe=8466-legacy");
|
||||
const status = await getMitmStatus();
|
||||
|
||||
assert.equal(
|
||||
status.dnsConfigured,
|
||||
false,
|
||||
"callers that omit agentId must keep the legacy Antigravity-only check"
|
||||
);
|
||||
});
|
||||
|
||||
test("diagnose route: threads ?agentId= query param through to getMitmStatus", async () => {
|
||||
const realReadFileSync = fs.readFileSync.bind(fs);
|
||||
mock.method(fs, "readFileSync", (p: string, enc?: BufferEncoding) => {
|
||||
if (p === "/etc/hosts") {
|
||||
return "127.0.0.1 localhost\n127.0.0.1 api.anthropic.com\n::1 api.anthropic.com\n";
|
||||
}
|
||||
return realReadFileSync(p, enc);
|
||||
});
|
||||
|
||||
const { GET } = await import(
|
||||
"../../src/app/api/tools/agent-bridge/diagnose/route.ts?probe=8466-route"
|
||||
);
|
||||
const res = await GET(
|
||||
new Request("http://localhost/api/tools/agent-bridge/diagnose?agentId=claude-code")
|
||||
);
|
||||
const body = (await res.json()) as {
|
||||
checks: Array<{ name: string; ok: boolean }>;
|
||||
};
|
||||
const dnsCheck = body.checks.find((c) => c.name === "dns-configured");
|
||||
|
||||
assert.ok(dnsCheck, "expected a dns-configured check in the diagnostics report");
|
||||
assert.equal(
|
||||
dnsCheck?.ok,
|
||||
true,
|
||||
"diagnose route must pass agentId through to getMitmStatus so dns-configured reflects the diagnosed agent's hosts"
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user