Skip to content

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

ItemWhere to find itUsed for
GitHub tokenOne of: a classic PAT, a fine-grained PAT, or a GitHub App installation tokenAuthenticates the SARIF upload API call
Repo mapping(s)The HarborGuard image name(s) you want to forward, plus the target owner/repo and refRoutes which image's findings end up in which repo

Token scopes

Token typeRequired permission
Classic PATsecurity_events (for private repos) or public_repo (for public repos only)
Fine-grained PATRepository → Code scanning alerts: Read & Write
GitHub App installation tokencode_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

  1. Create the token in GitHub with the scopes above.
  2. In HarborGuard, go to Settings → Integrations → GitHub Code Scanning.
  3. Paste the Personal Access Token (ghp_… for classic, github_pat_… for fine-grained, or the installation token).
  4. (GHES only) Fill in API Base URL. Leave blank for github.com.
  5. Add at least one Repo Mapping (see below).
  6. Leave Enabled checked.
  7. Click Save.
  8. Click Test Connection to verify the token. A green toast means the token authenticates and (for non-Enterprise) has the right metadata permissions.
  9. (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.

FieldRequiredFormatNotes
Image NameYesregistry/path/image, e.g. docker.io/library/nginxMust match the HarborGuard image name exactly (look at the image's detail page if unsure).
Image TagNotag string, e.g. 1.27.0Leave blank to push findings for all tags of the image. When set, only that tag's latest scan is included.
GitHub RepoYesowner/nameThe target repository. The token must have code-scanning write access on it.
RefYesrefs/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:
    1. Resolves the configured ref to a current commit SHA via the GitHub API. (Code scanning requires a SHA, not a symbolic ref.)
    2. Collects the latest completed scan's vulnerabilities for the matched image (and tag, if set).
    3. Builds a SARIF document, gzip-compresses it, base64-encodes it, and uploads via the Code Scanning SARIF upload endpoint.
    4. Records the upload's sarif_id so the next sweep can poll its processing status.
  • 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 / Failed with <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

SymptomLikely cause
Test Connection returns 401Token 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 URLURL 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 listThe 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_largeFindings 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 syncTwo 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 GitHubWait 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 GHESAPI Base URL is empty or was cleared during a re-save. Re-enter it; the field saves independently of the token.

On this page