MCPcopy Create free account
hub / github.com/garrytan/gstack / generateRedactInvocationBlock

Function generateRedactInvocationBlock

scripts/resolvers/redact-doc.ts:120–177  ·  view source on GitHub ↗
(ctx: TemplateContext, args?: string[])

Source from the content-addressed store, hash-verified

118};
119
120export function generateRedactInvocationBlock(ctx: TemplateContext, args?: string[]): string {
121 const sinkLabel = args?.[0] ?? 'pre-issue';
122 const brief = args?.[1] === 'brief';
123 const sink = SINKS[sinkLabel] ?? SINKS['pre-issue'];
124 const bin = `${ctx.paths.binDir}/gstack-redact`;
125
126 // Brief variant: a compact pointer for repeat sinks, so the full ~40-line
127 // procedure ships once per skill, not once per enforcement point.
128 if (brief) {
129 return `#### Redaction scan — ${sinkLabel} (${sink.noun})
130
131Run the SAME scan-at-sink procedure shown above (resolve \`$REDACT_VIS\` once and
132reuse it; write the exact bytes to \`$REDACT_FILE\`; \`${bin} --from-file "$REDACT_FILE"
133--repo-visibility "$REDACT_VIS" --json\`), now on ${sink.noun}. Apply the same
134exit-3/2/0 handling. On exit 3, do NOT ${sink.blockVerb}; HIGH has no skip. Pass the
135same \`$REDACT_FILE\` downstream so the bytes scanned are the bytes sent.`;
136 }
137
138 return `#### Redaction scan — ${sinkLabel} (${sink.noun})
139
140Scan-at-sink on the EXACT bytes that will be sent: write to a temp file, scan that
141file, pass the SAME file downstream. Never scan a string then re-render it.
142
143\`\`\`bash
144command -v bun >/dev/null 2>&1 || echo "redaction scan skipped — bun not on PATH"
145# Resolve visibility once; cache + reuse. Order: local config (~/.gstack, never
146# committed) → gh → glab → unknown(=public-strict).
147REDACT_VIS=$(~/.claude/skills/gstack/bin/gstack-config get redact_repo_visibility 2>/dev/null)
148[ -z "$REDACT_VIS" ] && REDACT_VIS=$(gh repo view --json visibility -q .visibility 2>/dev/null | tr 'A-Z' 'a-z')
149[ -z "$REDACT_VIS" ] && REDACT_VIS=$(glab repo view -F json 2>/dev/null | grep -o '"visibility":"[^"]*"' | head -1 | sed 's/.*:"//;s/"//' | tr 'A-Z' 'a-z')
150REDACT_VIS="\${REDACT_VIS:-unknown}"
151REDACT_FILE=$(mktemp)
152cat > "$REDACT_FILE" <<'REDACT_BODY_EOF'
153<the exact ${sink.noun} goes here>
154REDACT_BODY_EOF
155REDACT_JSON=$(${bin} --from-file "$REDACT_FILE" --repo-visibility "$REDACT_VIS" --self-email "$(git config user.email 2>/dev/null)" --json)
156REDACT_CODE=$?
157\`\`\`
158
159Branch on \`$REDACT_CODE\`:
160
1611. **Exit 3 (HIGH)** — print findings; do NOT ${sink.blockVerb}; tell the user to
162 rotate + redact at source, then re-run. No skip flag for HIGH. Do not persist
163 ${sink.noun} anywhere.
1642. **Exit 2 (MEDIUM)** — AskUserQuestion per finding (cluster identical ids; PUBLIC
165 repos get sterner wording, no batch-acknowledge, no silent-proceed). PII subset
166 (\`pii.email\`/\`pii.phone.e164\`/\`pii.ssn\`/\`pii.cc\`) gets **Auto-redact** (re-run
167 with \`--auto-redact <ids>\` → use the printed sanitized body) / **Edit** / **Cancel**;
168 non-PII MEDIUM gets **Proceed (acknowledged)** / **Edit** / **Cancel** (no auto-redact).
1693. **Exit 0 (clean)** — proceed; surface \`WARN\` (tool-fence degrades) + \`LOW\` as a
170 one-line FYI (never blocks).
171
172\`\`\`bash
173rm -f "$REDACT_FILE"
174\`\`\`
175
176Guardrail, not airtight enforcement — direct \`gh\`/\`git\` bypass it; it catches accidents.`;
177}

Callers 1

Calls

no outgoing calls

Tested by

no test coverage detected