GitHub Code Scanning
The GitHub Code Scanning integration uploads HarborGuard's container vulnerability findings as SARIF analyses to one or more GitHub repositories. Findings land in the repo's Security → Code scanning tab, alongside CodeQL alerts, and inherit GitHub's triage workflow (dismiss, mark as fixed, link to PRs). Each container image is uploaded as its own SARIF category, so per-image state is isolated even when several images target the same repo and ref.
What you'll need
| Item | Where to find it | Used for |
|---|---|---|
| GitHub token | One of: a classic PAT, a fine-grained PAT, or a GitHub App installation token | Authenticates the SARIF upload API call |
| Repo mapping(s) | The HarborGuard image name(s) you want to forward, plus the target owner/repo and ref | Routes which image's findings end up in which repo |
Token scopes
| Token type | Required permission |
|---|---|
| Classic PAT | security_events (for private repos) or public_repo (for public repos only) |
| Fine-grained PAT | Repository → Code scanning alerts: Read & Write |
| GitHub App installation token | code_scanning_alerts:write permission on the target repos |
GitHub will reject the upload if the token can't write code-scanning alerts on the target repo, even if it can read them.
GitHub Enterprise Server
For GHES, set API Base URL to your instance's API root, e.g. https://ghe.example.com/api/v3. The integration validates that the URL is https://, refuses private/loopback/link-local addresses, and re-checks the resolved IP on every request — you can't point this at internal-only hosts.
Connecting
- Create the token in GitHub with the scopes above.
- In HarborGuard, go to Settings → Integrations → GitHub Code Scanning.
- Paste the Personal Access Token (
ghp_…for classic,github_pat_…for fine-grained, or the installation token). - (GHES only) Fill in API Base URL. Leave blank for github.com.
- Add at least one Repo Mapping (see below).
- Leave Enabled checked.
- Click Save.
- Click Test Connection to verify the token. A green toast means the token authenticates and (for non-Enterprise) has the right metadata permissions.
- (Optional) Click Sync Now to enqueue an immediate run.
Repo mappings
Each row tells HarborGuard which image's findings to push and where they land.
| Field | Required | Format | Notes |
|---|---|---|---|
| Image Name | Yes | registry/path/image, e.g. docker.io/library/nginx | Must match the HarborGuard image name exactly (look at the image's detail page if unsure). |
| Image Tag | No | tag string, e.g. 1.27.0 | Leave blank to push findings for all tags of the image. When set, only that tag's latest scan is included. |
| GitHub Repo | Yes | owner/name | The target repository. The token must have code-scanning write access on it. |
| Ref | Yes | refs/heads/main, refs/tags/v1.2.3, etc. | The git ref to attach the analysis to. HarborGuard resolves it to a commit SHA before upload. |
Limits:
- Up to 100 mappings per organization.
- Each
(imageName, imageTag, repo, ref)tuple must be unique — duplicates are rejected at save time.
Categories are derived automatically: each upload uses harborguard:<imageName>[:<imageTag>] as the SARIF category, so two mappings that target the same (repo, ref) but different images don't overwrite each other on the GitHub side.
How sync works
- The cron worker runs every 15 minutes against every org with the integration enabled.
- For each mapping, HarborGuard:
- Resolves the configured
refto a current commit SHA via the GitHub API. (Code scanning requires a SHA, not a symbolic ref.) - Collects the latest completed scan's vulnerabilities for the matched image (and tag, if set).
- Builds a SARIF document, gzip-compresses it, base64-encodes it, and uploads via the Code Scanning SARIF upload endpoint.
- Records the upload's
sarif_idso the next sweep can poll its processing status.
- Resolves the configured
- The upload is a state-of-world replace per
(repo, ref, category): anything previously uploaded under the same triple that's missing from this payload is closed on GitHub.
Empty-result guard
If a mapping has never produced findings before, an empty SARIF push is suppressed. This prevents a typo in imageName from generating a "successful but empty" upload that closes every alert on the target. Once a mapping has uploaded at least one non-empty result, subsequent empty payloads will go through normally (so a clean image legitimately clears its alerts).
Orphan cleanup
Removing a mapping doesn't strand the alerts on GitHub. The next sweep notices that the (repo, ref, category) tuple has gone from your config and pushes a final empty SARIF to clear the analysis. If the GitHub branch has been deleted (so the ref no longer resolves), HarborGuard gives up after a few retry attempts to avoid an unbounded backlog.
Status panel
After a successful sync, the GitHub Code Scanning card shows:
- Status:
Connected - Token: masked (
••••xxxx) - Last sync: localised timestamp
- Last result:
Success/Failedwith<n>findings in<ms>ms - Errors: up to 10 most recent per-mapping errors, each tagged with a
kind(e.g.ref_resolve_failed,sarif_too_large,rate_limited) and the GitHub API message.
Permissions
- Connecting, editing, disconnecting: organization owner or admin only. Other roles see the card read-only.
- Audit events:
integration.github.connected,.updated,.disconnected,.sync_started,.sync_completed,.sync_failed.
Disabling vs disconnecting
- Uncheck Enabled → Save: pauses sync. Token, mappings, and bookkeeping (last-non-empty-at, pending polls) remain. Re-enable later without re-entering anything.
- Disconnect: deletes the encrypted token and all mappings. Alerts already uploaded to GitHub remain — to clear them, remove the mappings (so the orphan-cleanup pass closes them) before disconnecting.
Troubleshooting
| Symptom | Likely cause |
|---|---|
Test Connection returns 401 | Token revoked, expired, or lacks security_events (classic) / "Code scanning alerts" Read & Write (fine-grained). SSO-protected orgs require Configure SSO on the PAT. |
| Save rejects API Base URL | URL isn't https://, points at a private/loopback/link-local host, or carries userinfo (https://user:pass@host). Use the public GHES API root. |
ref_resolve_failed in error list | The configured ref doesn't exist on the target repo. Branch deleted, typo (main vs refs/heads/main), or the token lacks read access to the repo. |
sarif_too_large | Findings for that mapping exceed GitHub's 10 MB SARIF limit. Narrow the mapping to a specific tag or split into multiple repos. |
| Findings appear once and then vanish on the next sync | Two mappings target the same (repo, ref) with the same category. Check that imageName/imageTag are distinct — categories include both. |
| Removing a mapping leaves stale alerts on GitHub | Wait one sync cycle for the orphan-cleanup pass; the cleanup also requires the branch to still exist. If the branch is gone, dismiss the alerts manually in GitHub. |
| Sync runs against github.com instead of GHES | API Base URL is empty or was cleared during a re-save. Re-enter it; the field saves independently of the token. |