mirror of
https://github.com/morluto/rea.git
synced 2026-11-07 05:56:19 -10:00
fix(browser): keep opaque cookie partitions unaligned (#7203)
Keep cookies with opaque partitions distinct from unpartitioned identities while retaining value hashes and incomplete comparison coverage. Preserve known partition hashes and use the existing shared CLI/MCP fingerprint owner. Validated with 63 source and 57 storage boundary tests, builds/static checks, and real Chrome156 CLI/MCP controls. Live opaque-cookie emission was not reproduced; its protocol regression is explicit. Hosted CI's unrelated failures were reproduced against exact main a905a71e3; seven fail-fast-cancelled shards remain unverified; Greptile's sole existing-main finding was scoped and documented. Human readiness remains unasserted; bypass authorized by the requester. Co-authored-by: gensokyo-dev <[email protected]>
This commit is contained in:
1 parent
f53c256886
commit
6749bd090d
2 files changed
+126
-1
No files matched your search
@@ -1,6 +1,13 @@
|
||||
import { expect, it } from "vitest";
|
||||
|
||||
import { inspectWebPageInputSchema } from "../domain/browserObservation.js";
|
||||
import type { WebPageInspection } from "../domain/browserObservationSchemas.js";
|
||||
import {
|
||||
browserCaptureComparisonInputSchema,
|
||||
compareBrowserCaptures,
|
||||
} from "../domain/browserCaptureComparison.js";
|
||||
import { webCaptureDiffSchema } from "../domain/webCaptureDiffSchemas.js";
|
||||
import { passiveNetworkCapture } from "../../tests/fixtures/passiveNetworkCapture.js";
|
||||
import { captureStorage } from "./CdpCaptureStorage.js";
|
||||
import { CdpCommandRejection } from "./CdpCommandRejection.js";
|
||||
import type { CdpConnection } from "./CdpConnection.js";
|
||||
@@ -243,3 +250,115 @@ it.each(["indexed_db", "cache"] as const)(
|
||||
expect(value.fingerprints_complete).toBe(false);
|
||||
},
|
||||
);
|
||||
|
||||
const cookieBase = {
|
||||
name: "fixture",
|
||||
value: "same",
|
||||
domain: "example.test",
|
||||
path: "/",
|
||||
expires: -1,
|
||||
size: 11,
|
||||
httpOnly: false,
|
||||
secure: false,
|
||||
session: true,
|
||||
sameSite: "Lax",
|
||||
};
|
||||
|
||||
const captureCookies = async (
|
||||
cookies: readonly Record<string, unknown>[],
|
||||
): Promise<WebPageInspection["storage"]> => {
|
||||
const replies: Record<string, unknown> = {
|
||||
"Storage.getUsageAndQuota": { usage: 0, quota: 1000 },
|
||||
"DOMStorage.getDOMStorageItems": { entries: [] },
|
||||
"IndexedDB.requestDatabaseNames": { databaseNames: [] },
|
||||
"CacheStorage.requestCacheNames": { caches: [] },
|
||||
"Network.getCookies": { cookies },
|
||||
};
|
||||
const connection = {
|
||||
async send(method: string): Promise<unknown> {
|
||||
if (!(method in replies)) throw new Error(method);
|
||||
return replies[method];
|
||||
},
|
||||
} as unknown as CdpConnection;
|
||||
const { value } = await captureStorage(
|
||||
{
|
||||
connection,
|
||||
sessionId: undefined,
|
||||
input: inspectWebPageInputSchema.parse({
|
||||
cdp_endpoint: "http://127.0.0.1:9222",
|
||||
target_id: "fixture-page",
|
||||
include_storage_keys: true,
|
||||
include_storage_fingerprints: true,
|
||||
}),
|
||||
},
|
||||
"https://example.test/",
|
||||
[],
|
||||
);
|
||||
return value;
|
||||
};
|
||||
|
||||
const storageComparison = (
|
||||
before: WebPageInspection["storage"],
|
||||
after: WebPageInspection["storage"],
|
||||
) => {
|
||||
const inspection = (storage: WebPageInspection["storage"]) => {
|
||||
const capture = passiveNetworkCapture();
|
||||
capture.storage = storage;
|
||||
return capture;
|
||||
};
|
||||
return webCaptureDiffSchema.parse(
|
||||
compareBrowserCaptures(
|
||||
browserCaptureComparisonInputSchema.parse({
|
||||
before: { inspection: inspection(before) },
|
||||
after: { inspection: inspection(after) },
|
||||
}),
|
||||
),
|
||||
).dimensions.storage;
|
||||
};
|
||||
|
||||
it("keeps an opaque cookie partition unknown without dropping its value", async () => {
|
||||
const plain = await captureCookies([cookieBase]);
|
||||
const opaque = await captureCookies([
|
||||
{ ...cookieBase, partitionKeyOpaque: true },
|
||||
]);
|
||||
const known = await captureCookies([
|
||||
{
|
||||
...cookieBase,
|
||||
partitionKey: {
|
||||
topLevelSite: "https://top.example.test",
|
||||
hasCrossSiteAncestor: false,
|
||||
},
|
||||
partitionKeyOpaque: false,
|
||||
},
|
||||
]);
|
||||
const cookieFingerprint = (storage: WebPageInspection["storage"]) => {
|
||||
const fingerprint = storage.content_fingerprints.find(
|
||||
(item) => item.scope === "cookie",
|
||||
);
|
||||
expect(fingerprint).toBeDefined();
|
||||
return fingerprint!;
|
||||
};
|
||||
const plainCookie = cookieFingerprint(plain);
|
||||
const opaqueCookie = cookieFingerprint(opaque);
|
||||
const knownCookie = cookieFingerprint(known);
|
||||
expect(opaque.fingerprints_complete).toBe(false);
|
||||
expect(opaqueCookie).toMatchObject({
|
||||
complete: false,
|
||||
value_sha256: plainCookie.value_sha256,
|
||||
});
|
||||
expect(opaqueCookie.identity_sha256).not.toBe(plainCookie.identity_sha256);
|
||||
expect(known.fingerprints_complete).toBe(true);
|
||||
expect(knownCookie).toMatchObject({ complete: true });
|
||||
expect(knownCookie.identity_sha256).not.toBe(plainCookie.identity_sha256);
|
||||
expect(storageComparison(plain, opaque)).toMatchObject({
|
||||
status: "unknown",
|
||||
total_changes: 0,
|
||||
changes: [],
|
||||
});
|
||||
expect(storageComparison(opaque, opaque)).toMatchObject({
|
||||
status: "unknown",
|
||||
total_changes: 0,
|
||||
changes: [],
|
||||
});
|
||||
expect(storageComparison(plain, known).status).toBe("changed");
|
||||
});
|
||||
@@ -148,6 +148,11 @@ const addCookies = async (
|
||||
run.state.complete = false;
|
||||
continue;
|
||||
}
|
||||
// CDP Cookie.partitionKeyOpaque means the partition exists but is not
|
||||
// serializable. A missing partitionKey means unpartitioned, so hashing
|
||||
// that absence would align an unresolved partition with a different cookie.
|
||||
// https://chromedevtools.github.io/devtools-protocol/tot/Network/#type-Cookie
|
||||
const partitionOpaque = cookie.partitionKeyOpaque === true;
|
||||
addFingerprint(run.state, {
|
||||
scope: "cookie",
|
||||
identity: {
|
||||
@@ -155,9 +160,10 @@ const addCookies = async (
|
||||
path,
|
||||
name,
|
||||
partition_key: cookie.partitionKey ?? null,
|
||||
...(partitionOpaque ? { partition_opaque: true } : {}),
|
||||
},
|
||||
value,
|
||||
complete: cookie.partitionKeyOpaque !== true,
|
||||
complete: !partitionOpaque,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Reference in new issue
Block a user