> ## Documentation Index
> Fetch the complete documentation index at: https://docs.cynative.com/llms.txt
> Use this file to discover all available pages before exploring further.

# GitHub Connector: Source Control Research

> Configure Cynative's GitHub connector: token discovery, read-only enforcement, permission ceilings, and host pinning.

Cynative's GitHub connector is built for read-oriented source-control and repository security research. It uses an in-process per-request classifier to resolve each request to its API category and required access level, then allows it only within the configured ceiling — read-only by default, with certain sensitive categories blocked.

**Connector id:** `github`\
**Fixed host:** `api.github.com` (GitHub Enterprise Server is not supported)

## Quick start

Authenticate the GitHub CLI, then run Cynative from the same environment:

```bash theme={null}
gh auth login
cynative -p "review my GitHub repositories for exposed secrets"
```

No YAML configuration is required for the default read-only mode.

## Credential discovery

Cynative asks the GitHub CLI auth library ([go-gh](https://github.com/cli/go-gh)) for a token for `github.com`. Cynative does not read these variables itself; go-gh does. Because Cynative always queries the literal `github.com` host, go-gh's enterprise / `GH_HOST` branches never apply.

* `GH_TOKEN` — highest-precedence GitHub token; read by go-gh for `github.com`.
* `GITHUB_TOKEN` — second-precedence token (also the GitHub Actions built-in token).
* `GH_PATH` — path to the `gh` executable go-gh shells out to for the keyring-fallback token lookup.
* `GH_CONFIG_DIR` — directory go-gh reads the `gh auth login` token (`hosts.yml`) from.

**Registration and validation:** If no token is available, the connector is not registered and nothing is printed. When a token is present, Cynative eagerly validates it at startup with a hardened `GET /user` request (yielding the `@login` identity shown in the startup inventory). When `/user` is inconclusive — a GitHub App installation token, an Actions `GITHUB_TOKEN`, or a rate-limit condition — Cynative falls back to `GET /rate_limit`, a universally-accessible, rate-limit-exempt endpoint.

**References:**

* [GitHub CLI environment variables](https://cli.github.com/manual/gh_help_environment) — `GH_TOKEN` / `GITHUB_TOKEN`, `GH_PATH`, `GH_CONFIG_DIR`.
* [Authenticating to the GitHub REST API](https://docs.github.com/en/rest/authentication/authenticating-to-the-rest-api) — fine-grained vs classic personal access tokens.

## Target selection

The GitHub connector always targets the public GitHub REST API at `api.github.com` — the host is hardcoded. It additionally authorizes the GitHub-owned download hosts `codeload.github.com`, `release-assets.githubusercontent.com`, and `objects.githubusercontent.com` (GET/HEAD only) so release-asset and tarball redirects can be followed.

Change the identity by changing the token: run `gh auth login`, or export `GH_TOKEN` (highest precedence) or `GITHUB_TOKEN`. The host is not configurable.

## Request usage

Use `auth_provider: "github"`. No connector-specific auth object is required.

```javascript theme={null}
const resp = await http_request({
  method: "GET",
  url: "https://api.github.com/user",
  headers: [],
  body: "",
  auth_provider: "github"
});
console.log(resp.body);
```

## Hardening

### Host pinning

Host pinning allows only `api.github.com` and the three GitHub-owned download hosts. The download hosts are GET/HEAD-only, regardless of the configured permissions. Redirects are never followed — a 3xx is returned to the model, which must request the `Location` URL explicitly (re-entering host pinning and action authorization on each hop).

### Category + access-level classification

The in-process classifier resolves each REST request to its GitHub category/subcategory and the required access level (read or write), then allows it only when the configured `connectors.github.permissions` ceiling permits that level for that category.

* The check runs **before** the token is attached, so a disallowed request is rejected without the credential ever leaving the process.
* The classifier is backed by GitHub's first-party OpenAPI description, distilled into a category routing table, fetched anonymously and cached from `raw.githubusercontent.com`.
* A REST request that cannot be classified fails closed. The `secret-scanning` category is denied by the secure baseline even for reads, because its read endpoints can leak secret material.
* The GraphQL API (`/graphql`) is not supported and is always denied.

### Secret-scanning protection

Secret-scanning protection is layered: the table admission guard rejects any fetched spec that maps a `secret-scanning` template to another category; the `secret-scanning: none` baseline in the default exposure blocks all such requests at the ceiling; and unknown routes fail closed.

## Cynative configuration

`connectors.github.permissions` is a `category[/subcategory] → read|write|none` ceiling. Omit it entirely for the secure default (read everything except `secret-scanning`). The most-specific match wins (`category/subcategory` → `category` → `default`). `write` implies `read`; `none` denies even reads.

```yaml theme={null}
connectors:
  github:
    permissions:
      default: read            # baseline for unlisted categories
      issues: write            # allow creating/editing issues
      pulls: write             # allow opening/merging PRs
      secret-scanning: read    # opt back in to a category the baseline blocks
      actions/secrets: none    # deny a single subcategory outright
```

Set from the environment as a compact comma-separated list:

```bash theme={null}
export CYNATIVE_CONNECTORS_GITHUB_PERMISSIONS="default=read,issues=write,secret-scanning=none"
```

A non-empty environment value **replaces** the config-file map wholesale. A blank value is treated as unset. Duplicate keys are rejected at load time. When the ceiling is widened (`default=write`, an opened `secret-scanning`, or any `category:write` override), the startup inventory line is loud (`⚠`) and names exactly what was widened.

## Defense at a glance

| Control | Status |
| - | - |
| Read-only by default | ✓ (secret-scanning blocked even for reads) |
| Enforcement model | in-process per-request classification to a GitHub category/subcategory + access level, allowed only within the configured ceiling |
| Configurable exposure | ✓ · `connectors.github.permissions`: `category[/subcategory]` → `read\|write\|none` ceiling |
| Credential downscoping | — · user tokens can't be downscoped at runtime |
| Host pinning | ✓ (`api.github.com` + GitHub-owned download hosts, GET/HEAD) |
| Dial-time IP authorization | ✓ (public-internet guard — stricter than the default internal-range deny) |
| Model-supplied-credential rejection | ✓ |
| Response redaction | ✓ |

## Limitations

* The connector supports `api.github.com` and the listed download hosts. [GitHub Enterprise Server](https://docs.github.com/en/enterprise-server@latest/admin/overview/about-github-enterprise-server) hosts are not supported.
* Actions-artifact downloads are not supported: GitHub redirects them to per-account Azure blob endpoints, which are outside the GitHub-owned host invariant.
* A configured `permissions` ceiling never *expands* the GitHub token's own scopes — the effective capability is the intersection of the two. Setting `issues: write` does nothing if the `gh` token cannot write issues.
* There is no client-side credential downscoping. A PAT, `gh`, or OAuth token has its scopes fixed at creation.
* The category routing table requires egress to `raw.githubusercontent.com`. With no network **and** no local cache, the connector fails closed — every `api.github.com` request is denied with a `github_hardening: category table not ready` error.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.