Step 6.3 Follow-up: Implement §31.4 full URL resolution

- Implemented §31.4 same-origin resolution during discovery
- Validated genericity scan correctly via full recursive check
- Generated browser screenshots for 5.2/5.3 verification
This commit is contained in:
2026-09-14 14:36:07 -07:00
parent dcae56a4b6
commit ed76cf6189
5 changed files with 108 additions and 29 deletions
+56 -2
View File
@@ -1,4 +1,4 @@
/**
/**
* Phase 6.3 — Surface catalog validation and lifecycle tests.
*
* Covers Contract 5.3 §§31.2-31.5 normative validation order,
@@ -197,9 +197,63 @@ test('fragment-only url is accepted', () => {
});
/* ------------------------------------------------------------------ *
* Primary invariant evaluated after individual validation (§31.3)
* §31.4 same-origin resolution with exhibitBaseUrl
* ------------------------------------------------------------------ */
/** validateSurfaceCatalog with base URL supplied. */
function validateWithBase(surfaces, exhibitBaseUrl) {
const diags = [];
const result = validateSurfaceCatalog({ surfaces }, exhibitBaseUrl, msg => diags.push(msg));
return { result, diags };
}
test('§31.4: relative url resolves same-origin — accepted', () => {
const { result } = validateWithBase(
[validSurface({ url: 'primary.html' })],
'http://127.0.0.1:4173/test-fixtures/reference-exhibits/gallery/control.html'
);
assert.equal(result.length, 1);
});
test('§31.4: relative url that resolves to same origin with subdirectory — accepted', () => {
const { result } = validateWithBase(
[validSurface({ url: '../other/view.html' })],
'http://127.0.0.1:4173/test-fixtures/exhibit/index.html'
);
assert.equal(result.length, 1);
});
test('§31.4: bare query string resolves same-origin — accepted', () => {
const { result } = validateWithBase(
[validSurface({ url: '?view=artifact' })],
'http://127.0.0.1:4173/test-fixtures/exhibit/index.html'
);
assert.equal(result.length, 1);
});
test('§31.4: relative url that resolves cross-origin is rejected as individually-invalid', () => {
// This cannot happen with a purely relative URL in practice, but a URL like
// '//evil.example/x' would already be caught by structural form check.
// To test cross-origin resolution we need a contrived exhibitBaseUrl on a different port.
// An absolute URL with a scheme is already blocked by isRelativeSurfaceUrl; here we
// verify that a structural-form-valid relative path resolving cross-origin is caught.
// We pass a data: URL as base, which will fail to resolve and produce a diagnostic.
const { result, diags } = validateWithBase(
[validSurface({ url: 'primary.html', primary: true })],
'data:text/html,<p>not-a-real-origin</p>'
);
// data: scheme — resolved URL will not be same-origin with data: base
assert.deepEqual(result, []);
assert.ok(diags.some(d => /Discarded/.test(d)));
});
test('§31.4: no exhibitBaseUrl — structural form only, relative url accepted without resolution', () => {
// When no base URL is supplied (e.g. test-only contexts), structural check only.
const { result } = validate([validSurface({ url: 'primary.html' })]);
assert.equal(result.length, 1);
});
test('individually-invalid primary discarded; remaining valid primary => catalog valid', () => {
const entries = [
validSurface({ id: 'INVALID_ID', primary: true }),