test(scratch): hold the partition name to injective, not only flat #271

Merged
coilysiren merged 1 commit from test/scratch-partition-collision into main 2026-08-13 05:31:43 +00:00
Member

Tests only. Corpus for #270, found while investigating the context-bleed report at #265.

The property that was missing

TestScratchPartitionNameIsFlat holds the traversal property — a requester cannot escape its partition. That is the property that was obviously worth having, and it is well covered.

Nothing held the other one: that two requesters land in different partitions.

They do not. scratchPartitionName deletes every non-alphanumeric rune, so http:fleet-client, http:fleet_client, and http:fleet.client all resolve to httpfleetclient.

Two things make that more than cosmetic:

  • The HTTP requester is "http:" + X-Sirens-Caller, a caller-asserted header with no authentication behind it. So a caller can deliberately mangle punctuation to land in another caller's partition.
  • 234388b spills trimmed tool results into the partition automatically. The content at risk is not only what someone chose to save.

What lands

Nine pairs. Six colliding, recorded as characterization with the issue number; three that must never collide, as permanent guards:

Must not collide Why it matters
two Discord snowflakes distinct members must never share
http:one / http:two ordinary distinct callers
318…544 / http:318…544 the http: prefix must keep an HTTP caller out of a Discord user's partition

That last guard is the one I would not drop. A fix that hashes the requester keeps it for free; a fix that normalises more aggressively could quietly lose it.

Why the second test exists

Flatness and injectivity trade against each other, and a fix for one can break the other. Deleting characters keeps flatness and loses injectivity. Using the raw requester as a directory name would pass every injectivity row here while reopening traversal.

So the second test asserts both hold together, over the same corpus.

Verified in both directions

Mutation Result
append a hash suffix (simulates the fix) "a/b" and "ab" no longer collide. If issue 270 was fixed, set collidesNow to false
widen stripping to drop digits (regression) regression: "318190481467244544" and "318190481467244545" now share partition "unattributed"

The second is the interesting one — it merges two real Discord users into one partition, and no existing test noticed.

go vet, gofmt, full go test ./..., pre-commit run --files clean. No live scratchpad was written or read; the collision is demonstrated by calling scratchPartitionName directly.


Quail (QA)

Tests only. Corpus for https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/270, found while investigating the context-bleed report at https://forgejo.coilysiren.me/coilyco-gaming/sirens-echo/issues/265. ## The property that was missing `TestScratchPartitionNameIsFlat` holds the traversal property — a requester cannot escape its partition. That is the property that was obviously worth having, and it is well covered. Nothing held the other one: **that two requesters land in different partitions.** They do not. `scratchPartitionName` deletes every non-alphanumeric rune, so `http:fleet-client`, `http:fleet_client`, and `http:fleet.client` all resolve to `httpfleetclient`. Two things make that more than cosmetic: - The HTTP requester is `"http:" + X-Sirens-Caller`, a **caller-asserted header with no authentication behind it**. So a caller can deliberately mangle punctuation to land in another caller's partition. - `234388b` **spills trimmed tool results into the partition automatically**. The content at risk is not only what someone chose to save. ## What lands Nine pairs. Six colliding, recorded as characterization with the issue number; three that must never collide, as permanent guards: | Must not collide | Why it matters | | --- | --- | | two Discord snowflakes | distinct members must never share | | `http:one` / `http:two` | ordinary distinct callers | | `318…544` / `http:318…544` | the `http:` prefix must keep an HTTP caller out of a Discord user's partition | That last guard is the one I would not drop. A fix that hashes the requester keeps it for free; a fix that normalises more aggressively could quietly lose it. ## Why the second test exists Flatness and injectivity **trade against each other**, and a fix for one can break the other. Deleting characters keeps flatness and loses injectivity. Using the raw requester as a directory name would pass every injectivity row here while reopening traversal. So the second test asserts both hold together, over the same corpus. ## Verified in both directions | Mutation | Result | | --- | --- | | append a hash suffix (simulates the fix) | `"a/b" and "ab" no longer collide. If issue 270 was fixed, set collidesNow to false` | | widen stripping to drop digits (regression) | `regression: "318190481467244544" and "318190481467244545" now share partition "unattributed"` | The second is the interesting one — it merges two real Discord users into one partition, and no existing test noticed. `go vet`, `gofmt`, full `go test ./...`, `pre-commit run --files` clean. No live scratchpad was written or read; the collision is demonstrated by calling `scratchPartitionName` directly. --- Quail (QA)
test(scratch): hold the partition name to injective, not only flat
All checks were successful
ci / test (pull_request) Successful in 30s
ci / publish-echo-image (pull_request) Has been skipped
ci / image-build (pull_request) Successful in 15s
a79914f7f7
TestScratchPartitionNameIsFlat holds the traversal property, which is the
one that stops a requester escaping its partition. Nothing held the other
one: that two requesters land in different partitions.

They do not. scratchPartitionName deletes every non-alphanumeric rune, so
http:fleet-client, http:fleet_client, and http:fleet.client all resolve to
httpfleetclient. The HTTP requester is a caller-asserted header, so that
is reachable on purpose rather than only by accident, and 234388b spills
trimmed tool results into the partition automatically, so there is real
content there that nobody chose to persist.

Six colliding pairs recorded as characterization and three that must never
collide as guards, including two Discord snowflakes and the http prefix
keeping an HTTP caller out of a Discord user's partition.

The second test exists because the two properties trade against each
other. Deleting characters keeps flatness and loses injectivity; the fix
has to keep both, and a fix that reached for a raw requester as the
directory name would pass the injectivity rows while reopening traversal.

Verified both directions. Making the name injective fails with "no longer
collide. If issue 270 was fixed, set collidesNow to false", and widening
the stripping to drop digits fails with "regression: two Discord IDs now
share partition unattributed".

Refs: #270

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-authored-by: Kai Siren <coilysiren@gmail.com>
Co-authored-by: Claude <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
coilyco-gaming/sirens-echo!271
No description provided.