Skip to content

Punycode 4.0.0: manifest modernization, Linux support, decode hardening, URL-aware IDNA API - #81

Merged
futamura merged 10 commits into
mainfrom
develop
Aug 18, 2026
Merged

Punycode 4.0.0: manifest modernization, Linux support, decode hardening, URL-aware IDNA API#81
futamura merged 10 commits into
mainfrom
develop

Conversation

@futamura

Copy link
Copy Markdown
Owner

Summary

Everything staged for the 4.0.0 release:

  • Breaking — manifest: Package.swift requires swift-tools 5.9 (Xcode 15+ for SPM consumers) and declares explicit platforms (deployment targets unchanged: macOS 10.13, iOS 12, tvOS 12, watchOS 4, visionOS 1).
  • Linux support: verified by a new SPM: Linux, Swift 6.2 CI job on the official Swift container, part of the CI Success gate.
  • Decode hardening (Ability to insert invalid Unicode character #78): malformed punycode (mid-sequence truncation, C1 control output) now returns nil instead of garbage; RFC 3492 overflow checks implemented with checked arithmetic — adversarial inputs return nil instead of trapping.
  • IDNA mapping (punycodeEncoded and idnaEncoded inconsistency #4, breaking): idnaEncoded maps input first (NFKC folding, lowercasing, NFC, ideographic full stop); idnaDecoded accepts uppercase ACE prefixes; punycodeEncoded documented as the raw RFC 3492 single-label transform.
  • New API: idnaEncodedURL / idnaDecodedURL transform only the host of a URL-shaped string (motivated by Example with idna-encoded string does not work TLDExtractSwift#8).
  • Identity: bundle IDs renamed to dev.futamura.*; version bumped to 4.0.0; CocoaPods badges dropped from the README.

Merging closes #78 and #4.

Release plan

After merge: push the 4.0.0 tag — release.yml verifies it against MARKETING_VERSION, creates the GitHub Release from the changelog section, and pushes to CocoaPods trunk.

Test plan

  • CI Success gate passes (including the Linux job)
  • After tagging: Release workflow creates the GitHub Release and the pod push succeeds

BREAKING CHANGE: SPM consumers need Xcode 15 / Swift 5.9 or later.
Deployment targets are unchanged (macOS 10.13, iOS 12, tvOS 12,
watchOS 4, visionOS 1) but are now explicit in the manifest instead
of relying on SPM defaults.
Runs swift test on the official swift:6.2 container; the only
Foundation dependency is CharacterSet.urlHostAllowed, available in
swift-corelibs-foundation. Added to the CI Success gate.
Completes the gumob -> futamura account rename; the tools-version
requirement bump makes this a major release.
CocoaPods is sunsetting (trunk read-only 2026-12-02); the install
section keeps its migration warning.
decodePunycode returned garbage for malformed input and could trap on
adversarial input:
- inputs ending mid-digit-sequence now return nil (RFC 3492 bad input)
- decoded C1 control scalars (U+0080...U+009F) now return nil
- the overflow checks required by RFC 3492 sections 6.3/6.4 are
  implemented with checked arithmetic; overflowing inputs return nil
  instead of crashing

encodeIDNA now maps the hostname first (NFKC folding, lowercasing, NFC,
ideographic full stop to '.'), so full-width forms and alternate dots
encode correctly; the full UTS #46 table is intentionally out of scope.
decodedIDNA accepts an uppercase ACE prefix (RFC 5890). punycodeEncoded
stays raw RFC 3492 and is now documented as such, with idnaEncoded
pointed to for hostnames.

The UnicodeScalar.isValid helper checked surrogate bounds that
Unicode.Scalar cannot represent (and had a typo, 0xD880); it now
excludes C1 controls, shared by encode and decode.

Closes #78
Closes #4
Applying idnaEncoded to a full URL mangles it: the scheme and path get
swallowed into labels ("http://www" becomes one label). The new
variants locate the host of [scheme://][userinfo@]host[:port][/rest]
by hand (no new dependencies) and transform only that segment. IPv6
literals pass through; a "://" inside a query is not mistaken for a
scheme delimiter.

Motivated by futamura/TLDExtractSwift#8, whose README example applied
idnaEncoded to a URL.
Comment thread Package.swift
name: "PunycodeSwiftTests",
dependencies: ["Punycode"],
path: "Tests")
path: "Tests"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Trailing Comma Violation: Collection literals should not have trailing commas. (trailing_comma)

Comment thread Package.swift
.iOS(.v12),
.tvOS(.v12),
.watchOS(.v4),
.visionOS(.v1),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Trailing Comma Violation: Collection literals should not have trailing commas. (trailing_comma)

Comment thread Package.swift
name: "PunycodeSwiftTests",
dependencies: ["Punycode"],
path: "Tests")
path: "Tests"),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Trailing Comma Violation: Collection literals should not have trailing commas. (trailing_comma)

Comment thread Package.swift
.iOS(.v12),
.tvOS(.v12),
.watchOS(.v4),
.visionOS(.v1),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Trailing Comma Violation: Collection literals should not have trailing commas. (trailing_comma)

@codecov

codecov Bot commented Aug 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.55172% with 3 lines in your changes missing coverage. Please review.
✅ Project coverage is 98.73%. Comparing base (44589d2) to head (20351b4).

Files with missing lines Patch % Lines
Sources/Punycode.swift 96.15% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main      #81      +/-   ##
==========================================
+ Coverage   97.57%   98.73%   +1.15%     
==========================================
  Files           3        3              
  Lines         165      237      +72     
==========================================
+ Hits          161      234      +73     
+ Misses          4        3       -1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

The repeat-while with a break confused coverage region mapping (lines
after the break reported as unexecuted); the equivalent while-with-flag
form maps cleanly and drops the separate post-loop completeness guard.
Remaining uncovered lines are the practically unreachable overflow
guards required by RFC 3492.
@futamura
futamura merged commit a32282d into main Aug 18, 2026
36 of 37 checks passed
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.

Ability to insert invalid Unicode character

1 participant