Skip to content

Gatekeeper

Gatekeeper is the CI check that measures a pull request’s log coverage and either lets it through or opens an auto-fix pull request with the missing logs. The GitHub Action calls one backend route.

Code: backend controller/GatekeeperController.java, controller/GatekeeperKeyController.java, service/gatekeeper/{GatekeeperAuth,GatekeeperTarget,GatekeeperThreshold,GatekeeperCiKeys}.java.

{
"branch": "feature/login",
"baseCommit": "4f2a9c1",
"commit": "9b81e0d",
"repoUrl": "https://github.com/acme/payments",
"changedFiles": ["src/main/java/acme/Login.java"],
"logCoverageThreshold": ""
}
FieldRequiredRule
branchyesA git branch name (git check-ref-format --branch), at most 255 characters
commityesA commit sha, 7–40 hex characters
baseCommitnoA commit sha, 7–40 hex characters
repoUrlyesThe repository’s https URL naming owner and repository; at most 2048 characters
changedFilesyesA list of 1 to 10 000 non-blank paths of at most 4096 characters; an empty list is a 400 “changedFiles must list at least one path” (backend 05c9a46c, 2026-10-21)
logCoverageThresholdnoA number; "" (an unset Actions variable) means “not supplied”
githubTokennoUsed for the auto-fix pull request only when the scan’s owner has no GitHub token

The answer (GatekeeperResponse) is always 200 once a measurement exists:

{
"status": "block",
"message": "Not good",
"prLink": "https://github.com/acme/payments/pull/42",
"coveragePercent": "61.40",
"threshold": "80",
"thresholdSource": "server"
}
  • status is allow when coveragePercent ≥ threshold, otherwise block. On block the scan is saved and the log generator opens a pull request whose URL is prLink.
  • coveragePercent, threshold and thresholdSource are strings, reported on both outcomes, so the pipeline prints exactly what the server compared.
  • A scan that produced no coverage measurement is a 500 (the scan produced no coverage measurement for commit …), never a 0 % block.
  • A branch that does not exist in the repository is a 422 “Branch ‘<branch>’ does not exist in <repoUrl>.” (GatekeeperCheckout, backend 05c9a46c, 2026-10-21, dev and prod). It used to be a 500 from the failed clone.
  • Both outcomes are posted to the workspace’s Discord channel when one is connected.

Two credentials are accepted, both as Authorization: Bearer …:

CredentialWho uses itWorkspace
Gatekeeper CI key (lgck_live_…)The GitHub Action (secret LOGRITE_API_KEY)The key’s own workspace
Login JWTThe dashboardEvery workspace the user belongs to; the newest matching scan wins

An unknown or revoked CI key is 401 invalid or revoked Gatekeeper CI key; no credential is 401.

CI keys are managed by a signed-in Maintainer or above at /api/v1/gatekeeper/keys (POST ?workspaceId=&name= mints and returns the plaintext once, GET ?workspaceId= lists, DELETE /{id}?workspaceId= revokes). An lgp_live_ API key or an MCP connection is refused: no credential can mint a credential. Revoking a key in another workspace answers 404.

The check inherits its project and scan profile from the latest prior scan of the same repository inside the caller’s workspace (GatekeeperAuth):

  1. repoUrl is normalised: trimmed, trailing / removed, one trailing .git removed.
  2. The prior scan is the newest log_scan_result whose branch link starts with that URL plus / (stored links are <repo>/tree/<branch>, Bitbucket /branch/), compared case-insensitively.
  3. A repository the caller’s workspace never scanned answers 404 No prior scan found for repository '…'. Run an initial scan on this repository before calling the gatekeeper. — even when another workspace scanned it, so the route cannot enumerate other tenants’ repositories.

GatekeeperThreshold.resolve picks, in order:

SourcethresholdSource
logCoverageThreshold in the request, when it is a numberrequest
The workspace setting gatekeeper.coverageThresholdworkspace
The backend default GATEKEEPER_DEFAULT_COVERAGE_THRESHOLD (gatekeeper.default-coverage-threshold, default 80)server

A configured default that is not a percentage 0–100 is replaced by 80 at startup, with a log line. A request value above 100 is honoured as sent.

/api/v1/gatekeeper/check is in ApiChainPolicy.PUBLIC_API_PATHS and in ApiPublicMachineSurface (NON_BEARER_CREDENTIAL): the Spring API chain (SECURITY_API_CHAIN_ENABLED) cannot recognise an lgck_live_ key, so the route is let through the chain and GatekeeperAuth verifies the CI key or the JWT itself and answers 401 to anything else.