Skip to content

Commit 2e9c99d

Browse files
juliusmarmingecodex
andcommitted
[codex] Redact agent awareness relay diagnostics (#3410)
Co-authored-by: codex <codex@users.noreply.github.com>
1 parent 17ae1bd commit 2e9c99d

2 files changed

Lines changed: 91 additions & 7 deletions

File tree

apps/server/src/relay/AgentAwarenessRelay.test.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { CommandId, ProviderInstanceId } from "@t3tools/contracts";
2020
import { RelayClientTracer } from "@t3tools/shared/relayTracing";
2121
import { RELAY_ACTIVITY_PUBLISH_TYP, verifyRelayJwt } from "@t3tools/shared/relayJwt";
2222
import { describe, expect, it } from "@effect/vitest";
23+
import * as Cause from "effect/Cause";
2324
import * as Deferred from "effect/Deferred";
2425
import * as Effect from "effect/Effect";
2526
import * as Layer from "effect/Layer";
@@ -98,6 +99,50 @@ function makeMemorySecretStore() {
9899
}
99100

100101
describe.sequential("signRelayAgentActivityPublishProof", () => {
102+
it("redacts relay URL secrets from log attributes", () => {
103+
const relayUrl =
104+
"https://relay-user:relay-password@relay.example.test/private/path?token=relay-secret#fragment";
105+
const attributes = AgentAwarenessRelay.relayUrlLogAttributes(relayUrl);
106+
107+
expect(attributes).toEqual({
108+
relayUrlConfigured: true,
109+
relayUrlInputLength: relayUrl.length,
110+
relayUrlProtocol: "https:",
111+
relayUrlHostname: "relay.example.test",
112+
});
113+
const renderedAttributes = Object.values(attributes).join(" ");
114+
expect(renderedAttributes).not.toContain("relay-user");
115+
expect(renderedAttributes).not.toContain("relay-password");
116+
expect(renderedAttributes).not.toContain("private/path");
117+
expect(renderedAttributes).not.toContain("relay-secret");
118+
expect(renderedAttributes).not.toContain("fragment");
119+
});
120+
121+
it("summarizes publish causes without serializing nested failures or defects", () => {
122+
const privateFailureDetail = "private relay response body";
123+
const privateDefectDetail = "private relay defect detail";
124+
const cause = Cause.combine(
125+
Cause.fail({
126+
_tag: "RelayPublishError",
127+
cause: new Error(privateFailureDetail),
128+
detail: privateFailureDetail,
129+
}),
130+
Cause.die(new Error(privateDefectDetail)),
131+
);
132+
const attributes = AgentAwarenessRelay.relayPublishCauseLogAttributes(cause);
133+
134+
expect(attributes).toEqual({
135+
causeReasonCount: 2,
136+
causeFailureCount: 1,
137+
causeDefectCount: 1,
138+
causeInterruptionCount: 0,
139+
causeFailureTags: ["RelayPublishError"],
140+
});
141+
const renderedAttributes = Object.values(attributes).join(" ");
142+
expect(renderedAttributes).not.toContain(privateFailureDetail);
143+
expect(renderedAttributes).not.toContain(privateDefectDetail);
144+
});
145+
101146
it("distinguishes pending link credentials from disabled publication", () => {
102147
expect(
103148
AgentAwarenessRelay.resolveAgentActivityPublishingStartupState({

apps/server/src/relay/AgentAwarenessRelay.ts

Lines changed: 46 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
RELAY_ACTIVITY_PUBLISH_TYP,
1919
signRelayJwt,
2020
} from "@t3tools/shared/relayJwt";
21+
import { getUrlDiagnostics } from "@t3tools/shared/urlDiagnostics";
2122
import * as Cause from "effect/Cause";
2223
import * as Context from "effect/Context";
2324
import * as Crypto from "effect/Crypto";
@@ -98,6 +99,44 @@ export function isAgentActivityPublishingEnabled(value: string | null): boolean
9899
return value === "true";
99100
}
100101

102+
export function relayUrlLogAttributes(relayUrl: string | undefined) {
103+
if (relayUrl === undefined) {
104+
return { relayUrlConfigured: false };
105+
}
106+
const diagnostics = getUrlDiagnostics(relayUrl);
107+
return {
108+
relayUrlConfigured: true,
109+
relayUrlInputLength: diagnostics.inputLength,
110+
...(diagnostics.protocol === undefined ? {} : { relayUrlProtocol: diagnostics.protocol }),
111+
...(diagnostics.hostname === undefined ? {} : { relayUrlHostname: diagnostics.hostname }),
112+
};
113+
}
114+
115+
export function relayPublishCauseLogAttributes(cause: Cause.Cause<unknown>) {
116+
const failureTags = cause.reasons.flatMap((reason) => {
117+
if (!Cause.isFailReason(reason)) {
118+
return [];
119+
}
120+
const error = reason.error;
121+
if (
122+
typeof error !== "object" ||
123+
error === null ||
124+
!("_tag" in error) ||
125+
typeof error._tag !== "string"
126+
) {
127+
return [];
128+
}
129+
return [error._tag];
130+
});
131+
return {
132+
causeReasonCount: cause.reasons.length,
133+
causeFailureCount: cause.reasons.filter(Cause.isFailReason).length,
134+
causeDefectCount: cause.reasons.filter(Cause.isDieReason).length,
135+
causeInterruptionCount: cause.reasons.filter(Cause.isInterruptReason).length,
136+
causeFailureTags: [...new Set(failureTags)],
137+
};
138+
}
139+
101140
export function resolveAgentActivityPublishingStartupState(input: {
102141
readonly relayConfigured: boolean;
103142
readonly publishEnabled: boolean;
@@ -417,12 +456,12 @@ export const make = Effect.gen(function* () {
417456

418457
const publishThread: AgentAwarenessRelay["Service"]["publishThread"] = (threadId) =>
419458
publishThreadUnsafe(threadId).pipe(
420-
Effect.catchCause((cause) => {
421-
return Effect.logWarning("agent activity publish failed", {
459+
Effect.catchCause((cause) =>
460+
Effect.logWarning("agent activity publish failed", {
422461
threadId,
423-
cause: Cause.pretty(cause),
424-
});
425-
}),
462+
...relayPublishCauseLogAttributes(cause),
463+
}),
464+
),
426465
Effect.withSpan("AgentAwarenessRelay.publishThread"),
427466
withRelayClientTracing,
428467
);
@@ -467,7 +506,7 @@ export const make = Effect.gen(function* () {
467506
if (logEnabledWhenReady) {
468507
const relayConfig = yield* readRelayConfig.pipe(Effect.orElseSucceed(() => null));
469508
yield* Effect.logInfo("agent activity publishing enabled after link reconciliation", {
470-
relayUrl: relayConfig?.url,
509+
...relayUrlLogAttributes(relayConfig?.url),
471510
});
472511
}
473512
return;
@@ -499,7 +538,7 @@ export const make = Effect.gen(function* () {
499538
break;
500539
case "enabled":
501540
yield* Effect.logInfo("agent activity publishing enabled", {
502-
relayUrl: relayConfig?.url,
541+
...relayUrlLogAttributes(relayConfig?.url),
503542
});
504543
break;
505544
}

0 commit comments

Comments
 (0)