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.
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.
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: ReadandMetadata: Read. - GitHub — classic token: the
reposcope (read access to a private repo). - GitLab: a personal or project access token with the
read_repositoryorapiscope.
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.
AUTOFIX_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):
| Finding | Deterministic fix | Touches |
|---|---|---|
| Uncached static assets | Adds 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 script | Adds 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 assets | Enables 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.