testguard-cli 0.18.0 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.18.1] - 2026-10-01
11
+
12
+ Automated weekly release — everything merged since `v0.18.0`.
13
+
14
+ ### Changed
15
+
16
+ - test: consolidate native runtime acceptance checks
17
+ - perf: isolate native admission mutation defenders
18
+ - perf: size bounded report buffers to observed files
19
+ - chore(homebrew): sha256 for v0.18.0 (#194)
20
+
21
+
22
+ ### Changed
23
+
24
+ - Runner report and discovery-config reads reserve memory for the observed
25
+ file size instead of the maximum allowed size, retaining the hard byte
26
+ ceiling and checking file growth before parsing.
27
+ - Native-runner admission self-probes use focused defenders, preserving the
28
+ fault recipes and full runner acceptance coverage while avoiding unrelated
29
+ timeout and process-cleanup checks for each admission confirmation.
30
+
10
31
  ## [0.18.0] - 2026-10-01
11
32
 
12
33
  Automated weekly release — everything merged since `v0.17.0`.
package/README.md CHANGED
@@ -127,9 +127,9 @@ raises coverage. TestGuard admits it because it fails when the claim is false.
127
127
  | npm | `npm i -D testguard-cli` then `npx testguard probe` |
128
128
  | pip | `pip install testguard-cli` then `testguard probe` (needs Node ≥ 20) |
129
129
  | Homebrew | `brew tap raccioly/tap && brew install testguard` |
130
- | GitHub Action | `uses: raccioly/testguard@v0.18.0` — see [`action.yml`](./action.yml) |
130
+ | GitHub Action | `uses: raccioly/testguard@v0.18.1` — see [`action.yml`](./action.yml) |
131
131
  | pre-commit | `repo: https://github.com/raccioly/testguard`, hooks `testguard-claims`, `testguard-probe` |
132
- | GitLab CI | `include: - remote: https://raw.githubusercontent.com/raccioly/testguard/v0.18.0/packaging/gitlab/testguard.gitlab-ci.yml` with `inputs:` — see [`packaging/gitlab/`](./packaging/gitlab/testguard.gitlab-ci.yml) |
132
+ | GitLab CI | `include: - remote: https://raw.githubusercontent.com/raccioly/testguard/v0.18.1/packaging/gitlab/testguard.gitlab-ci.yml` with `inputs:` — see [`packaging/gitlab/`](./packaging/gitlab/testguard.gitlab-ci.yml) |
133
133
 
134
134
  Projects that set `min-release-age` in `.npmrc` cannot see a version published
135
135
  less than that many days ago (`ENOVERSIONS`); install that one with
@@ -785,12 +785,12 @@ detected base that does not resolve is a warning for `status` and `brief`
785
785
  # GitHub Actions
786
786
  - uses: actions/checkout@v4
787
787
  with: { fetch-depth: 0 }
788
- - uses: raccioly/testguard@v0.18.0
788
+ - uses: raccioly/testguard@v0.18.1
789
789
  with: { command: gate }
790
790
 
791
791
  # GitLab CI — the component-shaped template: gate + probe, brief as an artifact and, opted in, as a merge-request note
792
792
  include:
793
- - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.18.0/packaging/gitlab/testguard.gitlab-ci.yml'
793
+ - remote: 'https://raw.githubusercontent.com/raccioly/testguard/v0.18.1/packaging/gitlab/testguard.gitlab-ci.yml'
794
794
  inputs: { dir: backend, post_note: true } # post_note needs TESTGUARD_GITLAB_TOKEN (api scope); one note, updated in place
795
795
  ```
796
796
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "testguard-cli",
3
- "version": "0.18.0",
3
+ "version": "0.18.1",
4
4
  "description": "Breaks your code on purpose and reports every promise your tests did not notice breaking. Mutation testing bound to the claims a project makes — vitest, jest, Playwright, pytest and unittest.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -130,12 +130,21 @@ const readBoundedFile = (path, maxBytes, label, { optional = false } = {}) => {
130
130
  const stat = fstatSync(descriptor);
131
131
  if (!stat.isFile()) throw new DiscoveryError(`${label} is not a regular file`);
132
132
  if (stat.size > maxBytes) throw new DiscoveryError(`${label} exceeded ${maxBytes} bytes`);
133
- const bytes = Buffer.alloc(maxBytes + 1);
133
+ // Reserve the observed file size, not the allowance for the largest report.
134
+ // The extra byte detects growth; a full buffer grows within the same hard
135
+ // ceiling so a concurrently appended suffix can never be silently dropped.
136
+ let bytes = Buffer.alloc(stat.size + 1);
134
137
  let length = 0;
135
138
  while (length < bytes.length) {
136
139
  const read = readSync(descriptor, bytes, length, bytes.length - length, null);
137
140
  if (read === 0) break;
138
141
  length += read;
142
+ if (length > maxBytes) throw new DiscoveryError(`${label} exceeded ${maxBytes} bytes`);
143
+ if (length === bytes.length) {
144
+ const grown = Buffer.alloc(Math.min(maxBytes + 1, Math.max(4096, bytes.length * 2)));
145
+ bytes.copy(grown, 0, 0, length);
146
+ bytes = grown;
147
+ }
139
148
  }
140
149
  if (length > maxBytes) throw new DiscoveryError(`${label} exceeded ${maxBytes} bytes`);
141
150
  return bytes.subarray(0, length);