mcpField
S
ship-gate

ship-gate

github.com/unlearndevTesting & quality10559 installsUpdated 3w ago
Repository

About ship-gate

ship-gate is a pre-commit safety skill that scans staged changes for credentials, debug leftovers, commented-out code, and unintended large or binary files. It limits its scope to staged content and ends with a BLOCK or PASS verdict.

Key features

  1. 01Scan staged changes only
  2. 02Check for secrets and API credentials
  3. 03Find debug code and commented-out blocks
  4. 04Identify large or binary added files
  5. 05Report locations and a final verdict

Use cases

  1. 01Review staged content before committing
  2. 02Catch accidentally staged credentials or environment files
  3. 03Find leftover debug traces and large files

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/unlearndev/skills --skill ship-gate

After installing, type/ship-gatein Claude Code to confirm it loaded.

Details

From the project README

Check the staged diff before committing

Scan everything that is currently staged for commit and flag anything that should not be committed. This is a focused safety gate, not a code review — do not comment on style, naming, architecture, or correctness. Find only the four classes of problem below, report each with its file and line and why it matters, and finish with a single verdict.

1. Get the staged diff

Only inspect what is actually staged (--cached). Unstaged changes are out of scope.

git diff --cached --stat          # overview of staged files
git diff --cached                 # full staged diff (read this)
git diff --cached --numstat       # added/removed line counts; "-" marks binary files
git diff --cached --name-only --diff-filter=A   # newly ADDED files (for size/binary checks)

Read the whole staged diff. Only consider added lines (lines starting with +) for debug code, secrets, and commented-out blocks — pre-existing lines shown as context are not introduced by this commit and should not be flagged. For added/binary file checks, inspect the working-tree files reported as added.

If nothing is staged, say so plainly and stop — there is nothing to check.

2. What to flag

Go through the staged diff against each lens. Most commits trigger only a few — that's expected. Don't manufacture findings to fill a category; each finding must point at a real added line or file.

Secrets and API keys

Added lines that look like real credentials, not references to them. Look for:

  • Assignments where the value is a literal secret: API keys, tokens, passwords, private keys, connection strings with embedded credentials.
  • Recognisable key shapes: AKIA… (AWS access key), sk-… / sk-ant-… (OpenAI/Anthropic), ghp_… / gho_… (GitHub tokens), xox[baprs]-… (Slack), Google AIza…, Stripe sk_live_… / rk_live_…, JWTs (eyJ…), -----BEGIN … PRIVATE KEY----- blocks.
  • Long high-entropy strings assigned to names like *_KEY, *_SECRET, *_TOKEN, *_PASSWORD, PASSWD, *_DSN, AUTH, CREDENTIAL.

Distinguish real secrets from safe non-secrets so you don't cry wolf:

  • Safe / don't flag: placeholders (your-api-key-here, xxxxx, changeme, example, <token>), .env.example entries with empty or dummy values, values read from config (env('STRIPE_SECRET'), process.env.X, config(...)), obvious test fixtures.
  • Flag: a concrete-looking secret value committed in source, and any secret that appears in a real .env file staged for commit (a .env with live values should almost never be committed — call that out specifically).

When unsure whether a string is a live secret, flag it as suspected and explain why — better to surface it for a human to confirm than to stay silent.

Leftover debug code

Added lines that are clearly debugging scaffolding left behind, judged against the file's language:

  • PHP: dd(, dump(, ddd(, var_dump(, print_r( (when not returned/used), ray(, error_log(, \Log::debug( added ad hoc, Debugbar::.
  • JS / TS / Vue: console.log( / console.debug( / console.warn( added for debugging, debugger;, alert(.
  • General: TODO: remove, FIXME, XXX, temporary sleep(, hardcoded test toggles like if (true) / return; // skip.

Use judgement: a console.error in a legitimate error handler or a logging call that's part of the app's real logging is not debug litter. Flag what looks like a forgotten trace.

Large commented-out blocks

Added runs of commented-out code (not explanatory prose). Flag a contiguous block of roughly 5+ lines of commented-out code — dead code that should be deleted rather than committed. A short comment, a doc comment, or a one-line note is fine; don't flag those. Identify it by the file's comment syntax (//, #, /* … */, <!-- … -->) wrapping things that read as code (statements, function bodies, markup).

Accidentally added large or binary files

From the newly added files (--diff-filter=A):

  • Binary files — git diff --cached --numstat shows - for both add/remove columns on binary files. Flag added binaries that look unintended: compiled output, archives, images dumped into source, .zip, .tar, .gz, .pdf, .sqlite, .db, fonts, media. Use judgement — an intentional asset in an assets directory is fine.
  • Large files — check the on-disk size of added files (e.g. wc -c, or git cat-file -s :<path> for the staged blob). Flag anything roughly >1 MB, and flag hard regardless of size if it's the kind of thing that shouldn't be in git at all (vendor/, node_modules/, *.log, build artefacts, .env with real values, OS junk like .DS_Store).

3. Report findings

Output Markdown. Lead with the findings grouped by the four categories above; include only categories that actually have findings. For each finding give:

  • File and line — path/to/file.php:42. Use the line number of the added line in the new file. For a commented-out block, give the start–end range. For a whole-file problem (binary/large/.env), the path alone is enough.
  • What — the offending snippet (truncate/redact secrets — show enough to locate it, e.g. STRIPE_SECRET=sk_live_51H… — never echo a full live key).
  • Why — one short clause on why it shouldn't be committed.

Keep each finding to a line or two. No preamble, no code-quality asides.

4. Verdict

End with a single bold verdict word — **BLOCK** or **PASS** — and nothing after it. No trailing summary or explanation; the findings above already say why.

  • BLOCK — if there is any secret/API key, or any other finding serious enough that committing would be a mistake (real .env, committed credentials, a stray binary/large file, obvious debug litter). When in doubt about a suspected secret, lean to BLOCK.
  • PASS — only if nothing was found, or the only findings are clearly harmless.

Format:

**BLOCK**

or

**PASS**

Never soften a real secret finding — a leaked key in history is expensive to undo.

Comments

Markdown supported