Open source · a local CLI with no server, no account and no telemetry.

View source
GhostGrant
ai-automation-tools · CLI · MVP prototype

You retired the agent. Did its credentials actually die?

GhostGrant checks that a retired AI agent's GitHub, AWS and Slack credentials actually stopped working, then checks again at 24 hours, 7 days, 30 days and 90 days. If one comes back to life, it raises an alert.

What it does

Going back to check the revoke worked

When a team shuts down an AI agent, somebody clicks revoke on its tokens and keys and moves on. Nobody goes back to see whether the GitHub token still answers, whether the AWS key got cached into some other job, or whether the Slack bot quietly came back after a reinstall. GhostGrant does the going back.

Write a manifest

A YAML file naming the credentials the agent held: type and identifier, never the secret itself.

YAML manifest

Ask the provider

Each provider's own introspection endpoint says whether the credential is dead, and the answer is recorded.

24h · 7d · 30d · 90d

Get an alert on a flip

A credential that goes from dead to alive between checks raises an alert, then you get a dated report.

dead → alive

Only GitHub is wired up so far. check --live asks GitHub; Slack and AWS answer unknown until their adapters land. See the roadmap.

Features

What the CLI does today

decommission

ghostgrant decommission <manifest> records a decommission entry with a timestamp and the manifest's checksum.

records

check --mock

Runs every check that's due against canned responses and prints alive or dead.

canned answers

check --live

GitHub: asks GET /user with each token you pipe in. 200 is alive, 401 is dead, a timeout, 5xx or rate limit is unknown.

GitHub only

Re-check windows

Each check runs the window that's due and skips records with nothing due. Dead-to-alive prints an ALERT and goes to alerts.log.

24h · 7d · 30d · 90d

report

ghostgrant report <agent> prints a dated plain-text report of every check for one agent, or the same data with --json.

--json

Static demo

A bundled report for a fictional agent (GitHub credentials, every window, one flip), rendered with the CLI's own Report type.

site/

Coming later: a Slack adapter (slice 2), then AWS IAM, Okta and Google Workspace (slices 5 to 7).

Get started

Build it and try it in mock mode

Node 22.18 or newer. Records live under $GHOSTGRANT_HOME (default ~/.ghostgrant); point it somewhere else to try things without touching your real records.

bash
# 1. Install dependencies (Node 22.18 or newer)
$ npm install

# 2. Build the CLI into dist/ and the demo page into _site/site/
$ npm run build

# 3. Record the example manifest and check it in mock mode
$ node dist/cli.js decommission examples/manifest.yaml
$ node dist/cli.js check --mock
$ node dist/cli.js report billing-bot --mock

# 4. Tests and lint
$ npm test && npm run lint

Live checks. check --live needs the tokens themselves, which the manifest never holds. Pipe them in on stdin, one per line. Each token goes to the credential whose prefix it starts with, is sent to that provider once, and is dropped when the run ends.

bash
$ printenv OLD_AGENT_GH_TOKEN | node dist/cli.js check --live
Reports

What the checks add up to

The last line of a report is a verdict. unknown never counts as dead, so it keeps a report from being clean. A report says what was checked and what each provider answered; it isn't signed and isn't compliance evidence.

VerdictMeaning
cleanEvery credential answered dead at every window checked, through 90d
dead-so-farEvery answer so far is dead; the line says when the next check is due
unknownA credential has no alive or dead answer for a window that was checked
aliveA credential's latest answer is alive
flippedA credential went from dead back to alive
not-checkedNo checks of that kind yet

What it won't do, on purpose: revoke or rotate anything (it only asks read-only introspection endpoints), sign or attest its reports, run as a hosted service, or support providers beyond GitHub, Slack, AWS IAM, Okta and Google Workspace.

Resources

Everything is in the repo