Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4edf42ce9f | ||
|
|
2f53346b8c | ||
|
|
dcc0677270 | ||
|
|
9fd5a054b3 |
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "skills",
|
||||
"description": "Mathias's engineering skills library, plus the hooks and MCP servers that make it enforceable: TDD, clean code, debugging, specs, discovery, CI, and secret hygiene.",
|
||||
"version": "0.19.0",
|
||||
"version": "0.19.2",
|
||||
"author": {
|
||||
"name": "Mathias",
|
||||
"url": "https://git.d-ma.be/mathias"
|
||||
|
||||
+7
-2
@@ -145,8 +145,13 @@ tasks:
|
||||
# not run (no jq, or no env-file — CI has neither); that is reported
|
||||
# and not fatal, but it is never treated as a pass.
|
||||
if [ -x "{{.TASKFILE_DIR}}/bin/check-mcp-env" ]; then
|
||||
"{{.TASKFILE_DIR}}/bin/check-mcp-env" "{{.TASKFILE_DIR}}/.mcp.json" "$HOME/.op-env"
|
||||
case $? in
|
||||
# `|| rc=$?` is load-bearing, not style. Task runs this block under
|
||||
# `sh -e`, so a bare invocation exiting non-zero kills the shell
|
||||
# before `case` is reached -- the tolerance below never ran, and the
|
||||
# gate died with `exit status 2` on the commit that added it.
|
||||
rc=0
|
||||
"{{.TASKFILE_DIR}}/bin/check-mcp-env" "{{.TASKFILE_DIR}}/.mcp.json" "$HOME/.op-env" || rc=$?
|
||||
case $rc in
|
||||
0) ;;
|
||||
2) echo "NOTE: MCP env wiring unverified on this host" >&2 ;;
|
||||
*) fail=1 ;;
|
||||
|
||||
@@ -41,7 +41,17 @@ if [ ! -f "$CONFIG" ]; then
|
||||
fi
|
||||
|
||||
if [ ! -f "$ENVFILE" ]; then
|
||||
# EXPECTED IN CI, and permanently so. The env-file holds live credentials, so
|
||||
# it is not on the runner and must not be -- which means this check can only
|
||||
# ever verify on a host that has one. infra#368 added jq to the runner image
|
||||
# believing that would let CI verify; it removed the jq branch below and
|
||||
# changed nothing else, because this branch is the binding one.
|
||||
#
|
||||
# Said plainly so nobody concludes CI covers this. It does not, it cannot,
|
||||
# and putting ~/.op-env on the runner to make it would be trading a real
|
||||
# secret for a green tick.
|
||||
echo "ERROR: no such env-file: $ENVFILE -- cannot verify MCP variables" >&2
|
||||
echo " (expected in CI: this check only verifies on a host with ~/.op-env)" >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
#!/bin/sh
|
||||
# `task check` must survive a check that reports "could not verify".
|
||||
#
|
||||
# The regression these exist for: bin/check-mcp-env exits 2 to mean "I could
|
||||
# not run — no jq, or no env-file", which the gate deliberately treats as a
|
||||
# reported NOTE rather than a failure. The Taskfile said exactly that:
|
||||
#
|
||||
# "$DIR/check-mcp-env" "$DIR/.mcp.json" "$HOME/.op-env"
|
||||
# case $? in 0) ;; 2) echo "NOTE: ..." ;; *) fail=1 ;; esac
|
||||
#
|
||||
# and it did not work. Task runs each cmds block under `sh -e`, so a bare
|
||||
# command exiting non-zero aborts the shell *before* `case $?` is ever
|
||||
# reached. The whole gate died with `exit status 2`. Locally the check found
|
||||
# jq and exited 0, so it went green; CI has neither jq nor ~/.op-env, so main
|
||||
# went red on the very commit that added it (skills run #57, 2026-09-07).
|
||||
#
|
||||
# A tolerated exit code that is only tolerated on the host where it never
|
||||
# fires is not tolerated at all. This pins the tolerance itself.
|
||||
#
|
||||
# No mocking: pointing HOME at an empty directory removes ~/.op-env, which is
|
||||
# exactly the condition CI runs under, so check-mcp-env genuinely exits 2.
|
||||
|
||||
set -u
|
||||
|
||||
ROOT=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
|
||||
|
||||
pass=0
|
||||
fail=0
|
||||
|
||||
ok() { pass=$((pass + 1)); printf ' ok %s\n' "$1"; }
|
||||
no() { fail=$((fail + 1)); printf ' FAIL %s\n' "$1"; }
|
||||
|
||||
if ! command -v task >/dev/null 2>&1; then
|
||||
printf ' SKIP: task not installed -- cannot exercise the gate\n'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
TMP=$(mktemp -d)
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
|
||||
# Sanity: the precondition must actually hold, or the test proves nothing.
|
||||
# An empty HOME means no ~/.op-env, so check-mcp-env cannot verify anything.
|
||||
"$ROOT/bin/check-mcp-env" "$ROOT/.mcp.json" "$TMP/.op-env" >/dev/null 2>&1
|
||||
rc=$?
|
||||
if [ "$rc" -eq 2 ]; then
|
||||
ok 'precondition: check-mcp-env exits 2 when the env-file is absent'
|
||||
else
|
||||
no "precondition: expected check-mcp-env to exit 2, got $rc"
|
||||
fi
|
||||
|
||||
# The assertion. `task check` must still pass, and must say why it could not
|
||||
# verify -- silence would mean the check was skipped rather than tolerated.
|
||||
out=$(HOME="$TMP" task --dir "$ROOT" check 2>&1)
|
||||
rc=$?
|
||||
|
||||
if [ "$rc" -eq 0 ]; then
|
||||
ok 'task check passes when MCP env wiring cannot be verified'
|
||||
else
|
||||
no "task check exited $rc when check-mcp-env reported unverifiable"
|
||||
printf '%s\n' "$out" | sed 's/^/ | /' | tail -8
|
||||
fi
|
||||
|
||||
if printf '%s' "$out" | grep -q 'unverified'; then
|
||||
ok 'the unverifiable check is reported, not silently skipped'
|
||||
else
|
||||
no 'no NOTE reported -- an unverifiable check must never look like a pass'
|
||||
fi
|
||||
|
||||
printf ' %d passed, %d failed\n' "$pass" "$fail"
|
||||
[ "$fail" -eq 0 ]
|
||||
@@ -24,7 +24,7 @@ decision_for() {
|
||||
_tool=${2:-Bash}
|
||||
jq -n --arg t "$_tool" --arg c "$_cmd" \
|
||||
'{tool_name: $t, tool_input: {command: $c}}' \
|
||||
| sh "$GUARD" \
|
||||
| "$GUARD" \
|
||||
| jq -r '.hookSpecificOutput.permissionDecision // "MISSING"'
|
||||
}
|
||||
|
||||
@@ -42,6 +42,20 @@ expect() {
|
||||
fi
|
||||
}
|
||||
|
||||
# Invoked as a PROGRAM above, never as `sh "$GUARD"`. Claude Code executes the
|
||||
# hook directly, so its `#!/usr/bin/env bash` shebang decides the interpreter;
|
||||
# piping it into `sh` overrides that and tests something production never runs.
|
||||
#
|
||||
# It is not academic. On Debian /bin/sh is dash, which has no `set -o
|
||||
# pipefail`, so the guard died on line 23 before reading a byte of input and
|
||||
# every deny case returned empty -- 20 of 20 assertions failed in CI while
|
||||
# passing on a host where /bin/sh happens to be bash. A security gate that
|
||||
# tests green and cannot start is the worst of both.
|
||||
if [ ! -x "$GUARD" ]; then
|
||||
printf 'FAIL: %s is not executable -- it must run via its own shebang\n' "$GUARD"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$GUARD" ]; then
|
||||
printf 'FAIL: %s does not exist\n' "$GUARD"
|
||||
exit 1
|
||||
|
||||
Reference in New Issue
Block a user