Skip to content

fix: prevent ENAMETOOLONG crash for long parallel:matrix job names#1865

Merged
firecow merged 3 commits into
firecow:masterfrom
gyanranjan:fix/enametoolong-long-job-names
May 31, 2026
Merged

fix: prevent ENAMETOOLONG crash for long parallel:matrix job names#1865
firecow merged 3 commits into
firecow:masterfrom
gyanranjan:fix/enametoolong-long-job-names

Conversation

@gyanranjan
Copy link
Copy Markdown
Contributor

@gyanranjan gyanranjan commented May 22, 2026

Problem

When parallel:matrix entries contain long variable values, safeDockerString() encodes non-alphanumeric characters using base64url, which expands the string (e.g., /Lw, IA). The encoded name is used directly as a filename/volume name. Linux/macOS NAME_MAX is 255 bytes — the reproducer generates ~340 characters, causing an immediate crash.

Fixes #1862

Fix

When the encoded name exceeds 238 chars, truncate to a readable prefix + - + 16-char SHA-256 hash of the original name.

  • Limit: 238 chars (255 NAME_MAX − 17 worst-case suffix from gcl-...-999999-build)
  • Short names: Unchanged — no hashing when already within limit
  • Deterministic: Same input always produces same output
  • Unique: SHA-256 at 64 bits makes collisions negligible
  • Arbitrary length: Works for any job name length (500, 5000+ chars)

Changes

  • src/utils.ts: Added length guard to safeDockerString() with hash-based truncation
  • tests/utils.test.ts: Added 9 test cases covering short names, long names, extreme lengths, boundary conditions, volume name safety, determinism, and uniqueness

Verification

  • npm run typecheck
  • npm run lint
  • All 61 unit tests pass ✅
  • All 32 parallel-matrix integration tests pass ✅
  • Live end-to-end validation with the exact issue reproducer ✅ (was crashing, now passes)
  • Two-entry matrix with similar names produces separate files with different hashes ✅
  • Short job names produce unchanged output (no regression) ✅

Summary by cubic

Prevents ENAMETOOLONG crashes when parallel:matrix generates long job names whose base64url-expanded values exceed filesystem limits. Ensures Docker volume/file names stay within 255 bytes. Fixes #1862.

  • Bug Fixes
    • Derive and enforce MAX_FILENAME_LENGTH = 255 - 17 (NAME_MAX minus gcl-${name}-999999-build) in safeDockerString.
    • If over, truncate to a readable prefix and append a 16-char SHA-256 hash of the original; deterministic with low collision; short names unchanged.
    • Added tests: exact base64url assertion, boundaries, extreme lengths, volume safety, and an end-to-end parallel-matrix-long-name fixture (YAML updated) to ensure both long and short matrix entries complete.
    • Documented invariants: ASCII-only matching keeps length==bytes; hash the raw name since encoding isn’t injective.

Written for commit 62e73ba. Summary will update on new commits.

Review in cubic

…ob names

When parallel:matrix entries contain long variable values, the base64url
encoding in safeDockerString expands the job name beyond the 255-byte
NAME_MAX limit, crashing with ENAMETOOLONG before any job executes.

Fix: when the encoded name exceeds 238 chars (255 minus the 17-char
worst-case suffix from Docker volume names), truncate to a readable
prefix and append a 16-char SHA-256 hash of the original name. Short
names are unchanged.

Fixes firecow#1862
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

No issues found across 2 files

Re-trigger cubic

Copy link
Copy Markdown
Owner

@firecow firecow left a comment

Choose a reason for hiding this comment

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

Fix is correct, i have a few comments

Comment thread src/utils.ts Outdated
Comment thread src/utils.ts
Comment thread tests/utils.test.ts Outdated
Comment thread tests/utils.test.ts
… e2e test

- MAX_FILENAME_LENGTH now shows derivation (255 - 17) instead of magic 238
- Added invariant comment: \w without /u guarantees ASCII, so .length == bytes
- Noted why we hash jobName not encoded (encoding isn't injective)
- Changed toContain('Lw') to toBe('jobLwname') for exact assertion
- Added tests/test-cases/parallel-matrix-long-name/ integration fixture
  that exercises the actual crash path end-to-end (regression guard for firecow#1862)
@gyanranjan
Copy link
Copy Markdown
Contributor Author

Thanks for the thorough review @firecow — all four points addressed in the latest push:

  1. Derived constant — 255 - 17 instead of magic 238
  2. Invariant comment — documented why \w without /u guarantees .length == bytes, and why we hash jobName not encoded
  3. Exact assertion — toBe("jobLwname") instead of toContain("Lw")
  4. E2E integration test — added tests/test-cases/parallel-matrix-long-name/ with a matrix value long enough to trigger truncation, asserting the full handler completes without crash

Really appreciate the note about the /u invariant — exactly the kind of subtle correctness detail that would bite someone later. All tests green (61 unit + 33 integration).

Comment thread tests/test-cases/parallel-matrix-long-name/.gitlab-ci.yml Outdated
@firecow firecow merged commit 1206342 into firecow:master May 31, 2026
14 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.

ENAMETOOLONG crash when parallel:matrix generates long job names

2 participants