Skip to content

lab-ops-hub: judge U+0345 by its UTS-46 mapping in the container validator - #610

Merged
dezren39 merged 1 commit into
mainfrom
sweep/596-u0345-uts46-mapping
Oct 22, 2026
Merged

dezren39 merged 1 commit into
mainfrom
sweep/596-u0345-uts46-mapping

Conversation

@dezren39

@dezren39 dezren39 commented Oct 22, 2026 •

Copy link
Copy Markdown
Member

Fixes #596.

Problem

UTS-46 maps U+0345 (combining Greek ypogegrammeni) to U+03B9 (ι, bidi class L), but the container validator's mapped form is NFKC + lower(), and NFKC leaves U+0345 unchanged. The container therefore judged it as a combining mark (bidi NSM, legal mid-label in any context) while the Worker judges the mapped letter. Inside an RTL label the mapped form is R + L + R — a bidi-rule violation — so א\u0345א.com, א\u0345.com and the A-label spelling xn--jua51kba were certified by the container and refused by the Worker.

Solution

_judge_idna_label now applies the U+0345 → U+03B9 UTS-46 mapping before judging, so both call sites (raw labels and A-label decoded forms) judge the UTS-46-mapped label. The stale "known residual" comment that documented U+0345 as a leading mark is updated. Side effect, pinned by test: at label start the mapping closes the former over-refusal — \u0345abc.com is now accepted, matching the Worker (U+0345 maps to a letter, so the label starts with one).

Verification

  • Reproduced on main ae38cd65: all three RTL spellings container-ACCEPT / Worker-refuse.
  • Post-fix battery: RTL raw + A-label spellings REFUSE; ex\u0345ample.com, α\u0345.com, \u0345abc.com ACCEPT — identical to the Worker's verdicts under Bun on all six spellings.
  • Python suite 38/38, TS suite 31/31 (node --test). Ablation: the new Python test fails with only app.py reverted. ruff format clean.

Single-repo: _judge_idna_label exists only in developing-today/code.


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

…dator (#596)

UTS-46 maps U+0345 (combining Greek ypogegrammeni) to U+03B9
(iota, bidi class L), but NFKC leaves it unchanged, so the
container judged it as a combining mark (bidi NSM) — legal
mid-label anywhere — while the Worker judges the mapped letter.
Inside an RTL label the mapped form is R + L + R, a bidi-rule
violation: א\u0345א.com, א\u0345.com and the A-label spelling
xn--jua51kba were certified by the container and refused by the
Worker.

_judge_idna_label now applies the U+0345 -> U+03B9 mapping
before judging, covering both the raw-label and A-label-decoded
call sites. At label start the mapping also closes the former
leading-mark over-refusal (the mapped label starts with a
letter, matching the Worker); that behaviour change is pinned
by test.

Tests: new Python test_judges_u0345_by_its_uts46_mapping
(RTL spellings + A-label refused; Greek/LTR controls and the
label-start spelling accepted) and a TS pin of the Worker's
verdicts. Python 38/38, TS 31/31 (node --test); Bun differential
agrees on all six spellings; ablation: the new Python test
fails with only app.py reverted.
@dezren39
dezren39 requested a review from a team as a code owner October 22, 2026 20:03
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-22T20:17:21.741889Z 762d203 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@coderabbitai

coderabbitai Bot commented Oct 22, 2026

Copy link
Copy Markdown

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 58 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3ee185dd-13e4-404e-abfb-762e0b7df993
📥 Commits

Reviewing files that changed from the base of the PR and between ae38cd6 and 762d203.

📒 Files selected for processing: 3
  • pkgs/lab-ops-hub/container/app.py
  • pkgs/lab-ops-hub/test/lib.test.ts
  • pkgs/lab-ops-hub/test/test_container_validate.py
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@dezren39
dezren39 merged commit f05c555 into main Oct 22, 2026
5 checks passed
@dezren39
dezren39 deleted the sweep/596-u0345-uts46-mapping branch October 22, 2026 20:05

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 762d203562

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

# violation the Worker refuses, while at label start the mapped
# letter is an ordinary first character, closing the former
# leading-mark over-refusal (#596).
label = label.translate({0x0345: "ι"})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Do not remap decoded A-label payloads

_judge_idna_label also receives the decoded payload of xn-- labels, but UTS-46 mapping applies to raw U-label input, not after A-label decoding. Consequently, invalid A-labels such as xn--jua (decoding to U+0345) and xn--abc-blc (decoding to U+0345abc) are now translated to valid labels and accepted by the container, while Bun/WHATWG rejects both. Keep decoded A-labels on the unmapped validation path so redirects and initial requests cannot pass container validation with a hostname the Worker rejects.

Useful? React with 👍 / 👎.

# violation the Worker refuses, while at label start the mapped
# letter is an ordinary first character, closing the former
# leading-mark over-refusal (#596).
label = label.translate({0x0345: "ι"})

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Apply U+0345 mapping before enforcing the hostname limit

Because this translation happens only inside the per-label validator, the earlier whole-host length check still measures the unmapped punycode. For example, four labels consisting of U+0345 followed by 54 Greek alphas encode to 251 characters before this mapping but 255 afterward; the container now accepts that raw host because every mapped label is individually 63 characters, whereas the Worker's explicit 253-character guard rejects its canonical hostname. Map the raw host before computing encoded_labels, or recheck the mapped total, so an overlong redirect target is not accepted and passed to the resolver.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant