Skip to content

Commit 6a329d5

Browse files
committed
fix: correlate redacted adaptive policy errors
1 parent ada25cf commit 6a329d5

3 files changed

Lines changed: 28 additions & 6 deletions

File tree

packages/runtime-playground/src/browser-adaptive-explorer.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { stableJson } from "@automattic/wp-codebox-core/internals"
1919
import type { Frame, Page } from "playwright"
2020

2121
import { discoverBrowserActionCorpusDescriptors } from "./browser-action-discovery.js"
22+
import { redactBrowserNetworkUrl } from "./browser-metrics.js"
2223
import { browserPreviewNetworkDecision, type BrowserPreviewNavigationScope, type BrowserPreviewNetworkPolicy } from "./browser-preview-routing.js"
2324

2425
interface AdaptiveObservationSources {
@@ -595,7 +596,7 @@ function adaptiveOracleEvidence(consoleRecords: Record<string, unknown>[], netwo
595596
const message = recordMessage(record)
596597
const locationUrl = objectRecord(record.location).url
597598
const match = classifiedFailures.findIndex((failure, index) => unmatchedFailures.has(index)
598-
&& (typeof locationUrl === "string" && locationUrl ? failure.url === locationUrl && failureTokenMatches(message, failure.failure) : failureTokenMatches(message, failure.failure)))
599+
&& (typeof locationUrl === "string" && locationUrl ? networkUrlsMatch(failure.url, locationUrl) && failureTokenMatches(message, failure.failure) : failureTokenMatches(message, failure.failure)))
599600
if (match < 0) return [message]
600601
unmatchedFailures.delete(match)
601602
const failure = classifiedFailures[match]!
@@ -643,6 +644,10 @@ function failureTokenMatches(message: string, failure: string | undefined): bool
643644
return Boolean(token && message.toUpperCase().includes(token.toUpperCase()))
644645
}
645646

647+
function networkUrlsMatch(networkUrl: string, consoleUrl: string): boolean {
648+
return redactBrowserNetworkUrl(networkUrl) === redactBrowserNetworkUrl(consoleUrl)
649+
}
650+
646651
function networkFailureOracleMessage(failure: BrowserAdaptiveNetworkFailure): string {
647652
return stableJson({ type: "requestfailed", url: failure.url, failure: failure.failure, urlClassification: failure.urlClassification, policyDecision: failure.policyDecision, policyReason: failure.policyReason })
648653
}

packages/runtime-playground/src/browser-metrics.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ export function serializeBrowserRequestFailure(request: Request, timestamp = now
608608
}
609609
}
610610

611-
function redactBrowserNetworkUrl(url: string): string {
611+
export function redactBrowserNetworkUrl(url: string): string {
612612
return redactString(url, { redactAllUrlQueryValues: true, redactUrlHash: true, redactQueryAssignments: true })
613613
}
614614

tests/browser-adaptive-exploration.test.ts

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -500,7 +500,7 @@ test("declared network-policy blocks remain structured evidence without becoming
500500
assert.equal(run.result.summary.errors, 0)
501501
assert(transition?.observations.consoleErrors.some((message) => message.includes("ERR_BLOCKED_BY_CLIENT")), "raw browser console evidence remains available")
502502
assert.deepEqual(transition?.observations.networkFailures, [{
503-
url: "http://assets.example.invalid/tile.png",
503+
url: "http://assets.example.invalid/tile.png?cache=[redacted]",
504504
host: "assets.example.invalid",
505505
urlClassification: "external",
506506
policyDecision: "blocked",
@@ -563,6 +563,21 @@ test("same-URL product errors require a matching failure token before policy cor
563563
assert.equal(finding.result.transitions[0]?.observations.networkFailureSummary?.policyBlocks, 1)
564564
})
565565

566+
test("redacted policy-block URLs correlate without hiding independent console errors across browser contexts", async () => {
567+
for (const environment of ["desktop", "mobile"] as const) {
568+
const evidence = await runNetworkOracleFixture("block", "blocked", {}, false, false, environment)
569+
assert.equal(evidence.result.findings.length, 0, environment)
570+
assert.deepEqual(evidence.result.transitions[0]?.observations.oracleFingerprints, [], environment)
571+
assert.equal(evidence.result.transitions[0]?.observations.networkFailureSummary?.policyBlocks, 1, environment)
572+
573+
const independent = await runNetworkOracleFixture("block", "blocked", {}, false, true, environment)
574+
const productFingerprint = browserAdaptiveDigest("oracle", { environmentDigest: independent.contract.environmentDigest, value: "same-URL product defect" })
575+
assert.deepEqual(independent.result.transitions[0]?.observations.oracleFingerprints, [productFingerprint], environment)
576+
assert.equal(independent.result.findings[0]?.fingerprint, productFingerprint, environment)
577+
assert.equal(independent.result.transitions[0]?.observations.networkFailureSummary?.oracleFindings, 0, environment)
578+
}
579+
})
580+
566581
test("allow and record policies do not explain unexpected same-origin request failures", async () => {
567582
for (const mode of ["allow", "record"] as const) {
568583
const run = await runNetworkOracleFixture(mode, "unexpected")
@@ -737,7 +752,7 @@ async function runRoutedFixture(topology: ReturnType<typeof browserPreviewTopolo
737752
}
738753
}
739754

740-
async function runNetworkOracleFixture(mode: "allow" | "block" | "record", behavior: "blocked" | "unexpected" | "mixed" | "exception", input: Record<string, unknown> = {}, urlLessConsole = false, sameUrlProductError = false) {
755+
async function runNetworkOracleFixture(mode: "allow" | "block" | "record", behavior: "blocked" | "unexpected" | "mixed" | "exception", input: Record<string, unknown> = {}, urlLessConsole = false, sameUrlProductError = false, environment: "desktop" | "mobile" = "desktop") {
741756
const server = createServer((request, response) => {
742757
const path = new URL(request.url ?? "/", "http://preview.invalid").pathname
743758
if (path === "/failed.png") {
@@ -748,7 +763,7 @@ async function runNetworkOracleFixture(mode: "allow" | "block" | "record", behav
748763
response.end(`<!doctype html><style>button{display:block;width:180px;height:30px}</style><button id="trigger">Trigger</button><script>
749764
document.querySelector('#trigger').addEventListener('click', () => {
750765
const load = (src) => { const image = document.createElement('img'); image.src = src; document.body.append(image); };
751-
${behavior === "blocked" || behavior === "mixed" ? "load('http://assets.example.invalid/tile.png');" : ""}
766+
${behavior === "blocked" || behavior === "mixed" ? "load('http://assets.example.invalid/tile.png?cache=fixture-secret');" : ""}
752767
${behavior === "unexpected" || behavior === "mixed" ? "load('/failed.png');" : ""}
753768
${behavior === "exception" ? "setTimeout(() => { throw new Error('fixture page exception'); }, 0);" : ""}
754769
});
@@ -757,7 +772,8 @@ async function runNetworkOracleFixture(mode: "allow" | "block" | "record", behav
757772
const startUrl = await listenLocalHttpServer(server)
758773
const topology = browserPreviewTopology([`network-policy=${mode}`], undefined, startUrl)
759774
const browser = await chromium.launch({ headless: true })
760-
const context = await browser.newContext()
775+
const browserEnvironment = environment === "mobile" ? { hasTouch: true, isMobile: true, viewport: { height: 844, width: 390 } } : undefined
776+
const context = await browser.newContext(browserEnvironment)
761777
await routeBrowserPreviewContextNetwork(context, topology.networkPolicy, startUrl)
762778
const page = await context.newPage()
763779
const consoleMessages: Record<string, unknown>[] = []
@@ -779,6 +795,7 @@ async function runNetworkOracleFixture(mode: "allow" | "block" | "record", behav
779795
actionFamilies: ["click"],
780796
budgets: { maxActions: 1, maxStates: 2, maxTransitions: 1, maxDurationMs: 10_000 },
781797
stabilization: { pollIntervalMs: 25, quietWindowMs: 100, maxWaitMs: 1_500, maxMutationRecords: 20 },
798+
...(browserEnvironment ? { environment: browserEnvironment } : {}),
782799
...input,
783800
})
784801
try {

0 commit comments

Comments
 (0)