Skip to content

test(openemr-cmd): bats permission-case coverage — probe matrix + #836 reproducer#839

Merged
bradymiller merged 2 commits into
openemr:masterfrom
bradymiller:test/bats-probe-permission-cases
Jun 26, 2026
Merged

test(openemr-cmd): bats permission-case coverage — probe matrix + #836 reproducer#839
bradymiller merged 2 commits into
openemr:masterfrom
bradymiller:test/bats-probe-permission-cases

Conversation

@bradymiller

@bradymiller bradymiller commented Jun 26, 2026

Copy link
Copy Markdown
Member

Summary

Hermetic bats coverage for the permission scenarios that have been the most active bug surface in the recent worktree-cmd PRs (#833, #836, #838). Pure test scaffolding — no production code changes.

What's added

Four cases in tests/bats/openemr-cmd/mountpoint_precreate.bats:

  1. Empty non-writable + non-writable parent → probe fails. The probe-loosening rule from fix(openemr-cmd): pre-create volume mount-point dirs + loosen remove probe #838 ("empty + parent writable = rmdir-able") requires BOTH conditions; guards against accidentally accepting a case where the parent's perms would block the rmdir too.

  2. Unreadable dir (mode 0000) → probe fails conservatively. When we can't [[ -r && -x ]] the dir, we can't verify emptiness via find; the probe must treat it as blocking (rm could silently leave content behind otherwise).

  3. Multiple unwritable dirs (one empty-removable, one non-empty) → probe fails on the non-empty one. Early-termination correctness: the probe must evaluate each unwritable dir against the empty-removable rule rather than failing on the first unwritable it sees regardless of removability.

  4. Reproducer for the multi-3 CI failure in test(openemr-cmd): e2e — prek install + real git commit; expand multi-concurrent to 3 envs #836: stage ccdaservice/packages/oe-cqm-service/node_modules as empty 0555 — the exact path + state that broke pre-loosening. Confirms BOTH that pre-create populates the path AND that the loosened probe accepts the simulated post-volume-purge state. Pins the bug as a regression guard against future drift.

Why now

The permission-bug class has surfaced repeatedly across recent PRs (apache uid mismatch, docker daemon root-owned mount-points, probe over-strictness). Each fix added defensive logic; this PR turns those scenarios into bats that fail loudly if any future refactor breaks the invariants. The reproducer in particular locks down the specific bug from #836 so it can't silently regress.

What this PR can't pin

The bats simulates the FILESYSTEM STATE (root-owned-empty via chmod 0555/0000) but not the CAUSE (docker daemon creating dirs as root, apache chowning bind mount). The real-docker e2e job in test-bats-openemr-cmd-real-docker.yml covers the cause-side end-to-end. The two are complementary.

Test plan

  • BATS openemr-cmd (ubuntu-22.04) and (macos-14) pass — the new 4 tests + existing 12 in mountpoint_precreate.bats
  • No other workflow effects (no production code changes; the existing real-docker e2e jobs run unchanged)

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved handling of worktree remove when mount points or directories are not writable.
    • Added coverage ensuring the “empty directory” exemption is not used when the parent is also non-writable.
    • Added conservative behavior checks for effectively unreadable/unenterable directories, preventing unsafe verification.
    • Strengthened multi-candidate evaluation when multiple unwritable directories exist, ensuring the correct failure is surfaced.
    • Reproduced and protected a regression so removal succeeds for an empty, non-writable mount point.

…nemr#836 reproducer

Adds 4 bats cases to mountpoint_precreate.bats covering permission
scenarios that were previously script-logic-only (no hermetic tests
pinning the behavior):

1. Empty non-writable + non-writable parent → probe fails. The probe-
   loosening rule "empty + parent writable = rmdir-able" requires
   BOTH conditions; this guards against accidentally accepting a
   case where the parent's perms would block the rmdir too.

2. Unreadable dir (mode 0000) → probe fails conservatively. When we
   can't [[ -r && -x ]] the dir, we can't verify emptiness via find;
   the probe must treat it as blocking (rm could silently leave
   content behind otherwise).

3. Multiple unwritable dirs (one empty-removable, one non-empty) →
   probe fails on the non-empty one. Early-termination correctness:
   the probe must evaluate each unwritable dir against the empty-
   removable rule rather than failing on the first unwritable it
   sees regardless of removability.

4. Reproducer for the multi-3 CI failure in openemr#836: stage
   `ccdaservice/packages/oe-cqm-service/node_modules` as empty 0555
   (the exact path + state that broke pre-loosening). Confirms BOTH
   that pre-create populates the path AND that the loosened probe
   accepts the simulated post-volume-purge state. Pinning the bug as
   a regression guard against future drift.

No production code changes — pure scaffolding.

Assisted-by: Claude Code
@coderabbitai

coderabbitai Bot commented Jun 26, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 708e4f11-b9ec-4f68-b829-48ae284bef21

📥 Commits

Reviewing files that changed from the base of the PR and between f75c5ed and e55f5d4.

📒 Files selected for processing (1)
  • tests/bats/openemr-cmd/mountpoint_precreate.bats
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/bats/openemr-cmd/mountpoint_precreate.bats

📝 Walkthrough

Walkthrough

The PR adds four worktree remove test cases in mountpoint_precreate.bats covering parent-writability checks, unreadable directories, multiple unwritable candidates, and the #836 precreate regression path.

Changes

Worktree remove probe coverage

Layer / File(s) Summary
Probe edge cases
tests/bats/openemr-cmd/mountpoint_precreate.bats
Adds cases for an empty unwritable child with a non-writable parent, an unreadable or unenterable directory, and multiple unwritable directories in one worktree.
Precreate regression case
tests/bats/openemr-cmd/mountpoint_precreate.bats
Adds the #836 regression case validating the expected mountpoint path after worktree add and successful worktree remove on an empty unwritable mountpoint.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • openemr/openemr-devops#826: Covers the same openemr-cmd worktree remove writability-probe behavior around empty unwritable mountpoints.
  • openemr/openemr-devops#838: Related test-area changes around mountpoint_precreate and the worktree remove probe loosening behavior.

Poem

I hop where empty pockets sit,
and sniff for paths that won’t admit.
If parents frown, I leave a trace;
if mounts are precreated, I find the place.
🐰

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the new BATS permission-case test coverage and the #836 regression reproducer added to openemr-cmd.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/bats/openemr-cmd/mountpoint_precreate.bats (1)

264-279: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename this test to match the exercised mode.

The body intentionally switched from 0700 to 0000, but the @test name and leading comment still advertise a 0700 case. That makes CI output misleading when this scenario fails.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/bats/openemr-cmd/mountpoint_precreate.bats` around lines 264 - 279,
Update the test case name and the leading comment in mountpoint_precreate.bats
to match the actual permissions scenario being exercised. The current test body
uses the unreadable 0000 case, so rename the `@test` description and adjust nearby
commentary to reflect 0000 rather than 0700, keeping the intent aligned with the
probe-unreadable scenario.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@tests/bats/openemr-cmd/mountpoint_precreate.bats`:
- Around line 264-279: Update the test case name and the leading comment in
mountpoint_precreate.bats to match the actual permissions scenario being
exercised. The current test body uses the unreadable 0000 case, so rename the
`@test` description and adjust nearby commentary to reflect 0000 rather than 0700,
keeping the intent aligned with the probe-unreadable scenario.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 3aea6304-c317-45fd-b95f-90a1e63e614d

📥 Commits

Reviewing files that changed from the base of the PR and between 82bf49f and f75c5ed.

📒 Files selected for processing (1)
  • tests/bats/openemr-cmd/mountpoint_precreate.bats

… exercises

CodeRabbit caught a stale name: the test was titled "mode 0700" but
the body uses chmod 0000 (since 0700 keeps owner rwx and would never
trip the probe-fail branch for the test user who owns the dir). The
name mismatch would make CI output misleading on regression.

Rename to "mode 0000" and rewrite the leading comment to explain
the 0700 vs 0000 distinction inline — preserves the design rationale
that prompted the switch.

Assisted-by: Claude Code
@bradymiller bradymiller merged commit 2b62944 into openemr:master Jun 26, 2026
5 checks passed
@bradymiller bradymiller deleted the test/bats-probe-permission-cases branch June 26, 2026 04:19
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