# Repositories and Images

CAPTF lives in eleven repositories in the [captf-io](<https://github.com/captf-io>) GitHub organization. This page lists what each one holds, what it publishes, which container images exist and how they are tagged, and how the pieces fit together.

## How the pieces fit

A module image is built FROM a base image that supplies the runtime. The module image is what a `Terraform*` resource names in `spec.source.image`. The provider runs it as a Kubernetes Job: an init container started from the provider’s own image copies the `/runner` binary into a shared volume, and the main container runs your module image with that runner as its command.

```
flowchart LR
    base["opentofu-base / terraform-base<br/>runtime at /captf/runtime"]
    mod["module image<br/>module + provider mirror"]
    prov["cluster-api-provider-terraform image<br/>manager + /runner"]
    res["TerraformCluster, TerraformMachine,<br/>TerraformMachinePool<br/>spec.source.image"]
    job["Job"]
    init["init container: copies /runner<br/>from the provider image"]
    main["main container: your module image<br/>runs /captf/bin/runner run"]

    base -->|FROM| mod
    mod -->|referenced by| res
    res -->|reconciled by manager in| prov
    prov -->|creates| job
    job --> init
    job --> main
    prov -.->|image of| init
    mod -.->|image of| main
```

The init container, the `/captf/bin/runner` path and the rule that the image’s own `ENTRYPOINT` never runs are described in [Job Environment](<https://captf.io/docs/reference/environment/#anatomy-of-a-job>). The runner image defaults to the manager’s own image and can be overridden with `--runner-image`; see [Manager Flags](<https://captf.io/docs/reference/manager-flags/index.md>) and [The manager image and the runner image](<https://captf.io/docs/operator-guide/installation/#the-manager-image-and-the-runner-image>). The module image half of the contract is in [Image Contract](<https://captf.io/docs/module-author/image-contract/index.md>).

## Repositories

| Repository | Kind | What it holds | What it publishes |
| --- | --- | --- | --- |
| [`cluster-api-provider-terraform`](<https://github.com/captf-io/cluster-api-provider-terraform>) | Provider | The `manager` (controllers and webhooks), the `runner` (the in-Job driver) and the `tfcapi-lint` linter, with the API types, CRDs, kustomize bases and clusterctl templates. | The manager and runner image, and the clusterctl components, templates and `tfcapi-lint` binaries as release assets. |
| [`opentofu-base`](<https://github.com/captf-io/opentofu-base>) | Base image | The Dockerfile for the OpenTofu runtime layer of the [image contract](<https://captf.io/docs/module-author/image-contract/index.md>). | `ghcr.io/captf-io/opentofu-base`. |
| [`terraform-base`](<https://github.com/captf-io/terraform-base>) | Base image | The same layer for the Terraform runtime. | `ghcr.io/captf-io/terraform-base`. |
| [`aws-modules`](<https://github.com/captf-io/aws-modules>) | Modules | Reference `cluster`, `machine` and `machinepool` modules for AWS. | `ghcr.io/captf-io/aws-<role>`. |
| [`azure-modules`](<https://github.com/captf-io/azure-modules>) | Modules | Reference `cluster`, `machine` and `machinepool` modules for Azure. | `ghcr.io/captf-io/azure-<role>`. |
| [`gcp-modules`](<https://github.com/captf-io/gcp-modules>) | Modules | Reference `cluster`, `machine` and `machinepool` modules for Google Cloud. | `ghcr.io/captf-io/gcp-<role>`. |
| [`oci-modules`](<https://github.com/captf-io/oci-modules>) | Modules | Reference `cluster`, `machine` and `machinepool` modules for Oracle Cloud. | `ghcr.io/captf-io/oci-<role>`. |
| [`openstack-modules`](<https://github.com/captf-io/openstack-modules>) | Modules | Reference `cluster` and `machine` modules for OpenStack. There is no `machinepool`. | `ghcr.io/captf-io/openstack-<role>`. |
| [`noop-modules`](<https://github.com/captf-io/noop-modules>) | Modules | No-op `cluster`, `machine` and `machinepool` modules that create nothing, for trying CAPTF and for end-to-end tests. | `ghcr.io/captf-io/noop-<role>`. |
| [`captf-io.github.io`](<https://github.com/captf-io/captf-io.github.io>) | Website | The captf.io site: landing page, this docs book and the blog. | The site, deployed to GitHub Pages from `main` by `pages.yml`. |
| [`.github`](<https://github.com/captf-io/.github>) | Organization | The organization profile, the community health files and the shared README fragments synced into every repository’s README. | Nothing is built. Its workflow only checks license headers. |

The module repositories are described together in [Cloud Modules](<https://captf.io/docs/cloud-modules/index.md>); their layout is in [Module Repository Layout](<https://captf.io/docs/module-author/repository-layout/index.md>).

## Images

All images are in GitHub Container Registry under `ghcr.io/captf-io/`.

| Image | Published by | Tags | Platforms |
| --- | --- | --- | --- |
| `cluster-api-provider-terraform` | The `publish` workflow: every push to `main`, and a `vX.Y.Z` tag push | `edge` and `sha-<commit>` on a push to `main`; `vX.Y.Z` (or `vX.Y.Z-rc.N`) on a tag. Never `latest`. | `linux/amd64`, `linux/arm64` |
| `opentofu-base`, `terraform-base` | The `build` workflow of each repository: every push to `main`, plus a weekly rebuild | `<version>`, `<major.minor>`, `<version>-YYYYMMDD`, `latest`, where `<version>` is the runtime version. | `linux/amd64`, `linux/arm64` |
| `aws-<role>`, `azure-<role>`, `gcp-<role>`, `oci-<role>` with `<role>` one of `cluster`, `machine`, `machinepool` | The `build` workflow of each repository | `edge-<runtime>` on a push to `main`; `vX.Y.Z-<runtime>` and `<runtime>` on a `vX.Y.Z` tag. `<runtime>` is `opentofu` or `terraform`. | `linux/amd64`, `linux/arm64` |
| `openstack-<role>` with `<role>` one of `cluster`, `machine` | The `build` workflow | The same scheme as the other clouds. | `linux/amd64`, `linux/arm64` |
| `noop-<role>` with `<role>` one of `cluster`, `machine`, `machinepool` | The `build` workflow | The same scheme as the cloud modules. | `linux/amd64`, `linux/arm64` |

What exists today follows from those triggers:

- **The provider image is published by the `publish` workflow** on every push to `main` (`:edge` and `:sha-<commit>`) and on every release tag (`:vX.Y.Z`); `workflow_dispatch` republishes `:edge`. No release has been made yet, so no `:vX.Y.Z` tag exists. Until one does, use `:edge` or pin a `:sha-<commit>` tag or a digest. To build your own, use `make docker-build` and `make docker-push IMG=...`. A maintainer can fall back to `make release` when CI cannot run; see [Releasing](<https://captf.io/docs/developer-guide/releasing/#manual-fallback>).
- **The base images are published on every push to `main`** and weekly, so they exist now. See [Base Images](<https://captf.io/docs/module-author/base-images/#tags-and-pinning>) for how to pin them.
- **The module images publish `edge-<runtime>` from every push to `main`.** The `vX.Y.Z-<runtime>` and `<runtime>` tags appear only when a `vX.Y.Z` tag is pushed, so before the first module release only the `edge-` tags are available. Pin a release tag or a digest in anything you keep.

Every pushed module and base image carries an SBOM and provenance attestations (`mode=max`), and the manifests carry the `org.opencontainers.image.*` title, description and licence annotations. The provider image has its own scheme: every pushed digest gets a keyless cosign signature, a SLSA provenance attestation and an SPDX SBOM attestation, and its manifests carry the `org.opencontainers.image.*` source, revision, version, licenses and description annotations and labels. See [Releasing](<https://captf.io/docs/developer-guide/releasing/#signatures-and-attestations>) for the verification commands.

## Release assets

A provider release, created by the `publish` workflow when a release tag is pushed, attaches these files to the GitHub release:

| Asset | Source |
| --- | --- |
| `infrastructure-components.yaml` | `config/default` rendered by kustomize, with the manager image pinned by digest. |
| `metadata.yaml` | The file at the repository root: the clusterctl release series. |
| `cluster-template.yaml`, `cluster-template-clusterclass.yaml`, `clusterclass-noop.yaml`, `identity.yaml` | The [`templates/`](<https://github.com/captf-io/cluster-api-provider-terraform/tree/main/templates>) directory. |
| `tfcapi-lint-<os>-<arch>` and `tfcapi-lint-checksums.txt` | GoReleaser, configured in [`.goreleaser.yaml`](<https://github.com/captf-io/cluster-api-provider-terraform/blob/main/.goreleaser.yaml>). It builds the linter only, not the image. |
| `provenance.intoto.jsonl` | The provenance attestation bundle for the assets above. Every asset also has a provenance attestation in GitHub. |

The `publish` workflow runs `make release-assets` and `make release-github` on the tag push; `make release` is the manual fallback. The steps and the checklist are in [Releasing](<https://captf.io/docs/developer-guide/releasing/#assets>). The module and base repositories attach no release assets: their output is the images above.

## Versioning at a glance

| Repository | Version scheme | Owned by |
| --- | --- | --- |
| `cluster-api-provider-terraform` | Tags `vX.Y.Z` and `vX.Y.Z-rc.N`. `metadata.yaml` lists the clusterctl release series, append-only, currently `0.1` on contract `v1beta2`. | [Releasing](<https://captf.io/docs/developer-guide/releasing/index.md>) |
| `opentofu-base`, `terraform-base` | Not tagged in git. The image tags follow the runtime version (`1.12.6`, `1.12`), with a date-stamped build tag. | [Tags and pinning](<https://captf.io/docs/module-author/base-images/#tags-and-pinning>) |
| `<cloud>-modules`, `noop-modules` | Tags `vX.Y.Z`. Image tags add the runtime: `vX.Y.Z-opentofu`, `vX.Y.Z-terraform`. | [Releasing a Module](<https://captf.io/docs/module-author/releasing/index.md>) |

Which provider, Cluster API and runtime versions are tested together is in [Compatibility](<https://captf.io/docs/operator-guide/compatibility/index.md>).

## Shared across repositories

Every repository carries the same `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md` and `LICENSE.md`, and every source file is Apache-2.0 licensed with a license header that CI checks. The provider also has a `SECURITY_CONTACTS` file. The [`.github`](<https://github.com/captf-io/.github>) repository holds the organization’s community health files, and its `make readme` target keeps the banner, status note and footer of each repository’s README identical. See [Working Across Repositories](<https://captf.io/docs/developer-guide/cross-repo/index.md>) for changes that span repositories, and [Contributing](<https://captf.io/docs/developer-guide/contributing/index.md>) for how to contribute.

> [!NOTE]
>
> **See also**
>
> - [Working Across Repositories](<https://captf.io/docs/developer-guide/cross-repo/index.md>)
> - [Releasing](<https://captf.io/docs/developer-guide/releasing/index.md>)
> - [Base Images](<https://captf.io/docs/module-author/base-images/index.md>)
> - [Releasing a Module](<https://captf.io/docs/module-author/releasing/index.md>)
> - [Cloud Modules](<https://captf.io/docs/cloud-modules/index.md>)
