How to run AI code review in an air-gapped environment

Published 2026-07-26 · Target keyword: air-gapped AI code review

Running an AI reviewer with no internet access is mostly not a modelling problem. It is a dependency problem. The reviewer itself will usually run fine offline. What breaks is everything around it that quietly assumed a network: license checks, telemetry, registry pulls, model downloads, and vulnerability feeds.

This post is the operational version. If you are still deciding whether self-hosting is the right call at all, start with can you run AI code review without sending your code to the cloud? instead. This one assumes the decision is made and you now have to make it work behind a boundary.

Key takeaways

  • The reviewer is rarely the problem. Hidden outbound dependencies are.
  • Model inference must happen inside the perimeter, with weights transferred in advance, not fetched on first run.
  • Install by image tarball. docker save on a connected machine, transfer, docker load inside.
  • Check whether migrations run automatically on boot. Automatic migration inside an air gap is a way to corrupt a schema with no route to a hotfix.
  • Verify with an egress firewall rather than a datasheet. It takes an afternoon.

What actually breaks in an air gap?

Five dependencies account for most failures, and they fail in different ways.

DependencyHow it fails
License or entitlement checkHard fail at startup, or a silent degradation to a reduced mode after a grace period expires. The nastiest variant works for 30 days then stops.
Telemetry and crash reportingUsually non-fatal but generates blocked-egress alerts that your security team will, correctly, treat as an incident.
Container registry pullDeploy fails immediately. Obvious and easy to plan for.
Model weight download on first runSilent hang or timeout. Often mistaken for a performance problem rather than a network one.
Vulnerability or rules feedWorks, but quietly goes stale. The most dangerous failure because nothing looks wrong.

The one worth interrogating hardest is the license check, because it is the dependency vendors most often forget to mention. Ask directly: does this product make any outbound call that is not to a host I configured myself?

How do you install into an air-gapped network?

By file transfer. Because the image arrives as a file rather than being pulled from a registry, the offline install is a standard Docker save and load:

# On a connected machine (image provided during onboarding):
docker save gatekeep-image -o gatekeep.tar

# Transfer gatekeep.tar into the air-gapped network, then on the target host:
docker load -i gatekeep.tar
docker compose up -d          # config.yaml points llm.base_url at your LAN model

The media used for the transfer is whatever your policy allows. That is a question for your security team, not your vendor.

Where does the model run?

Inside the perimeter, or the deployment is not air-gapped. This is the point people most often get wrong, because the application can be entirely on-premise while the one step that matters, inference, still calls out.

Practically that means serving open-weight code models yourself, typically with vLLM for throughput or Ollama for a simpler deployment, and transferring the weights ahead of time along with the image. A model that downloads itself on first run is a network dependency wearing a different hat.

In Gatekeep the entire switch is one config value: point llm.base_url at a model on your LAN and the whole system runs with no public internet egress.

How do you verify there is genuinely no egress?

Test it. Do not accept a datasheet claim, including ours.

Run the container behind an egress firewall that permits only the hosts you expect, then exercise the full workflow: open a pull request, get a review, trip the gate, attempt an override, export the audit log. Any blocked outbound attempt to a vendor-owned host tells you the claim is false. This is an afternoon of work and it is the single highest-value piece of diligence you can do on any self-hosted tool.

For Gatekeep specifically, the only outbound connections the application makes are to two hosts you configure yourself: your GitHub API base URL, and your llm.base_url. There is no analytics, no crash reporting, and no license check that calls out. It is an architectural property rather than a setting you can accidentally flip.

Pointing that first one at an internal GitHub Enterprise Server instance is the piece most people ask about. The mechanics of registering the app and setting its permissions are covered in wiring a self-hosted AI code reviewer into GitHub, and the same walkthrough applies whether the host is public GitHub or your own.

Two honest caveats

The egress-restricted acceptance test described above is a release sign-off item for us, but today it is run by hand rather than automated in CI. Roadmap Treat it as a check you should run yourself in your own environment, which is what we would recommend regardless.

Gatekeep is GitHub-only as of July 2026. GitLab, Bitbucket and Gitea are roadmap. If your disconnected network runs self-hosted GitLab, that matters more than anything else in this post.

How do upgrades work without a registry?

The same transfer, repeated. Load the new image tarball, stop the app container, run migrations, start the new container.

The detail worth checking in any tool is whether migrations run automatically at boot. Inside an air gap, automatic migration is genuinely dangerous: a partially completed transfer can mutate your schema, and you cannot simply pull a hotfix. Gatekeep requires an explicit alembic upgrade head, so a half-rolled deploy cannot change the database on its own. Pin your image versions, and treat the audit database as the asset you are protecting during any upgrade.

On backup, all state lives in a single database: reviews, gate decisions, overrides, and the hash-chained audit log. That makes restore verification unusually simple, because the chain either validates or it does not. The X-Audit-Chain-Valid response header doubles as a restore-integrity check. Full detail is in the operations documentation.

Frequently asked questions

What usually breaks an air-gapped code review deployment?

Rarely the reviewer itself. The usual culprits are hidden outbound dependencies: a license check that calls home, telemetry or crash reporting enabled by default, a container image pulled from a public registry at deploy time, model weights fetched on first run, and vulnerability feeds that expect to update over the internet. Each fails differently, and some fail silently.

How do you install software into an air-gapped network?

Standard practice is an image tarball. Export the container image on a connected machine with docker save, transfer the tarball by whatever media your policy allows, then docker load and bring up compose on the target host. No registry access is required at any point inside the perimeter.

How do you verify a tool really makes no outbound connections?

Do not take the vendor's word for it. Run the container behind an egress firewall that allows only the hosts you expect, then exercise the full workflow end to end. Any blocked outbound attempt to a vendor-owned host tells you the claim is wrong. This test takes an afternoon and is worth more than any datasheet.

Can you upgrade software inside an air gap?

Yes, by repeating the transfer with a new image tarball. The thing to check is whether database migrations run automatically on boot. Automatic migration means a half-completed transfer can mutate your schema with no way to pull a fix. Gatekeep requires an explicit alembic upgrade head, so the operator controls when the schema changes.

Do you need a local model to run AI code review air-gapped?

Yes. If model inference is the one step that leaves the network, the deployment is not air-gapped regardless of where the application runs. You need weights served inside the perimeter, typically via vLLM or Ollama, and you need to have transferred those weights in advance rather than fetching them on first run.

The short version

Treat an air gap as a dependency audit rather than a deployment mode. Enumerate every outbound call the tool can make, insist that each one points at a host you chose, move the model inside the perimeter, and then prove it with a firewall instead of a datasheet. The install itself is the easy part.