← All docsFix & share

Fixes & source control

Connect GitHub or GitLab and analyse your repo read-only — 1–3 concrete fix recommendations, no writes to your repo.

Connecting a repo#

A connection is one repository plus a credential that lets Harpoon read it. The fastest way is one click: if this deployment has the Harpoon GitHub App configured, the Fixes page shows a Connect GitHub button. It sends you to GitHub's own install screen, where you choose exactly which repositories to grant; you land back on a picker and pick one. No token to create, no id to copy.

GitLab is just as quick: if a GitLab OAuth app is configured, a Connect GitLab button sends you to GitLab's consent screen, then back to a picker of your projects. GitLab issues a short-lived access token plus a refresh token (both sealed server-side); Harpoon refreshes the access token automatically, so the connection keeps working without you re-authorizing. If that authorization is ever revoked, the connection shows a Reconnect GitLab prompt.

Only an organization owner or admin can connect a repo. Re-connecting the same repo rotates its credential rather than erroring.

The credential never reaches your browser. The install returns to Harpoon's API, which stores only the installation id and redirects back with non-secret flags; the token that actually reads your repo is a short-lived, install-scoped token minted on demand from the App key — nothing long-lived is stored, and no secret is ever displayed or logged. See Security & your data.

What the GitHub App can access#

The Harpoon GitHub App is installed on only the repositories you select on GitHub's screen — not your whole account. For this feature Harpoon only ever performs a read-only clone: it never pushes a branch, opens a PR, or comments. You can change the repository selection any time in the App's install settings, or uninstall to revoke access; uninstalling also drops the affected connections here automatically.

After installing you can also add more repos without re-installing: the connect step shows an Add a repo chip for each account you've installed on, which re-opens the picker.

What connecting GitLab grants#

GitLab has no per-install token model, so one-click GitLab uses OAuth 2.0 (Authorization Code with PKCE) and requests the api scope. The picker lists projects you can access; Harpoon uses that access to clone the project read-only.

The access and refresh tokens are AES-256-GCM sealed at rest and never returned to the browser or logged — only a non-secret grant id rides the redirect back to the picker. Revoke access any time from GitLab's Applications settings; the connection then prompts you to reconnect.

Advanced — connecting with an access token#

If one-click connect isn't configured on your deployment (self-hosting, GitHub Enterprise, a self-managed GitLab without an OAuth app, or a CI setup), open Advanced — use an access token under the connect form and authenticate manually. On GitHub you can instead paste a GitHub App installation id — the number at the end of the install's Configure page URL, e.g. …/installations/12345678.

Read access is enough — Harpoon only clones the repo read-only for this feature, so scope the token as narrowly as your provider allows:

  • GitHub — fine-grained token: grant the one repository with Contents: Read and Metadata: Read.
  • GitHub — classic token: the repo scope (read access to a private repo).
  • GitLab: a personal or project access token with the read_repository or api scope.

Least privilege beats convenience: scope the token to just the repo you're connecting, and prefer a fine-grained/project token over an account-wide one. Tokens are sealed with AES-256-GCM on arrival and are write-only — never read back, displayed, or logged.

Choosing an analysis#

The run works from the findings of one saved analysis. Step 2 of the wizard is a combobox of your recent runs, grouped by domain: pick one, or type a bare domain like example.com to jump to its most recent analysis. Or, from any report, hit Fix in a repo to land on Fixes with that analysis already selected. If a domain has no saved analysis yet, the wizard links you to analyze it first.

Anonymous one-off analyses aren't saved and won't appear in the picker. Sign in and run the analysis from your account, or from a monitor, to get a permalink you can reference here.

What "Analyse my repo" does#

Analyse my repo is read-only. Harpoon clones your repo's default branch into a sandbox and, without ever running your build or writing anything:

  • dry-runs its deterministic codemods against your checkout — these are mechanical, reviewed transforms, so a match comes with a real unified-diff preview you can read;
  • then makes one call to our AI provider to fill the remaining slots (up to three fixes total), sending it the engine's findings plus a few small, relevant file snippets — never your raw HAR, and never a secret file (.env, keys, .npmrc, CI workflows, … are excluded before the call);
  • and shows the recommendations here, each linking back to the finding it addresses.

A live checklist follows the run — cloning, scanning, writing recommendations. When it finishes you get one to three fix cards, or an honest "nothing confident found" if no finding mapped to a safe repo-side change.

Nothing is ever pushed, committed, or commented — the recommendations stay in Harpoon. Because the run only reads files (it never executes your repo's scripts), it isn't gated by theAUTOFIX_ENABLED write kill-switch; it needs the Fleet plan and is bounded by the AI gateway's own rate and spend limits. See what the AI sees.

Which findings get a deterministic fix#

These findings have a registered codemod, so a match shows up as a Deterministic fix with a real diff preview (the rest are AI suggestions):

FindingDeterministic fixTouches
Uncached static assetsAdds a long-lived Cache-Control: public, max-age=31536000, immutable rule scoped to the assets' shared directory.vercel.json, _headers, or netlify.toml — only if one already exists.
Render-blocking scriptAdds defer to the one <script src> tag matching the flagged asset (skipped if it's already defer/async/module).The HTML file referencing that script.
Uncompressed text assetsEnables gzip (gzip on + text gzip_types) inside the http/server block; skipped if gzip is already on.A recognized nginx config (nginx.conf, conf.d/*.conf, …).

Everything else is filled by the AI slot — a specific, file-named suggestion you apply yourself. Deterministic codemods only ever read configs that already exist; Harpoon never guesses your hosting stack, and (in this read-only flow) never edits anything.

Still stuck? Email us or browse all guides.