85453da49f
CodeQL / Analyze (javascript-typescript) (push) Waiting to run
Docs / Validate docs (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
CodeQL / Analyze (python) (push) Waiting to run
Sync skills to ClawHub / Publish changed skills (push) Waiting to run
regression / regression-shards (style-16-prod style-9-prod style-17-prod iframe-render-compat variables-prod mp4-h265-sdr, shard-4) (push) Has been cancelled
regression / regression-shards (style-4-prod style-11-prod style-2-prod animejs-adapter typegpu-adapter parallel-capture-regression, shard-5) (push) Has been cancelled
regression / regression-shards (style-7-prod style-8-prod style-10-prod css-spinner-render-compat webm-transparency mp4-h264-sdr webm-vp9, shard-3) (push) Has been cancelled
regression / regression-shards (sub-composition-video style-18-prod raf-ball-render-compat font-variant-numeric sub-comp-t0 sub-comp-id-selector, shard-7) (push) Has been cancelled
Windows render verification / Detect changes (push) Has been cancelled
Windows render verification / Preflight (lint + format) (push) Has been cancelled
Windows render verification / Render on windows-latest (push) Has been cancelled
Windows render verification / Tests on windows-latest (push) Has been cancelled
CI / Detect changes (push) Has been cancelled
CI / Build (push) Has been cancelled
CI / Lint (push) Has been cancelled
CI / Fallow audit (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Typecheck (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Producer: integration tests (push) Has been cancelled
CI / Producer: unit tests (push) Has been cancelled
CI / File size check (push) Has been cancelled
CI / Test: skills (push) Has been cancelled
CI / Skills: manifest in sync (push) Has been cancelled
CI / CLI: npx shim (macos-latest) (push) Has been cancelled
CI / CLI: npx shim (ubuntu-latest) (push) Has been cancelled
CI / CLI: npx shim (windows-latest) (push) Has been cancelled
CI / SDK: unit + contract + smoke (push) Has been cancelled
CI / Test: runtime contract (push) Has been cancelled
CI / Studio: load smoke (push) Has been cancelled
CI / Smoke: global install (push) Has been cancelled
CI / CLI smoke (required) (push) Has been cancelled
CI / Semantic PR title (push) Has been cancelled
Player perf / Detect changes (push) Has been cancelled
Player perf / Preflight (lint + format) (push) Has been cancelled
Player perf / player-perf (push) Has been cancelled
Player perf / Perf: drift (push) Has been cancelled
Player perf / Perf: fps (push) Has been cancelled
Player perf / Perf: parity (push) Has been cancelled
Player perf / Perf: scrub (push) Has been cancelled
Player perf / Perf: load (push) Has been cancelled
preview-regression / Detect changes (push) Has been cancelled
preview-regression / Preflight (lint + format) (push) Has been cancelled
preview-regression / Preview parity (push) Has been cancelled
preview-regression / preview-regression (push) Has been cancelled
regression / regression (push) Has been cancelled
regression / Detect changes (push) Has been cancelled
regression / Preflight (lint + format) (push) Has been cancelled
regression / regression-shards (hdr-regression style-5-prod style-3-prod mov-prores, shard-1) (push) Has been cancelled
regression / regression-shards (overlay-montage-prod style-12-prod chat missing-host-comp-id png-sequence portrait-edge-bleed, shard-6) (push) Has been cancelled
regression / regression-shards (style-13-prod style-6-prod vignelli-stacking gsap-letters-render-compat audio-mux-parity, shard-8) (push) Has been cancelled
regression / regression-shards (style-15-prod hdr-hlg-regression style-1-prod many-cuts vfr-screen-recording render-symlinked-assets, shard-2) (push) Has been cancelled
103 lines
3.1 KiB
TypeScript
103 lines
3.1 KiB
TypeScript
function assert(condition: unknown, message: string): void {
|
|
if (!condition) {
|
|
throw new Error(message);
|
|
}
|
|
}
|
|
|
|
const ALLOWED_HOSTS = new Set(["runtime.example.com"]);
|
|
const ALLOWED_PATH_PREFIX = "/static/hyperframes-runtime/";
|
|
|
|
function isAllowedRuntimeUrl(candidate: string): boolean {
|
|
try {
|
|
const parsed = new URL(candidate);
|
|
return (
|
|
parsed.protocol === "https:" &&
|
|
ALLOWED_HOSTS.has(parsed.hostname.toLowerCase()) &&
|
|
parsed.pathname.startsWith(ALLOWED_PATH_PREFIX) &&
|
|
parsed.pathname.endsWith(".js")
|
|
);
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
function isGuardedPreviewMessage(data: unknown): boolean {
|
|
if (!data || typeof data !== "object") {
|
|
return false;
|
|
}
|
|
const record = data as { source?: unknown; type?: unknown };
|
|
const source = typeof record.source === "string" ? record.source : null;
|
|
const type = typeof record.type === "string" ? record.type : null;
|
|
const guardedTypes = new Set([
|
|
"state",
|
|
"timeline",
|
|
"element-picked",
|
|
"element-picked-many",
|
|
"element-pick-candidates",
|
|
"pick-mode-cancelled",
|
|
]);
|
|
if (!type || !guardedTypes.has(type)) {
|
|
return false;
|
|
}
|
|
return source === "hf-preview";
|
|
}
|
|
|
|
const allowedRuntimeFixtures = [
|
|
"https://runtime.example.com/static/hyperframes-runtime/hyperframe.runtime.iife.js",
|
|
"https://runtime.example.com/static/hyperframes-runtime/v2026.02.20/hyperframe.runtime.iife.js",
|
|
];
|
|
|
|
const blockedRuntimeFixtures = [
|
|
"http://runtime.example.com/static/hyperframes-runtime/hyperframe.runtime.iife.js",
|
|
"javascript:alert(1)",
|
|
"data:text/javascript,alert(1)",
|
|
"https://evil.example/static/hyperframes-runtime/hyperframe.runtime.iife.js",
|
|
"https://runtime.example.com/static/other/hyperframe.runtime.iife.js",
|
|
"https://runtime.example.com/static/hyperframes-runtime/hyperframe.runtime.iife.css",
|
|
];
|
|
|
|
for (const fixture of allowedRuntimeFixtures) {
|
|
assert(isAllowedRuntimeUrl(fixture), `Expected runtime URL to be allowed: ${fixture}`);
|
|
}
|
|
|
|
for (const fixture of blockedRuntimeFixtures) {
|
|
assert(!isAllowedRuntimeUrl(fixture), `Expected runtime URL to be blocked: ${fixture}`);
|
|
}
|
|
|
|
const allowedMessages = [
|
|
{ type: "state", source: "hf-preview" },
|
|
{ type: "timeline", source: "hf-preview" },
|
|
{ type: "element-picked", source: "hf-preview" },
|
|
];
|
|
const blockedMessages = [
|
|
{ type: "state", source: "hf-parent" },
|
|
{ type: "timeline", source: "evil-origin" },
|
|
{ type: "element-picked", source: "hf-parent" },
|
|
{ type: "pick-mode-cancelled", source: null },
|
|
{ type: "unknown-type", source: "hf-preview" },
|
|
];
|
|
|
|
for (const fixture of allowedMessages) {
|
|
assert(
|
|
isGuardedPreviewMessage(fixture),
|
|
`Expected message fixture to pass guard: ${JSON.stringify(fixture)}`,
|
|
);
|
|
}
|
|
|
|
for (const fixture of blockedMessages) {
|
|
assert(
|
|
!isGuardedPreviewMessage(fixture),
|
|
`Expected message fixture to fail guard: ${JSON.stringify(fixture)}`,
|
|
);
|
|
}
|
|
|
|
console.log(
|
|
JSON.stringify({
|
|
event: "hyperframe_runtime_security_fixtures_verified",
|
|
allowedRuntimeFixtures: allowedRuntimeFixtures.length,
|
|
blockedRuntimeFixtures: blockedRuntimeFixtures.length,
|
|
allowedMessages: allowedMessages.length,
|
|
blockedMessages: blockedMessages.length,
|
|
}),
|
|
);
|