Skip to content

fix(plugin): full-plugin audit fixes + cross-platform hardening + README refresh — 0.24.4#17

Merged
Cain-Ish merged 3 commits into
mainfrom
fix/full-plugin-audit
Jun 2, 2026
Merged

fix(plugin): full-plugin audit fixes + cross-platform hardening + README refresh — 0.24.4#17
Cain-Ish merged 3 commits into
mainfrom
fix/full-plugin-audit

Conversation

@Cain-Ish

@Cain-Ish Cain-Ish commented Jun 2, 2026

Copy link
Copy Markdown
Owner

What

Two workstreams from a full-plugin functional/contract audit (10 parallel auditors over every MCP tool, all 8 hook events, 21 skills, 7 agents, 47 scripts) + a cross-platform portability pass. The audit found 0 blocking issues — everything works; these are the surfaced warn/advisory fixes.

Audit fixes

  • Skill allowed-tools gaps (the v0.21.1 missing-mktemp class → permission prompts mid-run): dream +mktemp/mv/mkdir/rm · setup +grep/sed/awk/head/cat/wc · review +basename/dirname/tr/head · import-host +tr · status +knowledge_validate (+numeric-guard the persona-spend printf) · upgrade +node/cd/bash.
  • symlink-guard.sh now fails closed if realpath is absent (was fail-open exit 0).
  • wiki-recall-check.sh awk gate → -v + numeric coercion (the mawk shell-interp bug class, fixed at source).
  • minor: stop-extract timeout comment, maintainer unbound $KD, doubt example layer id.

Cross-platform (Linux / macOS BSD+bash-3.2 / Windows Git Bash)

  • mapfile (bash 4+) → portable read loop · unpaired stat -cstat -c || stat -f · PCRE grep -P → portable grep -F byte-prefix (the Unicode-tag-block scanner now works on BSD/macOS instead of silently no-op'ing) · timeouttimeout || gtimeout · portable realpath resolver.
  • New test-script-portability.sh guards the construct classes against regression.

README

Refreshed to a high-level, accessible framing and corrected the stale-wrong contradictions: search is BM25 + optional on-device vectors (not "token-overlap, no embeddings"); the plugin does auto-extract to wiki/graph at capture (not "no autonomous writes"); added the graph + AI-block + forgetting features; completed the skills + MCP-tool tables; v2.x → "the plugin"; test counts 24/5972/357.

Release gate — review found 1 HIGH (fixed), history found 0 regressions

The unit reviewer caught a real security gap I'd introduced: the new macOS realpath fallback resolved the parent's symlinks but appended the basename literally, so a benign-named file that is itself a symlink into ~/.ssh slipped through on stock macOS. Fixed — the fallback now follows the leaf symlink too (greadlink -f, then cd && pwd -P + readlink deref). test-symlink-guard.sh Test 19 locks it.

Verification

Full suite green (72 shell + 357 vitest, 0 fail); version lockstep 0.24.4; upgrade migration row added; new guards: test-skill-allowed-tools.sh, test-script-portability.sh, symlink-guard fail-closed + macOS-resolver + leaf-symlink cases. No state migration (prompt/script/doc/test only).

🤖 Generated with Claude Code

Cain-Ish and others added 3 commits June 2, 2026 21:52
… script hardening)

Full-plugin functional/contract audit (10 parallel auditors) found 0 blocking
issues; these are the warn/advisory fixes:

allowed-tools gaps (v0.21.1 missing-mktemp class -> permission prompts mid-run):
- dream:     + mktemp/mv/mkdir/rm (atomic status.json write + FORGET archive loop)
- setup:     + grep/sed/awk/head/cat/wc (persona-card pipeline)
- review:    + basename/dirname/tr/head
- import-host: + tr
- status:    + knowledge_validate MCP tool; numeric-guard SPEND (%.4f on non-numeric)
- upgrade:   + node/cd/bash (vector-deps health smoke-check)

script/agent hardening:
- symlink-guard.sh: deny-guard now fails CLOSED if realpath is absent (lexical
  fallback still denies a literal credential write) instead of fail-open exit 0
- wiki-recall-check.sh: awk gate uses -v + numeric coercion (no shell-interp into
  awk source -- the 0.21.4/0.22.3 mawk bug class), fix at source
- stop-extract.sh: SB_EXTRACT_TIMEOUT comment 40 -> 25 (matches code)
- knowledge-maintainer Phase 4b: drop unbound $KD (script defaults to $HOME/knowledge)
- doubt: example layer id stop-predicate -> stop-extract (real taxonomy id)

New guards: test-skill-allowed-tools.sh (per-skill verb requirements),
test-symlink-guard.sh Test 17 (realpath-absent fail-closed). Full suite green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ADME refresh + release 0.24.4

Cross-platform (the plugin is bash-heavy; this makes it runnable on macOS BSD
coreutils + /bin/bash 3.2 and under Git Bash on Windows, not just Linux/GNU):
- wiki-forget-candidates.sh: mapfile (bash 4+) -> portable read loop
- wiki-forget-score.sh + dream-autostage.sh: pair stat -c with stat -f (BSD/macOS)
- tool-return-scanner.sh: PCRE grep -P -> portable grep -F byte-prefix (the
  Unicode-tag-block scanner now WORKS on BSD/macOS instead of silently no-op'ing)
- symlink-guard.sh: portable realpath -m -> cd && pwd -P parent-resolver fallback
  (resolves symlink escapes on macOS where realpath lacks -m; still fail-closed)
- lib.sh: timeout -> 'command -v timeout || command -v gtimeout' (macOS coreutils)
- New test-script-portability.sh guards the construct classes (bash-4 builtins,
  unpaired stat -c/date -d, grep -P) against regression.

README: refreshed to high-level, accessible framing and corrected the stale-wrong
contradictions -- search is BM25 + optional on-device vectors (not 'token-overlap,
no embeddings'); the plugin DOES auto-extract to wiki/graph at capture (not 'no
autonomous writes'); added the graph + ai-block + forgetting features; completed
the skills (audit/track/using-second-brain) + MCP-tool (relate/neighbors) tables;
fixed 'v2.x' -> the plugin; test counts 24/59 -> 72/357; accurate cross-platform
section enforced by the new portability test.

Release 0.24.4 (plugin + marketplace lockstep) + upgrade migration row. Full
suite green (72 shell + 357 vitest).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… HIGH)

The release-gate review found that the new BSD/macOS realpath fallback resolved
the parent dir's symlinks but appended the basename literally -- so a benign-named
file that is ITSELF a symlink into a credential dir (e.g. innocent.txt -> ~/.ssh/
authorized_keys) slipped through on stock macOS (where the fallback is the active
path). GNU realpath -m follows the leaf; the fallback now does too: try greadlink
-f (macOS Homebrew coreutils), then cd && pwd -P on the parent + a leaf readlink
deref. Fail-closed preserved. test-symlink-guard.sh Test 19 locks it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 2, 2026 20:35
@Cain-Ish Cain-Ish merged commit 49b31e6 into main Jun 2, 2026
2 checks passed
@Cain-Ish Cain-Ish deleted the fix/full-plugin-audit branch June 2, 2026 20:35

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 rolls up advisory findings from a full functional/contract audit and a cross-platform hardening pass, plus a README refresh and version bump to 0.24.4. The changes primarily tighten safety/portability guards (especially around shell tooling differences on macOS/BSD and Git Bash) and ensure skills declare all required allowed-tools to avoid runtime permission prompts.

Changes:

  • Hardened shell scripts for macOS/BSD + Git Bash portability (e.g., timeoutgtimeout, stat -cstat -f fallbacks, remove mapfile, replace grep -P).
  • Expanded multiple skills’ allowed-tools declarations and added tests to prevent regressions.
  • Updated safety guard behavior (symlink guard fail-closed when realpath is absent) and refreshed README/product documentation; bumped plugin/marketplace version to 0.24.4.

Reviewed changes

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

Show a summary per file
File Description
tests/test-symlink-guard.sh Adds regression tests for symlink-guard fail-closed + macOS/BSD fallback scenarios.
tests/test-skill-allowed-tools.sh New guard test ensuring skills declare required allowed-tools.
tests/test-script-portability.sh New static portability linter for scripts/ (bash-3.2/BSD incompatibilities).
skills/upgrade/SKILL.md Adds allowed-tools for new dependencies and documents 0.24.4 migration row.
skills/status/SKILL.md Adds knowledge_validate tool grant and hardens persona spend parsing.
skills/setup/SKILL.md Adds missing allowed-tools for binaries used by the skill.
skills/review/SKILL.md Adds missing allowed-tools for binaries used by the skill.
skills/import-host/SKILL.md Adds missing allowed-tools (tr).
skills/dream/SKILL.md Adds missing allowed-tools (mktemp/mv/mkdir/rm).
skills/doubt/SKILL.md Fixes example layer id (stop-predicatestop-extract).
scripts/wiki-recall-check.sh Makes awk gating numeric-safe via -v and coercion.
scripts/wiki-forget-score.sh Adds BSD/macOS stat -f fallback for mtime extraction.
scripts/wiki-forget-candidates.sh Replaces mapfile with a bash-3.2-compatible read loop.
scripts/tool-return-scanner.sh Replaces grep -P with a portable fixed-string byte-prefix check.
scripts/symlink-guard.sh Changes resolver behavior to fail-closed when realpath is unavailable; adds macOS/BSD fallback.
scripts/stop-extract.sh Updates extractor timeout comment default (40 → 25).
scripts/lib.sh Adds gtimeout fallback for timeout-based extractor invocation.
scripts/dream-autostage.sh Adds BSD/macOS stat -f fallback for watermark mtime.
README.md Updates high-level product description, feature framing, and testing counts.
agents/knowledge-maintainer.md Removes unbound $KD from example invocation.
.claude-plugin/plugin.json Version bump to 0.24.4.
.claude-plugin/marketplace.json Version bump to 0.24.4.

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

Comment thread scripts/symlink-guard.sh
Comment on lines +63 to +74
_pd=$(dirname -- "$FILE_PATH"); _pb=$(basename -- "$FILE_PATH")
_rpd=$(cd "$_pd" 2>/dev/null && pwd -P)
if [ -n "$_rpd" ]; then
if [ -L "$_rpd/$_pb" ]; then
_tgt=$(readlink -- "$_rpd/$_pb" 2>/dev/null)
case "$_tgt" in /*) RESOLVED="$_tgt" ;; *) RESOLVED="$_rpd/$_tgt" ;; esac
else
RESOLVED="$_rpd/$_pb"
fi
else
RESOLVED="${FILE_PATH/#\~/$HOME}"
fi
Comment on lines +134 to +136
STUB="$TMP/stub"; mkdir -p "$STUB"
printf '#!/bin/sh\nexit 127\n' > "$STUB/realpath"; chmod +x "$STUB/realpath"
gen(){ jq -nc --arg t "$1" --arg p "$2" '{session_id:"t",hook_event_name:"PreToolUse",tool_name:$t,tool_input:{file_path:$p}}'; }
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