From 2fb6a536568eeb5b4cc04257255f98cde34b7f66 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN Date: Tue, 20 Oct 2026 09:44:01 -0400 Subject: [PATCH 1/3] storage-cors-1 preserve existing bucket CORS rules before adding origins --- ...ONTEXT_2026-10-20_13-39-30_storage-cors.md | 6 + ...ISIONS_2026-10-20_13-39-30_storage-cors.md | 6 + docs/agents/backlog/storage-cors-1.json | 14 +- docs/testing/storage-cors-integrity.md | 53 +++++++ js/storage/s3-client.js | 1 + js/storage/s3-multipart.js | 57 +++++-- ...ST_LOG_2026-10-20_13-39-30_storage-cors.md | 7 + ...ST_LOG_2026-10-20_13-43-30_storage-cors.md | 10 ++ tests/storage-cors-preservation.test.mjs | 140 ++++++++++++++++++ todo/TODO_2026-10-20_13-39-30_storage-cors.md | 7 + 10 files changed, 279 insertions(+), 22 deletions(-) create mode 100644 context/CONTEXT_2026-10-20_13-39-30_storage-cors.md create mode 100644 decisions/DECISIONS_2026-10-20_13-39-30_storage-cors.md create mode 100644 docs/testing/storage-cors-integrity.md create mode 100644 test_logs/TEST_LOG_2026-10-20_13-39-30_storage-cors.md create mode 100644 test_logs/TEST_LOG_2026-10-20_13-43-30_storage-cors.md create mode 100644 tests/storage-cors-preservation.test.mjs create mode 100644 todo/TODO_2026-10-20_13-39-30_storage-cors.md diff --git a/context/CONTEXT_2026-10-20_13-39-30_storage-cors.md b/context/CONTEXT_2026-10-20_13-39-30_storage-cors.md new file mode 100644 index 00000000..bd2cf829 --- /dev/null +++ b/context/CONTEXT_2026-10-20_13-39-30_storage-cors.md @@ -0,0 +1,6 @@ +# storage-cors-1 +- Start UTC: 2026-10-20T13:38:00Z; launch reported by dispatch ~13:37:59Z; acknowledgement 13:38:24Z. +- Goal: validate current-HEAD existing-origin loss via real helper and offline SDK/transport; propose preservation semantics before edits. +- Scope: investigation/evidence first; product/test changes require dispatch routing. No browser/cloud credentials/network bucket mutations; preserve preview3000. +- Done: claimed; traced callers; 5 characterization cases reproduced. See docs/testing/storage-cors-integrity.md. +- Pending: dispatch preservation semantics/fix routing, regression/mutants/focused checks, coordinated normal gates/build/landing. diff --git a/decisions/DECISIONS_2026-10-20_13-39-30_storage-cors.md b/decisions/DECISIONS_2026-10-20_13-39-30_storage-cors.md new file mode 100644 index 00000000..5803feac --- /dev/null +++ b/decisions/DECISIONS_2026-10-20_13-39-30_storage-cors.md @@ -0,0 +1,6 @@ +# storage-cors-1 proposed semantics (awaiting dispatch) +- Preserve every existing rule and field; do not union new origins into arbitrary rules (would grant their permissions to new origins). +- Read existing policy before writing; only explicit NoSuchCORSConfiguration indicates absent policy. Other failures propagate without PUT. +- Add the existing default rule for newly requested origins separately. Skip PUT when equivalent existing default rules already cover every requested origin. +- Preserve wildcard rules verbatim; never infer extra methods/headers or edit unknown fields. Exact equivalence/coverage details require routing before implementation. +- No dependencies/SDK version change. Inspect SDK export read-only until routing. diff --git a/docs/agents/backlog/storage-cors-1.json b/docs/agents/backlog/storage-cors-1.json index fa59181f..2082d5a9 100644 --- a/docs/agents/backlog/storage-cors-1.json +++ b/docs/agents/backlog/storage-cors-1.json @@ -1,9 +1,9 @@ { - "id": "storage-cors-1", - "area": "storage-cors", - "status": "open", - "title": "Reproduce existing-origin loss in bucket CORS provisioning using offline transport", - "blockedOn": null, - "addedOn": "2026-10-20", - "filedAt": "0c1dd7e86be3e28edc96aca47f7753a98990dde0" + "id": "storage-cors-1", + "area": "storage-cors", + "status": "in-progress", + "title": "Reproduce existing-origin loss in bucket CORS provisioning using offline transport", + "blockedOn": null, + "addedOn": "2026-10-20", + "filedAt": "0c1dd7e86be3e28edc96aca47f7753a98990dde0" } diff --git a/docs/testing/storage-cors-integrity.md b/docs/testing/storage-cors-integrity.md new file mode 100644 index 00000000..a09749dc --- /dev/null +++ b/docs/testing/storage-cors-integrity.md @@ -0,0 +1,53 @@ +# storage-cors-1 investigation + +Start UTC 2026-10-20T13:38:00Z. Investigation checkpoint 13:39:21Z. +HEAD bbc1be79e941add929c9c51f984778676822b5f2; filedAt0c1dd7e helper/client unchanged. + +Actual caller behavior: R2Service.getCorsOrigins returns current window origin (plus HTTPS localhost counterpart). ensureBucketConfigForNpub and verifyPublicAccess use this list; generic prepareS3Connection takes supplied origins, and its getCorsOrigins likewise returns current-site origins. r2-s3 reexports the helper. Thus existing policies are not passed through callers. + +Offline command `env -u NODE_TEST_CONTEXT node /tmp/storage-cors-reproduce.mjs` exit0, 5 characterization scenarios. Real s3-client and s3-multipart imported; registerHooks replaces only remote SDK with input-holding command classes; fake S3 send implements full-policy replacement on PutBucketCors. Unexpected HTTP imports throw. Fixtures use example.invalid and no credentials. + +- Existing GET-only rule: origin first.example.invalid, header Range, ETag exposure, maxAge75, ID existing-read-only. Request second.example.invalid. Result retains0/1 prior rules; origins only second.example.invalid; helper default methods/headers replace prior fields. +- Repeat same request: policy identical, PUT total2 (no skip). +- No existing CORS config: PUT1/GET0, default policy installed. +- AccessDenied on read: PUT1/GET0; configured read error cannot surface because helper never reads. +- Empty origins: zero transport calls, policy untouched. + +Proposed semantics sent dispatch: preserve all existing rules/fields verbatim; add default rule for new origins without widening arbitrary existing rules; skip PUT when exact equivalent default rules already satisfy all requested origins; only explicit NoSuchCORSConfiguration permits absent-policy creation; other read failures reject without PUT. Wildcards/unknown fields preserved; no speculative permission merging. Scope needs dispatch routing before implementation. + +No regression test changes yet, so no Test Integrity Note/mutants claimed. No browser/full-suite/lint/build/cloud/live-policy/concurrency qualification. PR overlap check unavailable (curl DNS exit6). Preview3000 untouched. Tool/browser/gate contention before reproduction0s; routing wait starts13:39:21Z. + +## Routed implementation and integrity (2026-10-20T13:43Z) + +Dispatch routed bounded product/test fix at13:40:50UTC after independent failure. Routing wait89s. Existing rules remain verbatim/in order; only explicit origins in rules with identical default permission/header/exposure/maxAge fields count as covered. ID is preserved metadata; unknown fields disqualify coverage. Wildcards remain unchanged and are not expanded/interpreted. Append current defaults for uncovered deduplicated origins. Only NoSuchCORSConfiguration permits creation after failed read; denied/404/transport failures propagate without PUT. Existing method defaults unchanged, no SDK upgrade. + +```yaml +test_integrity_note: + change_type: ["new_tests"] + scenarios: + - id: SCN-storage-cors-preservation + given: "existing custom or wildcard rules, or equivalent default coverage" + when: "real ensureBucketCors adds/repeats requested origins through actual SDK wrapper" + then: "all original rules and fields persist; only uncovered explicit origins get default rule; repeats issue no PUT" + - id: SCN-storage-cors-read-safety + given: "absent configuration, denied read, non-CORS 404, transport failure, or empty origins" + when: "real helper configures CORS" + then: "only explicit NoSuchCORSConfiguration creates policy; other read errors propagate identically with zero PUT; empty origins zero IO" + observable_outcomes: + - "full persisted CORS policy, unchanged rule fields/order, exact write count, original error identity" + determinism_controls: + - "actual helper and SDK wrapper; fake remote SDK command classes and S3 transport; no network, credentials, clock, retries, sleeps" + anti_cheat_rationale: + prevents: + - "hard-coded success/no-op" + - "over-mocking internal helper logic" + - "policy overwrite or arbitrary permission widening" + - "snapshot rubber-stamping and retry/sleep masking" + relaxation: + did_relax_any_assertion: false + if_true_explain_spec_basis: "" +``` + +Nine regression scenarios pass. Original helper fails8/9 with exit1; empty-origin control passes. Ten deliberately broken variants exit1 and were restored: overwrite existing rules; reverse rules; omit dedup; repeat PUT; include covered origins; reject absent policy; swallow read errors; empty-origins IO; ignore non-origin permissions (kills scenario5); remove SDK GetBucketCors export. Every scenario fails under at least one variant. Final focused runner passes3/3 files (13 scenarios total:9 CORS,3 cache-control,1 empty upload). + +`npm ci --offline --ignore-scripts`: exit0,441 installed packages in4s from local cache. Initial lint exit127 absent stylelint; after install lint exit2 sandbox EPERM read-only git subprocess. Unchanged lint with sandbox permission exits0,11 checks. `npm run build`: exit0 incl dist artifact verification. No dependency file changes. Normal full-suite/landing slot reserved after client; awaiting explicit grant. Cloud IAM permissions, actual provider response serialization, concurrent read-modify-write races, browser/live playback remain unverified. Read-modify-write has no provider CAS guarantee and concurrent writers can still race. diff --git a/js/storage/s3-client.js b/js/storage/s3-client.js index 1c929540..52da84ba 100644 --- a/js/storage/s3-client.js +++ b/js/storage/s3-client.js @@ -24,6 +24,7 @@ function assignAwsSdk(module) { AbortMultipartUploadCommand: module.AbortMultipartUploadCommand, ListBucketsCommand: module.ListBucketsCommand, HeadBucketCommand: module.HeadBucketCommand, + GetBucketCorsCommand: module.GetBucketCorsCommand, PutBucketCorsCommand: module.PutBucketCorsCommand, DeleteObjectCommand: module.DeleteObjectCommand, PutObjectCommand: module.PutObjectCommand, diff --git a/js/storage/s3-multipart.js b/js/storage/s3-multipart.js index fc23765f..9d9704f0 100644 --- a/js/storage/s3-multipart.js +++ b/js/storage/s3-multipart.js @@ -104,31 +104,58 @@ export async function ensureBucketCors({ s3, bucket, origins, region } = {}) { throw new Error("Bucket name is required to configure CORS"); } - const { PutBucketCorsCommand } = requireAwsSdk(); - - const allowedOrigins = (origins || []).filter(Boolean); + const allowedOrigins = [...new Set((origins || []).filter(Boolean))]; if (allowedOrigins.length === 0) { return; } + const { GetBucketCorsCommand, PutBucketCorsCommand } = requireAwsSdk(); await ensureBucketExists({ s3, bucket, region }); + let existingRules; + try { + const response = await s3.send(new GetBucketCorsCommand({ Bucket: bucket })); + existingRules = response.CORSRules || []; + } catch (error) { + // A denied or failed read must never turn into a destructive replacement. + if (error?.name !== "NoSuchCORSConfiguration") { + throw error; + } + existingRules = []; + } + + const defaultRule = { + AllowedHeaders: ["*"], + AllowedMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "OPTIONS"], + ExposeHeaders: ["ETag", "Content-Length", "Content-Range", "Accept-Ranges"], + MaxAgeSeconds: 3600, + }; + const equivalentRules = existingRules.filter((rule) => + // Only explicit origins in equivalent default rules count as coverage. + // Arbitrary rules (including wildcard rules) remain completely untouched. + Object.keys(rule).every((key) => + key === "AllowedOrigins" || key === "ID" || key in defaultRule + ) && + rule.MaxAgeSeconds === defaultRule.MaxAgeSeconds && + ["AllowedHeaders", "AllowedMethods", "ExposeHeaders"].every((key) => + Array.isArray(rule[key]) && + rule[key].length === defaultRule[key].length && + defaultRule[key].every((value) => rule[key].includes(value)) + ) + ); + const uncoveredOrigins = allowedOrigins.filter((origin) => + !equivalentRules.some((rule) => rule.AllowedOrigins?.includes(origin)) + ); + if (uncoveredOrigins.length === 0) { + return; + } + const command = new PutBucketCorsCommand({ Bucket: bucket, CORSConfiguration: { CORSRules: [ - { - AllowedHeaders: ["*"], - AllowedMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "OPTIONS"], - AllowedOrigins: allowedOrigins, - ExposeHeaders: [ - "ETag", - "Content-Length", - "Content-Range", - "Accept-Ranges", - ], - MaxAgeSeconds: 3600, - }, + ...existingRules, + { ...defaultRule, AllowedOrigins: uncoveredOrigins }, ], }, }); diff --git a/test_logs/TEST_LOG_2026-10-20_13-39-30_storage-cors.md b/test_logs/TEST_LOG_2026-10-20_13-39-30_storage-cors.md new file mode 100644 index 00000000..ada21496 --- /dev/null +++ b/test_logs/TEST_LOG_2026-10-20_13-39-30_storage-cors.md @@ -0,0 +1,7 @@ +# storage-cors-1 offline investigation +- HEAD: bbc1be79e941add929c9c51f984778676822b5f2; branch area/storage-cors. +- `git diff 0c1dd7e86be3e28edc96aca47f7753a98990dde0 HEAD -- js/storage/s3-multipart.js js/storage/s3-client.js`: no changes; filed report still applies. +- `env -u NODE_TEST_CONTEXT node /tmp/storage-cors-reproduce.mjs`: exit0, 5 characterization cases: existing-rule loss0/1 preserved; repeated call identical policy/2 PUTs; absent-config1 PUT; read-denial fixture1 PUT/0 GET; empty origins0 IO. +- Uses production s3-client and s3-multipart modules, registerHooks fake SDK import, replacing policy transport. No internal helper replacement. All unexpected HTTP imports throw. +- `curl -s --max-time 10 'https://api.github.com/repos/PR0M3TH3AN/bitvid/pulls?state=open&per_page=100' -o /tmp/storage-cors-open-prs.json`: exit6 DNS; no overlap verification claimed. +- No new regression tests or product edits yet. No full unit/lint/build/browser/cloud checks run. No resource wait before reproduction; awaiting routing since13:39:21Z. diff --git a/test_logs/TEST_LOG_2026-10-20_13-43-30_storage-cors.md b/test_logs/TEST_LOG_2026-10-20_13-43-30_storage-cors.md new file mode 100644 index 00000000..55759170 --- /dev/null +++ b/test_logs/TEST_LOG_2026-10-20_13-43-30_storage-cors.md @@ -0,0 +1,10 @@ +# storage-cors-1 routed verification +- Base HEAD bbc1be79e941add929c9c51f984778676822b5f2; uncommitted implementation. +- `env -u NODE_TEST_CONTEXT node tests/storage-cors-preservation.test.mjs`:9/9 pass; original HEAD helper variant8/9 fail, exit1. +- `python3 /tmp/storage-cors-mutants.py`:8/8 restored variants rejected; extra ignore-permissions/missing-SDK-export variants rejected,10 total. +- `env -u NODE_TEST_CONTEXT node scripts/run-unit-tests.mjs storage-cors-preservation storage-cache-control multipart-empty-file-guard`: exit0,3/3 files,13 scenarios. +- `env -u NODE_TEST_CONTEXT npm ci --offline --ignore-scripts`: exit0,4s,441 packages installed, no dependency manifest change. +- `env -u NODE_TEST_CONTEXT npm run lint`: first exit127 missing stylelint; second exit2 sandbox git subprocess EPERM; unchanged permission retry exit0 (11 checks). +- `env -u NODE_TEST_CONTEXT npm run build`: exit0 incl artifact verifier. +- `git diff --check`: exit0. +- Not run: full normal gate, browser/cloud. Dispatch reserves full/submit slot after client; awaiting explicit grant. diff --git a/tests/storage-cors-preservation.test.mjs b/tests/storage-cors-preservation.test.mjs new file mode 100644 index 00000000..49dd1a9e --- /dev/null +++ b/tests/storage-cors-preservation.test.mjs @@ -0,0 +1,140 @@ +// Real storage helper + SDK wrapper; only SDK classes and S3 transport are fake. +import test from "node:test"; +import assert from "node:assert/strict"; +import { registerHooks } from "node:module"; + +const commandNames = ["S3Client", "HeadBucketCommand", "CreateBucketCommand", "GetBucketCorsCommand", "PutBucketCorsCommand"]; +const hooks = registerHooks({ + resolve(specifier, context, nextResolve) { + if (specifier.startsWith("https://esm.sh/@aws-sdk/client-s3@")) { + return { url: "offline:storage-cors-sdk", shortCircuit: true }; + } + if (/^https?:/.test(specifier)) throw new Error("Network forbidden in CORS fixtures"); + return nextResolve(specifier, context); + }, + load(url, context, nextLoad) { + if (url === "offline:storage-cors-sdk") { + return { format: "module", shortCircuit: true, source: commandNames.map(name => + `export class ${name} { constructor(input) { this.input = input; } }` + ).join("\n") }; + } + return nextLoad(url, context); + }, +}); +// The full runner disables network imports globally. Our hook supplies the SDK locally. +globalThis.__BITVID_DISABLE_NETWORK_IMPORTS__ = false; +const { ensureS3SdkLoaded } = await import("../js/storage/s3-client.js"); +await ensureS3SdkLoaded(); +const { ensureBucketCors } = await import("../js/storage/s3-multipart.js"); +hooks.deregister(); +globalThis.__BITVID_DISABLE_NETWORK_IMPORTS__ = true; + +const first = "https://first.example.invalid"; +const second = "https://second.example.invalid"; +const third = "https://third.example.invalid"; +const custom = { ID: "read-only", AllowedOrigins: [first], AllowedMethods: ["GET"], AllowedHeaders: ["Range"], ExposeHeaders: ["ETag"], MaxAgeSeconds: 75 }; +const defaults = origins => ({ AllowedHeaders: ["*"], AllowedMethods: ["GET", "HEAD", "PUT", "POST", "DELETE", "OPTIONS"], AllowedOrigins: origins, ExposeHeaders: ["ETag", "Content-Length", "Content-Range", "Accept-Ranges"], MaxAgeSeconds: 3600 }); +function transport(rules, readError) { + return { + policy: rules === null ? null : { CORSRules: structuredClone(rules) }, puts: 0, calls: [], + async send(command) { + const name = command.constructor.name; + this.calls.push(name); + assert.equal(command.input.Bucket, "offline-bucket"); + if (name === "HeadBucketCommand") return {}; + if (name === "GetBucketCorsCommand") { + if (readError) throw readError; + if (this.policy === null) throw Object.assign(new Error("No policy"), { name: "NoSuchCORSConfiguration" }); + return structuredClone(this.policy); + } + if (name === "PutBucketCorsCommand") { + this.puts++; + this.policy = structuredClone(command.input.CORSConfiguration); + return {}; + } + throw new Error(`Unexpected command ${name}`); + }, + }; +} +const ensure = (s3, origins) => ensureBucketCors({ s3, bucket: "offline-bucket", origins }); + +test("adding a second origin preserves the complete existing custom policy", async () => { + const s3 = transport([custom]); + await ensure(s3, [second]); + assert.deepEqual(s3.policy, { CORSRules: [custom, defaults([second])] }); + assert.equal(s3.puts, 1); +}); + +test("wildcard and multiple custom rules keep their fields and order", async () => { + const wildcard = { ...custom, ID: "wildcard", AllowedOrigins: ["*"], AllowedHeaders: ["X-Custom"], AllowedMethods: ["HEAD"], ExtraField: "preserve" }; + const s3 = transport([wildcard, custom]); + await ensure(s3, [second]); + assert.deepEqual(s3.policy, { CORSRules: [wildcard, custom, defaults([second])] }); +}); + +test("duplicate origins and repeated calls are idempotent without another PUT", async () => { + const s3 = transport([custom]); + await ensure(s3, [second, second, null, ""]); + const once = structuredClone(s3.policy); + assert.deepEqual(once, { CORSRules: [custom, defaults([second])] }); + await ensure(s3, [second, second]); + assert.deepEqual(s3.policy, once); + assert.equal(s3.puts, 1); +}); + +test("equivalent default rules cover origins across rules regardless of array order", async () => { + const existing = [defaults([first]), { ...defaults([second]), AllowedMethods: [...defaults([]).AllowedMethods].reverse() }]; + const s3 = transport(existing); + await ensure(s3, [first, second]); + assert.deepEqual(s3.policy, { CORSRules: existing }); + assert.equal(s3.puts, 0); +}); + +test("similar rules with different non-origin permissions do not cover a new request", async () => { + for (const override of [ + { AllowedMethods: ["GET"] }, + { AllowedHeaders: ["Range"] }, + { ExposeHeaders: ["ETag"] }, + { MaxAgeSeconds: 75 }, + { ExtraField: "preserve" }, + ]) { + const existing = { ...defaults([second]), ...override }; + const s3 = transport([existing]); + await ensure(s3, [second]); + assert.deepEqual(s3.policy, { CORSRules: [existing, defaults([second])] }); + assert.equal(s3.puts, 1); + } +}); + +test("only uncovered origins receive a separate rule", async () => { + const existing = [defaults([first]), custom]; + const s3 = transport(existing); + await ensure(s3, [first, second, third]); + assert.deepEqual(s3.policy, { CORSRules: [...existing, defaults([second, third])] }); +}); + +test("an explicit absent policy creates defaults and then skips repeated writes", async () => { + const s3 = transport(null); + await ensure(s3, [first]); + assert.deepEqual(s3.policy, { CORSRules: [defaults([first])] }); + await ensure(s3, [first]); + assert.equal(s3.puts, 1); +}); + +test("all other policy read failures reject unchanged without PUT", async () => { + for (const error of [Object.assign(new Error("Denied"), { name: "AccessDenied" }), Object.assign(new Error("Not found"), { name: "NoSuchBucket", $metadata: { httpStatusCode: 404 } }), new Error("Transport failed")]) { + const s3 = transport([custom], error); + await assert.rejects(ensure(s3, [second]), actual => actual === error); + assert.deepEqual(s3.policy, { CORSRules: [custom] }); + assert.equal(s3.puts, 0); + } +}); + +test("empty or missing origins perform no IO and preserve policy", async () => { + for (const origins of [[], undefined, [null, "", false]]) { + const s3 = transport([custom]); + await ensure(s3, origins); + assert.deepEqual(s3.calls, []); + assert.deepEqual(s3.policy, { CORSRules: [custom] }); + } +}); diff --git a/todo/TODO_2026-10-20_13-39-30_storage-cors.md b/todo/TODO_2026-10-20_13-39-30_storage-cors.md new file mode 100644 index 00000000..aaaf8682 --- /dev/null +++ b/todo/TODO_2026-10-20_13-39-30_storage-cors.md @@ -0,0 +1,7 @@ +# storage-cors-1 +- [x] Read rules/mailbox/memory/known issues/test integrity; claim current applicable item. +- [x] Trace callers and reproduce offline loss at bbc1be79. +- [x] Send demonstrated loss and proposed preservation semantics to dispatch. +- [ ] Obtain fix routing; implement bounded regression and product change only after routing. +- [ ] Run mutant/focused checks, coordinated full gates/build, commit/merge/normal queue and durable ancestry check. +- Blocked: awaiting dispatch routing. PR overlap check unavailable: curl exit6 DNS resolution. From e9d8886c3a57e40d07a57da15e5253b0d65a7edc Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN Date: Tue, 20 Oct 2026 09:44:53 -0400 Subject: [PATCH 2/3] storage-cors-1 record merged-tree checks and pending coordinated gate --- test_logs/TEST_LOG_2026-10-20_13-44-40_storage-cors.md | 7 +++++++ todo/TODO_2026-10-20_13-44-40_storage-cors.md | 7 +++++++ 2 files changed, 14 insertions(+) create mode 100644 test_logs/TEST_LOG_2026-10-20_13-44-40_storage-cors.md create mode 100644 todo/TODO_2026-10-20_13-44-40_storage-cors.md diff --git a/test_logs/TEST_LOG_2026-10-20_13-44-40_storage-cors.md b/test_logs/TEST_LOG_2026-10-20_13-44-40_storage-cors.md new file mode 100644 index 00000000..39a82b4a --- /dev/null +++ b/test_logs/TEST_LOG_2026-10-20_13-44-40_storage-cors.md @@ -0,0 +1,7 @@ +# storage-cors-1 merged-tree verification +- Product commit:2fb6a536568eeb5b4cc04257255f98cde34b7f66. +- Required merge:0919be930c1c8cc8e26685381b3763b660f741ed (git merge unstable; sandbox EROFS required authorized permission retry). Incoming changes administrative only. +- `env -u NODE_TEST_CONTEXT node scripts/run-unit-tests.mjs storage-cors-preservation storage-cache-control multipart-empty-file-guard`: exit0,3/3 files,13 scenarios. +- `env -u NODE_TEST_CONTEXT npm run lint`: exit0,11 checks; same sandbox permission for read-only git subprocess. +- `env -u NODE_TEST_CONTEXT npm run build`: exit0 incl deployment-artifact verifier. +- Full/submit reserved after client; no explicit grant as of13:44:33UTC. No browser/cloud or concurrent-writer qualification. No landing claim. diff --git a/todo/TODO_2026-10-20_13-44-40_storage-cors.md b/todo/TODO_2026-10-20_13-44-40_storage-cors.md new file mode 100644 index 00000000..32c01380 --- /dev/null +++ b/todo/TODO_2026-10-20_13-44-40_storage-cors.md @@ -0,0 +1,7 @@ +# storage-cors-1 +- [x] Offline loss reproduced and dispatch independently confirmed; fix routed. +- [x] Preserve policy implementation2fb6a536; merged unstable0919be93. +- [x]9 regression scenarios,10 restored mutants,focused3/3 files/13 scenarios; lint11/11 and build pass on merged tree. +- [ ] Dispatch explicit full-suite/submit grant (client ahead). +- [ ] Full normal gate; submit/durable landing+unstable ancestry; close backlog; dispatch final evidence. +- Remaining scope: actual cloud/API permissions/serialization and concurrent policy writers unverified; no browser needed. From 699d72927bee46bdafb6a7775a12d05f75e3c7e1 Mon Sep 17 00:00:00 2001 From: thePR0M3TH3AN Date: Tue, 20 Oct 2026 10:04:14 -0400 Subject: [PATCH 3/3] storage-cors-1 record full 428-file gate before normal landing --- docs/testing/storage-cors-integrity.md | 2 ++ test_logs/TEST_LOG_2026-10-20_14-04-00_storage-cors.md | 9 +++++++++ 2 files changed, 11 insertions(+) create mode 100644 test_logs/TEST_LOG_2026-10-20_14-04-00_storage-cors.md diff --git a/docs/testing/storage-cors-integrity.md b/docs/testing/storage-cors-integrity.md index a09749dc..5cd43008 100644 --- a/docs/testing/storage-cors-integrity.md +++ b/docs/testing/storage-cors-integrity.md @@ -51,3 +51,5 @@ test_integrity_note: Nine regression scenarios pass. Original helper fails8/9 with exit1; empty-origin control passes. Ten deliberately broken variants exit1 and were restored: overwrite existing rules; reverse rules; omit dedup; repeat PUT; include covered origins; reject absent policy; swallow read errors; empty-origins IO; ignore non-origin permissions (kills scenario5); remove SDK GetBucketCors export. Every scenario fails under at least one variant. Final focused runner passes3/3 files (13 scenarios total:9 CORS,3 cache-control,1 empty upload). `npm ci --offline --ignore-scripts`: exit0,441 installed packages in4s from local cache. Initial lint exit127 absent stylelint; after install lint exit2 sandbox EPERM read-only git subprocess. Unchanged lint with sandbox permission exits0,11 checks. `npm run build`: exit0 incl dist artifact verification. No dependency file changes. Normal full-suite/landing slot reserved after client; awaiting explicit grant. Cloud IAM permissions, actual provider response serialization, concurrent read-modify-write races, browser/live playback remain unverified. Read-modify-write has no provider CAS guarantee and concurrent writers can still race. + +Final merged gate atbfa36a3f350d6a9751a1a43c83fc890c855091fc: full normal runner428/428 files exit0 with UNIT_TEST_TIMEOUT_MS=60000/NODE_TEST_CONTEXT unset; focused3/3 files(13 scenarios),lint11 checks,build/artifact pass. Resource wait949s before13:58:27UTC grant; full completed14:03:49UTC. No product changes since restored mutants. Normal landing pending; no real-cloud/concurrent-writer claim. diff --git a/test_logs/TEST_LOG_2026-10-20_14-04-00_storage-cors.md b/test_logs/TEST_LOG_2026-10-20_14-04-00_storage-cors.md new file mode 100644 index 00000000..2db5c497 --- /dev/null +++ b/test_logs/TEST_LOG_2026-10-20_14-04-00_storage-cors.md @@ -0,0 +1,9 @@ +# storage-cors-1 final pre-submit checks +- Product2fb6a536568eeb5b4cc04257255f98cde34b7f66; newest unstable merge bfa36a3f350d6a9751a1a43c83fc890c855091fc. +- Slot granted13:58:27UTC; requested13:42:38UTC; resource wait949s. Start acknowledgement13:58:42UTC. Full completed14:03:49UTC. +- `env -u NODE_TEST_CONTEXT UNIT_TEST_TIMEOUT_MS=60000 npm test`: exit0,428/428 files, no failed/cancelled files (normal runner,60s/file diagnostic). +- `env -u NODE_TEST_CONTEXT node scripts/run-unit-tests.mjs storage-cors-preservation storage-cache-control multipart-empty-file-guard`:exit0,3/3 files,13 scenarios. +- `env -u NODE_TEST_CONTEXT npm run lint`:exit0,11 checks, read-only git subprocess permission as before. +- `env -u NODE_TEST_CONTEXT npm run build`:exit0 including deploy-artifact verifier. +- No new product changes since10 rejected/restored mutants/9 CORS scenarios. No weakened assertions/retries/sleeps. +- Pending normal queue/durable status+ancestry before closure. No cloud/browser/concurrent-writer qualification; preserve preview3000. IAM/read permission and lost updates from concurrent non-CAS policy writes remain limitations.