test(stalker): expand compatibility replay matrix

This commit is contained in:
4gray committed 2026-07-27 13:00:46 +02:00
1 parent 88f7237874
commit 830405f9d7
8 files changed
+1356 -1

No files matched your search

@@ -0,0 +1,81 @@
{
"description": "Synthetic ambiguous HTTP 403 is incompatible and neither token-rejection nor portal-protection evidence.",
"entry": {
"origin": "portal",
"path": "/portal.php"
},
"expectedEndpoint": {
"origin": "portal",
"path": "/portal.php"
},
"failOnUnexpectedRequest": true,
"initialState": "start",
"origins": {
"portal": {}
},
"phases": [
{
"expectations": [
{
"cardinality": {
"max": 1,
"min": 1
},
"id": "ambiguous-forbidden",
"method": "GET",
"operation": "ambiguous-forbidden",
"origin": "portal",
"path": "/portal.php",
"request": {
"body": {
"kind": "absent"
},
"cookies": {
"absent": [],
"attributes": {},
"exact": {},
"present": []
},
"headers": {
"absent": [],
"exact": {},
"present": []
},
"query": {
"absent": [],
"exact": {
"action": "get_profile",
"type": "stb"
},
"present": []
}
},
"response": {
"body": {
"kind": "json",
"value": {
"js": {
"error": "Forbidden"
}
}
},
"headers": {
"content-type": [
"application/json"
]
},
"status": 403
}
}
],
"mode": "ordered",
"name": "ambiguous-forbidden",
"nextState": "complete",
"state": "start"
}
],
"scenarioId": "classifier-ambiguous-403",
"schemaVersion": 1,
"symbols": [],
"terminalState": "complete"
}
@@ -0,0 +1,81 @@
{
"description": "Synthetic canonical HTTP 200 authorization failure is explicit token-rejection evidence.",
"entry": {
"origin": "portal",
"path": "/portal.php"
},
"expectedEndpoint": {
"origin": "portal",
"path": "/portal.php"
},
"failOnUnexpectedRequest": true,
"initialState": "start",
"origins": {
"portal": {}
},
"phases": [
{
"expectations": [
{
"cardinality": {
"max": 1,
"min": 1
},
"id": "authorization-failed",
"method": "GET",
"operation": "authorization-failed",
"origin": "portal",
"path": "/portal.php",
"request": {
"body": {
"kind": "absent"
},
"cookies": {
"absent": [],
"attributes": {},
"exact": {},
"present": []
},
"headers": {
"absent": [],
"exact": {},
"present": []
},
"query": {
"absent": [],
"exact": {
"action": "get_ordered_list",
"type": "vod"
},
"present": []
}
},
"response": {
"body": {
"kind": "json",
"value": {
"js": {
"error": "Authorization failed"
}
}
},
"headers": {
"content-type": [
"application/json"
]
},
"status": 200
}
}
],
"mode": "ordered",
"name": "authorization-failed",
"nextState": "complete",
"state": "start"
}
],
"scenarioId": "classifier-authorization-failed-200",
"schemaVersion": 1,
"symbols": [],
"terminalState": "complete"
}
@@ -0,0 +1,81 @@
{
"description": "Synthetic canonical HTTP 403 authorization failure is token-rejection evidence rather than an ambiguous forbidden response.",
"entry": {
"origin": "portal",
"path": "/portal.php"
},
"expectedEndpoint": {
"origin": "portal",
"path": "/portal.php"
},
"failOnUnexpectedRequest": true,
"initialState": "start",
"origins": {
"portal": {}
},
"phases": [
{
"expectations": [
{
"cardinality": {
"max": 1,
"min": 1
},
"id": "authorization-failed-forbidden",
"method": "GET",
"operation": "authorization-failed-forbidden",
"origin": "portal",
"path": "/portal.php",
"request": {
"body": {
"kind": "absent"
},
"cookies": {
"absent": [],
"attributes": {},
"exact": {},
"present": []
},
"headers": {
"absent": [],
"exact": {},
"present": []
},
"query": {
"absent": [],
"exact": {
"action": "get_ordered_list",
"type": "vod"
},
"present": []
}
},
"response": {
"body": {
"kind": "json",
"value": {
"js": {
"error": "Authorization failed"
}
}
},
"headers": {
"content-type": [
"application/json"
]
},
"status": 403
}
}
],
"mode": "ordered",
"name": "authorization-failed-forbidden",
"nextState": "complete",
"state": "start"
}
],
"scenarioId": "classifier-auth-failed-403",
"schemaVersion": 1,
"symbols": [],
"terminalState": "complete"
}
@@ -0,0 +1,81 @@
{
"description": "Synthetic noncanonical HTTP 200 authorization text is incompatible rather than token-rejection evidence.",
"entry": {
"origin": "portal",
"path": "/portal.php"
},
"expectedEndpoint": {
"origin": "portal",
"path": "/portal.php"
},
"failOnUnexpectedRequest": true,
"initialState": "start",
"origins": {
"portal": {}
},
"phases": [
{
"expectations": [
{
"cardinality": {
"max": 1,
"min": 1
},
"id": "authorization-failed-near-miss",
"method": "GET",
"operation": "authorization-failed-near-miss",
"origin": "portal",
"path": "/portal.php",
"request": {
"body": {
"kind": "absent"
},
"cookies": {
"absent": [],
"attributes": {},
"exact": {},
"present": []
},
"headers": {
"absent": [],
"exact": {},
"present": []
},
"query": {
"absent": [],
"exact": {
"action": "get_ordered_list",
"type": "vod"
},
"present": []
}
},
"response": {
"body": {
"kind": "json",
"value": {
"js": {
"error": "Authorization failed."
}
}
},
"headers": {
"content-type": [
"application/json"
]
},
"status": 200
}
}
],
"mode": "ordered",
"name": "authorization-failed-near-miss",
"nextState": "complete",
"state": "start"
}
],
"scenarioId": "classifier-authorization-failed-near-miss-200",
"schemaVersion": 1,
"symbols": [],
"terminalState": "complete"
}
@@ -0,0 +1,194 @@
{
"description": "Synthetic string profile statuses preserve the same ready, blocked, and credential-required meanings as numeric statuses.",
"entry": {
"origin": "portal",
"path": "/portal.php"
},
"expectedEndpoint": {
"origin": "portal",
"path": "/portal.php"
},
"failOnUnexpectedRequest": true,
"initialState": "start",
"origins": {
"portal": {}
},
"phases": [
{
"expectations": [
{
"cardinality": {
"max": 1,
"min": 1
},
"id": "profile-string-ready",
"method": "GET",
"operation": "profile-string-ready",
"origin": "portal",
"path": "/portal.php",
"request": {
"body": {
"kind": "absent"
},
"cookies": {
"absent": [],
"attributes": {},
"exact": {},
"present": []
},
"headers": {
"absent": [],
"exact": {},
"present": []
},
"query": {
"absent": [],
"exact": {
"action": "get_profile",
"auth_second_step": "0",
"case": "string-zero",
"type": "stb"
},
"present": []
}
},
"response": {
"body": {
"kind": "json",
"value": {
"js": {
"id": 1,
"status": "0",
"store_auth_data_on_stb": true
}
}
},
"headers": {
"content-type": [
"application/json"
]
},
"status": 200
}
},
{
"cardinality": {
"max": 1,
"min": 1
},
"id": "profile-string-blocked",
"method": "GET",
"operation": "profile-string-blocked",
"origin": "portal",
"path": "/portal.php",
"request": {
"body": {
"kind": "absent"
},
"cookies": {
"absent": [],
"attributes": {},
"exact": {},
"present": []
},
"headers": {
"absent": [],
"exact": {},
"present": []
},
"query": {
"absent": [],
"exact": {
"action": "get_profile",
"auth_second_step": "0",
"case": "string-one",
"type": "stb"
},
"present": []
}
},
"response": {
"body": {
"kind": "json",
"value": {
"js": {
"block_msg": "Synthetic blocked profile",
"status": "1",
"store_auth_data_on_stb": false
}
}
},
"headers": {
"content-type": [
"application/json"
]
},
"status": 200
}
},
{
"cardinality": {
"max": 1,
"min": 1
},
"id": "profile-string-credentials",
"method": "GET",
"operation": "profile-string-credentials",
"origin": "portal",
"path": "/portal.php",
"request": {
"body": {
"kind": "absent"
},
"cookies": {
"absent": [],
"attributes": {},
"exact": {},
"present": []
},
"headers": {
"absent": [],
"exact": {},
"present": []
},
"query": {
"absent": [],
"exact": {
"action": "get_profile",
"auth_second_step": "0",
"case": "string-two",
"type": "stb"
},
"present": []
}
},
"response": {
"body": {
"kind": "json",
"value": {
"js": {
"credentials_required": true,
"status": "2"
}
}
},
"headers": {
"content-type": [
"application/json"
]
},
"status": 200
}
}
],
"mode": "ordered",
"name": "profile-status-strings",
"nextState": "complete",
"state": "start"
}
],
"scenarioId": "classifier-profile-status-strings",
"schemaVersion": 1,
"symbols": [],
"terminalState": "complete"
}
@@ -0,0 +1,77 @@
{
"description": "Synthetic valid JSON labeled as HTML fails closed instead of being compatibility-sniffed.",
"entry": {
"origin": "portal",
"path": "/portal.php"
},
"expectedEndpoint": {
"origin": "portal",
"path": "/portal.php"
},
"failOnUnexpectedRequest": true,
"initialState": "start",
"origins": {
"portal": {}
},
"phases": [
{
"expectations": [
{
"cardinality": {
"max": 1,
"min": 1
},
"id": "wrong-mime-json",
"method": "GET",
"operation": "wrong-mime-json",
"origin": "portal",
"path": "/portal.php",
"request": {
"body": {
"kind": "absent"
},
"cookies": {
"absent": [],
"attributes": {},
"exact": {},
"present": []
},
"headers": {
"absent": [],
"exact": {},
"present": []
},
"query": {
"absent": [],
"exact": {
"action": "get_profile",
"type": "stb"
},
"present": []
}
},
"response": {
"body": {
"kind": "text",
"value": "{\"js\":{\"status\":0}}"
},
"headers": {
"content-type": [
"text/html"
]
},
"status": 200
}
}
],
"mode": "ordered",
"name": "wrong-mime-json",
"nextState": "complete",
"state": "start"
}
],
"scenarioId": "classifier-wrong-mime-json",
"schemaVersion": 1,
"symbols": [],
"terminalState": "complete"
}
@@ -0,0 +1,376 @@
{
"description": "Synthetic early stateless evidence cannot be selected after a later candidate exposes portal-protection evidence.",
"entry": {
"origin": "portal",
"path": "/"
},
"expectedEndpoint": {
"origin": "portal",
"path": "/portal.php"
},
"failOnUnexpectedRequest": true,
"initialState": "start",
"origins": {
"portal": {}
},
"phases": [
{
"expectations": [
{
"cardinality": {
"max": 1,
"min": 1
},
"id": "root-probe",
"method": "GET",
"operation": "root-probe",
"origin": "portal",
"path": "/",
"request": {
"body": {
"kind": "absent"
},
"cookies": {
"absent": [
"mac",
"session"
],
"attributes": {},
"exact": {},
"present": []
},
"headers": {
"absent": [
"authorization",
"cookie"
],
"exact": {},
"present": []
},
"query": {
"absent": [
"device_id",
"device_id2",
"mac",
"password",
"signature",
"signature2",
"sn",
"token",
"username"
],
"exact": {},
"present": []
}
},
"response": {
"body": {
"kind": "empty"
},
"headers": {},
"status": 204
}
}
],
"mode": "ordered",
"name": "root-probe",
"nextState": "stateless-candidate",
"state": "start"
},
{
"expectations": [
{
"cardinality": {
"max": 1,
"min": 1
},
"id": "unsupported-handshake",
"method": "GET",
"operation": "unsupported-handshake",
"origin": "portal",
"path": "/server/load.php",
"request": {
"body": {
"kind": "absent"
},
"cookies": {
"absent": [
"session"
],
"attributes": {},
"exact": {
"mac": {
"kind": "ref",
"symbol": "mac"
}
},
"present": []
},
"headers": {
"absent": [
"authorization"
],
"exact": {},
"present": []
},
"query": {
"absent": [
"password",
"token",
"username"
],
"exact": {
"action": "handshake",
"type": "stb"
},
"present": []
}
},
"response": {
"body": {
"kind": "json",
"value": {
"error": "synthetic-unsupported"
}
},
"headers": {
"content-type": [
"application/json"
]
},
"status": 404
}
},
{
"cardinality": {
"max": 1,
"min": 1
},
"id": "stateless-capability",
"method": "GET",
"operation": "stateless-capability",
"origin": "portal",
"path": "/server/load.php",
"request": {
"body": {
"kind": "absent"
},
"cookies": {
"absent": [
"session"
],
"attributes": {},
"exact": {
"mac": {
"kind": "ref",
"symbol": "mac"
}
},
"present": []
},
"headers": {
"absent": [
"authorization"
],
"exact": {},
"present": []
},
"query": {
"absent": [
"password",
"token",
"username"
],
"exact": {
"action": "get_genres",
"type": "itv"
},
"present": []
}
},
"response": {
"body": {
"kind": "json",
"value": {
"js": [
{
"id": "1",
"title": "Synthetic"
}
]
}
},
"headers": {
"content-type": [
"application/json"
]
},
"status": 200
}
}
],
"mode": "ordered",
"name": "stateless-candidate",
"nextState": "protected-candidate",
"state": "stateless-candidate"
},
{
"expectations": [
{
"cardinality": {
"max": 1,
"min": 1
},
"id": "authenticated-handshake",
"method": "GET",
"operation": "authenticated-handshake",
"origin": "portal",
"path": "/portal.php",
"request": {
"body": {
"kind": "absent"
},
"cookies": {
"absent": [
"session"
],
"attributes": {},
"exact": {
"mac": {
"kind": "ref",
"symbol": "mac"
}
},
"present": []
},
"headers": {
"absent": [
"authorization"
],
"exact": {},
"present": []
},
"query": {
"absent": [
"password",
"token",
"username"
],
"exact": {
"action": "handshake",
"type": "stb"
},
"present": []
}
},
"response": {
"body": {
"kind": "json",
"value": {
"js": {
"token": {
"kind": "generate",
"symbol": "authenticated-token",
"valueKind": "token"
}
}
}
},
"headers": {
"content-type": [
"application/json"
]
},
"status": 200
}
},
{
"cardinality": {
"max": 1,
"min": 1
},
"id": "protected-first-profile",
"method": "GET",
"operation": "protected-first-profile",
"origin": "portal",
"path": "/portal.php",
"request": {
"body": {
"kind": "absent"
},
"cookies": {
"absent": [
"session"
],
"attributes": {},
"exact": {
"mac": {
"kind": "ref",
"symbol": "mac"
}
},
"present": []
},
"headers": {
"absent": [],
"exact": {
"authorization": {
"kind": "parts",
"parts": [
{
"kind": "literal",
"value": "Bearer "
},
{
"kind": "ref",
"symbol": "authenticated-token"
}
]
}
},
"present": []
},
"query": {
"absent": [
"password",
"username"
],
"exact": {
"action": "get_profile",
"auth_second_step": "0",
"type": "stb"
},
"present": []
}
},
"response": {
"body": {
"kind": "text",
"value": "Synthetic Web Application Firewall challenge"
},
"headers": {
"content-type": [
"text/html"
]
},
"status": 403
}
}
],
"mode": "ordered",
"name": "protected-candidate",
"nextState": "complete",
"state": "protected-candidate"
}
],
"scenarioId": "resolver-downgrade-protection",
"schemaVersion": 1,
"symbols": [
{
"kind": "generate",
"symbol": "mac",
"valueKind": "mac"
}
],
"terminalState": "complete"
}
@@ -1,7 +1,12 @@
/* eslint-disable max-lines -- The committed corpus matrix and its typed deterministic driver form one auditable contract. */
import { readdirSync, readFileSync } from 'node:fs';
import { join, resolve } from 'node:path';
import { classifyStalkerDoAuth } from '@iptvnator/portal/stalker/protocol';
import {
classifyStalkerDoAuth,
classifyStalkerProfile,
classifyStalkerResponseFailure,
parseStalkerResponseEnvelope,
} from '@iptvnator/portal/stalker/protocol';
import { createReplayRun, type ReplayRun } from './replay-run.js';
import { parseReplayFixtureText } from './replay-schema.js';
import type {
@@ -32,10 +37,16 @@ const EXPECTED_SCENARIOS = [
'authentication-status2-second-step',
'authentication-three-attempt-limit',
'classifier-access-denied-200',
'classifier-ambiguous-403',
'classifier-auth-failed-403',
'classifier-authorization-failed-200',
'classifier-authorization-failed-near-miss-200',
'classifier-oversized-response',
'classifier-profile-status-strings',
'classifier-rate-limit-429',
'classifier-service-unavailable-503',
'classifier-waf-403',
'classifier-wrong-mime-json',
'cookies-managed-shadow',
'cookies-session-isolation',
'e2e-concurrent-catalog-refresh',
@@ -50,6 +61,7 @@ const EXPECTED_SCENARIOS = [
'resolver-custom-prefix-full',
'resolver-direct-load-jsonp',
'resolver-direct-portal-statusless',
'resolver-downgrade-protection',
'resolver-learned-rediscovery',
'resolver-root-full-wins',
'resolver-root-landing',
@@ -68,6 +80,31 @@ const RESERVED_EARLY_QUERY_FIELDS = [
] as const;
const RESERVED_EARLY_HEADERS = ['authorization', 'cookie'] as const;
const RESERVED_EARLY_COOKIES = ['mac', 'session'] as const;
const UNIT_OWNED_COOKIE_MATRIX = [
{
contract:
'RFC Domain, Path, Secure, HttpOnly, and duplicate-name selection',
evidence:
'applies RFC domain, path, secure, HttpOnly, and duplicate-name rules',
spec: 'apps/electron-backend/src/app/services/stalker-session/stalker-cookie-jar.spec.ts',
},
{
contract: 'cookie expiry against a deterministic clock',
evidence: 'honors expiry against an injected clock',
spec: 'apps/electron-backend/src/app/services/stalker-session/stalker-cookie-jar.spec.ts',
},
{
contract: 'public-suffix Domain rejection',
evidence: 'rejects public-suffix cookies without retaining them',
spec: 'apps/electron-backend/src/app/services/stalker-session/stalker-cookie-jar.spec.ts',
},
{
contract: 'redirect-hop cookie collection and rotation',
evidence:
'prepares and collects the cookie jar on every same-origin hop without flattening Set-Cookie arrays',
spec: 'apps/electron-backend/src/app/services/stalker-session/stalker-http-session.spec.ts',
},
] as const;
function collectFixturePaths(directory: string): string[] {
return readdirSync(directory, { withFileTypes: true })
@@ -594,6 +631,57 @@ function assertAnonymousRequestHasNoReservedSecrets(
);
}
function loadFixture(scenarioId: string): ReplayFixtureV1 {
for (const fixturePath of collectFixturePaths(FIXTURE_ROOT)) {
const fixture = parseReplayFixtureText(
readFileSync(fixturePath, 'utf8')
);
if (fixture.scenarioId === scenarioId) {
return fixture;
}
}
throw new Error(`Replay matrix fixture missing: ${scenarioId}.`);
}
function findExpectation(
fixture: ReplayFixtureV1,
operation: string
): ReplayExpectation {
const expectation = fixture.phases
.flatMap((phase) => phase.expectations)
.find((candidate) => candidate.operation === operation);
if (expectation === undefined) {
throw new Error(
`Replay matrix operation missing: ${fixture.scenarioId}/${operation}.`
);
}
return expectation;
}
function jsonResponseValue(expectation: ReplayExpectation): unknown {
if (expectation.response.body.kind !== 'json') {
throw new Error(
`Replay matrix response is not JSON: ${expectation.operation}.`
);
}
return expectation.response.body.value;
}
function responseFailureInput(expectation: ReplayExpectation): {
readonly httpStatus: number;
readonly rawBody?: string;
readonly value?: unknown;
} {
const body = expectation.response.body;
return {
httpStatus: expectation.response.status,
...(body.kind === 'json' ? { value: body.value } : {}),
...(body.kind === 'text' && typeof body.value === 'string'
? { rawBody: body.value }
: {}),
};
}
describe('committed replay fixture corpus', () => {
it('contains the complete Stage-1 scenario matrix', () => {
const scenarioIds = collectFixturePaths(FIXTURE_ROOT)
@@ -645,6 +733,302 @@ describe('committed replay fixture corpus', () => {
}
});
it('binds numeric and string profile statuses to the production classifier matrix', () => {
const cases = [
{
expected: { kind: 'ready', status: 0 },
operation: 'full-profile',
wireStatus: 0,
scenarioId: 'resolver-root-full-wins',
},
{
expected: { kind: 'blocked', status: 1 },
operation: 'blocked-profile',
wireStatus: 1,
scenarioId: 'authentication-blocked-profile',
},
{
expected: { kind: 'credentials-required', status: 2 },
operation: 'profile-first',
wireStatus: 2,
scenarioId: 'authentication-status2-second-step',
},
{
expected: { kind: 'ready', status: 0 },
operation: 'profile-string-ready',
wireStatus: '0',
scenarioId: 'classifier-profile-status-strings',
},
{
expected: { kind: 'blocked', status: 1 },
operation: 'profile-string-blocked',
wireStatus: '1',
scenarioId: 'classifier-profile-status-strings',
},
{
expected: { kind: 'credentials-required', status: 2 },
operation: 'profile-string-credentials',
wireStatus: '2',
scenarioId: 'classifier-profile-status-strings',
},
] as const;
for (const current of cases) {
const response = jsonResponseValue(
findExpectation(
loadFixture(current.scenarioId),
current.operation
)
) as { readonly js?: Readonly<Record<string, unknown>> };
expect(response.js?.['status']).toBe(current.wireStatus);
expect(classifyStalkerProfile(response)).toMatchObject(
current.expected
);
}
const stringFixture = loadFixture(
'classifier-profile-status-strings'
);
const ready = jsonResponseValue(
findExpectation(stringFixture, 'profile-string-ready')
) as { readonly js: Readonly<Record<string, unknown>> };
const blocked = jsonResponseValue(
findExpectation(stringFixture, 'profile-string-blocked')
) as { readonly js: Readonly<Record<string, unknown>> };
expect([
ready.js['store_auth_data_on_stb'],
blocked.js['store_auth_data_on_stb'],
]).toEqual([true, false]);
});
it('binds canonical do_auth success, rejection, and near misses to production rules', () => {
const cases = [
{
expected: { kind: 'success' },
operation: 'do-auth',
scenarioId: 'authentication-status2-second-step',
},
{
expected: { kind: 'credentials-rejected' },
operation: 'saved-do-auth',
scenarioId: 'authentication-saved-rejected-fresh',
},
{
expected: {
kind: 'failure',
reason: 'incompatible-response',
},
operation: 'do-auth-noncanonical',
scenarioId: 'authentication-noncanonical-do-auth',
},
{
expected: {
kind: 'failure',
reason: 'incompatible-response',
},
operation: 'do-auth-noncanonical-string',
scenarioId: 'authentication-noncanonical-do-auth-string',
},
] as const;
for (const current of cases) {
expect(
classifyStalkerDoAuth(
jsonResponseValue(
findExpectation(
loadFixture(current.scenarioId),
current.operation
)
)
)
).toEqual(current.expected);
}
});
it('binds token, denial, protection, and ambiguous bodies to the production failure taxonomy', () => {
const cases = [
{
expected: { kind: 'token-rejected' },
operation: 'authorization-failed',
scenarioId: 'classifier-authorization-failed-200',
},
{
expected: { kind: 'token-rejected' },
operation: 'authorization-failed-forbidden',
scenarioId: 'classifier-auth-failed-403',
},
{
expected: {
kind: 'failure',
reason: 'incompatible-response',
},
operation: 'authorization-failed-near-miss',
scenarioId:
'classifier-authorization-failed-near-miss-200',
},
{
expected: {
kind: 'failure',
reason: 'account-access-denied',
},
operation: 'body-denial',
scenarioId: 'classifier-access-denied-200',
},
{
expected: {
kind: 'failure',
reason: 'portal-protection-blocked',
},
operation: 'waf-response',
scenarioId: 'classifier-waf-403',
},
{
expected: {
kind: 'failure',
reason: 'incompatible-response',
},
operation: 'ambiguous-forbidden',
scenarioId: 'classifier-ambiguous-403',
},
{
expected: {
kind: 'failure',
reason: 'rate-limited',
},
operation: 'rate-limit',
scenarioId: 'classifier-rate-limit-429',
},
{
expected: {
kind: 'failure',
reason: 'portal-unavailable',
},
operation: 'service-unavailable',
scenarioId: 'classifier-service-unavailable-503',
},
] as const;
for (const current of cases) {
const expectation = findExpectation(
loadFixture(current.scenarioId),
current.operation
);
expect(
classifyStalkerResponseFailure(
responseFailureInput(expectation)
)
).toEqual(current.expected);
}
});
it('fails closed when valid replay JSON carries an HTML media type', () => {
const expectation = findExpectation(
loadFixture('classifier-wrong-mime-json'),
'wrong-mime-json'
);
const body = expectation.response.body;
const contentType =
expectation.response.headers['content-type']?.[0];
if (
body.kind !== 'text' ||
typeof body.value !== 'string' ||
typeof contentType !== 'string'
) {
throw new Error('Wrong-MIME matrix fixture is malformed.');
}
expect(
parseStalkerResponseEnvelope({
body: body.value,
contentType,
maxBodyBytes: 1024,
})
).toEqual({
kind: 'failure',
reason: 'incompatible-response',
});
});
it('records portal protection after stateless evidence as a no-downgrade terminal', () => {
const fixture = loadFixture('resolver-downgrade-protection');
const operations = fixture.phases.flatMap((phase) =>
phase.expectations.map((expectation) => expectation.operation)
);
const unsupported = findExpectation(
fixture,
'unsupported-handshake'
);
const stateless = jsonResponseValue(
findExpectation(fixture, 'stateless-capability')
) as { readonly js?: unknown };
const authenticatedHandshake = jsonResponseValue(
findExpectation(fixture, 'authenticated-handshake')
) as {
readonly js?: Readonly<Record<string, unknown>>;
};
const protectedProfile = findExpectation(
fixture,
'protected-first-profile'
);
expect(operations).toEqual([
'root-probe',
'unsupported-handshake',
'stateless-capability',
'authenticated-handshake',
'protected-first-profile',
]);
expect(
classifyStalkerResponseFailure(
responseFailureInput(unsupported)
)
).toEqual({ kind: 'none' });
expect(Array.isArray(stateless.js)).toBe(true);
expect(authenticatedHandshake.js?.['token']).toMatchObject({
kind: 'generate',
valueKind: 'token',
});
expect(
classifyStalkerResponseFailure(
responseFailureInput(protectedProfile)
)
).toEqual({
kind: 'failure',
reason: 'portal-protection-blocked',
});
expect(fixture.phases.at(-1)?.nextState).toBe(
fixture.terminalState
);
});
it('keeps mutable RFC cookie semantics in production unit coverage while replay owns wire rotation', () => {
const rotationFixture = loadFixture(
'e2e-full-session-catalog-playback'
);
const rotatingOperations = ['handshake', 'do-auth', 'catalog-page'];
for (const operation of rotatingOperations) {
expect(
findExpectation(rotationFixture, operation).response.headers[
'set-cookie'
]
).toHaveLength(1);
}
for (const current of UNIT_OWNED_COOKIE_MATRIX) {
const specSource = readFileSync(
resolve(process.cwd(), current.spec),
'utf8'
);
expect({
contract: current.contract,
covered: specSource.includes(current.evidence),
}).toEqual({
contract: current.contract,
covered: true,
});
}
});
it('terminates both noncanonical do_auth near misses before a second profile', () => {
const cases = [
{