No description
  • Go 88.1%
  • Smarty 4.2%
  • Makefile 3.5%
  • Shell 2.7%
  • Nix 1.5%
Find a file
Manuel Ganter be0ed58197
All checks were successful
ci-charts / charts (push) Successful in 9s
ci-integration / test-integration (push) Successful in 2m52s
ci-main / test (push) Successful in 4m28s
ci / goreleaser (push) Successful in 4m9s
feat: auto-mirror APIExport permissionClaims onto APIBindings
EnsureAPIBindings now reads the referenced APIExport's spec.permissionClaims
at reconcile time and accepts each verbatim (verbs and identityHash copied,
selector from defaultSelector else matchAll). Previously bindings were created
with empty permissionClaims, so kcp warned that exported claims were not
specified, not accepted, and had mismatched verbs. Claims stay in sync via the
existing drift-reconcile path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 13:43:46 +00:00
.forgejo/workflows chore(deps): update dependency helm to v4.2.2 2026-06-18 03:22:56 +00:00
api/v1alpha1 chore: renamed project to workspace-controller 2026-05-27 10:44:47 +02:00
cmd/workspace-controller feat: auto-mirror APIExport permissionClaims onto APIBindings 2026-06-19 13:43:46 +00:00
config chore: regenerate APIResourceSchemas with s-prefixed names 2026-06-03 11:02:42 +02:00
deploy/charts feat: updated endpointSlice 2026-06-15 12:34:32 +02:00
hack fix: prefix schema hash with 's' to keep valid DNS label 2026-06-03 11:00:44 +02:00
internal feat: auto-mirror APIExport permissionClaims onto APIBindings 2026-06-19 13:43:46 +00:00
.envrc feat: bootstrap multi-cluster Workspace controller 2026-05-26 11:50:41 +02:00
.gitignore refactor: map permissionClaims via toYaml in apiexport template 2026-06-02 14:09:38 +02:00
.golangci.yml feat: adopt controller-util shared helpers + wire golangci-lint v2 2026-05-27 09:31:56 +02:00
.goreleaser.yaml chore: renamed project to workspace-controller 2026-05-27 10:44:47 +02:00
AGENTS.md feat: added AGENTS.md and CLAUDE.md 2026-05-29 10:39:45 +02:00
CLAUDE.md feat: added AGENTS.md and CLAUDE.md 2026-05-29 10:39:45 +02:00
Dockerfile.workspace.goreleaser chore: renamed project to workspace-controller 2026-05-27 10:44:47 +02:00
flake.nix feat: bootstrap multi-cluster Workspace controller 2026-05-26 11:50:41 +02:00
go.mod chore(security): bump Go to 1.26.4 (CVE-2026-42504) 2026-06-10 10:51:57 +02:00
go.sum test: add kcp integration harness for workspace provisioning 2026-06-05 12:25:58 +02:00
Makefile test: add kcp integration harness for workspace provisioning 2026-06-05 12:25:58 +02:00
README.md chore: renamed project to workspace-controller 2026-05-27 10:44:47 +02:00
renovate.json Add renovate.json 2026-05-29 09:02:31 +00:00

workspace-controller

kcp controller that owns the Workspace resource (per ADR-0020). A Workspace authored inside an org workspace (root:orgs:{org}) is reconciled into a kcp nested workspace at root:orgs:{org}:{name}, with:

  • the three controller-managed ClusterRoles (workspace-owner / workspace-editor / workspace-viewer) seeded inside it,
  • ClusterRoleBindings for every entry in spec.owners (the unified OwnerBinding{Kind, Name} shape from ADR-0021),
  • an APIBinding per configured customer-facing APIExport.

The controller is multi-cluster: a single binary watches Workspace CRs across every org workspace via an APIExport's virtual-workspace endpoint, using kcp-dev/multicluster-provider + multicluster-runtime.

Layout

.
├── api/v1alpha1/                  # CRD source of truth (kubebuilder annotations)
│   ├── groupversion_info.go
│   ├── ownerbinding_types.go      # canonical OwnerBinding{Kind, Name}
│   ├── workspace_types.go         # Workspace, WorkspaceSpec, WorkspaceStatus
│   └── zz_generated.deepcopy.go   # generated by `make generate`
├── cmd/
│   └── workspace-controller/      # main binary
├── internal/
│   ├── controller/
│   │   ├── util/                  # shared helpers (conditions)
│   │   ├── workspace/             # the Workspace reconciler
│   │   └── testutil/              # test fixtures + fake mcmanager
│   └── kcpws/                     # kcp-facing client (workspace + RBAC + APIBindings)
├── config/
│   ├── crd/                       # generated by `make manifests`
│   └── kcp/                       # generated by `make schemas`
├── deploy/charts/
│   ├── workspace-controller/      # deployment chart for the binary
│   └── workspace-controller-kcp/  # APIExport + APIResourceSchema + RBAC
├── Dockerfile.workspace.goreleaser
├── .goreleaser.yaml
├── Makefile
└── go.mod

Generating CRDs and APIResourceSchemas

make all                # generate + manifests + schemas
make generate           # zz_generated.deepcopy.go
make manifests          # CRD YAML in config/crd/
make schemas            # APIResourceSchema YAML in config/kcp/
make build              # build the controller binary to bin/
make vet
make test
make helm-lint

Running the controller

KCP_KUBECONFIG=/path/to/kcp.kubeconfig \
go run ./cmd/workspace-controller \
  --endpointslice=workspaces \
  --apibinding=workspaces:root:controllers:workspace-controller \
  --owner-cluster-role-name=workspace-owner

--apibinding may be repeated. Each value is name:exportPath (or name:exportPath:exportName when the binding name differs from the export name) and produces one APIBinding inside every provisioned workspace. The APIBindingsReady condition flips True once all of them report Bound / Ready. Pass none to skip the binding step entirely; the condition then trivially reports True.