Skip to content

feat: PAT improvements (UUIDv7 for random + hashing) - #2048

Merged
netomi merged 8 commits into
eclipse-openvsx:trusted-publishingfrom
cstamas:trusted-publishing-tokens
Aug 7, 2026
Merged

feat: PAT improvements (UUIDv7 for random + hashing)#2048
netomi merged 8 commits into
eclipse-openvsx:trusted-publishingfrom
cstamas:trusted-publishing-tokens

Conversation

@cstamas

@cstamas cstamas commented Aug 6, 2026

Copy link
Copy Markdown
Member

Changes:

  • use UUIDv7 for random tokens
  • implement token value hashing

cstamas added 2 commits August 6, 2026 14:24
Introduce faster `java-uuid-generator` library from Tatu.
For now just as "drop in replacement", but we should also
do cluster-wide-sync using Redis maybe?
@cstamas
cstamas requested a review from netomi August 6, 2026 12:36
@cstamas

This comment was marked as outdated.

@netomi

netomi commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Let me verify the current JUG API since I want to give you the right generator methods.The short version: the answer depends entirely on which UUID version you pick, and the good news is the modern choice makes cross-pod coordination a non-issue.

If you use v4 (random) or v7, you don't need to coordinate anything between pods. Both draw the bulk of their bits from a CSPRNG, so uniqueness comes from entropy rather than from any per-node identifier. For v7 the layout is a 48-bit millisecond timestamp plus ~74 bits of randomness. Two pods generating in the very same millisecond would both have to draw the same 74-bit value to collide — the birthday bound puts that at roughly 2³⁷ UUIDs within a single millisecond before collision probability becomes meaningful. That's not a scenario you'll hit, and it holds regardless of how many pods you run or how you schedule them. No downward API, no node assignment, nothing.

Given your stack (Spring Boot, JPA, TimescaleDB), I'd default to v7 specifically. It's time-sortable (lexicographic order matches creation order), which keeps B-tree index inserts near the right edge instead of scattering them like v4 does — much friendlier as a primary key, and it plays nicely with time-partitioned data. In JUG that's:

// v7 — recommended default, no per-pod setup needed
private static final NoArgGenerator UUIDS = Generators.timeBasedEpochGenerator();
UUID id = UUIDS.generate();

There's also Generators.timeBasedEpochRandomGenerator() (added in 5.0), which uses fresh random for the trailing bits on every call rather than a monotonic counter within a millisecond. The plain timeBasedEpochGenerator() gives you monotonicity within a pod, which is usually what you want for ordering; the random variant trades a bit of intra-millisecond ordering for slightly simpler entropy behavior. Either is fine across pods.

The only case where multi-pod coordination actually matters is v1 or v6 (time-based with a node identifier). These derive part of the value from the host's MAC address / node ID plus timestamp plus clock sequence. In containers the MAC is often randomly assigned or, worse, could repeat across pods depending on your CNI, and JUG falls back to a random "dummy" address if it can't read a real one. Collisions there require same node ID + same 100ns tick + same clock sequence — unlikely, but the whole design assumes the node ID is genuinely unique, so you'd want to guarantee it rather than hope. If you have a reason to use v6 (say you want time-ordering and the v1-style structure), inject a stable per-pod identifier via the downward API and hand it to JUG as the ethernet address:

env:
  - name: POD_UID
    valueFrom:
      fieldRef:
        fieldPath: metadata.uid
// derive a 48-bit node id from the pod UID, set the multicast bit
// so it can never collide with a real hardware MAC
byte[] node = deriveFrom(System.getenv("POD_UID")); // hash -> 6 bytes
node[0] |= 0x01;
EthernetAddress addr = new EthernetAddress(node);
UUID id = Generators.timeBasedReorderedGenerator(addr).generate(); // v6

Pod UID is better than pod name or IP here — names collide across namespaces and restarts, and pod IPs get recycled, whereas the UID is unique for the lifetime of that object. Setting the multicast bit (the 0x01 on the first byte) marks it as locally-administered so it's guaranteed disjoint from any real NIC address JUG might otherwise pick up.

So my recommendation: go v7 with timeBasedEpochGenerator() and skip the coordination problem entirely. Only reach for the downward-API node-ID wiring if you specifically need v1/v6 semantics.

One aside — for v4 you don't even need JUG, since java.util.UUID.randomUUID() is built in; JUG earns its place mainly for v1/v6/v7 and for its faster generators when you're producing them at high volume. Current JUG is 5.1.0.

Comment thread server/src/main/java/org/eclipse/openvsx/util/UUIDService.java Outdated
@cstamas

This comment was marked as outdated.

@cstamas cstamas changed the title feat: UUID use cleanup feat: UUIDv7 for random Aug 6, 2026
@cstamas
cstamas marked this pull request as ready for review August 6, 2026 13:30
@cstamas
cstamas requested a review from netomi August 6, 2026 15:17
Hash token values, also PAT table got version column that is 0 for existing tokens, and current version is 1.
"On the fly" upgrade added but also a job.

Changes:
* token config got hashAlg + salt
* token table got version smallint field (initialized to 0 on migration)
* new job upgrades token (replaces value with hash(value + salt) and sets version = 1)
* use token upgrade on the fly if (needed)
* tests reworked to use less mocks
@cstamas cstamas changed the title feat: UUIDv7 for random feat: PAT improvements (UUIDv7 for random + hashing) Aug 7, 2026
@netomi
netomi merged commit 063e431 into eclipse-openvsx:trusted-publishing Aug 7, 2026
1 check passed
@cstamas
cstamas deleted the trusted-publishing-tokens branch August 7, 2026 12:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants