Skip to content

fix(release): make archive checks locale-independent - #984

Merged
mergify[bot] merged 1 commit into
matrixorigin:mainfrom
endlesschasey-ai:fix/install-sort-locale-982
Oct 13, 2026
Merged

mergify[bot] merged 1 commit into
matrixorigin:mainfrom
endlesschasey-ai:fix/install-sort-locale-982

Conversation

@endlesschasey-ai

Copy link
Copy Markdown
Contributor

Summary

The release archive member checks compared tar -tzf | sort output against a hard-coded C byte-order expectation (LICENSE, astra, astra-edge), but sort follows the caller's locale collation. Under UTF-8 locales (macOS default en_US.UTF-8, zh_CN.UTF-8, glibc en_US.UTF-8) collation is case-insensitive, so the members sort as astra astra-edge LICENSE and:

  • scripts/install-astra.sh failed every real install with release archive must contain exactly astra, astra-edge, and LICENSE at its root.
  • scripts/verify-release-artifacts.sh (the pre-publication gate) rejected valid artifact sets with the equivalent error, and its sort -k2 ordering of checksums.txt depended on the publishing machine's locale, threatening non-reproducible manifests.

Fix: pin LC_ALL=C on both member sorts and on the checksums.txt manifest sort, so archive validation and published manifest bytes are locale-independent. scripts/ci/test_release_contract.sh now probes for a case-reordering UTF-8 locale (en_US/zh_CN candidates) and re-runs the installer's member-check path under it, skipping gracefully on runners that provide no such locale, so the regression stays covered where the locale exists without failing locale-poor environments.

Related issue

Fixes #982

Change type

  • Feature
  • Bug fix
  • Documentation
  • Refactor or performance improvement
  • Test
  • Build, CI, or maintenance

User and compatibility impact

curl | sh installs now succeed on machines running UTF-8 locales (all default macOS setups, many Linux desktops) instead of aborting at the archive check. verify-release-artifacts.sh no longer rejects valid release sets on such machines, and checksums.txt is now byte-identical regardless of the publishing locale (unchanged for CI, which already ran under a C-locale). No configuration, flags, or API surface changed.

Architecture and complexity delta

  • Canonical owner changed or extended: N/A (shell release scripts only).
  • Existing implementations and callers searched: every sort/comm/join/uniq under scripts/*.sh and scripts/ci/*.sh was audited (no comm/join uses exist).
  • Superseded code, states, tables, shims, or self-only tests removed: none; a minimal LC_ALL=C pin plus one regression block.
  • If parallel implementations remain, their boundary and retirement condition: none.

Inspected and deliberately left alone:

  • scripts/reconcile-docker-manifest.sh:53,153,158,191 — sort -u over lowercase-ASCII-only platform names (linux/amd64, linux/arm64) and hex digests; no case mixing, and the candidate/published files compared via cmp are both produced by the same sort, so ordering is self-consistent.
  • scripts/reconcile-docker-manifest.sh:105, scripts/validate-release-version.sh:157 — Python sorted(), which is codepoint order and locale-independent by definition.
  • scripts/phase0-production-baseline.sh:139,143 — sort -z only stabilizes input enumeration for harness assembly; not compared against a fixed C-order literal.
  • scripts/ci/test_interactive_setup_contract.sh:411 — sort -u | wc -l; a count-only assertion where order is never observed.

Verification

  • Commands and results (host locale for all runs: LANG=en_US.UTF-8, LC_COLLATE=en_US.UTF-8, no outer LC_ALL override unless noted):
    • Red, installer fix temporarily reverted (install-astra.sh back to | sort): PYTHONPATH="$PWD/.pyshim-982" bash scripts/ci/test_release_contract.sh → exit 1, error: release archive must contain exactly astra, astra-edge, and LICENSE at its root from the new UTF-8-locale installer run.
    • Red, verifier fix temporarily reverted (verify-release-artifacts.sh back to | sort): PYTHONPATH="$PWD/.pyshim-982" bash scripts/ci/test_release_contract.sh → exit 1, astra-v0.1.0-linux-amd64.tar.gz must contain exactly astra, astra-edge, and LICENSE at its root.
    • Green, both fixes in place: PYTHONPATH="$PWD/.pyshim-982" bash scripts/ci/test_release_contract.sh → exit 0.
    • PYTHONPATH only supplied a throwaway tomli→tomllib shim because the local dev host's default python3 is 3.9; CI runners use Python ≥ 3.11 where tomllib is stdlib. The shim was never committed and was deleted after the runs.
  • Public entrypoint exercised: scripts/install-astra.sh full download→verify→install path via the suite's fake-curl release fixture, both under the ambient locale and under the case-reordering UTF-8 locale; plus scripts/verify-release-artifacts.sh over a full four-platform dist set.
  • Unhappy paths exercised: the locale-collation failure itself (red runs above); the suite also covers installer rollback on simulated commit failure, tampered/mutated archives, ambiguous checksum sidecars, and invalid semantic versions.
  • Database verification: N/A (no database changes).

CI never caught this because GitHub-hosted runners execute under C.UTF-8/POSIX locale, where unpinned sort already produces byte order; only developer machines with UTF-8 default locales hit it.

Final checklist

  • I added or updated tests at the layer that owns the behavior, or explained why no test is needed.
  • I updated public or design documentation for contract changes, or the change needs no documentation update.
  • I checked the diff for credentials, private URLs, customer data, generated files, and other sensitive information.
  • The PR title follows the repository's Conventional Commit format.

@XuPeng-SH XuPeng-SH left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

结论:Approve。未发现需要阻止合并的明确问题。

审查范围:base / merge-base 2873a950f2c9fea00343757933e96070d1631596 → head 83a7c2cd25ef72aa472fa8e21f35a86922ac1fa1。完整阅读三个文件的修改及相关安装、发布校验、契约测试入口;提交前确认 head 未变。本轮未使用 subagent。

实现与用户影响

  • 两个 archive-member 排序使用命令局部的 LC_ALL=C,与固定的 LICENSE\nastra\nastra-edge 字节序比较契约一致。LC_ALL 能覆盖调用者的 LANG / LC_COLLATE 等设置,不会改变整个安装进程或调用 shell 的环境;installer 保持 POSIX sh 写法。
  • checksums.txt 的排序同样固定为 C locale,使发布清单的排序规则明确。没有引入新依赖、网络请求或运行时分支。
  • 校验仍是精确成员集合比较,未使用去重或模糊匹配;现有 checksum、binary version、安装暂存与 rollback 路径保持原样。
  • 新测试按实际排序行为选择 locale,使用已有 fake-curl fixture 经过完整安装路径并检查两个可执行文件的版本;不依赖在线 release,也没有修改机器全局 locale。

本轮实际验证

在 Linux 本地环境独立执行,非仅引用 PR 正文:

  1. 原始 sort 在 C 下产生 LICENSE, astra, astra-edge,在 en_US.utf8 下产生 astra, astra-edge, LICENSE,确认测试环境具有相关排序差异。
  2. LC_ALL=C bash scripts/ci/test_release_contract.sh:通过。
  3. LC_ALL=en_US.utf8 bash scripts/ci/test_release_contract.sh:通过。完整套件包含精确 checksum sidecar、意外发布资产、被修改的 archive、非法版本及模拟安装提交失败后的 rollback 检查。
  4. 仅临时撤回 installer 的成员排序修复、保留新测试,并在外层 C locale 运行完整套件:按预期失败,报 archive member mismatch。这确认新增 locale 测试实际执行并能检测原问题。
  5. 仅临时撤回 verifier 的成员排序修复,在 en_US.utf8 下运行套件:按预期失败,报合法四平台发布集的 archive member mismatch。
  6. 使用实际 reproducible archiver 创建四平台 fixture,再分别在 C / en_US.utf8 下调用实际 verifier:checksums.txt 和 checksums.txt.sha256 均逐字节相同。
  7. POSIX sh -n、Bash 语法检查、git diff --check 均通过;临时反向验证修改已恢复,worktree 干净。

当前 head 的 Static Checks / Test Suite 均成功;检查了 static lint 的 repository validation 执行入口。以上本地结果是 Linux 证据,不宣称本轮实际执行了 macOS 测试。

测试与复杂度评价

净增 31 行由 25 行测试和 6 行注释组成,生产修改为三条现有 sort 命令增加局部 locale 设置,复杂度与修复价值匹配。

一个非阻塞测试改进:新增的显式 UTF-8 分支目前只重跑 installer,verifier 仍取决于套件的外层 locale。后续可复用已选 locale 同时验证 verifier,并比较两份 manifest;这样普通 C-locale CI 也能持续覆盖发布端修复。本轮已经对发布端进行了上述独立正反验证,当前实现正确。

@mergify mergify Bot added the queued label Oct 13, 2026
@mergify

mergify Bot commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • ✅ Entered queue — 2026-10-13 11:59 UTC · Rule: main · triggered by rule Automatic queue on approval for main
  • ✅ Checks passed · in-place
  • ✅ Merged — 2026-10-13 12:19 UTC · at 365e313cba7e018edd8c35ab1552f8e67b85c5db · squash

This pull request spent 19 minutes 29 seconds in the queue, including 19 minutes 8 seconds running CI.

Required conditions to merge
  • #review-threads-unresolved = 0 [🛡 GitHub branch protection]
  • github-review-approved [🛡 GitHub branch protection]
  • any of [🛡 GitHub branch protection]:
    • check-success = Check PR title
    • check-neutral = Check PR title
    • check-skipped = Check PR title
  • any of [🛡 GitHub branch protection]:
    • check-success = check
    • check-neutral = check
    • check-skipped = check
  • any of [🛡 GitHub branch protection]:
    • check-success = Test: core crates + bridge hooks
    • check-neutral = Test: core crates + bridge hooks
    • check-skipped = Test: core crates + bridge hooks
  • any of [🛡 GitHub branch protection]:
    • check-success = Test: astra-runtime
    • check-neutral = Test: astra-runtime
    • check-skipped = Test: astra-runtime
  • any of [🛡 GitHub branch protection]:
    • check-success = Test: astra-cli (edge-fs-tools)
    • check-neutral = Test: astra-cli (edge-fs-tools)
    • check-skipped = Test: astra-cli (edge-fs-tools)
  • any of [🛡 GitHub branch protection]:
    • check-success = Test: astra-cli (edge-git-gix)
    • check-neutral = Test: astra-cli (edge-git-gix)
    • check-skipped = Test: astra-cli (edge-git-gix)
  • any of [🛡 GitHub branch protection]:
    • check-success = Test: astra-cli (edge-rest)
    • check-neutral = Test: astra-cli (edge-rest)
    • check-skipped = Test: astra-cli (edge-rest)
  • any of [🛡 GitHub branch protection]:
    • check-success = Test: astra-cli (edge-shell)
    • check-neutral = Test: astra-cli (edge-shell)
    • check-skipped = Test: astra-cli (edge-shell)
  • any of [🛡 GitHub branch protection]:
    • check-success = Test: astra-cli (non-edge)
    • check-neutral = Test: astra-cli (non-edge)
    • check-skipped = Test: astra-cli (non-edge)
  • any of [🛡 GitHub branch protection]:
    • check-success = Test: online (core)
    • check-neutral = Test: online (core)
    • check-skipped = Test: online (core)
  • any of [🛡 GitHub branch protection]:
    • check-success = Test: online (integration)
    • check-neutral = Test: online (integration)
    • check-skipped = Test: online (integration)
  • any of [🛡 GitHub branch protection]:
    • check-success = Test: turn-core + services + plan
    • check-neutral = Test: turn-core + services + plan
    • check-skipped = Test: turn-core + services + plan
  • any of [🛡 GitHub branch protection]:
    • check-success = web (typecheck, test, build)
    • check-neutral = web (typecheck, test, build)
    • check-skipped = web (typecheck, test, build)
  • any of [🛡 GitHub branch protection]:
    • check-success = Astra SDK (typecheck, test+coverage, build)
    • check-neutral = Astra SDK (typecheck, test+coverage, build)
    • check-skipped = Astra SDK (typecheck, test+coverage, build)
  • any of [🛡 GitHub branch protection]:
    • check-success = Test: macOS workspace coordination
    • check-neutral = Test: macOS workspace coordination
    • check-skipped = Test: macOS workspace coordination

The installer and the release artifact verifier compare 'tar -tzf | sort' output against a hard-coded C byte-order expectation (LICENSE, astra, astra-edge), but sort follows the caller's locale collation. Under UTF-8 locales (macOS en_US.UTF-8/zh_CN.UTF-8, glibc en_US.UTF-8) collation is case-insensitive, so every real install and any UTF-8-locale release verification failed with 'must contain exactly astra, astra-edge, and LICENSE at its root'. CI passed only because GitHub runners use C/C.UTF-8.

Pin LC_ALL=C on both member sorts and on the checksums.txt manifest ordering so published artifacts are byte-identical regardless of locale. The release contract test now probes for a case-reordering UTF-8 locale and re-runs the installer member check under it, skipping gracefully where no such locale exists.

Fixes matrixorigin#982
@mergify
mergify Bot force-pushed the fix/install-sort-locale-982 branch from 83a7c2c to d33b4c7 Compare October 13, 2026 11:59
@mergify
mergify Bot merged commit 365e313 into matrixorigin:main Oct 13, 2026
38 of 39 checks passed
@mergify mergify Bot removed the queued label Oct 13, 2026
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.

[Bug]: install-astra.sh always fails under UTF-8 locales: archive member check depends on sort collation

2 participants