From b707b1d8efc588e9104978d18f2933460b44ef70 Mon Sep 17 00:00:00 2001 From: Elijah ben Izzy Date: Sat, 25 Apr 2026 21:07:07 -0700 Subject: [PATCH] fix: remove stray newline from burr/examples symlink target (#748) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: remove stray newline from burr/examples symlink target The burr/examples symlink was committed with target '../examples\n' (12 bytes) instead of '../examples' (11 bytes). Most tools tolerate the trailing newline, but stricter consumers (Java's FileReader via Apache RAT, some Linux extractors of the source tarball) treat '../examples\n' as a literal nonexistent target and fail. Manifested in CI as a RAT crash on the source tarball produced by git-archive: the symlink in the tarball points to '../examples\n', which doesn't resolve, and RAT raises FileNotFoundException trying to read it as a file. Recreate the symlink via 'rm burr/examples && ln -s ../examples burr/examples' to write the correct 11-byte target. * fix: fail license verification when Apache RAT exits non-zero Previously, if RAT crashed partway through scanning (e.g. on the broken burr/examples symlink that motivated this PR), the verify script would print a warning, parse the truncated XML report, find zero unapproved licenses in whatever RAT managed to scan before the crash, and report success. That false green is what hid the symlink corruption when PR #745 merged into main, even though our release-validation workflow technically ran on main. The CI run scanned 14 files (out of ~700), saw RAT exit code 1, swallowed it, and called the build green. Treat any nonzero exit from RAT as a hard failure of license verification. Print the last 25 lines of RAT stderr so the next debug session has the trace immediately. * fix: exclude burr/examples symlink from end-of-file-fixer pre-commit hook end-of-file-fixer mistreats the symlink as a regular text file and appends '\n' to the link target, turning '../examples' (11 bytes) into '../examples\n' (12 bytes). Strict consumers (Apache RAT, Linux tar extractors) then fail to resolve the symlink. This is exactly the bug that motivated PR #748 — without this exclude, the next pre-commit run on a maintainer's machine would silently re-corrupt the symlink. Also exclude trailing-whitespace defensively for the same reason. --- .github/workflows/release-validation.yml | 4 ++-- .pre-commit-config.yaml | 11 ++++++++++- burr/examples | 2 +- scripts/verify_apache_artifacts.py | 10 +++++++++- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release-validation.yml b/.github/workflows/release-validation.yml index cfa447319..375ff4dfa 100644 --- a/.github/workflows/release-validation.yml +++ b/.github/workflows/release-validation.yml @@ -52,7 +52,7 @@ permissions: jobs: build-artifacts: - name: build-artifacts + name: "Release Validation / build-artifacts" runs-on: ubuntu-latest timeout-minutes: 20 outputs: @@ -133,7 +133,7 @@ jobs: retention-days: 14 install-and-smoke: - name: install-and-smoke + name: "Release Validation / install-and-smoke" needs: build-artifacts runs-on: ubuntu-latest timeout-minutes: 10 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9450bab75..472ccd441 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -32,8 +32,17 @@ repos: rev: v4.5.0 hooks: - id: trailing-whitespace - # ensures files are either empty or end with a blank line + # burr/examples is a symlink. trailing-whitespace would mangle the + # link target text (treating "../examples" as a "trailing whitespace" + # situation) and break the symlink. + exclude: '^burr/examples$' + # ensures files are either empty or end with a blank line. + # NOTE: burr/examples is excluded — end-of-file-fixer will append "\n" + # to the symlink target turning "../examples" into "../examples\n", + # which makes the symlink unresolvable on strict consumers (Apache RAT + # and several Linux tarball extractors). See PR #748. - id: end-of-file-fixer + exclude: '^burr/examples$' # sorts requirements - id: requirements-txt-fixer # valid python file diff --git a/burr/examples b/burr/examples index beeced1f9..a6573af9c 120000 --- a/burr/examples +++ b/burr/examples @@ -1 +1 @@ -../examples +../examples \ No newline at end of file diff --git a/scripts/verify_apache_artifacts.py b/scripts/verify_apache_artifacts.py index 54350deb5..1939f7242 100755 --- a/scripts/verify_apache_artifacts.py +++ b/scripts/verify_apache_artifacts.py @@ -318,7 +318,15 @@ def _check_licenses_with_rat( ) if result.returncode != 0: - print(f" ⚠️ RAT exited with code {result.returncode}") + # A nonzero exit means RAT crashed mid-scan (e.g. on a broken + # symlink). The XML report it produced will be truncated and + # parsing it gives a falsely clean result, so fail hard here. + print(f" ✗ RAT exited with code {result.returncode}") + if result.stderr: + print(" --- RAT stderr ---") + for line in result.stderr.splitlines()[-25:]: + print(f" {line}") + return False print(f" ✓ RAT XML report: {rat_report_xml}") except Exception as e: