mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-12 16:08:59 +02:00
fix(redact): prepush guard fails closed on git failure; /ship owns hook install (#1946)
Two gaps closed:
1. Fail closed. The git() helper returned "" on ANY non-zero exit or
maxBuffer overflow (status null), addedLinesFor produced an empty
string, and the push sailed through unscanned — fail-open on exactly
the oversized-diff case where a large secret-bearing blob is most
likely. The diff call now uses a strict variant that throws; main
blocks with a clear message naming the GSTACK_REDACT_PREPUSH=skip
escape valve. Probe calls (symbolic-ref, rev-parse, merge-base) keep
the permissive helper — their failures are normal control flow.
2. Install path. The hook was installed by nothing ("opt-in, installed by
nothing" was the issue's words). ./setup runs in the gstack checkout —
the wrong repo for a per-project hook — so it gets a one-line hint
only. /ship owns per-repo install: config redact_prepush_hook=true +
hook missing → silent install (consent already given); config unset +
no ~/.gstack/.redact-prepush-prompted marker → one-time machine-wide
AskUserQuestion offer, answer persisted. ship/SKILL.md regenerated in
this same commit (check-freshness bisect discipline).
Tests: unscannable diff (bogus SHAs) → exit 1 + valve named; empty-but-
successful diff → exit 0; static asserts pin setup as hint-only and the
ship template as the installer surface.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
c8f078b482
commit
6bc00abb0f
@@ -1218,6 +1218,49 @@ Claiming work is complete without verification is dishonesty, not efficiency.
|
||||
|
||||
## Step 17: Push
|
||||
|
||||
**Credential pre-push guard (#1946) — run before the push:**
|
||||
|
||||
```bash
|
||||
_REDACT_PREPUSH=$(~/.claude/skills/gstack/bin/gstack-config get redact_prepush_hook 2>/dev/null || echo "false")
|
||||
_HOOK_PATH=$(git rev-parse --git-path hooks/pre-push 2>/dev/null || echo "")
|
||||
_HOOK_INSTALLED="no"
|
||||
[ -n "$_HOOK_PATH" ] && [ -f "$_HOOK_PATH" ] && grep -q "gstack-redact" "$_HOOK_PATH" 2>/dev/null && _HOOK_INSTALLED="yes"
|
||||
_PREPUSH_PROMPTED=$([ -f ~/.gstack/.redact-prepush-prompted ] && echo "yes" || echo "no")
|
||||
echo "REDACT_PREPUSH: $_REDACT_PREPUSH"
|
||||
echo "HOOK_INSTALLED: $_HOOK_INSTALLED"
|
||||
echo "PREPUSH_PROMPTED: $_PREPUSH_PROMPTED"
|
||||
```
|
||||
|
||||
Branch on the echoed values:
|
||||
|
||||
1. **`REDACT_PREPUSH: true` and `HOOK_INSTALLED: no`** — consent already
|
||||
given; install silently (no question) and continue:
|
||||
```bash
|
||||
~/.claude/skills/gstack/bin/gstack-redact install-prepush-hook
|
||||
```
|
||||
2. **`REDACT_PREPUSH` not true AND `PREPUSH_PROMPTED: no`** — one-time
|
||||
offer (fires once EVER, machine-wide). AskUserQuestion:
|
||||
|
||||
> gstack can install a per-repo git pre-push hook that blocks pushes
|
||||
> containing credentials (API keys, tokens, private keys). It's a
|
||||
> guardrail, not enforcement — `GSTACK_REDACT_PREPUSH=skip` bypasses it.
|
||||
> Install it for repos you ship from?
|
||||
|
||||
Options:
|
||||
- A) Yes — install the credential guard (recommended)
|
||||
- B) No — never ask again
|
||||
|
||||
If A: run `~/.claude/skills/gstack/bin/gstack-config set redact_prepush_hook true`
|
||||
then `~/.claude/skills/gstack/bin/gstack-redact install-prepush-hook`.
|
||||
If B: run `~/.claude/skills/gstack/bin/gstack-config set redact_prepush_hook false`.
|
||||
ALWAYS (after either answer, but NOT if the question itself failed to
|
||||
render — a failed AskUserQuestion must re-offer next time):
|
||||
```bash
|
||||
touch ~/.gstack/.redact-prepush-prompted
|
||||
```
|
||||
3. **Anything else** (declined earlier, or already installed) — continue
|
||||
without comment.
|
||||
|
||||
**Idempotency check:** Check if the branch is already pushed and up to date.
|
||||
|
||||
```bash
|
||||
|
||||
@@ -381,6 +381,49 @@ Claiming work is complete without verification is dishonesty, not efficiency.
|
||||
|
||||
## Step 17: Push
|
||||
|
||||
**Credential pre-push guard (#1946) — run before the push:**
|
||||
|
||||
```bash
|
||||
_REDACT_PREPUSH=$(~/.claude/skills/gstack/bin/gstack-config get redact_prepush_hook 2>/dev/null || echo "false")
|
||||
_HOOK_PATH=$(git rev-parse --git-path hooks/pre-push 2>/dev/null || echo "")
|
||||
_HOOK_INSTALLED="no"
|
||||
[ -n "$_HOOK_PATH" ] && [ -f "$_HOOK_PATH" ] && grep -q "gstack-redact" "$_HOOK_PATH" 2>/dev/null && _HOOK_INSTALLED="yes"
|
||||
_PREPUSH_PROMPTED=$([ -f ~/.gstack/.redact-prepush-prompted ] && echo "yes" || echo "no")
|
||||
echo "REDACT_PREPUSH: $_REDACT_PREPUSH"
|
||||
echo "HOOK_INSTALLED: $_HOOK_INSTALLED"
|
||||
echo "PREPUSH_PROMPTED: $_PREPUSH_PROMPTED"
|
||||
```
|
||||
|
||||
Branch on the echoed values:
|
||||
|
||||
1. **`REDACT_PREPUSH: true` and `HOOK_INSTALLED: no`** — consent already
|
||||
given; install silently (no question) and continue:
|
||||
```bash
|
||||
~/.claude/skills/gstack/bin/gstack-redact install-prepush-hook
|
||||
```
|
||||
2. **`REDACT_PREPUSH` not true AND `PREPUSH_PROMPTED: no`** — one-time
|
||||
offer (fires once EVER, machine-wide). AskUserQuestion:
|
||||
|
||||
> gstack can install a per-repo git pre-push hook that blocks pushes
|
||||
> containing credentials (API keys, tokens, private keys). It's a
|
||||
> guardrail, not enforcement — `GSTACK_REDACT_PREPUSH=skip` bypasses it.
|
||||
> Install it for repos you ship from?
|
||||
|
||||
Options:
|
||||
- A) Yes — install the credential guard (recommended)
|
||||
- B) No — never ask again
|
||||
|
||||
If A: run `~/.claude/skills/gstack/bin/gstack-config set redact_prepush_hook true`
|
||||
then `~/.claude/skills/gstack/bin/gstack-redact install-prepush-hook`.
|
||||
If B: run `~/.claude/skills/gstack/bin/gstack-config set redact_prepush_hook false`.
|
||||
ALWAYS (after either answer, but NOT if the question itself failed to
|
||||
render — a failed AskUserQuestion must re-offer next time):
|
||||
```bash
|
||||
touch ~/.gstack/.redact-prepush-prompted
|
||||
```
|
||||
3. **Anything else** (declined earlier, or already installed) — continue
|
||||
without comment.
|
||||
|
||||
**Idempotency check:** Check if the branch is already pushed and up to date.
|
||||
|
||||
```bash
|
||||
|
||||
Reference in New Issue
Block a user