8000 GitHub - glueckkanja/gkvm-tools: Toolchain, profiles and reusable workflows for glueckkanja verified modules (GKVM) · GitHub
[go: up one dir, main page]

Skip to content

About

Toolchain, profiles and reusable workflows for glueckkanja verified modules (GKVM)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

gkvm-tools

Toolchain for glueckkanja verified modules (GKVM): Terraform/OpenTofu modules that follow the Azure Verified Modules (AVM) conventions but are not limited to Azure providers.

It replaces the AVM make targets and the mcr.microsoft.com/azterraform image, whose upstream (Azure/tfmod-scaffold, Azure/avm-terraform-governance) is archived. Everything here is owned by glueckkanja, pinned, signed, and works for azurerm/azapi as well as integrations/github or any other provider.

What you get

Piece Where Purpose
Container image ghcr.io/glueckkanja/gkvm-tools every tool, versions pinned in versions.env, cosign-signed
Make targets Makefile, scripts/ pre-commit, pr-check, fmt, fix, docs, validate, tflint, test-*
Profiles profiles/{base,azure,github} tflint rulesets per provider family, terraform-docs default
Reusable workflows .github/workflows/terraform-module.yml, release.yml, sweep-github-sandbox.yml the CI a module repository calls
Templates templates/ files to drop into a module repository
Fixtures fixtures/ minimal modules the image is self-tested against

Using it in a module repository

  1. Copy templates/ into the repository (see templates/README.md).
  2. Run ./gkvm pre-commit once and commit the result. avmfix and terrafmt will reorder blocks the first time.
  3. Open a pull request; the PR Check workflow runs the same targets inside the image.
./gkvm pre-commit   # fmt + fix + docs, writes files
./gkvm pr-check     # everything CI runs, read-only
./gkvm tflint       # a single target
./gkvm help

The wrapper runs the image with Docker (or CONTAINER_RUNTIME=podman). Inside the devcontainer the same commands run natively.

Targets

Target Writes What it does
fmt / fmtcheck yes / no tofu fmt -recursive
fix / fixcheck yes / no avmfix block ordering for root, modules/*, examples/*; terrafmt for HCL in markdown
docs / docscheck yes / no terraform-docs for every scope; check uses --output-check and never writes
validate no init -backend=false + validate for every scope
tflint no profile ruleset per scope kind (root, module, example); warnings fail
test-unit no tofu test -test-directory=tests/unit (mock providers, no credentials)
test-integration no tofu test -test-directory=tests/integration (real providers)
test-examples no plan every example; GKVM_E2E=1 applies and always destroys; .e2eignore skips
zizmor no audit .github/
pre-commit yes fmt, fix, docs
pr-check no fmtcheck, fixcheck, docscheck, validate, tflint, test-unit, zizmor

Scopes are the repository root, every modules/* and every examples/* directory that contains .tf files.

Unique names in examples

test-examples exports TF_VAR_gkvm_suffix, a short random string that is stable for one run. An example that creates objects in a shared namespace declares the input and builds its names from it:

variable "gkvm_suffix" {
  type    = string
  default = "local"
}

locals {
  name = "gkvm-e2e-something-${var.gkvm_suffix}"
}

Use this rather than a random_string resource whenever the name ends up in a for_each key. Those keys must be known at plan time, and a resource attribute is not; an input is. Override the value with GKVM_SUFFIX. Examples that do not declare the variable ignore it.

Profiles

The profile is detected from the root required_providers: azurerm, azapi or azuread selects azure, integrations/github selects github, anything else base. Override with GKVM_PROFILE or profile: in .gkvm.yml.

  • base: tflint-ruleset-terraform (recommended preset plus the AVM-era generic rules). Structural conventions (variables in variables*.tf, outputs in outputs*.tf, ordering) are enforced by avmfix.
  • azure: base plus Azure/tflint-ruleset-avm v1. Rules the fleet already complies with are blocking. Rules AVM added later run at severity notice: reported, not blocking. Promote them per repository with an override. avm_provider_azurerm_disallowed and avm_provider_modtm_version_constraint are off by policy: GKVM modules use azurerm and ship no Microsoft telemetry.
  • github: base. No provider-specific ruleset exists yet.

Overrides: .gkvm/tflint.{root,module,example}.override.hcl is merged over the profile file with hclmerge (override semantics). The legacy AVM names avm.tflint.override.hcl, avm.tflint_module.override.hcl and avm.tflint_example.override.hcl still work.

terraform-docs config resolution per scope: <scope>/.terraform-docs.yml, then the parent directory (examples/, modules/), then the repository root, then the profile default.

CI

terraform-module.yml runs every job inside the image, so CI and laptop execute the same scripts.

Job Credentials Runs
static none fmtcheck, fixcheck, docscheck, tflint, zizmor
validate none validate
unit none test-unit
discover + examples environment: test plan (examples: smoke) or apply and destroy (examples: e2e) per example, matrix
complete none single required status check

Inputs: profile (auto), binary (tofu), examples (off), environment (test), image, runs-on.

Callers use secrets: inherit: the per-repository ARM_CLIENT_ID_OVERRIDE, ARM_TENANT_ID_OVERRIDE and ARM_SUBSCRIPTION_ID_OVERRIDE secrets live on the test environment and only resolve inside the called job that declares that environment. They win over the organisation-wide ARM_CLIENT_ID, ARM_TENANT_ID, ARM_SUBSCRIPTION_ID. Azure examples authenticate with OIDC: the providers exchange the Actions token themselves (ARM_USE_OIDC=true) using the organisation secrets ARM_CLIENT_ID, ARM_TENANT_ID, ARM_SUBSCRIPTION_ID. The Entra app needs a federated credential whose subject matches repo:glueckkanja/<repo>:environment:test, or one flexible federated credential matching all GKVM repositories. GitHub examples run against a sandbox organisation, configured on the test environment. Only the App private key is a secret:

Name Kind Purpose
GKVM_GITHUB_OWNER variable the sandbox organisation
GKVM_GITHUB_APP_ID variable GitHub App id
GKVM_GITHUB_APP_INSTALLATION_ID variable the App's installation on that organisation
GKVM_GITHUB_APP_PEM_FILE secret the App private key, contents not a path
GKVM_GITHUB_TOKEN secret a personal access token instead of the App
GKVM_GITHUB_BASE_URL variable only for GitHub Enterprise Server or GHEC with data residency

Prefer the App: its tokens are short-lived and belong to no person. The provider picks App credentials over a token on its own.

A live GitHub example needs organisation-wide write in that organisation, because creating a repository, setting organisation custom property values and managing teams cannot be scoped to a single repository. Point it at an organisation that holds nothing but test resources, and put a required reviewer on the test environment.

release.yml publishes a GitHub release with generated notes on a vX.Y.Z tag; tags with a hyphen become pre-releases.

sweep-github-sandbox.yml deletes leftovers of cancelled GitHub e2e runs from the sandbox organisation: repositories and teams matching a name prefix and older than max_age_hours, plus organisation rulesets and custom property definitions matching the prefix. It defaults to dry_run: true, refuses a prefix shorter than five characters, and skips the organisation-level objects entirely while a prefixed repository or team is younger than the cutoff, because that means a run may still be in flight. Those two endpoints expose no creation timestamp, which is why they cannot be age-gated themselves. One caller per organisation is enough.

Names starting with gkvm-fixture- or gkvm_fixture_ are never deleted, whatever the prefix: they mark permanent fixtures of the sandbox, such as a custom property definition an example targets instead of creating. GitHub answers a property definition delete with a 500 while still performing it, so a failed property delete only counts as failed if the definition is still listed afterwards.

Image

Built by release-image.yml for linux/amd64 and linux/arm64 on every vX.Y.Z tag, pushed to GHCR with the tags X.Y.Z, X.Y, vX (currently v0) and sha-…, signed with cosign (keyless) and attested with build provenance.

Verify a pull:

cosign verify ghcr.io/glueckkanja/gkvm-tools:v0 \
  --certificate-identity-regexp='^https://github.com/glueckkanja/gkvm-tools/' \
  --certificate-oidc-issuer=https://token.actions.githubusercontent.com

Releasing: bump versions.env if needed, set the image default in .github/workflows/terraform-module.yml and the checkout ref in .github/workflows/sweep-github-sandbox.yml to the new version, commit, tag vX.Y.Z, push the tag. Then pin templates/ to the tag's commit SHA in a follow-up commit.

Tools inside (gkvm versions): OpenTofu, Terraform, tflint (plugins pre-installed for every profile), terraform-docs, terrafmt, avmfix, hclmerge, zizmor, git, jq, make. Versions live in versions.env; bump them in a pull request, tag, done.

Developing gkvm-tools

ci.yml runs shellcheck and zizmor (auditor persona, over .github/ and templates/.github/; .pre-commit-config.yaml runs the same check locally), builds the image for the runner and runs pr-check and pre-commit against every directory in fixtures/. To run the scripts without the image:

export GKVM_HOME=$PWD
cd fixtures/github-basic
make -f "$GKVM_HOME/Makefile" pr-check

Design notes

  • No runtime downloads. AVM's Makefile curled scripts and tflint configs on every run; everything here ships in the image at a pinned version.
  • Provider-neutral core, provider-specific profiles. Adding a provider family means adding a profiles/<name>/ directory and one line in gkvm_profile.
  • Native tofu test instead of the Go-based avmtester, so unit and integration tests are written the same way for every provider.
  • Read-only checks are really read-only: docscheck uses --output-check, fixcheck diffs a scratch copy.
  • Microsoft's replacement, Avm.Authoring with the azure-verified-modules-tools reusable workflow, stays Azure-bound (metadata schema, managed-file sync, subscription round-robin). Its ideas (pins manifest, verb chain, scope discovery) are reused here without the dependency.

About

Toolchain, profiles and reusable workflows for glueckkanja verified modules (GKVM)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

0