Live proof setup
Configure a disposable GitHub App and one-repository installation.
Live proof is optional. Do not target a production App, a production repository, or an installation spanning real repositories.
GrantTrace never creates an App, changes App permissions, broadens an
installation, or creates a repository. Complete setup manually, then use
granttrace doctor before any authenticated run.
1. Create a dedicated GitHub App
Use an unmistakable fixture-only name.
- Disable webhooks.
- Grant only the repository permissions required by the scenarios and controls you intend to prove.
- Grant no organization or account permissions.
- Limit installation availability to the fixture owner/account.
- Generate one private key and keep it outside the repository.
The App's configured permissions may be broader than a particular scenario.
prove requests a narrower installation token and verifies the raw response.
GitHub's mandatory metadata:read is modeled separately from the selected
contract.
2. Create and isolate a disposable repository
- Use a private repository whose name ends in
-granttrace-fixture. - Store no real source, customer data, or secrets in it.
- Install the App with Only select repositories and select exactly this repository.
- Create one disposable issue if using the built-in issue-comment scenarios.
The positive example creates a comment and deletes it in finally. The
mutating negative control creates nothing on the expected path; if a removed
permission unexpectedly succeeds, it attempts deletion with the positive
restricted token before reporting failure.
3. Configure nonsecret fixture values
Supply these values transiently through the process environment:
GRANTTRACE_APP_ID
GRANTTRACE_INSTALLATION_ID
GRANTTRACE_LIVE_OWNER
GRANTTRACE_LIVE_REPOSITORY
GRANTTRACE_LIVE_ISSUE_NUMBER
GRANTTRACE_LIVE_CONFIRM_DISPOSABLE=1The guard requires decimal identifiers, a repository name ending in
-granttrace-fixture, and explicit confirmation equal to 1. Rejected values
are not echoed.
Do not commit a populated .env, paste values into issue reports, or pass any
credential as a CLI argument.
4. Choose exactly one private-key provider
GrantTrace refuses missing or multiple providers.
Private-key file (recommended locally)
Set an absolute path:
export GRANTTRACE_APP_PRIVATE_KEY_FILE="/absolute/path/to/app.private-key.pem"The immediate parent directory must:
- be a real directory, not a symlink;
- be owned by the current user where ownership checks are available; and
- have exact mode
0700.
The key must:
- be a regular nonsymlink file;
- be owned by the current user where ownership checks are available;
- have exact mode
0600; - be between 1 and 32,768 bytes; and
- contain a valid RSA private key.
Set modes before running doctor:
chmod 700 "/absolute/path/to/private-directory"
chmod 600 "/absolute/path/to/private-directory/app.private-key.pem"macOS Keychain
Store the PEM as a generic password using labels you control, then configure both selectors:
export GRANTTRACE_APP_PRIVATE_KEY_KEYCHAIN_SERVICE="granttrace-fixture"
export GRANTTRACE_APP_PRIVATE_KEY_KEYCHAIN_ACCOUNT="github-app-private-key"GrantTrace invokes /usr/bin/security find-generic-password directly with an
argv array, suppresses diagnostic output, enforces safe label characters, and
bounds the lookup. Keychain support is available only on macOS.
One way to add the item interactively is:
security add-generic-password \
-s "granttrace-fixture" \
-a "github-app-private-key" \
-wEnter the PEM when prompted. Do not place it on the command line or in shell history.
Secret environment value
For a protected CI environment or an existing secret manager that injects multiline values:
GRANTTRACE_APP_PRIVATE_KEYThis is supported but is easier to leak through process configuration than a private file or Keychain. Never print the environment or enable shell tracing around setup.
5. Diagnose without using GitHub
npx granttrace doctordoctor checks:
- Node 22 or newer;
- private ignored local state and stale sessions;
- whether
granttrace.lock.jsonis valid schema v3 or needs migration; and - whether optional live configuration is complete and whether key providers conflict.
It does not mint a JWT or token, contact GitHub, or print provider values or
fixture identities. “Optional live proof is not configured” is informational;
local record/check workflows remain available. Incomplete or conflicting live
providers are warnings because they do not block offline work; prove repeats
strict validation and refuses to continue until every required live field is
safe.
Doctor labels local blockers FAIL, incomplete optional live setup WARN,
unconfigured optional features INFO, and satisfied checks PASS. Inspect
stale session artifacts and any possible fixture residue before removing them.
6. Prove one accepted scenario
First make sure current recordings have an accepted schema-v3 contract:
npx granttrace check
npx granttrace prove <safe-name> -- <command> [args...]Before it loads credentials or mints a token, proof requires exact tool, API, and catalog identity and rebinds every accepted route DNF to the current pinned catalog. Production proof has no broad-token discovery path; it mints only the restricted positive and applicable negative-control tokens.
Live proof is Unix-like only because GrantTrace must be able to terminate and verify the managed child process group. Windows remains supported for package installation, recording, checking, analysis, and contract review.
The standard Node global-fetch and Octokit path to exactly
https://api.github.com is instrumented automatically. Off-origin responses
cannot supply automatic permission evidence. Custom fetch implementations,
transports, or runtimes need the
explicit fallback. The command must clean up every
resource it intentionally creates. examples/live-issue-comment/scenario.ts
shows the reversible comment pattern.
The broker retains the App ID, installation ID, and private key. The child gets only:
- a restricted, short-lived installation token as
GITHUB_TOKEN; - recorder mode, scenario, and private session path;
- the focused fixture coordinates; and
- a small allowlist of operating-system environment variables.
It does not inherit HOME, NODE_OPTIONS, existing GitHub tokens, private-key
provider settings, broker identifiers, disposable confirmation, or arbitrary
environment variables.
The raw token response must prove:
requested permissions
= selected permissions for this scenario
+ all manual keeps
effective permissions
= requested permissions
+ mandatory metadata:readIt must also identify exactly one expected repository and a fresh expiry consistent with GitHub's one-hour token lifetime. Every other effective-permission difference blocks.
Results and cleanup
Each proof execution after accepted-contract validation writes an identity-free report to:
.granttrace/reports/<scenario>.jsonThe reports directory is 0700; the report is 0600. It records only
allowlisted contract, permission, child-status, negative-control, and cleanup
facts. It does not record the command, token, JWT, key, raw URL, owner,
repository, issue number, response body, or rich error.
After any failure:
- read the terminal's safe failure class and report state;
- inspect the disposable fixture manually for mutation residue;
- resolve any residue before another proof;
- fix the distinct cause—configuration, authentication, authorization, hidden resource, rate limit, expiry, outage, test, timeout, contract mismatch, or cleanup; and
- rerun
granttrace doctorbefore retrying.
A cleanup failure is never an unqualified pass.
CI secrets
Do not run live proof on untrusted pull requests or forked code. If a trusted, manual workflow is added later:
- use a protected environment;
- expose nonsecret fixture selectors and one private-key secret only to that job;
- use minimal workflow permissions;
- disable command tracing;
- never upload
.granttrace/as an artifact; and - retain the fixture-only repository and exact one-repository validation.
GrantTrace's package-verification workflow is offline and requires no fixture credentials. Documentation deployment runs separately.