Skip to content

feat(bats): add bats-core 1.11.0 - 1.14.0 and default to 1.14.0 - #1290

Open
Wito-1 wants to merge 1 commit into
bazel-contrib:mainfrom
Wito-1:bats-core-1.14
Open

Wito-1 wants to merge 1 commit into
bazel-contrib:mainfrom
Wito-1:bats-core-1.14

Conversation

@Wito-1

@Wito-1 Wito-1 commented Aug 24, 2026

Copy link
Copy Markdown

Problem

BATS_CORE_VERSIONS has held exactly one entry, v1.10.0, since it was added — released 2023-07-15, four minor versions behind upstream's current 1.14.0 (2026-07-21). Because register_bats_toolchains reads the sha256 out of that map:

http_archive(
    name = "%s_toolchains" % name,
    sha256 = BATS_CORE_VERSIONS[core_version],
    ...
)

core_version is effectively not a choice — passing anything else to bazel_lib_toolchains.bats(core_version = ...) fails on the dict lookup. There is no way to move off 1.10.0 without vendoring your own toolchain.

That matters because 1.10.0 carries a timeout bug that bats_test is unusually exposed to. The launcher sets:

export BATS_TEST_TIMEOUT="$TEST_TIMEOUT"

so bats' per-test timeout equals the build system's per-target timeout. In 1.10.0 the per-test timeout watchdog leaks its inherited file descriptors, so a test that finishes in milliseconds can block until the watchdog's sleep expires — which, given the line above, is exactly as long as the harness is willing to wait. The run can then only ever end as a harness timeout, and raising the target's timeout raises both in lockstep.

Upstream fixed the leak for the inner subshell in the bats-core #1067 series (shipped in 1.13.0) by closing the watchdog's fds:

(eval exec {0..255}">&-"; sleep "$timeout") &

Measured on a 4-core Linux box, running a 4-assertion file where every case passes in <10ms, BATS_TEST_TIMEOUT=5, 250 runs per version at 10-way concurrency:

bats-core runs ending at the full timeout max wall clock
1.10.0 2 / 250 5341 ms
1.14.0 0 / 250 1043 ms

Neither version reproduces when run serially — it needs concurrency, which is exactly what CI does.

Change

  • Add v1.11.0, v1.11.1, v1.12.0, v1.13.0, v1.14.0 to BATS_CORE_VERSIONS.
  • Bump DEFAULT_BATS_CORE_VERSION to v1.14.0.

Verification

  • Every sha256 was computed from the same URL the rule already uses, https://github.com/bats-core/bats-core/archive/{version}.tar.gz. As a control, recomputing v1.10.0 that way reproduces the existing pinned hash byte for byte.
  • All five archives were checked to have the layout BATS_CORE_TEMPLATE globs (bin/bats, lib/**, libexec/**).
  • v1.14.0 was run end-to-end through bats_test in a large Bazel monorepo — three targets, including one asserting a bats failure still fails — all passing.

Note on the default bump

The second commit (the DEFAULT_BATS_CORE_VERSION bump) is separable. Adding the map entries alone unblocks anyone who wants to opt in, and I am happy to drop the default change if you would rather move it independently. My reasoning for including it: without it, the default stays on a 2023 release carrying a bug that this repo's own bats_test rule maximally exposes, and most users will never think to set core_version.

bats-support / bats-assert / bats-file are left alone; their pins are current.

BATS_CORE_VERSIONS has held exactly one entry, v1.10.0 (released 2023-07-15),
since it was added. register_bats_toolchains reads the sha256 out of that map,
so core_version is effectively not a choice -- passing anything else fails on
the dict lookup, and there is no way off 1.10.0 without vendoring a toolchain.

That matters because bats_test exports BATS_TEST_TIMEOUT="$TEST_TIMEOUT",
tying bats' per-test timeout to the build system's per-target timeout. 1.10.0's
timeout watchdog leaks its inherited file descriptors, so a test that finishes
in milliseconds can block until the watchdog's sleep expires -- which is then
exactly as long as the harness is willing to wait, making it a harness timeout.
Upstream closed the watchdog's fds in the bats-core bazel-contrib#1067 series (1.13.0).

Measured on a 4-core Linux box with a 4-assertion file where every case passes
in <10ms, BATS_TEST_TIMEOUT=5, 250 runs per version at 10-way concurrency:
1.10.0 hung for the full timeout 2/250 times (max 5341ms); 1.14.0 0/250 (max
1043ms). Neither reproduces serially.

Every sha256 was computed from the URL the rule already uses. As a control,
recomputing v1.10.0 that way reproduces the existing pinned hash exactly. All
five archives were checked for the layout BATS_CORE_TEMPLATE globs, and 1.14.0
was run end-to-end through bats_test in a large Bazel monorepo.
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.

1 participant