Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,15 @@ jobs:
pkg_target: node22-linux-x64
binary_name: playwright-runner
ps_binary_name: personal-server
- platform: windows-latest
# Pinned to windows-2022 (not windows-latest) because that runner image's Visual
# Studio install path changed to a bare "\18\" (VS 2026 naming) that node-gyp's
# bundled-with-npm version can't parse ("unknown version \"undefined\"" when
# building better-sqlite3). npm_config_node_gyp does not work around this: npm's
# run-script hardcodes its own bundled node-gyp for automatic native rebuilds
# during `npm ci`, ignoring that config (npm/cli#2839). Unpin once actions/setup-node's
# Node 22 LTS bundles npm>=11.6.3 (node-gyp>=12.1.0, which added VS2026 detection).
# TODO(2026-09-02): revisit and unpin — see PDP-Connect/data-connect#47.
- platform: windows-2022
os_family: windows
target: x86_64-pc-windows-msvc
artifact_key: windows-x64
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion reference-implementation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
"test:seam:pr89": "node --import tsx ../scripts/test-scratch/run-command.ts -- node --import tsx scripts/run-pr89-seam.ts",
"test:seam:pr89:receipt": "node --import tsx ../scripts/test-scratch/run-command.ts -- node --test --import tsx scripts/check-pr89-seam-receipt.test.ts",
"test:semantic-multilingual-smoke": "PDPP_MULTILINGUAL_MINILM_SMOKE=1 node --import tsx ../scripts/test-scratch/run-command.ts -- node --test --test-timeout=240000 --test-name-pattern \"multilingual-minilm profile\" test/semantic-retrieval.test.ts",
"typecheck": "tsc --noEmit",
"typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit -p tsconfig.dom.json",
"verify": "pnpm typecheck && pnpm check"
},
"dependencies": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ export function createBrowserSurfaceLeaseSweepTimer(
options: BrowserSurfaceLeaseSweepTimerOptions
): BrowserSurfaceLeaseSweepTimer {
const { sweep, intervalMs, onSweepError } = options;
const setIntervalFn = options.setIntervalFn ?? setInterval;
const setIntervalFn: (callback: () => void, ms: number) => NodeJS.Timeout =
options.setIntervalFn ?? setInterval;
const clearIntervalFn = options.clearIntervalFn ?? clearInterval;
let timer: NodeJS.Timeout | null = null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ function unsafeAuthorityInput(value: unknown): StreamHealthAuthorityInput {
return value as StreamHealthAuthorityInput;
}

function response(body: unknown, status = 200, revision = REVISION) {
function response(body: unknown, status = 200, revision: string | null = REVISION) {
const text = typeof body === "string" ? body : JSON.stringify(body);
return {
headers: {
Expand Down Expand Up @@ -1425,7 +1425,7 @@ for (const accepted of ["deferred", "inventory_only"]) {
connection_health: {
state: "healthy",
axes: { coverage: accepted, freshness: "fresh", attention: "none", outbox: "idle" },
conditions: healthyConnection().connection_health.conditions,
conditions: (healthyConnection().connection_health as Json).conditions,
},
});
const result = evaluate(connection);
Expand All @@ -1447,7 +1447,7 @@ for (const accepted of ["unavailable", "unsupported"]) {
connection_health: {
state: "degraded",
axes: { coverage: accepted, freshness: "fresh", attention: "none", outbox: "idle" },
conditions: healthyConnection().connection_health.conditions,
conditions: (healthyConnection().connection_health as Json).conditions,
},
rendered_verdict: { pill: { tone: "amber", label: "Some records stuck" } },
});
Expand All @@ -1469,7 +1469,7 @@ test("a genuinely degrading coverage axis still disagrees with an entirely compl
connection_health: {
state: "degraded",
axes: { coverage: "retryable_gap", freshness: "fresh", attention: "none", outbox: "idle" },
conditions: healthyConnection().connection_health.conditions,
conditions: (healthyConnection().connection_health as Json).conditions,
},
rendered_verdict: { pill: { tone: "amber", label: "Some records stuck" } },
});
Expand Down
19 changes: 19 additions & 0 deletions reference-implementation/scripts/stream-health-audit/live.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,15 @@ interface OwnerAuthForStreamHealth {
const OWNER_DOM_RESOLUTION_TIMEOUT_MS = 15_000;
const OWNER_DOM_PAGE_BUDGET = 512;

// This program deliberately runs without "DOM" lib (its ambient fetch/Headers
// types must stay the undici-types-backed ones, not the browser spec's), so
// `document` isn't ambiently available -- but OwnerSourcesBrowserPage's
// `waitForFunction` predicate below is serialized and actually executed
// inside the browser page it drives (a real Playwright page in production;
// see launchOwnerSourcesBrowser), where a real `document` exists. Declared
// locally, narrowly, to the one method this file calls on it.
declare const document: { querySelector: (selector: string) => unknown };

interface BrowserNavigationResponse {
headers?: () => Record<string, string>;
}
Expand Down Expand Up @@ -630,6 +639,16 @@ export async function runLiveStreamHealthAuthority({
headers: { accept: "application/json", ...auth.header },
onRevision: (revision) => summaryRevisions.push(revision),
});
// auth.header.cookie is genuinely always set here: the `!auth.supported`
// guard above already returned for every mode ("bearer", "none") that
// doesn't populate a cookie header, leaving only "cookie" and a
// successful "password-session", both of which set `header: { cookie }`
// in resolveOwnerAuthForStreamHealth. TypeScript can't see that
// cross-branch guarantee through header's plain `Record<string, string>`
// shape, so it's asserted explicitly rather than widening the type.
if (!auth.header.cookie) {
throw new Error(`resolveOwnerAuthForStreamHealth returned mode ${auth.mode} without a cookie header`);
}
const domResult = await fetchOwnerSourcesDom({
base,
browserFactory,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1006,7 +1006,7 @@ test("the dedicated scratch lifecycle leaf removes every inherited capability va
const missingBoundary = structuredClone(localManifest);
const [missingSuite] = missingBoundary.suites;
assert.ok(missingSuite);
missingSuite.environment_unset = undefined;
delete missingSuite.environment_unset;
await writeFile(join(root, "test-accounting.manifest.json"), `${JSON.stringify(missingBoundary)}\n`);
await assert.rejects(
readManifest(join(root, "test-accounting.manifest.json"), { root }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/

import { strict as assert } from "node:assert/strict";
import { readFileSync } from "node:fs";
import { existsSync, readFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { test } from "node:test";
import { fileURLToPath } from "node:url";
Expand Down Expand Up @@ -155,24 +155,49 @@ function assertNoViolations(violations: { file: string; method: string }[]): voi
}

test("streaming code only sends allowlisted CDP methods", () => {
// @opendatalabs/remote-surface is an OPTIONAL dependency (see
// runtime/browser-surface/remote-surface-optional.ts) requiring Node >=24;
// this test suite's own CI job runs on Node 22.23.1, where npm silently
// skips installing it. Inspect its CDP backend when present, but both the
// allowlist guarantee and the presence assertions below must still hold
// for our own adapter/companion/registry code when it is absent.
const remoteSurfaceCdpBackend = join(
__dirname,
"../../node_modules/@opendatalabs/remote-surface/dist/backends/cdp/backend.js"
);
const remoteSurfaceInstalled = existsSync(remoteSurfaceCdpBackend);
const files = [
"cdp-adapter.ts",
"cdp-companion.ts",
"run-target-registry.ts",
join(__dirname, "../../node_modules/@opendatalabs/remote-surface/dist/backends/cdp/backend.js"),
...(remoteSurfaceInstalled ? [remoteSurfaceCdpBackend] : []),
];

const { allMethods, violations } = inspectStreamingFiles(files);

// If any violations found, report them clearly
assertNoViolations(violations);

// Assert that at least some basic Page/Input methods are present
// (so we know streaming code actually exists and the test is working)
assert.ok(allMethods.has("Page.enable"), "Expected Page.enable to be present in streaming code");
assert.ok(allMethods.has("Page.startScreencast"), "Expected Page.startScreencast to be present in streaming code");
// Assert that basic Page/Input methods are present, so a gutted or
// relocated streaming layer fails here instead of passing an allowlist
// check that has nothing left to check. `assertNoViolations` above is
// vacuously true when no methods are extracted at all, so these presence
// assertions are the only thing keeping the suite honest.
//
// Page.startScreencast and Input.dispatchMouseEvent are sent by this
// repo's own cdp-companion.ts, so they must hold unconditionally --
// including on the Node 22.23.1 CI job where the optional package is
// absent. Only Page.enable lives solely in @opendatalabs/remote-surface's
// CDP backend, so only that one is conditional.
assert.ok(
allMethods.has("Page.startScreencast"),
"Expected Page.startScreencast to be present in streaming code"
);
assert.ok(
allMethods.has("Input.dispatchMouseEvent"),
"Expected Input.dispatchMouseEvent to be present in streaming code"
);
if (remoteSurfaceInstalled) {
assert.ok(allMethods.has("Page.enable"), "Expected Page.enable to be present in streaming code");
}
});
12 changes: 6 additions & 6 deletions reference-implementation/test/cli-ref-wrapper.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ test("wrapper delegates public CLI namespaces (including ref) to @pdpp/cli", ()
// ---- integration: spawn the wrapper for help-only smoke ---------------------

test("pdpp --help mentions delegation to @pdpp/cli and ref namespace", async () => {
const { stdout, stderr } = await execFile(process.execPath, [CLI_PATH, "--help"]);
const { stdout, stderr } = await execFile(process.execPath, ["--import", "tsx", CLI_PATH, "--help"]);
assert.equal(stderr, "");
// biome-ignore lint/performance/useTopLevelRegex: test assertion patterns remain colocated with the assertion they explain.
assert.match(stdout, /Public commands delegated/);
Expand All @@ -57,7 +57,7 @@ test("pdpp --help mentions delegation to @pdpp/cli and ref namespace", async ()
});

test("pdpp ref --help is served by the @pdpp/cli delegate and advertises login", async () => {
const { stdout } = await execFile(process.execPath, [CLI_PATH, "ref", "--help"]);
const { stdout } = await execFile(process.execPath, ["--import", "tsx", CLI_PATH, "ref", "--help"]);
// biome-ignore lint/performance/useTopLevelRegex: test assertion patterns remain colocated with the assertion they explain.
assert.match(stdout, /ref login/);
// biome-ignore lint/performance/useTopLevelRegex: test assertion patterns remain colocated with the assertion they explain.
Expand All @@ -69,7 +69,7 @@ test("pdpp ref --help is served by the @pdpp/cli delegate and advertises login",
});

test("workspace package entrypoint runs through the real CLI guard", async () => {
const { stdout, stderr } = await execFile(process.execPath, [CLI_PACKAGE_LINK_PATH, "ref", "--help"]);
const { stdout, stderr } = await execFile(process.execPath, ["--import", "tsx", CLI_PACKAGE_LINK_PATH, "ref", "--help"]);
assert.equal(stderr, "");
// biome-ignore lint/performance/useTopLevelRegex: test assertion patterns remain colocated with the assertion they explain.
assert.match(stdout, /ref login/);
Expand All @@ -80,7 +80,7 @@ test("workspace package entrypoint runs through the real CLI guard", async () =>
test('pdpp run timeline (legacy alias) emits a deprecation hint pointing at "pdpp ref run timeline"', async () => {
// Missing --as-url ensures the command exits non-zero quickly without
// requiring a live reference server.
const result = await execFile(process.execPath, [CLI_PATH, "run", "timeline", "run-abc"]).catch((e) => e);
const result = await execFile(process.execPath, ["--import", "tsx", CLI_PATH, "run", "timeline", "run-abc"]).catch((e) => e);

const stderr = result.stderr || "";
// biome-ignore lint/performance/useTopLevelRegex: test assertion patterns remain colocated with the assertion they explain.
Expand All @@ -90,7 +90,7 @@ test('pdpp run timeline (legacy alias) emits a deprecation hint pointing at "pdp
});

test("pdpp grant timeline (legacy alias) emits a deprecation hint", async () => {
const result = await execFile(process.execPath, [CLI_PATH, "grant", "timeline", "grant-x"]).catch((e) => e);
const result = await execFile(process.execPath, ["--import", "tsx", CLI_PATH, "grant", "timeline", "grant-x"]).catch((e) => e);

const stderr = result.stderr || "";
// biome-ignore lint/performance/useTopLevelRegex: test assertion patterns remain colocated with the assertion they explain.
Expand All @@ -100,7 +100,7 @@ test("pdpp grant timeline (legacy alias) emits a deprecation hint", async () =>
});

test("pdpp trace show (legacy alias) emits a deprecation hint", async () => {
const result = await execFile(process.execPath, [CLI_PATH, "trace", "show", "trace-y"]).catch((e) => e);
const result = await execFile(process.execPath, ["--import", "tsx", CLI_PATH, "trace", "show", "trace-y"]).catch((e) => e);

const stderr = result.stderr || "";
// biome-ignore lint/performance/useTopLevelRegex: test assertion patterns remain colocated with the assertion they explain.
Expand Down
12 changes: 9 additions & 3 deletions reference-implementation/test/cli.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1051,7 +1051,7 @@ interface ExecFileError extends Error {
}

async function runCli(args: readonly string[], env: Record<string, string> = {}) {
const { stdout, stderr } = await execFile(process.execPath, [CLI_PATH, ...args], {
const { stdout, stderr } = await execFile(process.execPath, ["--import", "tsx", CLI_PATH, ...args], {
cwd: REFERENCE_IMPL_DIR,
env: {
...process.env,
Expand Down Expand Up @@ -1083,7 +1083,7 @@ async function runCli(args: readonly string[], env: Record<string, string> = {})

async function runCliExpectFailure(args: readonly string[], env: Record<string, string> = {}) {
try {
await execFile(process.execPath, [CLI_PATH, ...args], {
await execFile(process.execPath, ["--import", "tsx", CLI_PATH, ...args], {
cwd: REFERENCE_IMPL_DIR,
env: {
...process.env,
Expand Down Expand Up @@ -1336,6 +1336,8 @@ test("PDPP CLI smoke", async (t) => {
const proc = spawn(
process.execPath,
[
"--import",
"tsx",
CLI_PATH,
"auth",
"login",
Expand Down Expand Up @@ -1423,6 +1425,8 @@ test("PDPP CLI smoke", async (t) => {
const proc = spawn(
process.execPath,
[
"--import",
"tsx",
CLI_PATH,
"auth",
"login",
Expand Down Expand Up @@ -3723,6 +3727,8 @@ test("PDPP CLI smoke", async (t) => {
const proc = spawn(
process.execPath,
[
"--import",
"tsx",
CLI_PATH,
"auth",
"login",
Expand Down Expand Up @@ -8925,7 +8931,7 @@ test("legacy operator aliases emit a deprecation hint pointing at `pdpp ref ...`
// round-trip.
const { stderr } = await execFile(
process.execPath,
[CLI_PATH, "trace", "show", "trc_nope", "--as-url", asUrl, "--format", "json"],
["--import", "tsx", CLI_PATH, "trace", "show", "trc_nope", "--as-url", asUrl, "--format", "json"],
{
cwd: REFERENCE_IMPL_DIR,
env: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,25 @@
// SPDX-License-Identifier: Apache-2.0

/**
* Release-boundary tests for the two data-connect packages consumed by PDPP.
* Release-boundary test for the two data-connect packages consumed by PDPP.
*
* The source repositories have independent release workflows. These tests
* keep the installed consumer contract honest: protocol 0.0.2 remains
* The source repositories have independent release workflows. This test
* keeps the installed consumer contract honest: protocol 0.0.2 remains
* parseable without being advertised by the withdrawn device runtime, while a
* connector that declares STREAM_EVIDENCE is rejected before it can spawn.
*
* A second test used to live here asserting PDPP's OWN vendored tarball pins
* (hashes, pnpm-lock.yaml entries, packages/polyfill-connectors/package.json)
* via scripts/check-pdpp-vendored-package-pins.ts. That checker and its
* fixture-based unit test both live in PDP-Connect/pdpp, which is the only
* repo with the pnpm-lock.yaml/vendor/SHA256SUMS layout it checks against;
* this repo has neither. Re-derive from PDP-Connect/pdpp's
* scripts/check-pdpp-vendored-package-pins.test.ts if coverage from this
* side is ever needed.
*/

import assert from "node:assert/strict";
import test from "node:test";
import { fileURLToPath } from "node:url";

import { verifyPdppVendoredPackagePins } from "../../scripts/check-pdpp-vendored-package-pins.ts";

test("PDPP consumes both reviewed data-connect package-release 1.0.0 artifacts at exact hashes", () => {
verifyPdppVendoredPackagePins(fileURLToPath(new URL("../../", import.meta.url)));
});

test("withdrawn device runtime rejects STREAM_EVIDENCE while protocol 0.0.2 still validates it", async () => {
const runtime = await import("@pdpp/collector-runtime");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import assert from "node:assert/strict";
import test from "node:test";
// biome-ignore lint/correctness/noUnresolvedImports: remote-surface 1.5.1 is installed in the reference implementation workspace; the repository-root checker does not resolve that local package.
import { createRemoteSurfaceSession } from "@opendatalabs/remote-surface/client";
// @ts-expect-error jsdom is a test-only dev dependency without declarations in the reference tsconfig.
// biome-ignore lint/correctness/noUnresolvedImports: jsdom is installed for this DOM-only session test.
import { JSDOM } from "jsdom";

Expand Down
20 changes: 20 additions & 0 deletions reference-implementation/tsconfig.dom.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
// Typecheck program for the one test file that legitimately needs the DOM
// lib. `tsconfig.json` excludes it because TypeScript applies `lib` per
// program, not per file: pulling "DOM" in there would replace every other
// file's ambient Headers/RequestInit/ReadableStream with the DOM versions
// instead of the undici-types-backed ones the runtime actually provides.
//
// Without this second program the excluded file would run under Node's
// test runner while getting no `tsc` coverage at all, so a type error in
// it could not fail any check. Run both programs to cover the whole tree:
// tsc --noEmit -p tsconfig.json
// tsc --noEmit -p tsconfig.dom.json
"extends": "./tsconfig.json",
"compilerOptions": {
"lib": ["ES2023", "DOM"],
"types": ["node"]
},
"include": ["test/run-interaction-stream-remote-surface-session.test.ts"],
"exclude": ["node_modules"]
}
13 changes: 12 additions & 1 deletion reference-implementation/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,16 @@
"examples/**/*.ts",
"examples/**/*.js"
],
"exclude": ["node_modules"]
// run-interaction-stream-remote-surface-session.test.ts drives
// @opendatalabs/remote-surface/client's real HTMLElement/HTMLCanvasElement
// API against a jsdom fake, so it genuinely needs "DOM" lib -- unlike
// every other file here, which deliberately runs without it (this
// program's ambient Headers/RequestInit/ReadableStream must stay the
// undici-types-backed ones). Node's own test runner executes this file
// via type-stripping regardless (this program only ever runs `tsc
// --noEmit`, never emits), so excluding it from tsc's program doesn't
// affect what actually runs -- it only stops its DOM-only types from
// being force-checked (and, previously, from leaking DOM lib into every
// other file's ambient globals) under this tsconfig.
"exclude": ["node_modules", "test/run-interaction-stream-remote-surface-session.test.ts"]
}
Loading
Loading