Skip to content

Add ShellSpec harness and coverage - #414

Merged
shunkakinoki merged 7 commits into
mainfrom
add-shell-tests
Dec 13, 2025
Merged

Add ShellSpec harness and coverage#414
shunkakinoki merged 7 commits into
mainfrom
add-shell-tests

Conversation

@shunkakinoki

@shunkakinoki shunkakinoki commented Dec 13, 2025

Copy link
Copy Markdown
Owner

Adds a reusable mock harness for ShellSpec and expands test coverage for the Claude hook scripts. Also fixes security hook parsing for legacy deny patterns and command chaining on macOS.


Summary by cubic

Adds a reusable ShellSpec mock harness and expands tests for Claude hook scripts to improve reliability and coverage. Fixes security command parsing for legacy patterns and command chaining on macOS.

  • New Features

    • Added mock_bin_setup/cleanup to stub commands and log calls; replaced ad‑hoc temp binaries with the shared harness.
    • Expanded notify/pushover tests: permission alerts, auto-compact, subagent stop, risky Bash warnings, and Stop/plan-mode via transcript/priority; plus shell script syntax checks for all tracked files.
    • Added coverage for credential sourcing via HOME/dotfiles/.env (prefer env vars; skip when incomplete or invalid).
  • Bug Fixes

    • Legacy deny patterns like Bash(sudo:) now match correctly as prefix globs (sudo).
    • Properly split chained commands (;, &&, ||, |) with sed -E to catch hidden dangerous operations.

Written for commit 9d8b256. Summary will update automatically on new commits.

Copilot AI review requested due to automatic review settings December 13, 2025 04:54
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@mesa-dot-dev

mesa-dot-dev Bot commented Dec 13, 2025

Copy link
Copy Markdown

You do not have enough credits to review this pull request. Please purchase more credits to continue.

@coderabbitai

coderabbitai Bot commented Dec 13, 2025

Copy link
Copy Markdown

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Summary by CodeRabbit

  • Tests

    • Expanded test coverage for security pattern matching, command validation, and blocked command scenarios.
    • Added comprehensive notification and Pushover hook integration tests with environment credential sourcing.
    • Introduced shell syntax validation testing for multiple shell types (bash, sh, fish, zsh, ksh).
  • Chores

    • Enhanced test infrastructure with centralized mocking utilities and improved cleanup procedures for better test isolation and reliability.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

Security matching now conditionally converts legacy trailing :* into a prefix-glob and uses sed -E for command segmentation. Test infrastructure gained centralized mock-bin helpers and many expanded notification, pushover, and security tests. A new spec added that syntax-checks tracked shell files.

Changes

Cohort / File(s) Summary
Security module logic
config/claude/security.sh
matches_pattern now only converts a trailing :* into a prefix-glob when present (removes : then appends *); segmentation switched to sed -E with an extended regex to split on `[;&
Test helper infrastructure
spec/support/custom_matcher.sh
Added set -euo pipefail; new helpers mock_bin_setup(...) (creates temp mock bin dir, MOCK_LOG, prepends to PATH, writes simple mock executables that log invocations) and mock_bin_cleanup() (restores PATH, removes temp dir, unsets vars).
Notification tests (notify)
spec/notify_spec.sh
Replaced per-test osascript mocks with mock_bin_setup/mock_bin_cleanup; added Pushover .env credential sourcing scenarios, credential edge-case tests, error/fallback handling, PreCompact/SubagentStop/Stop/PreToolUse hook scenarios, marker-file checks, and consolidated cleanup.
Pushover tests
spec/pushover_spec.sh
Replaced ad-hoc curl mocks with centralized mock helpers; added HOME/dotfiles/.env credential sourcing tests, incomplete/invalid .env handling, SessionEnd and Stop hook scenarios (plan-mode, work-completed), expanded notification priorities and log assertions, and added transcript-driven inputs.
Security spec tests
spec/security_spec.sh
Expanded "blocked commands" cases: legacy sudo:* patterns, hidden dangerous commands after ; and &&, legacy dd if=:*, chmod -R 777, and an empty-input edge case; tests expect exit status 2 and stderr containing BLOCKED.
Spec additions
spec/shell_files_spec.sh
New spec to detect shell type (by shebang/content) and run syntax checks (bash -n, sh -n, fish -n, zsh -n, ksh -n) across tracked shell files; skips tests if linters are absent.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Inspect config/claude/security.sh for edge-case handling of :* patterns and portability of sed -E across target environments.
  • Review spec/support/custom_matcher.sh for safe PATH manipulation, atomic cleanup on failures, and potential leakage of MOCK_* env vars.
  • Spot-check representative tests in spec/notify_spec.sh and spec/pushover_spec.sh for correct mock expectations, .env sourcing semantics, and transcript-based assertions.
  • Validate spec/shell_files_spec.sh detection logic and that it gracefully skips when linters are absent.

Possibly related PRs

  • kyber #408 — Modifies config/claude/security.sh and relates to the command-deny matching and segmentation behavior changed here.

Poem

🐰 I hopped through mocks and tiny logs,
Tweaked patterns, cleared the fog,
Tests now march with tidy bins,
Shells inspected, quiet grins —
A carrot-coded spring of docs. 🥕✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 3.70% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Add ShellSpec harness and coverage' is concise, specific, and directly reflects the main objective of the changeset: introducing a reusable ShellSpec mock harness and expanding test coverage.
Description check ✅ Passed The description is well-detailed and directly related to the changeset, covering new features (mock harness, expanded tests, credential sourcing), bug fixes (legacy pattern parsing, command chaining), and implementation details.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch add-shell-tests

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

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

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @shunkakinoki, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the testing infrastructure by introducing a reusable ShellSpec harness, making it easier to write and maintain tests for the Claude hook scripts. Concurrently, it expands the test suite to cover various notification scenarios and critical security checks. Furthermore, the security.sh script has been refined to correctly interpret legacy deny patterns and robustly detect chained commands, bolstering the system's security posture.

Highlights

  • Testing Infrastructure: Introduced a reusable ShellSpec testing harness to simplify writing and maintaining tests for Claude hook scripts.
  • Test Coverage Expansion: Expanded test coverage for Claude hook scripts, including various notification scenarios and critical security behaviors.
  • Security Hook Improvements: Improved parsing of legacy deny patterns in security hooks to correctly handle Bash(sudo:*) style configurations.
  • Command Chaining Detection: Enhanced detection of command chaining on macOS within security hooks to prevent hidden dangerous commands from being executed.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@mesa-dot-dev

mesa-dot-dev Bot commented Dec 13, 2025

Copy link
Copy Markdown

Mesa Description

TL;DR

Adds a reusable ShellSpec mock harness and expands tests for Claude hook scripts to improve reliability and coverage. Fixes security command parsing for legacy patterns and command chaining on macOS.

What changed?

  • config/claude/security.sh: Updated pattern matching logic to convert legacy trailing ":" patterns to prefix globs (e.g., "sudo:") and refactored a sed command to use extended regular expressions.
  • spec/notify_spec.sh: Introduced new and refactored test suites for notification mechanisms, including comprehensive tests for Pushover credential sourcing from HOME/dotfiles/.env, suppression of local notifications when Pushover is active, and specific notification hooks for permission requests, auto-compacting context, subagent/work completion, and risky Bash commands. Refactored osascript mock setup.
  • spec/pushover_spec.sh: Extensively refactored and expanded test coverage, moving curl mock setup into helper functions, adding new test suites for credential handling from .env files and for the Stop hook event. Enhanced existing SessionEnd and Notification hook tests with more detailed assertions.
  • spec/security_spec.sh: Added several new security specification tests to verify dangerous commands are blocked, including sudo with arguments, rm -rf after semicolons or && operators, dd if=..., and chmod -R 777.
  • spec/shell_files_spec.sh: New file introducing a shellspec test suite for dynamic syntax checks on all tracked shell files, automatically detecting shell type and skipping tests if the interpreter is not installed.
  • spec/support/custom_matcher.sh: New file introducing mock_bin_setup and mock_bin_cleanup shell functions to create a temporary mock binary path for testing, setting up mock executable scripts that log invocations, and restoring the environment afterward.

Description generated by Mesa. Update settings

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This is a great pull request that significantly improves the test infrastructure and coverage for the hook scripts. The introduction of the reusable mock_bin_setup harness is an excellent addition that cleans up the test files nicely. The expanded test suites for notify.sh, pushover.sh, and security.sh add a lot of value and confidence in the scripts' behavior. The fixes for legacy security patterns and command chaining on macOS are also well-implemented and now properly covered by tests. I have one minor suggestion for improving robustness.

Comment thread config/claude/security.sh
# This handles: cmd1 ; cmd2, cmd1 && cmd2, cmd1 || cmd2, cmd1 | cmd2
# shellcheck disable=SC2001
IFS=$'\n' read -r -d '' -a segments < <(echo "$command" | sed 's/[;&|]\+/\n/g' && printf '\0') || true
IFS=$'\n' read -r -d '' -a segments < <(echo "$command" | sed -E 's/[;&|]+/\n/g' && printf '\0') || true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

For better robustness and portability, it's recommended to use printf instead of echo when piping variable content to other commands. echo can have surprising behavior if the variable's content starts with a hyphen (-) or contains backslash escape sequences, and its implementation varies between shells. printf '%s' "$command" is a safer alternative that will print the string exactly as is.

Suggested change
IFS=$'\n' read -r -d '' -a segments < <(echo "$command" | sed -E 's/[;&|]+/\n/g' && printf '\0') || true
IFS=$'\n' read -r -d '' -a segments < <(printf '%s' "$command" | sed -E 's/[;&|]+ /\n/g' && printf '\0') || true

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 5 files

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a reusable mock harness for ShellSpec testing and significantly expands test coverage for Claude hook scripts. It also includes two important fixes to the security hook: proper handling of legacy deny patterns (e.g., sudo:*sudo*) and improved command chaining detection on macOS through explicit extended regex in sed.

Key Changes

  • Introduced mock_bin_setup and mock_bin_cleanup helper functions to standardize mock binary creation across tests
  • Fixed security.sh to properly convert legacy pattern:* deny patterns to glob format pattern*
  • Enhanced command splitting to use explicit extended regex (sed -E) for better macOS compatibility
  • Added comprehensive test coverage for security blocking, notification handling, and Pushover integration

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
spec/support/custom_matcher.sh New reusable mock harness providing mock_bin_setup and mock_bin_cleanup functions for creating temporary mock binaries that log invocations
spec/security_spec.sh Added tests for legacy sudo:* pattern blocking and semicolon command chaining detection
spec/pushover_spec.sh Refactored to use new mock harness and added tests for Stop hook scenarios (plan approval vs work completed)
spec/notify_spec.sh Refactored to use new mock harness and expanded coverage for permission requests, PreCompact, SubagentStop, and risky command warnings
config/claude/security.sh Fixed legacy pattern conversion logic (sudo:*sudo*) and switched to explicit extended regex (sed -E) for better portability

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

#!/usr/bin/env bash
set -euo pipefail
: "${MOCK_LOG:?MOCK_LOG must be set}"
printf '%s\n' "$0 $*" >>"$MOCK_LOG"

Copilot AI Dec 13, 2025

Copy link

Choose a reason for hiding this comment

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

The mock script uses $* which may not properly handle arguments with spaces or special characters. Consider using $@ instead, which preserves the original argument structure and is more suitable for logging invocations. While this may not cause issues in the current tests, it could lead to incorrect logging if mocked commands are called with arguments containing spaces.

Suggested change
printf '%s\n' "$0 $*" >>"$MOCK_LOG"
printf '%s' "$0" >>"$MOCK_LOG"
for arg in "$@"; do printf ' %s' "$arg" >>"$MOCK_LOG"; done
printf '\n' >>"$MOCK_LOG"

Copilot uses AI. Check for mistakes.
Comment on lines +5 to +35
mock_bin_setup() {
MOCK_BIN="$(mktemp -d)"
MOCK_LOG="$MOCK_BIN/mock.log"
: >"$MOCK_LOG"

MOCK_ORIGINAL_PATH="${PATH:-}"
export MOCK_BIN MOCK_LOG MOCK_ORIGINAL_PATH
export PATH="$MOCK_BIN:$MOCK_ORIGINAL_PATH"

local cmd
for cmd in "$@"; do
cat >"$MOCK_BIN/$cmd" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
: "${MOCK_LOG:?MOCK_LOG must be set}"
printf '%s\n' "$0 $*" >>"$MOCK_LOG"
exit 0
EOF
chmod +x "$MOCK_BIN/$cmd"
done
}

mock_bin_cleanup() {
if [[ -n "${MOCK_ORIGINAL_PATH:-}" ]]; then
export PATH="$MOCK_ORIGINAL_PATH"
fi
if [[ -n "${MOCK_BIN:-}" ]]; then
rm -rf "$MOCK_BIN"
fi
unset MOCK_BIN MOCK_LOG MOCK_ORIGINAL_PATH
}

Copilot AI Dec 13, 2025

Copy link

Choose a reason for hiding this comment

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

The mock harness functions lack documentation comments. Consider adding comments to explain the purpose and usage of mock_bin_setup and mock_bin_cleanup, including the environment variables they set (MOCK_BIN, MOCK_LOG, MOCK_ORIGINAL_PATH) and how they should be used in tests. This would improve maintainability and help other developers understand how to use these testing utilities.

Copilot uses AI. Check for mistakes.
@shunkakinoki
shunkakinoki enabled auto-merge (squash) December 13, 2025 05:13

@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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
spec/security_spec.sh (1)

80-114: Nice coverage expansion, but add || and | chaining cases to match stated parsing fixes.

These new blocked-command scenarios are well-targeted and should catch regressions in legacy :* handling and command segmentation. Since the PR summary calls out splitting on || and | too, I’d add at least one case for each (e.g., echo ok || rm -rf /* and echo ok | rm -rf /*) to ensure the macOS sed -E path is fully covered.

spec/pushover_spec.sh (1)

29-64: Avoid coupling assertions to cat "$MOCK_LOG" output ordering.

Right now, the test output is script stdout + mock log stdout in one stream, which can get brittle. If feasible in ShellSpec here, prefer checking the log file separately (or add a tiny helper matcher like The file "$MOCK_LOG" should include ...) so the SUT output and mock-call assertions don’t interfere.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between b9c63dd and 1010155.

📒 Files selected for processing (5)
  • spec/notify_spec.sh (3 hunks)
  • spec/pushover_spec.sh (2 hunks)
  • spec/security_spec.sh (1 hunks)
  • spec/shell_files_spec.sh (1 hunks)
  • spec/support/custom_matcher.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • spec/notify_spec.sh
  • spec/support/custom_matcher.sh
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{sh,bash}

📄 CodeRabbit inference engine (CLAUDE.md)

Use shfmt with 2-space indentation for shell scripts

**/*.{sh,bash}: Use 2 spaces for indentation in shell scripts
Add proper shebang lines to shell scripts
Follow shellcheck recommendations in shell scripts
Document complex commands in shell scripts
Use consistent variable naming in shell scripts

Files:

  • spec/pushover_spec.sh
  • spec/security_spec.sh
  • spec/shell_files_spec.sh
🧠 Learnings (5)
📚 Learning: 2025-11-25T09:34:32.423Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/formatting.mdc:0-0
Timestamp: 2025-11-25T09:34:32.423Z
Learning: Applies to **/*.{sh,bash} : Follow shellcheck recommendations in shell scripts

Applied to files:

  • spec/shell_files_spec.sh
📚 Learning: 2025-11-25T09:34:32.423Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/formatting.mdc:0-0
Timestamp: 2025-11-25T09:34:32.423Z
Learning: Applies to **/*.{sh,bash} : Add proper shebang lines to shell scripts

Applied to files:

  • spec/shell_files_spec.sh
📚 Learning: 2025-11-25T09:34:32.423Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/formatting.mdc:0-0
Timestamp: 2025-11-25T09:34:32.423Z
Learning: Applies to **/*.{sh,bash} : Use consistent variable naming in shell scripts

Applied to files:

  • spec/shell_files_spec.sh
📚 Learning: 2025-11-25T09:34:23.224Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-25T09:34:23.224Z
Learning: Applies to **/*.{sh,bash} : Use shfmt with 2-space indentation for shell scripts

Applied to files:

  • spec/shell_files_spec.sh
📚 Learning: 2025-11-25T09:34:32.423Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/formatting.mdc:0-0
Timestamp: 2025-11-25T09:34:32.423Z
Learning: Applies to **/*.{sh,bash} : Document complex commands in shell scripts

Applied to files:

  • spec/shell_files_spec.sh
🧬 Code graph analysis (1)
spec/pushover_spec.sh (1)
spec/support/custom_matcher.sh (2)
  • mock_bin_setup (5-25)
  • mock_bin_cleanup (27-35)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: docker-build-push (linux/arm64, arm64, ubuntu-24.04-arm)
  • GitHub Check: docker-build-push (linux/amd64, amd64, ubuntu-latest)
  • GitHub Check: nix-flake
  • GitHub Check: nix-darwin
  • GitHub Check: nix-linux
  • GitHub Check: nix-nixos
  • GitHub Check: e2e-run (NixOS, ubuntu-latest)
  • GitHub Check: e2e-run (Ubuntu, ubuntu-latest)
  • GitHub Check: e2e-run (MacOS, macos-latest)
  • GitHub Check: shellcheck
  • GitHub Check: shellspec
  • GitHub Check: lua-neovim
  • GitHub Check: lua-hammerspoon
  • GitHub Check: lua-neovim-test
🔇 Additional comments (4)
spec/shell_files_spec.sh (2)

1-3: Verify necessity of SC2329 disable.

Line 2 disables SC2329 (unreachable code after return), but I don't see any return/exit statements that would trigger this warning in the code. This disable may be unnecessary or precautionary without clear justification.

Please clarify: Is this disable needed for ShellSpec's dynamic parameter generation, or can it be removed?


19-38: Good use of ShellSpec Parameters:dynamic for dual-phase collection.

The test setup cleverly collects both .sh-extension files (lines 20–22) and executable scripts with bash/sh shebangs (lines 24–37), ensuring comprehensive coverage. Defensive file checks and read patterns are sound.

Consider adding a comment above line 19 to explain the collection strategy for future reviewers:

+# Collect tracked shell files in two phases:
+# 1. All files with .sh extension
+# 2. Non-.sh files with bash or sh shebang (executable scripts)
 Parameters:dynamic

This minor clarification aligns with the coding guideline to document complex commands.

spec/pushover_spec.sh (2)

7-17: Good move centralizing curl mocking via mock_bin_setup/mock_bin_cleanup.


161-201: Stop-hook coverage looks solid; transcript-driven cases are well chosen.

Comment thread spec/pushover_spec.sh
Comment on lines +144 to +155
It 'prefers environment variables over HOME/dotfiles/.env'
cat >"$TRANSCRIPT" <<'JSON'
{"type":"user","message":{"content":[{"type":"text","text":"Do not source"}]}}
JSON
TEMP_HOME=$(mktemp -d)
mkdir -p "$TEMP_HOME/dotfiles"
cat >"$TEMP_HOME/dotfiles/.env" <<'ENV'
PUSHOVER_API_TOKEN=bad_token
PUSHOVER_USER_KEY=bad_user
ENV
When run bash -c 'echo "{\"message\": \"Claude is waiting for your input\", \"transcript_path\": \"'"$TRANSCRIPT"'\"}" | env HOME="'"$TEMP_HOME"'" PUSHOVER_API_TOKEN="test_token" PUSHOVER_USER_KEY="test_user" bash '"$SCRIPT"'; rm -rf "'"$TEMP_HOME"'"; cat "$MOCK_LOG"'
The status should be success

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Don’t rm -rf temp dirs inside the When run command.

Line 154 deletes TEMP_HOME inline; if the SUT exits early/fails before the rm -rf, the temp dir will leak. Prefer moving that cleanup into the surrounding cleanup() (or track TEMP_HOME at the Describe scope and always remove it in After).

🤖 Prompt for AI Agents
In spec/pushover_spec.sh around lines 144 to 155, the test currently performs rm
-rf "$TEMP_HOME" inside the When run command which may never execute if the SUT
exits early; remove the inline rm -rf invocation and instead ensure TEMP_HOME is
cleaned up unconditionally by registering it with the existing cleanup()
mechanism or by creating/setting TEMP_HOME at the Describe scope and adding an
After/tearDown that always removes the directory (or call cleanup "$TEMP_HOME"
in the surrounding test harness) so temporary directories are never leaked even
on failures.

Comment thread spec/shell_files_spec.sh Outdated
Comment on lines +6 to +17
syntax_check() {
local file="$1"
local first_line=""

IFS= read -r first_line <"$file" || first_line=""

case "$first_line" in
'#!'*bash*) bash -n "$file" ;;
'#!'*sh*) sh -n "$file" ;;
*) bash -n "$file" ;;
esac
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add documentation to the syntax_check function.

The function lacks a docstring explaining its purpose and behavior. Given that it conditionally selects a linter based on shebang detection, adding comments would improve clarity for future maintainers.

Apply this diff to document the function:

 syntax_check() {
+  # Validate shell file syntax using the appropriate linter based on shebang.
+  # Falls back to bash -n if no shebang is detected.
   local file="$1"
   local first_line=""

   IFS= read -r first_line <"$file" || first_line=""

   case "$first_line" in
   '#!'*bash*) bash -n "$file" ;;
   '#!'*sh*) sh -n "$file" ;;
   *) bash -n "$file" ;;
   esac
 }
🤖 Prompt for AI Agents
In spec/shell_files_spec.sh around lines 6 to 17, the syntax_check function
lacks documentation; add a concise docstring comment above the function that
states its purpose (validate shell script syntax), explains parameters (file
path), describes behavior (reads first line to detect shebang and chooses bash
-n for bash or default, sh -n for sh, falls back to bash -n), and notes return
behavior (exit status mirrors linter); keep the comment short, use single-line
or block comment style consistent with the file, and ensure it precedes the
function definition.

@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.

Actionable comments posted: 0

♻️ Duplicate comments (1)
spec/pushover_spec.sh (1)

29-64: Move inline rm -rf "$TEMP_HOME" out of When run and into cleanup().

The prefers environment variables over HOME/dotfiles/.env test still deletes TEMP_HOME inline (Line 154). If the SUT/execution fails before that segment runs, the temp dir can leak and make the spec flaky. Prefer creating TEMP_HOME in setup() (or at Describe scope) and always removing it in cleanup().

- TEMP_HOME=$(mktemp -d)
- mkdir -p "$TEMP_HOME/dotfiles"
+ TEMP_HOME=$(mktemp -d)
+ mkdir -p "$TEMP_HOME/dotfiles"
  cat >"$TEMP_HOME/dotfiles/.env" <<'ENV'
  PUSHOVER_API_TOKEN=bad_token
  PUSHOVER_USER_KEY=bad_user
  ENV
- When run bash -c '...'; rm -rf "'"$TEMP_HOME"'"; cat "$MOCK_LOG"'
+ When run bash -c '...; cat "$MOCK_LOG"'

…and ensure cleanup() does rm -rf "$TEMP_HOME" for that scope (like the earlier .env Describe already does).

Also applies to: 66-92, 94-159, 161-201

🧹 Nitpick comments (1)
spec/notify_spec.sh (1)

21-45: Consider quoting $SCRIPT inside the bash -c one-liners (and add brief comments for the complex ones).

Most When run bash -c '... bash '"$SCRIPT"' ...' invocations expand $SCRIPT unquoted, which can break if $PWD contains spaces; also these are complex pipelines/chained commands and would benefit from a short explanatory comment per shell-script guidelines/learnings.

Example pattern:

- When run bash -c 'echo "{\"message\": \"Test message\"}" | bash '"$SCRIPT"'; cat "$MOCK_LOG"'
+ # Run SUT with stdin JSON; then print mock log for assertions.
+ When run bash -c 'echo "{\"message\": \"Test message\"}" | bash "$1"; cat "$MOCK_LOG"' -- "$SCRIPT"

(Apply similarly across the other When run cases.)
As per coding guidelines / retrieved learnings.

Also applies to: 48-56, 72-78, 80-105, 107-148, 172-217

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 1010155 and 9d8b256.

📒 Files selected for processing (3)
  • spec/notify_spec.sh (4 hunks)
  • spec/pushover_spec.sh (2 hunks)
  • spec/shell_files_spec.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • spec/shell_files_spec.sh
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{sh,bash}

📄 CodeRabbit inference engine (CLAUDE.md)

Use shfmt with 2-space indentation for shell scripts

**/*.{sh,bash}: Use 2 spaces for indentation in shell scripts
Add proper shebang lines to shell scripts
Follow shellcheck recommendations in shell scripts
Document complex commands in shell scripts
Use consistent variable naming in shell scripts

Files:

  • spec/notify_spec.sh
  • spec/pushover_spec.sh
🧠 Learnings (3)
📚 Learning: 2025-11-25T09:34:32.423Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/formatting.mdc:0-0
Timestamp: 2025-11-25T09:34:32.423Z
Learning: Applies to **/*.{sh,bash} : Document complex commands in shell scripts

Applied to files:

  • spec/notify_spec.sh
📚 Learning: 2025-11-25T09:34:32.423Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/formatting.mdc:0-0
Timestamp: 2025-11-25T09:34:32.423Z
Learning: Applies to **/*.{sh,bash} : Use consistent variable naming in shell scripts

Applied to files:

  • spec/notify_spec.sh
📚 Learning: 2025-11-25T09:34:32.423Z
Learnt from: CR
Repo: shunkakinoki/dotfiles PR: 0
File: .cursor/rules/formatting.mdc:0-0
Timestamp: 2025-11-25T09:34:32.423Z
Learning: Applies to **/*.{sh,bash} : Follow shellcheck recommendations in shell scripts

Applied to files:

  • spec/notify_spec.sh
🧬 Code graph analysis (2)
spec/notify_spec.sh (1)
spec/support/custom_matcher.sh (2)
  • mock_bin_setup (5-25)
  • mock_bin_cleanup (27-35)
spec/pushover_spec.sh (1)
spec/support/custom_matcher.sh (2)
  • mock_bin_setup (5-25)
  • mock_bin_cleanup (27-35)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (14)
  • GitHub Check: docker-build-push (linux/amd64, amd64, ubuntu-latest)
  • GitHub Check: docker-build-push (linux/arm64, arm64, ubuntu-24.04-arm)
  • GitHub Check: nix-darwin
  • GitHub Check: nix-nixos
  • GitHub Check: nix-flake
  • GitHub Check: nix-linux
  • GitHub Check: e2e-run (Ubuntu, ubuntu-latest)
  • GitHub Check: e2e-run (MacOS, macos-latest)
  • GitHub Check: e2e-run (NixOS, ubuntu-latest)
  • GitHub Check: lua-neovim
  • GitHub Check: lua-hammerspoon
  • GitHub Check: lua-neovim-test
  • GitHub Check: shellspec
  • GitHub Check: shellcheck

@shunkakinoki
shunkakinoki merged commit 75bd6a9 into main Dec 13, 2025
29 checks passed
@shunkakinoki
shunkakinoki deleted the add-shell-tests branch December 13, 2025 06:47
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.

2 participants