The control plane is a Go service that leverages protocol buffers and gRPC for its API, ent as ORM, wire for dependency injection and the kratos framework for additional utilities such middlewares, configuration management or error handling.
It's implemented following(ish) Hexagonal architecture with the following top to down layers.
- API definition layer
./api/. proto definitions and generated code for the external gRPC API - Server layer
./internal/server. Definition and registration of the HTTP and gRPC servers and middlewares. - Service layer
./internal/service. Implementation of the protocol buffer services. - Business layer
./pkg/biz. Implementation of use-cases referenced by the service layer and definition of the data repository abstractions. - Data layer
./pkg/data. Implementation of data repositories interfaces defined in the business layer.
The source code and documentation for the different supported plugins can be found at ./plugins.
The control plane has 4 main dependencies
- OpenID Connect (OIDC) provider. Chainloop authentication backend is delegated to a OIDC provider (i.e Google, GitHub or Auth0) for single sign on.
- The persistance layer requires a PostgreSQL database.
- Sensitive information provided by the user such as OCI registry credentials is sent to a secret storage backend. Currently we support Hashicorp Vault, AWS Secret Manager and GCP Secret Manager.
- In addition to those third party dependencies, the control plane also has a dependency on Chainloop own Artifact CAS. It is used to upload the received attestation to the end-user storage backend.
NOTE: The control plane does not store artifacts, these get forwarded to the user storage backend (i.e OCI registry) through the Artifact CAS.
We use make for most development tasks. Run make -C app/controlplane to see a list of the available tasks.
Refer to development guide for more information but in a nutshell.
# Run external dependencies (Dex for OIDC, bitnami/postgreSQL container for persistence and Vault for secret management)
docker compose -f devel/compose.yml up
# Run the control plane
make -C app/controlplane run
Next, follow the steps that can be found here to configure the CLI
We've implemented two kinds of tests, unit tests (make run test-unit) and integration tests. The latter launch a containerized database and hence they are expensive to run.
To run all the tests make test
make build
We use buf.io to lint and generate proto files. Make sure you install buf first.
Once done, generating the API code is as easy as executing
make api
We use ent as database Object Relational Mapping (ORM) and atlas versioned migrations to manage the database schema changes.
The way you can make a change in the data model is
Update the schema
- Add a new/update an existing entity via a schema update. Schemas can be found at
pkg/data/ent/schema - Run
make -C app/controlplane generate. It generates both the code changes associated with that schema change and, viamake migration_sync, a new versioned migration atpkg/data/ent/migrate/migrations. Review and commit that generated file - do not hand-write it. Note the rootmake generatedoes not write migrations. - If the change also needs a data backfill, add a second, hand-written migration with
make -C app/controlplane migration_new(which creates an empty file), as in thelast_run_atbackfill20251001215625.sql.
Apply the schema change in development DB
make migration_applywill apply the migration to the development database- Restart the control plane
The service runtime configuration is implemented by using kratos built-in config module.
Meaning that the configuration schema is defined at internal/conf/conf.proto.
To regenerate it run:
make config
In order to enforce inversion of control and prevent import cycles we use wire for dependency injection.
Wire has a fairly steep learning curve, so we recommend taking a look at their tutorial. In practice, in this project you will find a couple of wire_gen.go files (i.e cmd/wire_gen.go) and different provider defined.
If you need to re-generate the injection code after a change just run make generate
Please make sure to review the Contribution guidelines and feel free to reach out if you have any questions!
Welcome!
