Skip to content

Source control & the policy check

Concept

Greenlight enforces a single delivery path: pull request, policy check, merge, deploy. There are no out-of-band writes and no shortcuts. The same path applies to the coding agent, the citizen developer, and IT.

Policy gate flow diagram: one check between every change and production. A pull request (how every change ships) enters the Greenlight policy check — secret scanning, static analysis, supply chain, and org policy rules. On pass: merge, build, deploy into the isolated per-app environment. On fail: merge blocked with a structured reason returned to the agent, and a loop-back arrow labeled 'the agent reads the reason, fixes, pushes again' returning to the pull request.

Greenlight’s policy check is a single status that posts on every pull request and aggregates four kinds of analysis.

CheckWhat it catches
Secret scanningAPI keys, tokens, and private keys committed in the diff.
Static analysisKnown-bad patterns, OWASP rules, and any custom organization rules you’ve enabled.
Supply chainContainer CVEs, dependency vulnerabilities, and license-policy violations.
Org policy bundleOrganization-specific rules evaluated by OPA — approved base images, resource limits, dependency allow-lists, and anything else in your policy bundle.

The policy bundle is org-scoped, and changes to it live as structured rows. Adding a rule means inserting a row in the dashboard, not redeploying the platform.

A pull request that passes the check shows a single green status from Greenlight and is mergeable through the normal source-control flow. A pull request that fails shows the same status with a structured reason that the agent reads and acts on:

✗ greenlight/policy-check Failed (2/4 checks)
• secret-scanning: API key found in src/integrations/snowflake.ts
• org-policy/approved-base-images: base image not on the allow-list
Status: merge blocked

The dashboard’s Pipeline tab on each app detail page shows every run with its per-check verdict, the OPA decision JSON, and a link to the raw logs.

A pipeline run detail page showing commit a1b2c3d on main, status Passed, with six checks all green: gitleaks (1200ms), semgrep (1800ms), trivy (2400ms), opa-policy (3000ms), build (3600ms), and deploy (4200ms), followed by the OPA decision block showing allow: true.

Policies are structured data, not free-form scripts. A representative base-image policy:

id: approved-base-images
kind: deny_if
description: Containers must use an approved base image.
match:
resource: dockerfile
field: from
not_in:
- ghcr.io/shiftengineering/node:20-alpine
- ghcr.io/shiftengineering/python:3.12-slim
on_violation:
status: failed
message: "Base image not on the approved list."

The agent can read the active policy set at any time via the getPolicies MCP tool — so it can fix violations on the first try instead of guessing.

  1. The status goes red. The PR comment includes the structured failure reason.
  2. The agent reads the failure. Either from the PR comment or by calling getPolicies to compare its diff against the active rules.
  3. The agent fixes and pushes. Same branch, same pull request. The check re-runs automatically.
  4. The status goes green. The PR becomes mergeable. Merging triggers deployment.

Greenlight talks to your source-control system through the Greenlight GitHub App, which scopes access to a specific GitHub organization and specific repositories. GitLab and Bitbucket will follow the same App-based pattern; GitHub is the supported provider today.

The App is responsible for:

  • Creating repositories when an agent calls registerApp.
  • Opening pull requests on behalf of agents (the PR’s author is the bound user; the App is the source).
  • Posting the single Greenlight Review and Policy Check status on every PR, after Greenlight verifies the scanner evidence and runs the policy engine.
  • Reading metadata Greenlight needs to display the app’s status and history in the dashboard.

The App does not have admin permissions on your GitHub organization, push to main, or modify branch-protection rules outside the repositories Greenlight created.

  1. Start from the dashboard. Navigate to Admin → Source control and click Install GitHub App. You’ll be redirected to GitHub’s App install flow.
  2. Pick the target organization. Install the App on the GitHub organization that will host your Greenlight-managed repositories.
  3. Choose repository scope. Greenlight needs to create repositories, so install with “All repositories” or with the + Create new repositories permission. Existing-repo adoption is a separate post-install workflow.
  4. Confirm permissions. GitHub lists the permissions the App asks for — they map to the responsibilities above; no admin or org-owner permissions are requested.
  5. Verify in the dashboard. Back in Greenlight, the Source control page should show the App as installed with a green checkmark.

Reinstalling, replacing, or moving the App

Section titled “Reinstalling, replacing, or moving the App”

The install isn’t a one-way door. Settings → Source control supports three lifecycle operations, all restricted to org admins and all audit-logged:

  • Reinstall on the same org. If the App was uninstalled, installing it again reconnects automatically — Greenlight detects the new installation and verifies it can still reach every managed repository. Any repos the new install can’t see (for example, a “selected repositories” install missing entries) are flagged for you rather than silently skipped, and a Verify access action lets you re-check on demand.
  • Re-create the App. If the App was deleted on GitHub, its key was compromised, or your Greenlight URL changed, an admin action re-runs the App creation flow and rotates Greenlight’s stored App credentials to the new App. Webhooks from the new App verify immediately — no restart. Greenlight never deletes the old App on GitHub; once the replacement is working, remove the old one yourself.
  • Migrate to a different GitHub org. Install the existing App on the target org (Greenlight records it as a pending target without disturbing the current connection), transfer the managed app and plugin-marketplace repositories in GitHub, then run the migration from settings. A preview shows exactly which repositories will be re-pointed before anything changes, and the migration only completes once every repo is reachable under the new org — then all coordinates move in one step and app-repository branch protection is re-verified. Marketplace visibility and automatic updates carry over at the new coordinates, and deployed apps keep serving throughout.

Greenlight creates new repositories with branch-protection rules pre-configured: main requires the single Greenlight Review and Policy Check status to be green before merge, and force-push to main is disabled. There are no human reviewers in the loop — the scanners and policy engine behind that one status are the review. The rules are visible and editable in GitHub’s branch-protection UI; Greenlight does not silently reset them.

The default path is for Greenlight to create new repositories for every app. Bringing an existing repository under Greenlight governance — repo adoption — is a more deliberate workflow, since the existing history needs a one-time policy scan and existing branch protection has to be reconciled; ask in your install for the adoption playbook.

A Greenlight-managed repo has the same shape as any other repo, plus:

  • A greenlight.yml at the root with app_id, required docs metadata, and the declared workloads / resources / grants / env blocks. Env-var values are set via MCP; everything else is declared in the file.
  • A pre-commit hook (optional) that runs the same scanners the policy check runs, so the agent gets fast feedback.
  • A GitHub Actions workflow Greenlight installs and updates, which runs the scanners and uploads their evidence. Greenlight verifies that evidence, runs the policy engine, and posts the resulting status — the workflow itself doesn’t decide the outcome.

The developer and the agent both treat the repo as a normal Git repo. Policy enforcement happens through PR statuses, not hidden tooling.