Gromit is the template generation and policy management tool that produces CI/CD workflows, Dockerfiles, and GoReleaser configurations for Tyk repositories.
Install from the releases page. To keep up with releases using zinit in turbo mode,
zinit wait lucid from"gh-r" nocompile for \
bpick"*Linux_x86_64.tar.gz" TykTechnologies/gromitThis is ostensibly a cobra app and can be configured with a config file to save a bunch of typing. The embedded config.yaml contains the configuration that drives the templates.
All parameters can also be set by environment variables with the GROMIT_ prefix. So the environment variable for the config parameter cluster.domain would be GROMIT_CLUSTER_DOMAIN.
To various degrees of competence, gromit can:
- manage templated files that can be rendered into any repo under management
- releng
- gpac (github policy as code)
- fetch developer licenses for dashboard and mdcb
- generate config files from a
text/template - dump redis and mongo data for a classic cloud org to local disk (broken)
- restore redis and mongo data for a classic cloud org from local disk (broken)
Policies are implemented by rendering template bundles, which are usually embedded into the binary. The rendering is mere text substitution and is agnostic to the language used in the template. It is best to use declarative or some sort of well-understood configuration language like YAML in the templates though.
This bundle contains all of the code required to build and test all the artefacts that are created when a release is made. Releases are made by pushing a tag to github.
This bundle implements terraform manifests that model the state of the repos under management in github. This is used to keep track of release branches as they are created.
% gromit help
It also has a grab bag of various ops automation.
Each gromit command has its own config section. For instance, the policy command uses the policy key in the config file. Config values can be overridden by environment variables. For instance, policy.prefix can be overridden using the variable $GROMIT_POLICY_PREFIX.
Usage:
gromit [command]
Available Commands:
bundle Operate on bundles
completion Generate completion script
git Top-level git command, use a sub-command to perform an operation
help Help about any command
licenser Get a trial license and writes it to path, overwriting it
orgs Dump/restore org keys and mongodb
passwd Returns the password hash of the given plaintext
policy Templatised policies that are driven by the config file
version Print version
Flags:
-f, --conf string YAML config file. If not supplied, embedded defaults will be used
-h, --help help for gromit
--loglevel string Log verbosity: trace, debug, info, warn, error/fatal (default "info")
--textlogs Logs in plain text (default true)
Use "gromit [command] --help" for more information about a command.All tests in the cmd directory are system tests. Tests in other directories are unit tests. make test runs the tests and requires access to the Engg PoC AWS account.
If your AWS account does not have the power to run the tests, please find us on Slack.
The Release action builds a new docker image.
| Term | Meaning |
|---|---|
buildenv |
The tykio/golang-cross image tag used for cross-compilation (e.g., 1.25-bullseye) |
| CGO | C-Go interop — binaries that link against C libraries (e.g., gateway, dashboard) |
| PGO | Pure Go — statically linked binaries with no C dependencies (e.g., pump, sink) |
| DHI | Docker Hardened Images — commercially supported base images from Docker with FIPS, SBOM, and provenance attestations |
pcrepo |
Packagecloud repository for uploading deb/rpm packages |
csrepo |
Cloudsmith Docker registry |
cirepo |
ECR (AWS) CI registry for internal builds |
dhrepo |
DockerHub registry |
| Feature | A flag that controls which templates get rendered and which builds are included |
https://github.com/TykTechnologies/gromit
gh repo clone TykTechnologies/gromit /tmp/gromit
cd /tmp/gromit
go build ./...
go test ./policy/...go run . policy gen /tmp/output --repo tyk --branch master
go run . policy gen /tmp/output --repo tyk --branch release-5.12
go run . policy gen /tmp/output --repo tyk-analytics --branch master# 1. Generate the output
go run . policy gen /tmp/output --repo tyk --branch master
# 2. In the target repo, create a branch
cd /path/to/tyk
git checkout -B feat/my-change origin/master
# 3. Copy the generated files
cp /tmp/output/ci/Dockerfile.distroless ci/Dockerfile.distroless
cp /tmp/output/ci/goreleaser/goreleaser.yml ci/goreleaser/goreleaser.yml
cp /tmp/output/.github/workflows/release.yml .github/workflows/release.yml
# 4. Commit and push
git add ci/Dockerfile.distroless ci/goreleaser/goreleaser.yml .github/workflows/release.yml
git commit -m "chore: update gromit-generated files"
git push -u origin feat/my-change
# 5. Create PR
gh pr create --base master --title "chore: update gromit-generated files"The Go version is controlled by buildenv. It sets the tykio/golang-cross image tag.
For all repos in a group:
cgo-services:
buildenv: 1.25-bullseyeFor a specific branch only:
branches:
release-5.12:
buildenv: 1.25-bullseyeVerify the image exists before committing:
docker manifest inspect tykio/golang-cross:1.25-bullseyeThen regenerate and confirm:
go run . policy gen /tmp/check --repo tyk --branch master
grep "golang_cross" /tmp/check/.github/workflows/release.ymlAdd the branch with its features. Builds are inherited from repo level automatically:
release-5.13:
buildenv: 1.25-bullseye
features:
- release-test
- distroless
- fipsAdd fips to the features list to enable, omit it to disable:
# FIPS enabled
release-5.12:
features:
- release-test
- distroless
- fips
# FIPS disabled
release-5.10:
features:
- release-test
- distrolessThe fips build must be defined at repo level with feature: fips. It is only included in branches where fips is in the features list.
Use case: EE on release-5.12 should use distroless instead of DHI.
release-5.12:
builds:
ee:
dockerbaseimage: distroless # use default distroless base
archs:
- go: amd64
deb: amd64
docker: linux/amd64
- go: arm64
deb: aarch64
docker: linux/arm64
- go: s390x
deb: s390x
docker: linux/s390x
features:
- release-test
- distroless
- fipsSetting dockerbaseimage: distroless tells the template to use the default distroless image rather than the repo-level custom base image. This is a sentinel value — the template checks for it and does not pass BASE_IMAGE to Docker.
Example: adding a PAYG build to tyk gateway.
# At repo level under tyk.builds:
payg:
feature: payg # only on branches with "payg" in features
flags:
- -tags=goplugin,ee,payg
buildpackagename: tyk-gateway-payg
pcrepo: tyk-ee-unstable
dhrepo: tykio/tyk-gateway-payg
cirepo: tyk-payg
description: >-
Tyk Gateway Pay-As-You-Go Edition
imagetitle: Tyk Gateway PAYG
archs:
- go: amd64
deb: amd64
docker: linux/amd64
- go: arm64
deb: aarch64
docker: linux/arm64Then add payg to the features of branches that need it.
For all builds (distroless default):
distrolessbaseimage: base-debian13:latestFor specific builds (DHI override):
ee:
dockerbaseimage: tykio/dhi-busybox:1.37-fipsUse skipdocker: true. Packages (.deb/.rpm) are still built.
archs:
- go: s390x
deb: s390x
docker: linux/s390x
skipdocker: truefips:
env:
- GOFIPS140=v1.0.0Each build can publish to multiple registries:
| Field | Registry | Example |
|---|---|---|
dhrepo |
DockerHub | tykio/tyk-gateway |
csrepo |
Cloudsmith | docker.tyk.io/tyk-gateway/tyk-gateway |
cirepo |
ECR (CI) | tyk |
Add the field to the build definition. No template changes needed:
std:
dhrepo: tykio/tyk-pump
csrepo: docker.tyk.io/tyk-pump/tyk-pump # add this line-
Choose the group:
cgo-services(needs CGO) orpgo-services(pure Go). -
Add the repo to
config/config.yaml:
pgo-services:
repos:
my-new-service:
binary: my-new-service
packagename: tyk-my-new-service
configfile: my-new-service.conf
versionpackage: github.com/TykTechnologies/my-new-service/version
builds:
std:
buildpackagename: tyk-my-new-service
pcrepo: tyk-my-new-service-unstable
dhrepo: tykio/tyk-my-new-service
cirepo: my-new-service
description: >-
My New Service
imagetitle: Tyk My New Service
archs:
- go: amd64
deb: amd64
docker: linux/amd64
- go: arm64
deb: aarch64
docker: linux/arm64
branches:
master:
features:
- release-test
- distroless- Generate and verify:
go run . policy gen /tmp/output --repo my-new-service --branch master
ls /tmp/output/Checklist:
- Packagecloud repos exist
- DockerHub repo exists
- ECR repo exists (if using
cirepo) -
versionpackagematches the Go source -
configfilematches the binary's expected config
upgradefromver: 5.0.0This sets which old version is installed from the stable packagecloud repo during smoke tests.
# 1. Run tests
go test ./policy/... -count=1
# 2. Generate and inspect
go run . policy gen /tmp/output --repo tyk --branch master
# 3. Check key values
grep "golang_cross" /tmp/output/.github/workflows/release.yml
head -5 /tmp/output/ci/Dockerfile.distroless
grep "BASE_IMAGE" /tmp/output/.github/workflows/release.yml
# 4. If your change affects multiple branches, test them all
for branch in master release-5.12 release-5.11; do
go run . policy gen /tmp/output-$branch --repo tyk --branch $branch
echo "=== $branch ==="
grep "golang_cross\|BASE_IMAGE" /tmp/output-$branch/.github/workflows/release.yml
doneWhen changes are merged to gromit's main branch, the policy sync command runs automatically. This generates output for every repo and branch, and creates or updates PRs in each target repo.
To run sync manually:
go run . policy sync --repo tyk # single repo
go run . policy sync # all reposgh pr list --repo TykTechnologies/tyk --search "gromit" --state open# Revert in gromit
git revert <commit-sha>
git push
# Sync will create corrective PRs, or run manually:
go run . policy sync --repo tykTemplates live in policy/templates/<feature>/. Before editing, understand the blast radius — a template change affects every repo and branch that has the feature enabled.
grep -B10 "features:" config/config.yaml | grep -A10 "<feature-name>"for repo in tyk tyk-analytics tyk-pump portal; do
go run . policy gen /tmp/output-$repo --repo $repo --branch master 2>/dev/null
echo "=== $repo: $(grep -c 'BASE_IMAGE' /tmp/output-$repo/.github/workflows/release.yml 2>/dev/null) BASE_IMAGE refs ==="
done{{range}}changes the dot context —.inside a range is the current element. Use$r := .before the range to preserve access to the root.- Adding a field that doesn't exist for all repos causes
missingkey=errorpanics. - YAML is whitespace-sensitive.
{{-trims preceding whitespace,-}}trims following.
Do not modify generated files. Instead:
- Preferred: add the step to the gromit template so it's generated for all repos.
- Alternative: create a separate workflow file (e.g.,
.github/workflows/custom-tests.yml) that is not managed by gromit. Generated files are marked with# Generated by: gromit policy.
panic: template: goreleaser.gotmpl:380: unexpected {{end}}
Mismatched {{if}} / {{range}} / {{end}} blocks in the template file.
A conditional is evaluating to false. Add temporary debug output to the template:
{{/* DEBUG */}} features={{ .Branchvals.Features }}
Generate, check the output, then remove the debug line.
The build has feature: <name> set, and that feature is not in the branch's features list. Check both:
grep -A2 "feature:" config/config.yaml # find the required feature
grep -A5 "release-5.12:" config/config.yaml # check branch featuresEmpty strings don't override in mergo. Use a sentinel value. For example, dockerbaseimage: distroless tells the template to use the default:
{{- if and $bv.DockerBaseImage (ne $bv.DockerBaseImage "distroless") }}
BASE_IMAGE={{ $bv.DockerBaseImage }}
{{- end }}
The central config is at config/config.yaml with a three-level hierarchy:
policy:
groups:
<group>: # e.g., cgo-services, pgo-services
buildenv: ... # Group-level defaults
baseimage: ...
distrolessbaseimage: ...
features: [...]
repos:
<repo>: # e.g., tyk, tyk-analytics
builds: # Repo-level build definitions
std: ...
ee: ...
fips: ...
branches:
master: # Branch-level overrides
features: [...]
Values cascade: group → repo → branch. Branch-level values override repo-level, which override group-level.
- Most fields: later levels override earlier (empty values do not override)
- Builds: branch-level fields merge into repo-level fields for the same build name
- Features: unioned across all levels
Features control which template directories get rendered and provide conditional logic in templates.
| Feature | What it provides |
|---|---|
releng |
Release workflow, goreleaser config, Dockerfile.std, install scripts |
distroless |
Dockerfile.distroless (used instead of Dockerfile.std) |
release-test |
Smoke tests, upgrade tests in release workflow |
fips |
Enables FIPS build variants (builds with feature: fips) |
nightly-e2e |
Nightly end-to-end test workflow |
el7-pgo-build |
Legacy EL7 build support |
ai-studio-frontend-build |
Frontend build step for AI Studio |
default-distros |
Uses hardcoded distro list instead of TUI service |
policy/templates/
├── distroless/ # Feature: distroless
│ └── ci/Dockerfile.distroless
├── releng/ # Feature: releng
│ ├── ci/
│ │ ├── Dockerfile.std
│ │ └── goreleaser/goreleaser.yml
│ └── .github/workflows/
│ ├── release.yml
│ └── release.yml.d/ # Sub-templates
│ ├── goreleaser.gotmpl
│ ├── smoke-tests.gotmpl
│ └── ...
├── subtemplates/ # Available to ALL templates
│ └── goreleaser.yml.d/
│ ├── builds.gotmpl
│ ├── nfpm.gotmpl
│ └── ...
├── nightly-e2e/
├── el7-pgo-build/
└── test-square/
Templates use Go text/template with Sprig functions.
These files are marked with # Generated by: gromit policy. Never edit them directly.
| File | Feature |
|---|---|
ci/Dockerfile.distroless |
distroless |
ci/Dockerfile.std |
releng |
ci/goreleaser/goreleaser.yml |
releng |
.github/workflows/release.yml |
releng |
ci/bin/pc.sh |
releng |
ci/bin/unlock-agent.sh |
releng |
ci/install/*.sh |
releng |
| Repo | Group | CGO | FIPS | Branches |
|---|---|---|---|---|
| tyk | cgo-services | Yes | Yes | master, release-5.8 through 5.12 |
| tyk-analytics | cgo-services | Yes | Yes | master, release-5.8 through 5.12 |
| portal | cgo-services | Yes | Yes | master |
| ai-studio | cgo-services | Yes | No | main |
| tyk-pump | pgo-services | No | Yes | master |
| tyk-sink | pgo-services | No | Yes | master |
| tyk-identity-broker | pgo-services | No | No | master |
Not managed by gromit: tyk-operator-internal, midsommar
| Field | Purpose | Example |
|---|---|---|
flags |
Go build flags | ["-tags=goplugin,ee"] |
buildpackagename |
Package name for deb/rpm | tyk-gateway-ee |
dockerbaseimage |
Docker base image override | tykio/dhi-busybox:1.37-fips |
feature |
Feature gate for this build | fips |
pcrepo |
Packagecloud repo for uploads | tyk-ee-unstable |
upgraderepo |
Packagecloud repo for upgrade tests | tyk-gateway |
dhrepo |
DockerHub image name | tykio/tyk-gateway-ee |
csrepo |
Cloudsmith image name | docker.tyk.io/tyk-gateway/tyk-gateway-ee |
cirepo |
ECR CI repo name | tyk-ee |
description |
OCI image description | |
imagetitle |
OCI image title | |
env |
Build environment variables | ["GOFIPS140=v1.0.0"] |
archs |
Target architectures |
| Field | Purpose | Example |
|---|---|---|
go |
GOARCH value | amd64 |
deb |
Debian arch name | aarch64 |
docker |
Docker platform | linux/arm64 |
skipdocker |
Skip Docker image for this arch | true |
| Variable | Description |
|---|---|
.Name |
Repo name |
.Branch |
Branch name |
.Binary |
Binary name |
.PackageName |
Package name |
.Branchvals.Buildenv |
Go cross-compile image tag |
.Branchvals.BaseImage |
Debian base for deb stage |
.Branchvals.DistrolessBaseImage |
Distroless base image |
.Branchvals.Features |
Active features |
.Branchvals.Builds |
Build variants |
.Branchvals.Cgo |
CGO enabled |
.Branchvals.ConfigFile |
App config filename |
| Function | Description |
|---|---|
GetDockerBuilds |
Returns builds with Docker registry configs |
GetDockerPlatforms |
Returns Docker platforms (respects skipdocker) |
GetCC target host |
Returns cross-compiler name |
GetImages "DHRepo" "CSRepo" |
Returns image names for given registries |
HasBuild "fips" |
Checks if a build exists |
has "feature" .Features |
Checks if a feature is active (Sprig) |