gitops-cicd — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited gitops-cicd (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Tool availability: some MCP tools named here live in thefulltoolset profile — if one is not advertised on this connection, tell the user to reconnect the MCP server with?toolsets=full(or use thecplnCLI fallback). Reads and deletes work on every profile via the genericlist_resources/get_resource/delete_resourcetools.
In pipelines the CLI is the primary interface: authenticate with a service-account key in CPLN_TOKEN (no profile needed), push an image, cpln apply --ready the manifests. MCP tools do the work around the pipeline — mcp__cpln__get_resource_schema before authoring manifests, mcp__cpln__list_deployments to confirm a deploy landed. The usual failure is image builds: cpln image build runs the build locally through Docker, so on runners without a Docker daemon it cannot work — pick the build flow by runner capability, not by habit.
cpln serviceaccount create --name ci-deployer --org ORG
cpln serviceaccount add-key ci-deployer --description "ci key" --org ORG # --description is requiredThe JSON response's key value is the credential — store it as a masked/secret variable in the CI platform. MCP: mcp__cpln__add_key_to_service_account does both steps (and creates the service account if missing).
Grant least privilege (access-control skill): pushing images needs create on the image kind; cpln apply needs create/edit on every kind the manifests contain. cpln group add-member superusers --serviceaccount ci-deployer works but grants full org access — prefer a scoped policy (mcp__cpln__create_policy).
Set in the platform's variable settings, never inline in scripts:
| Variable | Role |
|---|---|
CPLN_TOKEN | Service-account key (secret/masked) |
CPLN_ORG | Target org |
CPLN_GVC | Target GVC, when the pipeline targets one |
CPLN_SKIP_UPDATE_CHECK=1 | Silence CLI update checks in logs |
With CPLN_TOKEN set the CLI runs a profile-less session; resolution is flag, then env var, then profile (cpln skill). The official example repos persist the token instead — cpln profile update default --token "$CPLN_TOKEN" (create is an alias of update) — either works. Never pass --token on ad-hoc commands and never echo the token.
npm install -g @controlplane/[email protected] — pin the version. This installs both cpln and docker-credential-cpln.cpln image build is a local build wrapper, not a remote build: with a Dockerfile (--dockerfile, or auto-detected in --dir) it shells out to docker buildx build (legacy docker build fallback); with no Dockerfile it downloads the pack CLI and runs buildpacks. Every mode needs a working Docker daemon, and --push errors unless docker-credential-cpln is on PATH. It configures registry auth itself — no separate docker-login step.
| Runner | Build flow |
|---|---|
Daemon available — GitHub-hosted runners, GitLab with the docker:dind service (privileged runners, including gitlab.com SaaS), CircleCI setup_remote_docker, Bitbucket docker service | cpln image build --name APP:TAG --push, or keep an existing docker-native pipeline: login below, then docker build --platform linux/amd64 + docker push (image skill, Option B) |
| No daemon — self-managed GitLab runners without privileged mode, locked-down Kubernetes executors | Daemonless builder (kaniko, buildah, rootless BuildKit) pushing straight to the registry; the build job needs no cpln CLI at all |
The org registry is a standard Docker registry: ORG.registry.cpln.io, username = the literal string <token>, password = the service-account key. Any tool that can push an OCI image works:
echo "$CPLN_TOKEN" | docker login ORG.registry.cpln.io -u '<token>' --password-stdinWith the CLI installed, cpln image docker-login is the faster equivalent for raw docker push/docker pull jobs: instead of storing a secret it registers the docker-credential-cpln helper for the org registry, and Docker resolves the token from CPLN_TOKEN (or the profile) at every later call. Use the raw docker login form only where the CLI isn't on the box — kaniko auth files, CLI-less build jobs.
GitLab job without a daemon (kaniko; the runner must be amd64 — kaniko cannot cross-build):
build:
image:
name: gcr.io/kaniko-project/executor:debug
entrypoint: [""]
script:
- mkdir -p /kaniko/.docker
- printf '{"auths":{"%s.registry.cpln.io":{"username":"<token>","password":"%s"}}}' "$CPLN_ORG" "$CPLN_TOKEN" > /kaniko/.docker/config.json
- /kaniko/executor --context "$CI_PROJECT_DIR" --destination "$CPLN_ORG.registry.cpln.io/my-app:$CI_COMMIT_SHORT_SHA"On GitHub, docker/login-action + docker/build-push-action also work with the same registry/credentials. Images must be linux/amd64; buildpack and multi-platform detail in the image skill.
Tag every build uniquely ($CI_COMMIT_SHORT_SHA, ${GITHUB_SHA:0:7}). Re-pushing the same tag does not redeploy workloads — if a tag must be reused, set supportDynamicTags on the workload or run cpln workload force-redeployment WORKLOAD after the push.
Author YAML against the real shape first: mcp__cpln__get_resource_schema for each kind. The pipeline then runs:
cpln apply --file ./manifests/ --ready--file takes a file, a multi-document YAML (---), repeated --file flags, a directory (recursed; only .yaml/.yml/.json are picked up), or stdin (--file -).cpln delete --file applies the reverse order.gvc: that differs from --gvc/CPLN_GVC aborts the whole apply.--ready waits only for the workloads applied in that run: 5-second polls, three consecutive ready checks to pass, a ~5-minute cap, non-zero exit on timeout — a usable deploy gate.cpln workload get NAME -o yaml-slim > workload.yaml (strips server-managed fields).cpln helm install|upgrade|rollback tracks revisions — the platform's only rollback primitive (environment-promotion skill).name: deploy
on: { push: { branches: [main] } }
env:
CPLN_TOKEN: ${{ secrets.CPLN_TOKEN }}
CPLN_ORG: my-org
CPLN_GVC: my-gvc
jobs:
deploy:
runs-on: ubuntu-latest # GitHub-hosted: Docker daemon available
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22 }
- run: npm install -g @controlplane/[email protected]
- run: cpln image build --name my-app:${GITHUB_SHA:0:7} --push
# manifests reference //image/my-app:IMAGE_TAG — substitute per commit
- run: sed -i "s|IMAGE_TAG|${GITHUB_SHA:0:7}|" manifests/workload.yaml
- run: cpln apply --file ./manifests/ --readyOfficial starter repos (CLI): GitHub Actions, GitLab CI, Bitbucket, CircleCI, Google Cloud Build. Terraform pipelines: iac-terraform-pulumi skill.
cpln apply --ready exit code is the deploy gate.mcp__cpln__list_deployments for per-location readiness, mcp__cpln__get_resource (kind="image") to confirm the push landed. A workload that never goes ready: workload skill or the /cpln:troubleshoot command.| Symptom | Cause / fix |
|---|---|
Cannot connect to the Docker daemon from cpln image build | Runner has no daemon — enable dind/privileged mode, or switch to the daemonless flow above |
The docker-credential-cpln command is not accessible on --push | Helper missing from PATH — npm installs it next to cpln; binary installs must copy both binaries |
docker login or push gets 401 | Username must be the literal <token>; the key is the password; check it wasn't truncated |
| Push rejected for permissions | Pipeline service account lacks create on the image kind (access-control) |
cpln apply 403 on one kind | Service-account policy doesn't cover that kind — grant per-kind create/edit |
Apply aborts: --gvc option ... does not match the gvc value | Inline gvc: in a manifest disagrees with --gvc/CPLN_GVC |
| Pipeline pushed, workload kept the old code | Same tag re-pushed — use unique tags, supportDynamicTags, or cpln workload force-redeployment |
--ready exits non-zero after ~5 min | Workload never became ready — check mcp__cpln__list_deployments and workload events |
exec format error at runtime | Image isn't linux/amd64 (image skill) |
| Tool | Purpose |
|---|---|
mcp__cpln__get_resource_schema | Manifest shape for any kind before authoring |
mcp__cpln__add_key_to_service_account | Pipeline service account + key in one call |
mcp__cpln__create_policy | Scope the pipeline service account's permissions |
mcp__cpln__list_deployments | Per-location readiness after a deploy |
mcp__cpln__export_terraform / mcp__cpln__convert_to_terraform | Seed IaC pipelines from live resources or manifests |
| Skill | When |
|---|---|
cpln | CLI conventions — profile-less sessions, flag/env/profile precedence |
image | Build mechanics, buildpacks, registry auth, pull secrets |
environment-promotion | Moving images/configs across dev/staging/prod, rollback patterns |
iac-terraform-pulumi | Terraform/Pulumi pipelines instead of cpln apply |
access-control | Service accounts, groups, policies, least privilege |
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.