Skip to content

Truncate a hostname longer than 64 characters for self-signed certificates - #6900

Merged
ikhoon merged 8 commits into
line:mainfrom
ikhoon:pin-self-signed-cert-hostname
Aug 6, 2026
Merged

Truncate a hostname longer than 64 characters for self-signed certificates#6900
ikhoon merged 8 commits into
line:mainfrom
ikhoon:pin-self-signed-cert-hostname

Conversation

@ikhoon

@ikhoon ikhoon commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Motivation:

Self-signed certificate generation uses the local hostname as the certificate CN. On a machine whose hostname exceeds
64 characters — e.g. a GitHub Actions macOS runner named sjc20-cw714-0e535ccf-aeaf-489f-8a27-1ab749ed681c-fe6ab157f2e4.local
(67 characters) — it fails with:

java.lang.IllegalArgumentException: commonName length 67 exceeds RFC 5280 ub-common-name (64)

Both TlsKeyPair.ofSelfSigned() and ServerBuilder.tlsSelfSigned() are affected, so any test using them fails whenever such
a runner is assigned (example failure:
:athenz:shadedTest failed at class initialization).

Modifications:

  • Truncate an fqdn longer than 64 characters in the SelfSignedCertificate constructor, which covers every self-signed
    certificate generation path, and log a debug message when truncation happens.

Result:

  • Self-signed certificate generation no longer fails on a machine whose hostname exceeds 64 characters.

Motivation:

`TlsKeyPair.ofSelfSigned()` uses `SystemInfo.hostname()` as the certificate CN. On a machine whose
hostname exceeds 64 characters — e.g. a GitHub Actions macOS runner named
`sjc20-cw714-0e535ccf-aeaf-489f-8a27-1ab749ed681c-fe6ab157f2e4.local` (67 characters) — certificate
generation fails with `IllegalArgumentException: commonName length 67 exceeds RFC 5280
ub-common-name (64)`, so every test that calls the no-arg overload fails before it starts.
This broke `:athenz:shadedTest` on a macOS CI runner (`RoleTokenClientTest` and
`AthenzTokenClientErrorHandlingTest` failed at class initialization) and can hit any test that
uses the no-arg overload whenever such a runner is assigned.

Modifications:

- Replace all 20 no-arg `TlsKeyPair.ofSelfSigned()` call sites in tests with
  `TlsKeyPair.ofSelfSigned("localhost")`. None of these tests depend on the certificate CN.

Result:

- Tests no longer derive the self-signed certificate CN from the machine hostname, so they pass
  regardless of the hostname of the machine they run on.
@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Self-signed certificate generation now truncates hostnames longer than 64 characters when creating the subject common name. Documentation and tests cover certificate generation and server TLS setup with overlong hostnames.

Changes

TLS certificate hostname handling

Layer / File(s) Summary
Certificate common-name length handling
core/src/main/java/com/linecorp/armeria/internal/common/util/SelfSignedCertificate.java, core/src/main/java/com/linecorp/armeria/common/TlsKeyPair.java
Self-signed certificate creation truncates hostnames to 64 characters, logs the original and truncated values, and documents the behavior.
Hostname limit validation
core/src/test/java/com/linecorp/armeria/common/TlsKeyPairTest.java, core/src/test/java/com/linecorp/armeria/internal/common/util/SelfSignedCertificateTest.java, core/src/test/java/com/linecorp/armeria/server/VirtualHostBuilderTest.java
Tests verify the truncated subject common name and successful self-signed TLS setup with an overlong default hostname.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • line/armeria#6534: Both changes modify SelfSignedCertificate and its tests, but this PR handles hostname truncation while that PR adds Subject Alternative Name support.

Suggested labels: improvement

Suggested reviewers: minwoox, jrhee17

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly and concisely describes the main change: truncating hostnames longer than 64 characters for self-signed certificates.
Description check ✅ Passed The description explains the hostname length failure, the truncation change, affected APIs, logging, and test impact.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

…ed()

Motivation:

`TlsKeyPair.ofSelfSigned()` uses the local hostname as the certificate CN as is, so it fails with
`IllegalArgumentException: commonName length 67 exceeds RFC 5280 ub-common-name (64)` on a machine
whose hostname exceeds 64 characters, such as a GitHub Actions macOS runner.

Modifications:

- Truncate the local hostname to 64 characters in `TlsKeyPair.ofSelfSigned()` before generating
  a self-signed certificate, and document the behavior.

Result:

- `TlsKeyPair.ofSelfSigned()` no longer fails on a machine whose hostname exceeds 64 characters.
@ikhoon ikhoon changed the title Pin the self-signed certificate hostname to "localhost" in tests Fix self-signed certificate generation on machines with long hostnames Aug 6, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
core/src/test/java/com/linecorp/armeria/common/TlsKeyPairTest.java (1)

27-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Make the truncation test deterministic.

This test uses the test runner's actual hostname. It exercises the new truncation branch only when that hostname exceeds 64 characters. A regression that removes truncation can pass on ordinary runners.

Extract the truncation calculation into a package-private helper, or inject the hostname source, and test it with a fixed 65-character ASCII hostname. Keep this test for the local-hostname integration path.

As per PR objectives, this test is intended to cover hostname truncation behavior.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/src/test/java/com/linecorp/armeria/common/TlsKeyPairTest.java` around
lines 27 - 36, Extract the hostname truncation logic used by
TlsKeyPair.ofSelfSigned into a package-private helper, then add a deterministic
unit assertion using a fixed 65-character ASCII hostname that verifies the
result is limited to 64 characters. Retain selfSignedWithLocalHostname() to
cover the actual local-hostname integration path, but do not rely on it to
exercise truncation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@core/src/test/java/com/linecorp/armeria/common/TlsKeyPairTest.java`:
- Around line 27-36: Extract the hostname truncation logic used by
TlsKeyPair.ofSelfSigned into a package-private helper, then add a deterministic
unit assertion using a fixed 65-character ASCII hostname that verifies the
result is limited to 64 characters. Retain selfSignedWithLocalHostname() to
cover the actual local-hostname integration path, but do not rely on it to
exercise truncation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 3cf42b4e-79b3-4698-91ef-3ee13325fd9c

📥 Commits

Reviewing files that changed from the base of the PR and between f75df0a and 935411c.

📒 Files selected for processing (2)
  • core/src/main/java/com/linecorp/armeria/common/TlsKeyPair.java
  • core/src/test/java/com/linecorp/armeria/common/TlsKeyPairTest.java

@ikhoon ikhoon closed this Aug 6, 2026
@ikhoon ikhoon reopened this Aug 6, 2026
ikhoon added 4 commits August 6, 2026 12:20
…t-hostname

# Conflicts:
#	core/src/main/java/com/linecorp/armeria/common/TlsKeyPair.java
#	core/src/test/java/com/linecorp/armeria/common/TlsKeyPairTest.java
Motivation:

Without a log, a truncated certificate CN is hard to trace back to the hostname length limit.

Modifications:

- Log a debug message with the original and truncated hostname when `TlsKeyPair.ofSelfSigned()`
  truncates the local hostname.

Result:

- Easier to diagnose a certificate whose CN differs from the local hostname.
@ikhoon ikhoon changed the title Fix self-signed certificate generation on machines with long hostnames Truncate the local hostname to 64 characters in TlsKeyPair.ofSelfSigned() Aug 6, 2026
@ikhoon ikhoon added the defect label Aug 6, 2026
@ikhoon ikhoon added this to the 1.41.0 milestone Aug 6, 2026
@ikhoon
ikhoon marked this pull request as ready for review August 6, 2026 05:27
@ikhoon
ikhoon requested review from jrhee17 and minwoox as code owners August 6, 2026 05:27
@mergify

mergify Bot commented Aug 6, 2026

Copy link
Copy Markdown

Tick the box to add this pull request to the merge queue (same as @mergifyio queue).

  • Queue this pull request

@jrhee17 jrhee17 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

👍👍

@minwoox minwoox left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

👍 👍 👍

Motivation:

macOS CI runners kept failing through `ServerBuilder.tlsSelfSigned()`, which generates
a self-signed certificate via `VirtualHostBuilder` and bypasses `TlsKeyPair.ofSelfSigned()`.

Modifications:

- Move the 64-character truncation from `TlsKeyPair.ofSelfSigned()` to the `SelfSignedCertificate`
  constructor so that every self-signed certificate generation path is covered.
- Add regression tests with a synthetic 67-character fqdn.

Result:

- Self-signed certificate generation no longer fails on a machine whose hostname exceeds
  64 characters, regardless of the API used.
@ikhoon ikhoon changed the title Truncate the local hostname to 64 characters in TlsKeyPair.ofSelfSigned() Truncate a hostname longer than 64 characters for self-signed certificates Aug 6, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
core/src/main/java/com/linecorp/armeria/common/TlsKeyPair.java (1)

141-143: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document truncation for the explicit-hostname overload.

SelfSignedCertificate now applies the 64-character rule to every constructor. Therefore, TlsKeyPair.ofSelfSigned(String) also truncates a long hostname. The new note covers only ofSelfSigned() with the local hostname. Add the same behavior note to the explicit-hostname Javadoc.

As per path instructions, public API behavior must be documented and the project requires Javadoc for public APIs.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@core/src/main/java/com/linecorp/armeria/common/TlsKeyPair.java` around lines
141 - 143, Update the Javadoc for the explicit-hostname
TlsKeyPair.ofSelfSigned(String) overload to document that hostnames longer than
64 characters are truncated to satisfy the RFC 5280 common name limit, matching
the existing note for the local-hostname overload.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@core/src/main/java/com/linecorp/armeria/internal/common/util/SelfSignedCertificate.java`:
- Around line 249-250: Update truncateToCommonNameLength to validate fqdn with
the existing meaningful validation utility and the parameter name "fqdn" before
calling fqdn.length(), ensuring null input produces the standard validation
exception and message.
- Around line 245-246: Update SelfSignedCertificate’s CertificateParams
construction and SignedCertificate.generate() flow so the original fqdn is
retained for automatic DNS SAN generation while only the common name is
truncated to its permitted length. Ensure the generated certificate contains the
full requested FQDN in its DNS SAN, and add coverage for an over-64-character
FQDN.

---

Outside diff comments:
In `@core/src/main/java/com/linecorp/armeria/common/TlsKeyPair.java`:
- Around line 141-143: Update the Javadoc for the explicit-hostname
TlsKeyPair.ofSelfSigned(String) overload to document that hostnames longer than
64 characters are truncated to satisfy the RFC 5280 common name limit, matching
the existing note for the local-hostname overload.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a6c8dab6-4e92-4afd-b4fa-b8dc44df5ce0

📥 Commits

Reviewing files that changed from the base of the PR and between a0644fc and 394ea1c.

📒 Files selected for processing (4)
  • core/src/main/java/com/linecorp/armeria/common/TlsKeyPair.java
  • core/src/main/java/com/linecorp/armeria/internal/common/util/SelfSignedCertificate.java
  • core/src/test/java/com/linecorp/armeria/internal/common/util/SelfSignedCertificateTest.java
  • core/src/test/java/com/linecorp/armeria/server/VirtualHostBuilderTest.java

Comment on lines +245 to +246
super(new CertificateParams(truncateToCommonNameLength(fqdn), random, bits, notBefore, notAfter,
algorithm, subjectAlternativeNames, isCA));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

root=core/src/main/java/com/linecorp/armeria/internal/common/util

fd -0 -t f -e java '^(CertificateParams|SignedCertificate)\.java$' "$root" |
  xargs -0 -r rg -n -C 8 \
    'params\.fqdn\(\)|ownerName\(\)|subjectAlternativeName|dNSName|new GeneralName'

Repository: line/armeria

Length of output: 25781


🏁 Script executed:

#!/bin/bash
set -euo pipefail

fd -0 -t f -e java '^(SelfSignedCertificate|SelfSignedCertificateTest)\.java$' \
  core/src/main/java/com/linecorp/armeria/internal/common/util/ \
  core/src/test/java/com/linecorp/armeria/internal/common/util/ |
  sort -z | xargs -0 -r wc -l

fd -0 -t f -e java '^(SelfSignedCertificate|SelfSignedCertificateTest)\.java$' \
  core/src/main/java/com/linecorp/armeria/internal/common/util/ \
  core/src/test/java/com/linecorp/armeria/internal/common/util/ |
  sort -z | xargs -0 -r sed -n '1,380p'

# Extract SelfSignedCertificate constructor context around the truncated fqdn line.
root=core/src/main/java/com/linecorp/armeria/internal/common/util
sed -n '220,260p' "$root/SelfSignedCertificate.java" | cat -n

# Programmatically inspect whether OwnerName is truncated on SelfSignedCertificate contruction.
# This uses the source text as data; it does not compile or execute repository code.
python3 - <<'PY'
from pathlib import Path
p = Path('core/src/main/java/com/linecorp/armeria/internal/common/util/SelfSignedCertificate.java')
src = p.read_text()
start = src.index('public SelfSignedCertificate(String fqdn')
end = src.index('}', start) + 2
body = src[start:end]
print("--- SelfSignedCertificate constructor body ---")
print(body)
print("passes truncated fqdn to super:", 'new CertificateParams(truncateToCommonNameLength(fqdn)' in body)
print("passes original fqdn to super:", 'new CertificateParams(fqdn' in body)
PY

Repository: line/armeria

Length of output: 18420


Preserve the original FQDN in the DNS SAN.

truncationToCommonNameLength(fqdn) is passed to CertificateParams, and SignedCertificate.generate() uses params.fqdn() as the automatic DNS SAN. A FQDN over 64 characters therefore produces a SAN that is also truncated, so hostname validation against the requested FQDN can fail. Store the original FQDN separately or pass it to SAN generation, and add a test that asserts the full FQDN in the SAN when the common name is truncated.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@core/src/main/java/com/linecorp/armeria/internal/common/util/SelfSignedCertificate.java`
around lines 245 - 246, Update SelfSignedCertificate’s CertificateParams
construction and SignedCertificate.generate() flow so the original fqdn is
retained for automatic DNS SAN generation while only the common name is
truncated to its permitted length. Ensure the generated certificate contains the
full requested FQDN in its DNS SAN, and add coverage for an over-64-character
FQDN.

Comment on lines +249 to +250
private static String truncateToCommonNameLength(String fqdn) {
if (fqdn.length() <= MAX_COMMON_NAME_LENGTH) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Validate fqdn before measuring its length.

truncateToCommonNameLength(fqdn) calls fqdn.length() without validation. A null FQDN produces an NPE without a useful message. Validate fqdn with "fqdn" before this call.

As per path instructions, validation must use meaningful validation and exception messages.

Proposed fix
 private static String truncateToCommonNameLength(String fqdn) {
+    requireNonNull(fqdn, "fqdn");
     if (fqdn.length() <= MAX_COMMON_NAME_LENGTH) {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
private static String truncateToCommonNameLength(String fqdn) {
if (fqdn.length() <= MAX_COMMON_NAME_LENGTH) {
private static String truncateToCommonNameLength(String fqdn) {
requireNonNull(fqdn, "fqdn");
if (fqdn.length() <= MAX_COMMON_NAME_LENGTH) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@core/src/main/java/com/linecorp/armeria/internal/common/util/SelfSignedCertificate.java`
around lines 249 - 250, Update truncateToCommonNameLength to validate fqdn with
the existing meaningful validation utility and the parameter name "fqdn" before
calling fqdn.length(), ensuring null input produces the standard validation
exception and message.

Source: Path instructions

@codecov

codecov Bot commented Aug 6, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 75.16%. Comparing base (8150425) to head (865a056).
⚠️ Report is 563 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #6900      +/-   ##
============================================
+ Coverage     74.46%   75.16%   +0.70%     
- Complexity    22234    25510    +3276     
============================================
  Files          1963     2267     +304     
  Lines         82437    94558   +12121     
  Branches      10764    12377    +1613     
============================================
+ Hits          61385    71078    +9693     
- Misses        15918    17609    +1691     
- Partials       5134     5871     +737     

☔ 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.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Motivation:

The hostname tag of `armeria.server.tls.handshakes` is derived from the server certificate,
whose common name is now truncated to 64 characters. The test compared it against the full
default hostname, so it failed on a machine whose hostname exceeds 64 characters.

Modifications:

- Compare the hostname tag against the certificate hostname, truncated to 64 characters.

Result:

- `ServerTlsHandshakeMetricsTest` passes on a machine whose hostname exceeds 64 characters.
@ikhoon
ikhoon merged commit 11b5886 into line:main Aug 6, 2026
18 of 19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants