Zum Inhalt springen

Run CodeCharter rule bundles in air-gapped, offline CI

Export a signed bundle from the portal and use it directly in air-gapped or fully offline CI, without portal access at analyze time.

Offline bundles let you use platform profiles and your own profiles in environments that have no direct internet access, such as air-gap CI systems or internal artifact repositories.

Why offline bundles

In some environments your CI runner is not allowed to reach the internet directly:

  • Air-gap CI: Isolated build infrastructure without outbound connectivity to the portal.
  • Internal artifact repository: Bundles are downloaded once and mirrored internally so every team accesses the same version.
  • Regulatory requirements: Audited environments where external network connections from CI are prohibited or restricted.

Exporting a bundle from the portal

You can download a bundle for a published profile version from the portal:

  1. Open the profile list or the Platform tab of the profile list.
  2. On your own profiles, click the kebab menu (⋮) on the desired profile row and select Download bundle; this offers the latest published version. On the Platform tab, click the Download bundle button directly on the profile card — same restriction, latest version only.
  3. For an older published version, open the profile's detail page instead and use Download bundle there, where every version is available.

The downloaded file is a signed .cgbundle: a ZIP archive containing the rule files (.cgr) for the pinned version, a manifest with metadata and a content hash, and an Ed25519 signature over that manifest.

Using a bundle file directly, without portal access at analyze time

For CI that has no route to the portal at all, you can point a profile entry in .codecharter/config.yml at a local bundle instead of a slug:

# .codecharter/config.yml
version: 1
profiles:
  - path: "./bundles/dotnet-standard-2.1.0.cgbundle"

This is the mechanism air-gapped and fully offline setups build on: nothing about a path: entry ever talks to the portal. To make it work, extract the downloaded .cgbundle (it is a plain ZIP) into .codecharter/cache/extracted/<name>/, where <name> is the bundle's file name without the .cgbundle extension — for the example above, that is .codecharter/cache/extracted/dotnet-standard-2.1.0/. Do this as a step in your own CI pipeline or image build, ahead of codecharter analyze; there is no CodeCharter command that performs the download or extraction for you. codecharter analyze then reads the rules straight from that directory. If it is missing, codecharter analyze prints a warning and simply skips that profile entry rather than failing the run, so a typo in the path is easy to miss — check the warning output after your first setup.

CodeCharter does not re-verify the bundle's signature or content hash for a path: entry; the SHA-256 pinning that protects slug-based profiles (see Using platform profiles) applies only to bundles resolved through codecharter update. Treat the bundle file itself as the trust boundary: fetch it over a channel you already trust (an authenticated download from the portal, checked into your own signed artifact store, or transferred with your organization's existing integrity controls), and do not commit it directly into your source repository — pull it from your internal store as a preceding CI step instead.

Update workflow in air-gap environments

In a fully isolated environment we recommend the following process:

  1. On a machine with internet access: download the new bundle from the portal.
  2. Extract it and upload the extracted contents to your internal artifact repository, keyed by the bundle name so the CI runner can fetch them into .codecharter/cache/extracted/<name>/.
  3. Update the version in .codecharter/config.yml (either the path: value, if it encodes the version, or the referenced file name).
  4. On the internet-connected machine, run codecharter update --portal-url <url> --api-key <key> to refresh the lockfile if you also use slug-based profiles alongside the offline one. This command requires portal connectivity and cannot run inside the air gap.
  5. Merge .codecharter/config.yml and .codecharter/codecharter.lock.json in a PR.
  6. On the CI runner: have a preceding pipeline step place the extracted bundle at .codecharter/cache/extracted/<name>/, then run codecharter analyze as usual — it reads the path: profile straight from that directory.

Further reading