Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
23c3e22
CI-3567: Design Release CRD (#413)
goelozev Dec 8, 2025
3302da1
CI-3567: Release CR webhooks (#414)
goelozev Dec 12, 2025
98c2367
CI-3567: Release CRD conditions (#422)
goelozev Dec 18, 2025
50f1a4b
Release controller boilerplate (#430)
goelozev Dec 19, 2025
ca32a10
Add Rollback CRD (#412)
goelozev Jan 6, 2026
3e94d94
Add rollback controller boilerplate (#436)
IsaacJames Jan 8, 2026
c9a64fb
Add pkg/cicd Deployer interface and Github implementation (#437)
IsaacJames Jan 12, 2026
63b28c9
Update ginkgo to v2 (#439)
0x0013 Jan 12, 2026
d429933
Add rollback controller reconcile loop (#438)
IsaacJames Jan 16, 2026
0b19fe2
Add deploy package runner (#442)
IsaacJames Jan 19, 2026
0967fb4
Release Reconciler (#443)
goelozev Jan 21, 2026
063f262
Remove status.nextRelease from the Release CRD (#444)
goelozev Jan 21, 2026
9be9266
Use helpers in rollback controller tests (#446)
IsaacJames Jan 21, 2026
3250851
Use pkg/recutil in rollback controller (#445)
IsaacJames Jan 21, 2026
8b6b4bc
Release controller: Add permissions to create/patch events (#447)
goelozev Jan 22, 2026
fe1d5cf
Release controller: fix name uniqueness flag default value + CRD full…
goelozev Jan 22, 2026
aa5bd2a
Release/rollback CRD FQDN updates (#449)
goelozev Jan 22, 2026
7205c5a
Add CreateRollback & GetRelease runners (#450)
goelozev Jan 26, 2026
2c76fe4
refactor(deploy): use table tests for deploy helpers (#453)
0x0013 Jan 29, 2026
90e5f63
Implement Analysis Templater (#452)
0x0013 Feb 3, 2026
bb2edc3
fix(analysis): no-global annotation key (#456)
0x0013 Feb 4, 2026
e63d255
CI-3722: Add RollbackTargetWebhook mutating webhook (#454)
IsaacJames Feb 5, 2026
03aa057
fix(release-manager): conditionally add of analysis schema (#458)
0x0013 Feb 5, 2026
6cdb6da
Rollback CRD: adding printer columns (#457)
goelozev Feb 5, 2026
937b9b6
fix: add missing rollback-mutate webhook resource (#459)
IsaacJames Feb 5, 2026
e621738
CI-3767: make Rollback ToReleaseRef immutable (#460)
IsaacJames Feb 5, 2026
451b796
Add release-manager analysis permissions (#461)
0x0013 Feb 6, 2026
d50e431
GitHub Deployer: parsable templates in deployment options (#451)
goelozev Feb 6, 2026
d421e6b
Rollback CRD: adding "Age" printer column (#462)
goelozev Feb 6, 2026
f09e77f
fix(analysis): add health/rollback labels from template (#463)
0x0013 Feb 6, 2026
b48b2a1
Set Release owners for Rollback resources (#464)
IsaacJames Feb 9, 2026
50f34f7
CI-3697 Allow configurable release culling (#455)
goelozev Feb 10, 2026
feb5d12
Release: add missing permissions needed for culling (#465)
goelozev Feb 10, 2026
62251fd
AutomatedRollbackPolicy CRD (#466)
goelozev Feb 19, 2026
af8ddb2
Add Target field to ReleaseReference (#469)
IsaacJames Feb 20, 2026
0fdc639
Rollback: validating webhook (#471)
goelozev Feb 23, 2026
dca19f0
Change ownership on Rollback resources (#468)
goelozev Feb 23, 2026
839e06a
Adding specific service label selectors (#473)
goelozev Feb 24, 2026
aa46774
AutomatedRollbackPolicy: fix printer columns (#474)
goelozev Feb 25, 2026
56818f1
Add rollback prometheus counter (#477)
IsaacJames Mar 2, 2026
abf797a
Simplify AutomaticRollbackPolicy (#479)
goelozev Mar 3, 2026
8d9251a
Adding deploy runner helpers for AutomatedRollbackPolicy (#478)
goelozev Mar 4, 2026
4e9e3b8
Fix: automated rollback policy runner helpers (#480)
goelozev Mar 5, 2026
87036b2
Deploy runner: list rollbacks (#481)
goelozev Mar 9, 2026
5264f24
fix: github deployment URL (#482)
IsaacJames Mar 9, 2026
017d914
Automated rollback controller (#467)
goelozev Mar 11, 2026
69b8abc
Shorthand names for Release and AutomatedRollbackPolicy (#485)
goelozev Mar 11, 2026
244ef13
AutomatedRollbackPolicy: validating webhook (#484)
goelozev Mar 13, 2026
1f800ad
fix(runner): update ginkgo to v2
0x0013 Mar 13, 2026
aa678e5
fix: incorrect status update when retrying deployments (#486)
goelozev Mar 16, 2026
5876ee7
fix: wrongly re-enabling of automated rollbacks when trigger conditio…
goelozev Mar 16, 2026
03c9fd9
AutomatedRollbackPolicy - adding rollback template (#489)
goelozev Mar 18, 2026
f9b158c
chore: export GenerateSignature function
IsaacJames Mar 18, 2026
8e99343
chore: improve rollback Github deployment description
IsaacJames Mar 19, 2026
95ce4f1
feat: more rollback metrics (#491)
IsaacJames Mar 19, 2026
a4c47de
Adding the `controller` label to rbac, vault & workloads controllers …
goelozev Apr 15, 2026
739d350
Adding Claude Code files to pre-release branch (#501)
goelozev May 6, 2026
c4114b5
Add eviction annotation for theatre-secrets-install
epatmalnieks-gc Jun 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 91 additions & 0 deletions .claude/agents/code-reviewer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
---
name: code-reviewer
description: Expert code review specialist for the Theatre Kubernetes extensions project. Reviews Go code, CRD definitions, controllers, webhooks, and Kubernetes manifests for quality, security, correctness, and adherence to project conventions.
tools: Read, Grep, Glob, Bash
model: inherit
---

You are a senior Go and Kubernetes engineer performing code reviews on the Theatre project — GoCardless' Kubernetes extensions repository (`github.com/gocardless/theatre/v5`).

## Project Context

Theatre provides Kubernetes operators & admission controller webhooks.

## How to get the diff

- If given a PR number: run `gh pr diff <number>` and `gh pr view <number>` for title/description context
- If given a branch name: `git diff <base_branch>...<head_branch>`
- Otherwise: `git diff <base_branch>...HEAD`

After getting the diff, identify all changed files and **read each one in full** to understand surrounding context before starting the review.

## When Invoked

1. Get the diff
2. Focus review on modified Go files, CRD types, controllers, webhooks, manifests, and tests
3. Begin the review immediately without preamble

## Review Checklist

### Go Code Quality

- Code is clear, idiomatic Go — follows standard patterns used elsewhere in the codebase
- Functions and variables are well-named and scoped appropriately
- No duplicated logic; shared helpers belong in `pkg/`
- Proper use of Go error handling (no swallowed errors, errors wrapped with context)
- Interfaces used appropriately; avoid over-abstraction
- Concurrency is safe (race-free); check mutex usage and goroutine lifecycle

### Kubernetes / Controller Patterns

- Controllers follow the reconcile loop pattern correctly (idempotent, returns `ctrl.Result`)
- Status conditions updated correctly; avoid patching the full object when a status patch suffices
- RBAC markers (`+kubebuilder:rbac:...`) present and correct for new resource access
- Webhook handlers validate inputs and return informative `admission.Denied` / `admission.Errored` responses
- CRD type changes include updated `+kubebuilder:validation:` markers where appropriate
- No direct `pods/exec` permissions granted unnecessarily (security-sensitive in this codebase)
- The `pkg/recutil` package is used across the board to standardise reconciliation patterns and event emission
- Follow the good practice guides in https://kubebuilder.io/reference/good-practices.html and https://github.com/kubernetes-sigs/controller-runtime/blob/main/FAQ.md. You might open any links in those pages, but do not open exceed going deeper than 2 levels.

### Security

- No secrets, API keys, or credentials hardcoded or logged
- Vault integration: secrets fetched at runtime, not embedded in images or manifests
- Admission webhooks fail closed (deny on error) where appropriate
- RBAC minimal-privilege: roles grant only required verbs/resources

### Testing

- New behaviour is covered by tests at the appropriate level (unit → integration → acceptance)
- Ginkgo tests use `Describe`/`Context`/`It` structure consistent with existing suites
- Integration tests use `envtest`; acceptance tests use the Kind cluster via `cmd/acceptance`
- No tests deleted or weakened without explicit justification

### Manifests & Kustomize

- CRD changes regenerated via `make manifests generate`
- Kustomize overlays reference versioned bases (`?ref=vX.Y.Z`)
- New CRDs included in both `config/crd` and referenced in `config/base` if needed

## Output format

```
## Code Review: <PR title or branch>

### 🔴 Critical Issues
- [file:line] <issue> — <why it matters and what to do>

### 🟡 Major Concerns
- [file:line] <issue> — <why it matters and what to do>

### 🔵 Minor Improvements
- [file:line] <suggestion> — <rationale>

### ✅ Positive Observations
- <noteworthy good practices>

### Summary & Next Steps
<1-3 sentence overall assessment and clear recommended actions>
```

Only include sections that have content. Always include file and line number. Explain _why_ each issue matters, not just what it is.
6 changes: 4 additions & 2 deletions .github/workflows/build-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ on:
pull_request:
branches:
- master
- pre-release-5.1.0
types:
- opened
- reopened
Expand All @@ -17,6 +18,7 @@ on:
push:
branches:
- master
- pre-release-5.1.0

workflow_dispatch:

Expand All @@ -29,7 +31,7 @@ jobs:
name: Set up Go
uses: actions/setup-go@v6
with:
go-version: 1.24.5
go-version: 1.25.5
- name: Ensure generated CRDs and manifests are up to date
run: make manifests && git diff --exit-code config/

Expand Down Expand Up @@ -68,7 +70,7 @@ jobs:
chmod a+x /usr/local/bin/kustomize /usr/local/bin/kubectl /usr/local/bin/kind
EOF
- name: Prepare the cluster
run: bin/acceptance.linux prepare --verbose && sleep 10
run: bin/acceptance.linux prepare --verbose && sleep 30
- name: Run acceptance tests
run: bin/acceptance.linux run --verbose
- name: Show all pods
Expand Down
41 changes: 41 additions & 0 deletions .github/workflows/claude-code-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Claude Code

on:
issue_comment:
types: [created]
pull_request_review_comment:
types: [created]
issues:
types: [opened, assigned]
pull_request_review:
types: [submitted]

jobs:
claude:
if: |
(github.event.comment.author_association == 'MEMBER' || github.event.comment.author_association == 'COLLABORATOR') &&
(
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
)
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
issues: write
id-token: write
actions: read # Required for Claude to read CI results on PRs
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 1

- name: Run Claude Code
id: claude
uses: anthropics/claude-code-action@3ac52d0da9f8ec9ca7b4dc23bb477e36ef9c77a9 # v1.0.79
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
claude_args: "--agent code-reviewer"
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ jobs:
fetch-depth: 0
- uses: actions/setup-go@v6
with:
go-version: 1.24.5
go-version: 1.25.5
- name: Create tag for new version
run: |
CURRENT_VERSION="v$(cat VERSION)"
Expand Down
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,7 @@ go.work
.vscode
*.swp
*.swo
*~
*~

# Ignore tmp folder files used by air
tmp/*
79 changes: 79 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Theatre — CLAUDE.md

## Project Overview

Theatre is GoCardless' Kubernetes extensions project, providing operators, admission controller webhooks, and supporting CLIs. The Go module is `github.com/gocardless/theatre/v5`.

## Repository Structure

- `api/` — CRD API types (RBAC, Vault, Workloads)
- `internal/` — Controllers and webhooks (unexported)
- `pkg/` — Shared/exported packages
- `cmd/` — CLI entry points (`rbac-manager`, `vault-manager`, `workloads-manager`, `theatre-consoles`, `theatre-secrets`, `acceptance`)
- `config/` — Kustomize manifests, CRDs, base configs

## Key API Groups

- **RBAC** (`rbac.crd.gocardless.com`) — `DirectoryRoleBinding`: provisions `RoleBinding`s from Google group members
- **Workloads** (`workloads.crd.gocardless.com`) — `Console`: temporary dedicated pods for operational tasks
- **Vault** (`vault.crd.gocardless.com`) — `secrets-injector` webhook for injecting Vault secrets into pods
- **Deploy** (`deploy.crd.gocardless.com`) — `Release`, `Rollback`, `AutomatedRollbackPolicy`: release management and rollback controls

## Build & Development Commands

```shell
make build # Build all binaries
make test # Run unit + integration tests (requires setup-envtest)
make lint # Run golangci-lint
make lint-fix # Run golangci-lint with auto-fix
make fmt # go fmt ./...
make vet # go vet ./...
make generate # Generate DeepCopy methods via controller-gen
make manifests # Generate CRDs/RBAC/Webhook configs via controller-gen
make acceptance-e2e # Full E2E: prepare Kind cluster + run + destroy
make acceptance-run # Run acceptance tests against existing cluster
make install-tools # Download all dev tool binaries into ./bin/
```

## Testing

Tests use [Ginkgo](https://onsi.github.io/ginkgo) and run with `-race -randomizeSuites -randomizeAllSpecs`.

**Setup before running tests:**

```shell
make install-tools
eval $(setup-envtest use -i -p env 1.24.x)
```

Three test levels:

- **Unit** — `make test` (fast, no cluster needed)
- **Integration** — `make test` (uses `envtest` with a temporary API server, no nodes)
- **Acceptance** — `make acceptance-e2e` (full Kind cluster, slow, used sparingly)

## Local Development Cluster (Kind)

```shell
make build
make test
make acceptance-e2e
# or step-by-step:
make prepare # provisions Kind cluster
make acceptance-run --verbose
make acceptance-destroy
```

Re-run `make acceptance-prepare` after any code changes to rebuild and redeploy images.

## Toolchain

- **Go**
- **controller-gen** — CRD/webhook/RBAC manifest generation
- **kustomize**
- **golangci-lint**
- **ginkgo**
- **setup-envtest** — manages `etcd`/`kube-apiserver` binaries for integration tests
- **kind** — Kubernetes-in-Docker for acceptance tests

All tool binaries are installed locally into `./bin/` via `make install-tools`.
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Build Go binary without cgo dependencies
FROM golang:1.24.5 as builder
FROM golang:1.25.5 as builder
WORKDIR /go/src/github.com/gocardless/theatre

COPY . /go/src/github.com/gocardless/theatre
Expand Down
10 changes: 5 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
PROG=bin/rbac-manager bin/vault-manager bin/theatre-secrets bin/workloads-manager bin/theatre-consoles
PROG=bin/rbac-manager bin/vault-manager bin/theatre-secrets bin/workloads-manager bin/theatre-consoles bin/release-manager bin/rollback-manager bin/automated-rollback-manager
PROJECT=github.com/gocardless/theatre
IMAGE=eu.gcr.io/gc-containers/gocardless/theatre
VERSION=$(shell git describe --tags --dirty --long)
Expand Down Expand Up @@ -58,7 +58,7 @@ vet: ## Run go vet against code.
go vet ./...

test: manifests generate fmt vet setup-envtest setup-ginkgo ## Run tests.
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" ginkgo -race -randomizeSuites -randomizeAllSpecs -r ./...
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) -p path)" ginkgo -race -randomize-suites -randomize-all -r ./...

acceptance-e2e: install-tools acceptance-prepare acceptance-run acceptance-destroy ## Requires the following binaries: kubectl, kustomize, kind, docker

Expand Down Expand Up @@ -99,7 +99,7 @@ bin/%: ## Build a binary
CGO_ENABLED=0 $(BUILD_COMMAND) -o $@ ./cmd/$*/.

clean: ## Clean up the build artifacts
rm -rvf $(PROG) $(PROG:%=%.linux) $(PROG:%=%.darwin) hack/boilerplate.go.txt
rm -rvf $(PROG) $(PROG:%=%.linux) $(PROG:%=%.darwin)

# If you wish to build the manager image targeting other platforms you can use the --platform flag.
# (i.e. docker build --platform linux/arm64). However, you must enable docker buildKit for it.
Expand Down Expand Up @@ -139,7 +139,7 @@ ENVTEST_VERSION ?= $(shell go list -m -f "{{ .Version }}" sigs.k8s.io/controller
#ENVTEST_K8S_VERSION is the version of Kubernetes to use for setting up ENVTEST binaries (i.e. 1.31)
ENVTEST_K8S_VERSION ?= $(shell go list -m -f "{{ .Version }}" k8s.io/api | awk -F'[v.]' '{printf "1.%d", $$3}')
GOLANGCI_LINT_VERSION ?= v2.4.0
GINKGO_VERSION ?= v1.16.5
GINKGO_VERSION ?= v2.27.4

install-tools: kustomize controller-gen setup-envtest golangci-lint setup-ginkgo

Expand All @@ -160,7 +160,7 @@ setup-envtest: envtest ## Download the binaries required for ENVTEST in the loca

setup-ginkgo: $(GINKGO) ## Download ginkgo locally if necessary.
$(GINKGO): $(LOCALBIN)
go install github.com/onsi/ginkgo/ginkgo@$(GINKGO_VERSION)
go install github.com/onsi/ginkgo/v2/ginkgo@$(GINKGO_VERSION)

envtest: $(ENVTEST) ## Download setup-envtest locally if necessary.
$(ENVTEST): $(LOCALBIN)
Expand Down
27 changes: 27 additions & 0 deletions PROJECT
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,31 @@ resources:
kind: Console
path: github.com/gocardless/theatre/api/workloads/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: crd.gocardless.com
group: deploy
kind: Release
path: github.com/gocardless/theatre/api/deploy/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: crd.gocardless.com
group: deploy
kind: Rollback
path: github.com/gocardless/theatre/api/deploy/v1alpha1
version: v1alpha1
- api:
crdVersion: v1
namespaced: true
controller: true
domain: crd.gocardless.com
group: deploy
kind: AutomatedRollbackPolicy
path: github.com/gocardless/theatre/api/deploy/v1alpha1
version: v1alpha1
version: "3"
Loading