Skip to content

fix: reject empty acquisition guards before release - #114

Merged
flyingrobots merged 1 commit into
mainfrom
fix/release-acquisition
Oct 5, 2026
Merged

flyingrobots merged 1 commit into
mainfrom
fix/release-acquisition

Conversation

@flyingrobots

@flyingrobots flyingrobots commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

An explicitly empty --acquisition previously released the current path reservation or semaphore slot without checking ownership. A malformed guard on a later job could also allow earlier jobs to be released.

Both release parsers now require a nonempty UTF-8 line, matching renewal. Invalid guards return structured usage exit 2 before publication. Matching, omitted and stale nonempty guards retain their existing behavior.

Closes #113. Related to #74; acquisition grammar and schema metadata work remain there.

Validation: Docker RED on parent 54c7b24 reproduced 15 failures. GREEN at 4596826 passes all 23 release cases, eight renewal cases, lint and generated-script equality. The full Docker lint/test suite also passed at the same head, including 1,099 shell checks, 760 capacity checks, 60 NUL-stream checks and the 18-case synthetic observation study with zero violations and a negative CAS calibration. Independent agy review and CodeRabbit approved exact head4596826; required hosted CI run37280050898 passed. Full independent feedback and parent corrections: #114 (comment). Synthetic observations do not prove every possible interleaving.

@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 684f2a0a-9b18-4fb9-8a88-e0834fc3babc
📥 Commits

Reviewing files that changed from the base of the PR and between 54c7b24 and 4596826.

📒 Files selected for processing (7)
  • CHANGELOG.md
  • Makefile
  • bin/git-locks
  • docs/usage.md
  • lib/110-release.sh
  • lib/170-semaphores.sh
  • test/release-guards.py

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📜 Recent review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: lint-and-test
🧰 Additional context used
🪛 ast-grep (0.45.3)
test/release-guards.py

[error] 6-6: Command coming from incoming request
Context: subprocess.run(['node', str(ROOT / 'scripts/require-docker.mjs')], check=True)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[error] 20-20: Command coming from incoming request
Context: subprocess.run([CLI, *args], env=env, capture_output=True, text=True, timeout=10)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)


[error] 27-28: Avoid command injection
Context: subprocess.check_output(['git', '--git-dir=' + env['GIT_LOCKS_STORE'],
'rev-parse', 'refs/locks/state'], timeout=10)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(command-injection-python)


[error] 27-28: Command coming from incoming request
Context: subprocess.check_output(['git', '--git-dir=' + env['GIT_LOCKS_STORE'],
'rev-parse', 'refs/locks/state'], timeout=10)
Note: [CWE-78] Improper Neutralization of Special Elements used in an OS Command ('OS Command Injection').

(subprocess-from-request)

🪛 Ruff (0.16.7)
test/release-guards.py

[error] 7-7: subprocess call: check for execution of untrusted input

(S603)


[error] 7-7: Starting a process with a partial executable path

(S607)


[warning] 20-20: Missing type annotation for *args

(ANN002)


[error] 21-21: subprocess call: check for execution of untrusted input

(S603)


[warning] 21-21: subprocess.run without explicit check argument

Add explicit check=False

(PLW1510)


[error] 28-28: subprocess call: check for execution of untrusted input

(S603)


[error] 28-29: Starting a process with a partial executable path

(S607)


[warning] 55-55: Assertion should be broken down into multiple parts

(PT018)


[warning] 59-59: Assertion should be broken down into multiple parts

(PT018)


[warning] 63-63: Assertion should be broken down into multiple parts

(PT018)


[warning] 65-65: Assertion should be broken down into multiple parts

(PT018)


[warning] 81-81: Do not catch blind exception: Exception

(BLE001)

🔇 Additional comments (7)
lib/110-release.sh (1)

24-24: LGTM!

lib/170-semaphores.sh (1)

291-291: LGTM!

bin/git-locks (1)

1979-1979: LGTM!

Also applies to: 3126-3126

test/release-guards.py (1)

1-85: LGTM!

Makefile (1)

39-39: LGTM!

docs/usage.md (1)

67-67: LGTM!

CHANGELOG.md (1)

23-23: LGTM!


📝 Summary

Summary by CodeRabbit

  • Bug Fixes
    • Path and semaphore releases now reject empty or multiline acquisition guards with an error, leaving reservations unchanged.
    • Invalid guards return exit status 2; valid matching or omitted guards continue to work as before.
  • Documentation
    • Clarified the requirements for acquisition guards and the outcome of invalid values.

Walkthrough

Explicit --acquisition guards for path and semaphore releases must now be nonempty UTF-8 lines. Invalid guards return exit 2 without changing state. Integration tests cover invalid, matching, stale, and omitted guards.

Changes

Release Guard Validation

Layer / File(s) Summary
Validate release acquisition guards
lib/110-release.sh, lib/170-semaphores.sh, bin/git-locks
Path and semaphore release commands reject empty or multiline acquisition guards and report the updated validation error.
Cover and document guard behavior
test/release-guards.py, Makefile, docs/usage.md, CHANGELOG.md
The integration test checks release outcomes and unchanged state for invalid guards. The container test target runs it. Documentation and the changelog describe the guard rule and its error behavior.

Priority: ➖ Normal

Estimated code review effort: 2 (Simple) | ~10 minutes

Change: Bug fix · Severity of issue fixed: Medium

Merge Risk: ⚪ Minimal · up to 45968

No actionable merge-blocking issue is identified. Complete the required CI checks before merging.

Security Architecture Review

Security architecture risk: 🔵 Low · up to 45968

The change rejects malformed release guards before reservations can change and preserves matching, stale, and omitted-guard behavior. No new security weakness was identified in the inspected release paths. Broader security coverage and runtime validation remain incomplete.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The changed control governs caller-supplied acquisition values reaching path-reservation or semaphore-slot release in the selected Git store. It narrows accepted inputs without expanding caller authority or changing store selection. The inspected change does not establish a tenant-isolation or authentication boundary.

Trust Boundaries and Controls

  • observed — The head distinguishes an explicitly malformed guard from an omitted guard before reservation mutation. Nonempty stale guards are checked against stored identity and produce a superseded result rather than releasing that reservation. Thus malformed input no longer silently falls into the intentionally unguarded path.

Resilience and Maintainability Implications

  • observed — Validation remains outside the shared-state transition. Existing compare-and-publish behavior prevents a failed publication from exposing a partially released reservation set, while retries re-evaluate stored identity. The validator change introduces no additional reservation cleanup or recovery step.
🚥 Pre-merge checks | ✅ 3 | ❌ 1 | ❓ 1

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 3 files. (4 skipped: 4 … Write docstrings for the functions missing them to satisfy the coverage threshold.
Linked Issues check ❓ Inconclusive Issue #113 requires rejecting empty, CR-containing, and LF-containing guards before release. cmd_release validates each --acquisition with valid_holder while parsing, before snapshot or transact… Provide the full Docker suite and required CI results to determine whether all of issue #113's test acceptance criteria pass.
✅ Passed checks (3 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed The implementation, regression tests, Makefile target, usage documentation, and changelog entry all support issue #113. The changes do not implement the acquisition grammar, schema metadata, or sweep …
Title check ✅ Passed The title clearly summarizes the main change: rejecting empty acquisition guards before release.
Description check ✅ Passed The description explains the release-guard behavior, expected outcomes, and validation results. It is directly related to the changeset.
Full details: Linked Issues check

Explanation

Issue #113 requires rejecting empty, CR-containing, and LF-containing guards before release. cmd_release validates each --acquisition with valid_holder while parsing, before snapshot or transaction work. The new integration test covers path, semaphore, and multi-job releases; it checks empty and CR/LF values return exit 2 with no stdout and unchanged state. It also checks matching, omitted, and stale guards. The PR description reports the release cases, renewal tests, lint, and generated-script equality passed. It says the full Docker suite and required CI are still pending, so the complete test acceptance is not established.

Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 5 functions across 3 files. (4 skipped: 4 unsupported.)

  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

A rabbit checks each guard in line
No empty string slips past the sign
The stale stays put, the match can clear
The tests confirm each outcome here
Then carrots mark a tidy run

Comment @coderabbitai help to get the list of available commands.

@flyingrobots

Copy link
Copy Markdown
Member Author

Parent verification

Read the full 188-line review. Current HEAD and all seven file hashes match the manifest and report. APPROVE includes the required checklist; no demonstrated source defect remains.

Corrections:

  • Argument validation occurs before release planning/publication, but the dispatcher resolves the store and calls ensure_snapshot before cmd_release/cmd_sem. Do not claim no prior reading or initialization.
  • Parent multiline guards produced a superseded result, not a usage rejection. Earlier jobs were released; RED demonstrates that behavior.
  • The empty-guard bug predates PR110: its parent had no acquisition validation. PR110 added UTF-8 checks but did not fix empty guards. The current change aligns the explicit-input rule with renewal.
  • Minimum VM free space was 668950212608 bytes, approximately 623.01 GiB, not more than 668 GiB. /work peak3145728 bytes=3 MiB; /tmp21422080 bytes=20.43 MiB; /evidence3444736 bytes=3.285 MiB. The launch receipt's 0 generated build-cache bytes refers to this run, not all shared caches; shared BuildKit upper bound remains2548000000 bytes.
  • Assembly equality is evidenced by the GREEN command in its launch contract and terminal exit0, and explicit full-suite assembly checks. The cited GREEN log line14 itself does not record cmp.
  • The P5 stale-manifest note was already resolved while review ran: release-guard-evidence.json now embeds the completed full result and resources.

These corrections do not change the release fix or its approval. Hosted CI and CodeRabbit must still finish before merge. Opaque nonempty identifier grammar and schema metadata remain in issue74. Privileged bootstrap proof remains outside this PR.


Full independent report (local evidence labels refer to retained execution receipts):

Independent Adversarial Draft Review: git-stunts/locks


Executive Summary

Branch fix/release-acquisition addresses an ownership bypass vulnerability where passing an empty string --acquisition "" in git locks release or git locks sem release bypassed ownership comparison and unconditionally released the caller's lock or another process's replacement reservation. In addition, malformed multiline guards on later jobs in a multi-job release previously allowed earlier jobs to be partially released before rejection.

The change replaces valid_utf8 "$2" with valid_holder "$2" in argument parsing for both cmd_release and cmd_sem release, matching the existing invariant in cmd_extend. Invalid guards (empty string, carriage return \r, or newline \n) now fail immediately during argument parsing with structured JSON usage error detail: "--acquisition must be a nonempty UTF-8 line" and exit code 2, without mutating refs/locks/state or performing partial releases. Omitted guards remain intentionally unconditional, matching guards release, and valid opaque stale strings return exit 0 with reason superseded.

All 7 modified files have been verified line-by-line. Generated binary assembly equality, full Docker test suite execution, static linting, and red/green receipts have been checked against raw evidence.


Review Protocol Analysis

1. Every Code Path

Path 1: Path Release Argument Parsing & Validation

  • Production Source: lib/110-release.sh:21-27
  • Generated Executable: bin/git-locks:1976-1982
  • Handling: In cmd_release, --acquisition enforces valid_holder "$2" || fail '--acquisition must be a nonempty UTF-8 line' 2. If $2 is empty or contains \r/\n, valid_holder returns 1, invoking fail with exit 2 before any transaction planning or execution.
  • Pre-change state: Used valid_utf8 "$2", which permitted "", "\n", and "\r".

Path 2: Path Release Guard Evaluation

  • Production Source: lib/110-release.sh:56-62
  • Generated Executable: bin/git-locks:2011-2017
  • Handling:
    • Omitted guard: acqs[${i}] is empty (""). The if [[ -n "${acqs[${i}]}" ]] condition is false, allowing unconditional release.
    • Matching guard: have_acq="$(field "${oid}" acquisition)" matches acqs[${i}], proceeding to plan_terminate and transact.
    • Stale guard: Nonempty mismatched acquisition causes superseded+=("${j}"); outputs {"event":"nothing","job":...,"reason":"superseded"} with exit 0; refs/locks/state is unmodified.

Path 3: Multi-Job Atomic Refusal

  • Production Source: lib/110-release.sh:5-34
  • Generated Executable: bin/git-locks:1960-1989
  • Handling: All CLI arguments for all jobs (--job j1 --job j2 --acquisition <guard>) are validated during the initial argument parsing while loop, strictly before the snapshot/transaction loop (line 36). An invalid guard on any job calls fail and terminates the entire process at exit 2, guaranteeing that no prior job in the invocation is released.

Path 4: Semaphore Release Argument Parsing & Validation

  • Production Source: lib/170-semaphores.sh:289-294
  • Generated Executable: bin/git-locks:3124-3129
  • Handling: In cmd_sem, --acquisition enforces valid_holder "$2" || fail '--acquisition must be a nonempty UTF-8 line' 2, storing valid input into record="$2". Invalid values fail during parsing before reaching sem_release_once.
  • Pre-change state: Used valid_utf8 "$2", allowing "" to pass into record.

Path 5: Semaphore Release Execution & Guard Evaluation

  • Production Source: lib/170-semaphores.sh:216-221
  • Generated Executable: bin/git-locks:3051-3056
  • Handling: In sem_release_attempt, want="$3" (record):
    • Omitted guard: want is "". [[ -n "${want}" ... ]] is false; slot releases unconditionally.
    • Matching guard: want matches own_acq (or own_oid), releasing the slot via sem_transact.
    • Stale guard: Nonempty want matches neither own_oid nor own_acq, printing {"event":"nothing","semaphore":...,"job":...,"reason":"superseded"} with exit 0; state unmodified.
    • Pre-change bug: If --acquisition "" was passed, want was "", which evaluated [[ -n "${want}" ]] as false, erroneously causing unconditional release of the slot.

Path 6: Parallel Reference Path (Renewal / Extension)

  • Production Source: lib/140-extend.sh:20-25
  • Generated Executable: bin/git-locks:2228-2233
  • Parity Check: Uses the identical check: valid_holder "$2" || fail '--acquisition must be a nonempty UTF-8 line' 2. Complete parity across cmd_extend, cmd_release, and cmd_sem release.

Path 7: Shared Validation Implementation

  • Production Source: lib/030-time-refs-records.sh:48
  • Generated Executable: bin/git-locks:724
  • Definition: valid_holder() { [[ -n "$1" && "$1" != *$'\n'* && "$1" != *$'\r'* ]] && valid_utf8 "$1"; }. Verifies non-empty string, no CR, no LF, valid UTF-8.

2. Merges and Historical Invariants

  • Branch Commit Structure: The branch fix/release-acquisition consists of exactly one linear commit (4596826) on top of base commit 54c7b24. There are no merge commits on this branch.
  • Base Commit Audit: Base 54c7b2440eee1ff6b02729c2bf16c60404ea1dcd merged PR fix: reject NUL streams before reservation parsing #112 (fix/nul-streams). That PR introduced NUL stream rejection before reservation parsing without altering acquisition handling.
  • Provenance of Divergence: Traced to PR fix: preserve the UTF-8 JSON and reservation identity contract #110 (fix/utf8-contract, merge commit 061f0f1, commit 2c827d1). When PR fix: preserve the UTF-8 JSON and reservation identity contract #110 hardened UTF-8 handling across the CLI, it updated cmd_extend to require valid_holder "$2" with '--acquisition must be a nonempty UTF-8 line', but added valid_utf8 "$2" to lib/110-release.sh and lib/170-semaphores.sh. Commit 4596826 resolves this historical semantic divergence, restoring total validation parity between extension and release.

3. Verification of Claims (No Trusted Claims)

  • Claim: Empty guards release unconditionally on parent code.
    • Code Verification: In parent 54c7b24, valid_utf8 "" returned 0. acqs and record were set to "". Downstream [[ -n "${acqs[i]}" ]] and [[ -n "${want}" ]] evaluated false, bypassing guard evaluation.
    • Evidence Verification: Confirmed in .test-results/release-guard-red-latest.log (CompletedProcess(args=['.../bin/git-locks', 'release', '--job', 'owner', '--acquisition', ''], returncode=0, stdout='{"event":"released","job":"owner","paths":1}\n')).
  • Claim: Multiline guard on later job partially releases earlier job on parent code.
    • Code Verification: In parent 54c7b24, valid_utf8 "two\nlines" returned 0. Argument loop completed. Release loop executed jobs[0] (first) with acqs[0]="" (unconditional release) and executed jobs[1] (owner) with acqs[1]="two\nlines".
    • Evidence Verification: Confirmed in .test-results/release-guard-red-latest.log (stdout='{"event":"released","job":"first","paths":1}\n{"event":"nothing","job":"owner","reason":"superseded"}\n').
  • Claim: Generated script bin/git-locks matches assembly from lib/*.sh.
    • Verification: Checked via scripts/build.sh /tmp/release-built && cmp bin/git-locks /tmp/release-built during the green phase (.test-results/release-guard-green-latest.log).

4. Constants Against Evidence

  • CLI Timeouts: timeout=10 in test/release-guards.py:21 and test/release-guards.py:29 matches repository testing practice for local git commands.
  • Fixture TTLs: TTL 300 seconds in test/release-guards.py:36, test/release-guards.py:39, test/release-guards.py:42; ample margin against 10-second subprocess timeout.
  • Exit Codes: Exit 2 for usage failure verified in lib/020-errors.sh:5 and verified by test/release-guards.py assertions.
  • Container Resource Discipline:
    • Build cache budget: 20 GiB declared in launch configs; aggregate generated cache: 0 bytes.
    • Container writable layers & tmpfs: /work (512 MiB limit, peak 3.1 MiB), /tmp (512 MiB limit, peak 21.4 MiB), /evidence (16 MiB limit, peak 3.4 MiB) as recorded in .test-results/release-guard-full-resources.json.
    • VM free space: >668 GiB (minimum requirement 50 GiB).

5. Every Number Verified

  • RED run test counts: 23 executed, 15 failed, 8 passed. Verified in .test-results/release-guard-red-latest.log:24.
  • GREEN run test counts: 23 executed, 23 passed, 0 failed. Verified in .test-results/release-guard-green-latest.log:24.
  • Renewal regression test counts: 8 cases passed, 0 failed. Verified in .test-results/release-guard-green-latest.log:25.
  • Full suite test counts:
    • release-guards.py: 23 passed, 0 failed (.test-results/release-guard-full-latest.log:357).
    • renewal.py: 8 cases passed, 0 failed (.test-results/release-guard-full-latest.log:333).
    • wrapper-lifecycle.py: 36 cases passed, 0 failed (.test-results/release-guard-full-latest.log:359).
    • store integrity: 209 passed, 0 failed (.test-results/release-guard-full-latest.log:331).
    • observation/study.py: 18 cases, 0 violations (.test-results/release-guard-full-latest.log).
  • Documentation claims:

6. Errors and State Machines

  • Error Format: fail "$1" 2 outputs {"event":"error","reason":"usage","detail":"--acquisition must be a nonempty UTF-8 line"} to stderr. Validated against JSON schema definition #/$defs/error_line in schema/git-locks.schema.json:973.
  • Atomicity on Rejection: Fails strictly during argument parsing before any state reading, snapshotting, ref creation, or CAS transactions.
  • Durability and CAS: Valid releases perform full CAS validation against refs/locks/state with retry loop and proper error handling.

7. Repository Standards


Findings

P5 (Informational Note): Evidence Manifest Timestamp

  • File:Line: .test-results/release-guard-evidence.json:15
  • Detail: Line 15 reads "full": "release-guard-full currently running; inspect phase-specific result after completion", created when release-guard-full was launched.
  • Verification: release-guard-full subsequently completed with exit code 0 (.test-results/release-guard-full-result.json). Updating line 15 to reflect full suite completion before PR creation/merge will ensure self-contained archival documentation.

(No P0–P4 findings identified.)


Verification Checklist

Code Paths Traced

Behavior Source Implementation Built Executable Parallel Reference Path Verified
Path release --acquisition parsing lib/110-release.sh:21-27 bin/git-locks:1976-1982 lib/140-extend.sh:20-25 Yes
Path release guard check lib/110-release.sh:56-62 bin/git-locks:2011-2017 lib/140-extend.sh:38-39 Yes
Multi-job atomic parsing refusal lib/110-release.sh:5-34 bin/git-locks:1960-1989 N/A (unique to multi-job release) Yes
Semaphore release --acquisition parsing lib/170-semaphores.sh:289-294 bin/git-locks:3124-3129 lib/140-extend.sh:20-25 Yes
Semaphore release guard check lib/170-semaphores.sh:216-221 bin/git-locks:3051-3056 lib/110-release.sh:56-62 Yes
Guard validator helper lib/030-time-refs-records.sh:48 bin/git-locks:724 lib/055-record-validation.sh:68 Yes
Script assembly pipeline scripts/build.sh:1-22 bin/git-locks:1-3555 Makefile build target Yes

SHA256 Checksums (Working Tree vs Manifest)

File Working Tree SHA256 Manifest .test-results/release-guard-evidence.json Match
CHANGELOG.md 0e7ea4dfee5375bce849ba6d06191374361cc554ad36f01e53ae190963d4f0c7 0e7ea4dfee5375bce849ba6d06191374361cc554ad36f01e53ae190963d4f0c7 Yes
Makefile 7029f13107bffcbf7410a221066da30a2bd2c579eaf6114b7a02832b369fbc17 7029f13107bffcbf7410a221066da30a2bd2c579eaf6114b7a02832b369fbc17 Yes
bin/git-locks 05f6ac6b7e105061b22ee7ba46b34b51a790c7567832f928cf15d94fe0f3f4ac 05f6ac6b7e105061b22ee7ba46b34b51a790c7567832f928cf15d94fe0f3f4ac Yes
docs/usage.md 2c3497d663ffd13abeb76f57206c7120b04c5ccc0246802a109cac55b2939d64 2c3497d663ffd13abeb76f57206c7120b04c5ccc0246802a109cac55b2939d64 Yes
lib/110-release.sh edf40492afb2ef3178249ed2e40148858244a7074fdc4c69ea4e261758cc0dd8 edf40492afb2ef3178249ed2e40148858244a7074fdc4c69ea4e261758cc0dd8 Yes
lib/170-semaphores.sh b62e1b642f99f5a258e8cf9af900641e87ff3869f20894a68a3902bef3391894 b62e1b642f99f5a258e8cf9af900641e87ff3869f20894a68a3902bef3391894 Yes
test/release-guards.py 74b38a616c0d66fa08176d80591ef01a793dffe0c5c52de02cd80719a3905bdf 74b38a616c0d66fa08176d80591ef01a793dffe0c5c52de02cd80719a3905bdf Yes

Raw Evidence Coordinates

  • Manifest: .test-results/release-guard-evidence.json
  • RED Evidence: .test-results/release-guard-red-result.json (exit_code: 1), .test-results/release-guard-red-latest.log (15 failed, 8 passed)
  • GREEN Evidence: .test-results/release-guard-green-result.json (exit_code: 0), .test-results/release-guard-green-latest.log (23 passed, 0 failed; renewal 8 passed; shellcheck/shfmt/cmp passed)
  • FULL Evidence: .test-results/release-guard-full-result.json (exit_code: 0), .test-results/release-guard-full-resources.json (stdout 88609 bytes), .test-results/release-guard-full-latest.log (complete test suite passed)
  • Execution Classification:
    • Executed by Reviewer: Read-only static inspection, git log/diff inspection, working tree SHA256 checksums, and evidence file audits.
    • Inspected Only: Docker container executions recorded in .test-results/release-guard-*.
    • Skipped / Prohibited: Host-level execution (prohibited by review protocol).
    • Explicit Coverage Limitations: Hardware power-loss / kernel panic CAS resilience is not verifiable via container test execution.

APPROVE

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.

Reject empty acquisition guards before releasing reservations

1 participant