chore: sync the frontend template from 4dc033c to 8157ad4
The product was materialized from the template at `4dc033c` and has stayed on it through 43 template commits, so it was missing all three rounds of adapter remediation — including files it never had, such as the shared `abortable-operation` primitive and the `exact-snapshot` decoder that later fixes are written against. Taking only the newest round was not possible for that reason: the delta is coherent only as a whole. The product had not touched `src/adapters` at all since materialization, so the 140-file delta applied with a three-way merge and no conflicts. `package.json` was the single overlap and merged cleanly: the product owns `name`, the template contributed `check:adapter-inventory`, `check:remediation-ledger` and the image-resolve-signal type fixture. All 24 product-owned files — README, index.html, CI workflow, i18n catalog, home page, generated schemas, evidence scripts, component and visual snapshots — are byte-identical to `main`. `template.lock.json` now pins the synced revision and tree. Verified in this repository, not inherited from the template: six type projects, lint, nine gates (adapter inventory, remediation ledger, registries, diagnostics, realtime boundaries, architecture, browser file/storage boundaries, optional recipes, documentation), the production build, and 2,054 of 2,073 tests. The 19 failures are all in `tests/unit/ci-artifact-contract.test.ts` and are the same pre-existing sandbox RLIMIT, EMFILE, umask and `/tmp` permission behaviour the template records; four suites that failed once under parallel load pass in isolation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
002ba3624e
commit
4bff9ca151
@@ -443,20 +443,23 @@ function browserManagedHandoff(context: Readonly<{
|
||||
context.options.observer,
|
||||
);
|
||||
}
|
||||
const href = capability.value.href;
|
||||
if (
|
||||
!safeBrowserManagedTarget(href, context.baseOrigin, {
|
||||
const target = resolveBrowserManagedTarget(
|
||||
capability.value.href,
|
||||
context.baseOrigin,
|
||||
{
|
||||
allowCrossOrigin:
|
||||
context.options.allowCrossOriginBrowserHandoff ?? false,
|
||||
allowQuery: context.options.allowBrowserManagedQuery ?? false,
|
||||
})
|
||||
) {
|
||||
return observeResult(
|
||||
browserDataFailure("POLICY_REJECTED", "DOWNLOAD"),
|
||||
context.options.observer,
|
||||
);
|
||||
},
|
||||
);
|
||||
if (!target.ok) {
|
||||
return observeResult(target, context.options.observer);
|
||||
}
|
||||
context.options.host.handoff(href, context.suggestedFileName);
|
||||
// The host receives the parsed canonical URL, never the raw string.
|
||||
context.options.host.handoff(
|
||||
target.value.absoluteHref,
|
||||
context.suggestedFileName,
|
||||
);
|
||||
return observeResult(
|
||||
browserDataSuccess(
|
||||
Object.freeze({
|
||||
@@ -566,11 +569,13 @@ async function promptAndStream(context: Readonly<{
|
||||
);
|
||||
}
|
||||
|
||||
const sourceHolder = createSourceHolder();
|
||||
try {
|
||||
const sourceResult = await resolveByteSource(
|
||||
context.input,
|
||||
context.input.signal,
|
||||
context.options,
|
||||
sourceHolder,
|
||||
);
|
||||
if (!sourceResult.ok) {
|
||||
return observeResult(sourceResult, context.options.observer);
|
||||
@@ -699,6 +704,10 @@ async function promptAndStream(context: Readonly<{
|
||||
mapDownloadException(error),
|
||||
context.options.observer,
|
||||
);
|
||||
} finally {
|
||||
// TR-RR-04. Exactly once, on every path: success, validation failure,
|
||||
// writer failure and abort.
|
||||
closeHeldSource(sourceHolder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -721,12 +730,15 @@ async function boundedObjectUrlHandoff(context: Readonly<{
|
||||
context.options.observer,
|
||||
);
|
||||
}
|
||||
const sourceHolder = createSourceHolder();
|
||||
const sourceResult = await resolveByteSource(
|
||||
context.input,
|
||||
context.input.signal,
|
||||
context.options,
|
||||
sourceHolder,
|
||||
);
|
||||
if (!sourceResult.ok) {
|
||||
closeHeldSource(sourceHolder);
|
||||
return observeResult(sourceResult, context.options.observer);
|
||||
}
|
||||
const source = sourceResult.value;
|
||||
@@ -735,6 +747,7 @@ async function boundedObjectUrlHandoff(context: Readonly<{
|
||||
(source.byteLength > context.input.maxBufferedBytes ||
|
||||
source.byteLength > context.input.maxTransferBytes)
|
||||
) {
|
||||
closeHeldSource(sourceHolder);
|
||||
return observeResult(
|
||||
browserDataFailure("LIMIT_EXCEEDED", "DOWNLOAD"),
|
||||
context.options.observer,
|
||||
@@ -835,6 +848,9 @@ async function boundedObjectUrlHandoff(context: Readonly<{
|
||||
context.options.observer,
|
||||
transferred,
|
||||
);
|
||||
} finally {
|
||||
// TR-RR-04. Exactly once, on every path.
|
||||
closeHeldSource(sourceHolder);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -994,10 +1010,63 @@ function validateDownloadInput(
|
||||
return browserDataSuccess(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* TR-RR-04. A presigned byte source owns a fetch reader and a capability lease,
|
||||
* and its port requires `close()`. The delivery consumer never called it, so
|
||||
* every success, validation failure, writer failure and abort leaked both. The
|
||||
* closeable subtype is lost in the `FileByteSource` projection, so the holder
|
||||
* keeps it and the outermost boundary closes it exactly once.
|
||||
*/
|
||||
type CloseableSourceHolder = { source: FileByteSource | null; closed: boolean };
|
||||
|
||||
function createSourceHolder(): CloseableSourceHolder {
|
||||
return { source: null, closed: false };
|
||||
}
|
||||
|
||||
/**
|
||||
* TR-02. Closes a lease that fulfilled after the delivery already ended. The
|
||||
* holder's own `closed` latch is the single close-once authority, so a lease
|
||||
* the holder did adopt is never closed twice and a lease it never saw is still
|
||||
* closed exactly once. A late rejection is observed and discarded.
|
||||
*/
|
||||
function compensateLateSource(
|
||||
pending: Promise<BrowserDataResult<FileByteSource>>,
|
||||
holder: CloseableSourceHolder | undefined,
|
||||
): void {
|
||||
if (!holder) return;
|
||||
void pending.then(
|
||||
(result) => {
|
||||
if (!result.ok || !holder.closed) return;
|
||||
// The holder was already closed, so this lease was never adopted.
|
||||
if (!isVerifiedPresignedSource(result.value)) return;
|
||||
try {
|
||||
result.value.close();
|
||||
} catch {
|
||||
// Compensation is best effort and never changes the outcome.
|
||||
}
|
||||
},
|
||||
() => undefined,
|
||||
);
|
||||
}
|
||||
|
||||
function closeHeldSource(holder: CloseableSourceHolder): void {
|
||||
if (holder.closed) return;
|
||||
holder.closed = true;
|
||||
const source = holder.source;
|
||||
holder.source = null;
|
||||
if (!source || !isVerifiedPresignedSource(source)) return;
|
||||
try {
|
||||
source.close();
|
||||
} catch {
|
||||
// Closing is best effort and never changes the delivery outcome.
|
||||
}
|
||||
}
|
||||
|
||||
async function resolveByteSource(
|
||||
input: DeliveryInput,
|
||||
signal: AbortSignal,
|
||||
options: DownloadDeliveryAdapterOptions,
|
||||
holder?: CloseableSourceHolder,
|
||||
): Promise<BrowserDataResult<FileByteSource>> {
|
||||
const source = input.source;
|
||||
if (signal.aborted) {
|
||||
@@ -1013,20 +1082,26 @@ async function resolveByteSource(
|
||||
}
|
||||
const open = options.openAuthorizedSource;
|
||||
if (!open) return browserDataFailure("UNSUPPORTED", "DOWNLOAD");
|
||||
const result = await awaitWithSignal(
|
||||
open({
|
||||
resourceId: source.resourceId,
|
||||
capability: source.capability,
|
||||
signal,
|
||||
}),
|
||||
const pendingOpen = open({
|
||||
resourceId: source.resourceId,
|
||||
capability: source.capability,
|
||||
signal,
|
||||
);
|
||||
});
|
||||
// TR-02. A lease that arrives after the abort already ended the delivery
|
||||
// never reaches the holder, so nothing would ever close it: the fetch reader
|
||||
// and the capability lease outlived the terminal result. The compensator and
|
||||
// the holder share one close-once latch, so exactly one of them closes it.
|
||||
compensateLateSource(pendingOpen, holder);
|
||||
const result = await awaitWithSignal(pendingOpen, signal);
|
||||
if (!result.ok) {
|
||||
return browserDataFailure(result.error.code, "DOWNLOAD", {
|
||||
retryable: result.error.retryable,
|
||||
recovery: result.error.recovery,
|
||||
});
|
||||
}
|
||||
// Held from the moment the lease exists, so a validation failure below still
|
||||
// closes it.
|
||||
if (holder) holder.source = result.value;
|
||||
return validPresignedByteSource(
|
||||
result.value,
|
||||
source.capability,
|
||||
@@ -1245,28 +1320,45 @@ function validateBrowserManagedCapability(
|
||||
);
|
||||
}
|
||||
|
||||
function safeBrowserManagedTarget(
|
||||
type ResolvedBrowserManagedTarget = Readonly<{ absoluteHref: string }>;
|
||||
|
||||
/**
|
||||
* STO-02. Parse once, canonicalize, then execute the canonical value.
|
||||
*
|
||||
* Returning a boolean and handing the raw href to the host let the browser
|
||||
* re-resolve a relative target against `document.baseURI`, so a hostile
|
||||
* `<base>` could send the navigation to a different origin than the one this
|
||||
* policy just approved.
|
||||
*/
|
||||
function resolveBrowserManagedTarget(
|
||||
href: string,
|
||||
baseOrigin: string,
|
||||
policy: Readonly<{
|
||||
allowCrossOrigin: boolean;
|
||||
allowQuery: boolean;
|
||||
}>,
|
||||
): boolean {
|
||||
): BrowserDataResult<ResolvedBrowserManagedTarget> {
|
||||
let base: URL;
|
||||
let target: URL;
|
||||
try {
|
||||
const base = new URL(baseOrigin);
|
||||
const target = new URL(href, base);
|
||||
return (
|
||||
["http:", "https:"].includes(target.protocol) &&
|
||||
target.username.length === 0 &&
|
||||
target.password.length === 0 &&
|
||||
(policy.allowCrossOrigin || target.origin === base.origin) &&
|
||||
(policy.allowQuery || target.search.length === 0) &&
|
||||
target.hash.length === 0
|
||||
);
|
||||
base = new URL(baseOrigin);
|
||||
target = new URL(href, base);
|
||||
} catch {
|
||||
return false;
|
||||
return browserDataFailure("POLICY_REJECTED", "DOWNLOAD");
|
||||
}
|
||||
if (
|
||||
!["http:", "https:"].includes(target.protocol) ||
|
||||
target.username.length > 0 ||
|
||||
target.password.length > 0 ||
|
||||
(!policy.allowCrossOrigin && target.origin !== base.origin) ||
|
||||
(!policy.allowQuery && target.search.length > 0) ||
|
||||
target.hash.length > 0
|
||||
) {
|
||||
return browserDataFailure("POLICY_REJECTED", "DOWNLOAD");
|
||||
}
|
||||
return browserDataSuccess(
|
||||
Object.freeze({ absoluteHref: target.href }),
|
||||
);
|
||||
}
|
||||
|
||||
function safeOpaqueId(value: unknown): value is string {
|
||||
|
||||
Reference in New Issue
Block a user