Skip to content

The image

The WhyStack Agent ships as a container image. This page describes what it contains: the material for a security review before you hand it credentials.

Terminal window
# AWS (ECR)
docker pull <whystack-account>.dkr.ecr.<region>.amazonaws.com/rootpilot-agent:<version>
# GCP (Artifact Registry)
docker pull <region>-docker.pkg.dev/<whystack-project>/rootpilot/rootpilot-agent:<version>

Access is granted to your AWS account or GCP project: the pull uses your cloud’s identity, and there is no WhyStack credential for you to store or rotate.

The registry is private, so a docker pull without authentication fails with no basic auth credentials. Authenticate with your credentials, because it is the authorization we granted to them that unlocks the pull.

AWS (ECR). The token comes from your account; the login targets WhyStack’s registry:

Terminal window
aws ecr get-login-password --region <region> \
| docker login --username AWS --password-stdin <whystack-account>.dkr.ecr.<region>.amazonaws.com

Use the same <region> as the image address. Read access to the repository was already granted to your account on our side, but a cross-account pull needs permission on both sides: the principal that pulls needs ecr:GetAuthorizationToken and, on the WhyStack repository, ecr:BatchGetImage, ecr:GetDownloadUrlForLayer and ecr:BatchCheckLayerAvailability. The managed policies AmazonEC2ContainerRegistryReadOnly (common on EKS node roles) and AmazonECSTaskExecutionRolePolicy (the ECS task execution role’s) already cover all four.

GCP (Artifact Registry). Register the credential helper once:

Terminal window
gcloud auth configure-docker <region>-docker.pkg.dev

Your principal needs roles/artifactregistry.reader on the repository, already granted to the project you gave us.

Property Value
Architectures linux/amd64 and linux/arm64
Base node:22-alpine
User node (uid 1000), non-root
Entrypoint loads the PEMs from /certs and runs the Agent process
Exposed ports none

Only what the process opens at runtime: the compiled JavaScript artifacts (dist/), the package manifests, and production dependencies.

By construction, the final build stage does not copy the development tree:

  • no source code (src/);
  • no tests and no test fixtures;
  • no build toolchain: python3, make, and g++ exist only in an intermediate stage and never reach the runtime;
  • no secrets. The image is identical for every customer; what varies is the certificate and the credentials you mount at runtime.

Excluding fixtures is deliberate and matters to you: without it, one customer’s test data would travel into another customer’s infrastructure.

In production, reference the image by digest rather than tag:

<address>/rootpilot-agent@sha256:<digest>

The Agent is ephemeral and pulls often. A moving tag lets different replicas run different builds without anyone noticing. The digest is immutable.

To find the digest behind a tag:

Terminal window
docker buildx imagetools inspect <address>/rootpilot-agent:<version>

The same command lists the architectures present in the multi-platform index.

The image is signed at publish time, without a key: the workflow that builds it exchanges its own identity for an ephemeral certificate, and the signature is recorded in a public transparency log. What this proves is not “someone holding a key signed this” but which workflow, from which repository, at which tag produced that digest.

Requires cosign:

Terminal window
cosign verify \
--certificate-identity https://github.com/sunnysystems/rootpilot-edge/.github/workflows/release-image.yml@refs/tags/v<version> \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
<address>/rootpilot-agent@sha256:<digest>

The --certificate-identity flag is the one that matters, and that is why it carries the version: without pinning the identity, cosign verify would accept any valid Sigstore signature, including one from a repository that is not ours. Verifying without it is close to not verifying at all.

If you enforce admission policy on your cluster (Kyverno, policy-controller), that same identity is what goes into the rule. Recommended, but your call: we publish the signature, we do not require verification.

No special privileges: no --privileged, no added capabilities, no Docker socket access, no host filesystem mounts. The only volume needed is /certs, read-only.

Memory and CPU: 0.5 vCPU and 512 MB cover most installations. RUNNER_LEARNED_STORE_PATH defaults to :memory:, so nothing is written to disk. Point it at a volume and the container starts writing there, with the permissions being yours to own.