Custom transports

Use explicit instrumentation when GrantTrace's automatic Node preload cannot observe your GitHub client.

You normally do not need to change your code. granttrace record and granttrace prove inject a Node preload that observes supported GitHub REST requests made through global fetch to exactly https://api.github.com. Standard Octokit clients use that transport and are covered automatically. The automatic path ignores off-origin requests even when their response supplies a permission-like header.

Automatic recording is deliberately bounded. It does not observe a client that:

  • replaces global fetch with a custom implementation;
  • uses a custom Octokit transport or wrapper that bypasses global fetch;
  • runs the request in a subprocess or worker that discards the injected Node options;
  • runs outside Node.js; or
  • targets an unsupported GitHub Enterprise endpoint.

These requests are outside the contract unless you route them through the explicit integration below.

Explicit fallback

github-client.ts
import { GrantTraceOctokit } from "granttrace/octokit";

export function createGitHubClient(token: string) {
  return new GrantTraceOctokit({ auth: token });
}

Use that factory everywhere the scenario creates a GitHub client. Any second client that bypasses both global fetch and this adapter remains unobserved. The pre-composed constructor uses GrantTrace's exact compatible Octokit dependency.

Advanced Octokit composition

If the project must combine GrantTrace with other Octokit plugins, manual composition remains supported with the exact compatible core version:

github-client.ts
import { Octokit } from "@octokit/core";
import { grantTrace } from "granttrace/octokit";

const TracedOctokit = Octokit.plugin(grantTrace);

Use exactly @octokit/core@7.0.6. Other core versions and third-party wrappers are outside the explicit beta compatibility claim. Prefer GrantTraceOctokit unless composition is necessary.

Runtime behavior

The explicit plugin is inert during normal application execution. When the process is launched by granttrace record or granttrace prove, it:

  • pins the GitHub REST API to 2026-03-10;
  • reads the pre-expansion Octokit route template;
  • observes the accepted-permissions header on success and error responses; and
  • writes a new safe observation containing only allowlisted fields.

An explicitly conflicting API version fails instead of recording evidence against the wrong catalog.

Keep route templates intact

When using the explicit adapter, call Octokit with canonical route templates:

scenario.ts
await octokit.request(
  "POST /repos/{owner}/{repo}/issues/{issue_number}/comments",
  {
    owner,
    repo,
    issue_number: issueNumber,
    body: "Looks good",
  },
);

Concrete URLs, absolute URLs, query-bearing route strings, GraphQL, and unmatched templates are not heuristically redacted. They become blocking safe findings.

Authentication boundary

Recording observes route behavior; it does not authenticate or prove that the configured credential is a GitHub App installation token. Use a dedicated GitHub App test setup, and treat the accepted contract as scenario-bound route evidence rather than an authentication audit.

For a repository example, see examples/triage-bot. It uses a local fixture and the explicit adapter to demonstrate a hermetic consumer workflow; the fixture omits runtime permission evidence, so the result is catalog-backed.