Skip to content

Container registry

Registry (/gravity/registry) is where you find container images to deploy and where your organization keeps its own private images. Every container image pushed to your organization’s registry is signed and scanned for known vulnerabilities automatically - see What happens on every push - and the signature lets you prove which image you deployed.

The registry opens on a curated list of well-known official images - nginx, postgres, redis, node, python, ubuntu, and similar - with a search box and a row of quick-search shortcuts above it. Click any image (or a search result) to open its detail page, which shows:

  • Star count, pull count, and when it was last updated.
  • A tag table you can filter, each with its size and when it was pushed.
  • A ready-to-copy pull command for the selected tag.
  • A Deploy button that opens the instance creation wizard with this image and tag chosen. The server the wizard creates then pulls that exact image and starts it.

Star the heart icon on any card to pin it to a Favourites section at the top of the default view - favourites are remembered on your device.

Public images are not scanned or signed by Sencai. Scanning and signing apply to the images in your organization’s own registry, described next. Images in a registry you run yourself can be scanned on request or on a schedule, but are not signed.

The Sencai tab is your organization’s own, private registry. Every image name is git.sencai.space/<organization>/<image>. Do not work out <organization> from the organization’s display name: it is the organization’s short name (its slug, for example acme), and the Access panel shows the exact Image prefix to use.

The tab lists every image in the registry (Image, Processing, Scan, Signature, Attestation and Pushed), and each image has its own page. The image page lists its tags with when each was pushed, who pushed it, its digest (the fingerprint of the exact image content), and the same four status badges, followed by the selected version in detail, a Push history and the Signing keys card. See What the statuses mean. Scanning, signing and the commands below apply to container images. Other OCI artifacts pushed the same way, such as a Helm chart, are signed but not scanned. Packages of other types (npm, PyPI and similar) are listed under Other packages and are neither scanned nor signed.

Select a version and choose Deploy to a new server to start it on a new instance: the wizard opens with the image and its digest chosen, and only a signed version can be deployed. Running on lists the servers Sencai has deployed that version to. See Deploy a container to a new instance.

The private registry itself is part of every paid plan. See sencai.space/pricing for what comes with it.

The Storage card shows approximate registry usage: the compressed layers of every current image, added up. A layer that several images share is counted for each of them, so the figure can overstate. When your environment has a storage limit configured, the card shows the usage next to it and warns when you are close.

At the moment the registry enforces one limit that is the same for every organization: 20 GB in total, and 5 GB for a single image (its manifest and layers). A push that would go over either is rejected by the registry with an error in your Docker client. A larger allowance is not something you can set yourself; ask your account team if you need one.

Pushing and pulling images needs a registry token, because your Sencai sign-in is not a registry password. A token belongs to you, works for one organization only, and can be revoked at any time.

  1. Open Registry and select the Sencai tab.
  2. In the Access panel, choose Create token.
  3. Give it a Name, choose under What may it do either Pull (download images) or Push (upload images, which are then scanned and signed), and pick Expires after 30, 90 or 365 days. The default is 90 days.
  4. Choose Create token. The Copy your token window shows the token, your username and a ready-made docker login command. The token is shown once and Sencai never stores it - only its name, last eight characters, scope and expiry. When you close the window it is gone; if you lose it, revoke it and create another.

The Access panel also shows the Registry host, the Image prefix your images must be pushed under, your registry login, and Your tokens with each token’s name, scope, last eight characters, expiry and status. To revoke a token choose Revoke, then Confirm revoke.

Then sign in with Docker. Do not put the token in the command itself - that would leave it in your shell history. Run the command from the window (it uses --password-stdin, so the token is not part of it) with the username shown there, paste the token, and press Enter:

Terminal window
docker login git.sencai.space -u <username-from-the-dialog> --password-stdin

Then press Ctrl-D to end the input. After that, a normal push works:

Terminal window
docker tag api:1.4 git.sencai.space/acme/api:1.4
docker push git.sencai.space/acme/api:1.4

A few things to know:

  • Push needs permission. The Push option is offered only if your role allows pushing; if it is missing, ask an organization admin. Pulling is available to every member, auditors included. See Who can do what.
  • Admins see everyone’s tokens. Admins can switch the token list to Show everyone’s and revoke other members’ tokens.
  • Access follows your membership. Change someone’s role and their access follows within about two minutes; remove them from the organization and their tokens stop working. A token cannot do more than its owner can.
  • Limits. You can hold up to 10 active tokens in one organization. You are notified in the app seven days before one of your own tokens expires; for the CI and runtime credentials below, the people who can manage them (admins) are notified.
  • Push to your organization’s name only. Only git.sencai.space/<organization>/... is scanned and signed. An image pushed anywhere else on the registry (for example under your personal name) is removed and you are notified.
  • Names are lower case. The registry lower-cases image names and tags, so Acme/API:V1 is stored as acme/api:v1.

A personal token is the wrong tool for a build server or a cluster: it belongs to a person, and it stops working when that person leaves. Admins can create two kinds of organization credentials instead, from the CI push credential and Runtime pull credential cards beside the Access panel (they are shown only to people who can manage them). Jobs on Sencai’s own hosted runners need neither: they get a credential of their own for the length of the job, described in Push images from CI.

Credential Can do Use it for
CI push credential Push and pull Build systems outside Sencai (GitHub Actions, GitLab CI, any other CI) and runners you provision yourself
Runtime pull credential Pull only Servers and clusters that run your images (imagePullSecret)

Both are created with New credential on their card (a name and an expiry), shown once, and revocable from the same card with Revoke and Confirm revoke. Each card also shows the credential’s login. A push made with the CI credential is attributed to the CI credential in the image history and is signed like any other authorized push.

GitHub Actions

- name: Log in to the Sencai registry
env:
SENCAI_REGISTRY_USER: ${{ secrets.SENCAI_REGISTRY_USER }}
SENCAI_REGISTRY_TOKEN: ${{ secrets.SENCAI_REGISTRY_TOKEN }}
run: printf '%s' "$SENCAI_REGISTRY_TOKEN" | docker login git.sencai.space -u "$SENCAI_REGISTRY_USER" --password-stdin
- name: Build and push
run: |
docker build -t git.sencai.space/acme/api:${{ github.sha }} .
docker push git.sencai.space/acme/api:${{ github.sha }}

GitLab CI

build:
image: docker:27
services: [docker:27-dind]
script:
- printf '%s' "$SENCAI_REGISTRY_TOKEN" | docker login git.sencai.space -u "$SENCAI_REGISTRY_USER" --password-stdin
- docker build -t git.sencai.space/acme/api:$CI_COMMIT_SHA .
- docker push git.sencai.space/acme/api:$CI_COMMIT_SHA

Store the token and username as masked secrets in the CI system, not in the repository.

Kubernetes (pull secret)

Do not pass the token to kubectl as an argument (--docker-password=...): that puts it in your shell history and in the process list. Let Docker write the credentials file into a scratch directory instead, using the same --password-stdin login as above, and create the secret from that file:

Terminal window
mkdir ./sencai-pull-config
docker --config ./sencai-pull-config login git.sencai.space -u <runtime-credential-username> --password-stdin

Paste the runtime credential’s token, press Enter, then Ctrl-D. Then create the secret and remove the directory:

Terminal window
kubectl create secret generic sencai-registry \
--type=kubernetes.io/dockerconfigjson \
--from-file=.dockerconfigjson=./sencai-pull-config/config.json
rm -r ./sencai-pull-config

The scratch directory holds the token in readable form until you remove it, so delete it straight away as shown. Reference the secret from your pods with imagePullSecrets: [{ name: sencai-registry }]. Rotate it by creating a new runtime credential, updating the secret, and revoking the old one before it expires.

Within moments of a push, Sencai picks it up and does three things without you asking:

  1. Records the push. The exact image content (its digest) is captured as soon as the push lands, so a tag that is overwritten later does not make the earlier push disappear from the Push history on the image page. If a tag was overwritten within seconds, before the earlier push could be captured, the history says so. If a push is ever missed, a check that runs every 15 minutes finds it, so the worst case is “processed up to 15 minutes late”, never “never processed”.
  2. Signs it. The image is signed with your organization’s own signing key
  3. Scans it. The image is scanned with Trivy for known vulnerabilities in its operating system and application packages. After the first scan, and after every rescan you start yourself, a signed attestation of the scan result is attached to the image.

Typically a single image is recorded, signed and scanned within a couple of minutes. Large images, many pushes at once, or a refresh of the vulnerability data take longer; every image shows where it is in the process, including its place in the queue. Work is shared between organizations in turn, so another organization’s backlog cannot starve yours, although a busy platform can still make you wait for your turn. A scan you start yourself with Scan again queues behind scans of fresh pushes.

Details that matter:

  • Tagged images are rescanned. A scan reflects the vulnerability data of the day it ran, and new vulnerabilities are published every day. Images that a tag currently points to (and the platform images inside a multi-platform image that a tag points to) are rescanned automatically once their latest scan is more than seven days old. Rescans are queued a few at a time, hourly, after the scans of fresh pushes, so the interval is about a week and can be longer when many images are due at once. A rescan that failed is not tried again for six hours. A digest that no tag points to any more is not rescanned automatically, so if you still run it (for example because you pull by digest), rescan it yourself with Scan again. An automatic rescan updates the findings but does not replace the attached scan attestation; the attestation is refreshed on the first scan and on rescans you start yourself.
  • Multi-platform images (an image index) are signed as a whole and each platform image inside is signed and scanned separately. The index shows a combined state, for example “Partially scanned (1 of 2 platforms)”.
  • Container images only. Other artifacts, such as Helm charts, are signed but show “Not a container image - not scanned”. The signature and attestation objects themselves, and build attestations from your builder, are hidden from the list unless you switch on Show signatures and attestations.
  • Nothing blocks a deploy. Scanning and signing report on an image; they do not stop it from being pulled or run, and Sencai has no policy that refuses a vulnerable image. If you want a gate, your pipeline can check the signed scan attestation with cosign verify-attestation (see Image signing and verification). The registry screens themselves are not an interface for pipelines. Keep in mind that the attestation is refreshed only on the first scan and on rescans you start yourself, not by the automatic weekly rescan.
  • Not the instance scan. The registry scan is separate from the scanning of images that run on your cloud instances. Both appear under Vulnerabilities, with a switch between them.

Every status is shown as text; none of them is shown as “clean” unless Sencai has evidence that something was actually analyzed. A page that has something in progress refreshes itself every few seconds until everything has settled.

Processing

Status Meaning
Waiting to be processed The push was seen or listed but processing has not started yet
Queued — N ahead Waiting its turn
Processing… Being worked on
Processed Done
Processing failed (<reason>), retrying at <time> A step failed for a temporary reason; it is repeated automatically with growing delays (one minute, five, fifteen, an hour, six hours, a day), up to eight times
Gave up after N attempts — <reason> Retries ran out. The reason is shown; Scan again or Sign again (if your role allows) starts again
Scanning is not enabled in this environment The environment you are using has not switched the feature on. This never means the image is clean

Scan

Status Meaning
Scan queued / Scanning… Waiting, or running
Waiting for vulnerability data Scanning is paused because the vulnerability data is missing or more than seven days old. Signing carries on
Too large to scan (limit <size>) The compressed image exceeds the scan size limit (3 GB at the moment). It is signed; it is not scanned
Not a container image — not scanned A Helm chart or another artifact
Not scanned No scan has been recorded for this image
Partially scanned (1 of 2 platforms) A multi-platform image where only some platform images have a finished scan
Scan failed (<reason>), retrying at <time> / Scan failed — <reason> A scan failed; temporary failures are retried

Scan results

Result Meaning
Clean The scan succeeded, found no vulnerabilities, and recognized the operating system (or found application packages) - so there was something to check
Counts by severity, for example 3 critical, 5 high One or more vulnerabilities were found. Severities are Critical, High, Medium, Low and Unknown
Scanned — no packages found, cannot confirm the image is clean The scan succeeded, but the image has no recognizable operating system or packages (for example a scratch image holding one binary). Sencai does not call this clean
<OS> is end of life — results may be incomplete The base operating system no longer receives security updates, so the vulnerability data for it is incomplete. Counts are shown, and they are a minimum
Based on vulnerability data from <date> The scan ran with vulnerability data three to seven days old

Signature

Status Meaning
Signing… In progress
Signed · key <fingerprint> · checked <time> The signature is attached and was found in place at the last check
Not signed — pushed by an account that may not push here The image was refused for signing (see below)
Signature removed — re-signing / Signature changed — re-signing The signature objects next to the image were deleted or replaced; Sencai is attaching the signature again
Signing failed (<reason>), retrying at <time>, Gave up after N attempts — <reason>, Not signed — signing service unavailable, retrying at <time> Signing hit a problem; temporary ones are retried
Not signed — signing key check failed See When an image is not signed
Nothing to sign The item is not an image or artifact that gets signed
Signing is not enabled in this environment The environment you are using has not switched signing on

Attestation (the signed scan result attached to the image): No attestation, Attestation pending, Attested with the time it was attached, Attestation failed, retrying, Attestation failed, and Attestation: gave up. The attestation badge reports whether the attestation was attached. It does not report whether someone tampered with it; a deleted or replaced signature is reported by the signature status above.

A push that is overwritten by a newer one within seconds, before it could be captured, is listed in the Push history as Overwritten by a newer push before it could be captured; only the newer one is processed.

An image is refused for signing when it was pushed by an account that was not allowed to push to your registry at that moment, for example a credential whose owner lost the permission. A refused image is never signed, the members who have access to security findings (Read security findings, see Who can do what) are notified in the app, and the only way forward is a push by an authorized account.

Sencai also re-checks the signatures it attached every 15 minutes (in batches, oldest check first). If a signature is deleted or replaced behind your back, the image shows Signature removed or Signature changed, Sencai attaches it again, and a changed signature also notifies the members with access to security findings and writes an audit log entry. You usually see this within 15 minutes; deleting or replacing one of the signature tags is looked at sooner.

Severity counts are security data. People who can read the registry but do not have access to security findings see the processing, scan and signature states but not the counts, the findings, or the attestation.

Open an image, select a tag, and the Findings card lists what its latest finished scan found, grouped by vulnerability and package (Severity, CVE, Package, Fix, Installed at, Decision). Installed at lists the places in the image where the package was found; Fix shows the fix version when there is one, or No fix yet. Findings in a tag that were present in the previous tagged version and are gone now are marked Fixed in <digest>. If a newer scan is queued, running or failed, the card says so and keeps showing the findings of the last scan that finished. Below the findings, Scan history lists every scan of the version (what started it, when it finished, the counts, the scanner version and the date of the vulnerability data).

Under Security → Vulnerabilities (/gravity/security/vulnerabilities) a switch chooses between Instances & manual findings and Registry images, and the summary shows coverage next to the counts: for example “3 critical in 12 of 13 images - 1 not scanned”. An image that has not been scanned is never counted as zero.

People with response access can record a decision on a finding. On the image page, choose Decide next to the finding, then choose Accept the risk, Mark as false positive, or Reopen, give a Reason (required for the first two) and, for an accepted risk, an optional expiry date, and Save. The finding then shows Risk accepted or False positive. The decision applies to that vulnerability and package in that image across every future push and rescan, an expired decision stops applying, and every decision is recorded in the audit log. The registry table under Vulnerabilities shows the decision but you record it on the image page. See Vulnerabilities.

When a critical or high vulnerability that is new to an image appears in your registry, the members with access to security findings get a notification in the app. It is batched: at most one notification per image per hour, and only for findings the image has not had before.

On an image page, Scan again queues a new scan of the selected version (a multi-platform image gets one scan per platform image). It runs behind scans of fresh pushes, the earlier result stays in place until the new scan succeeds, and the new scan replaces the attached scan attestation when it finishes. Sign again appears when the signature failed, was given up on, went missing or was changed; it attaches a new signature and does not override a refused image. Both need permission to update the registry and each is limited to ten requests an hour for the organization. Scan again is unavailable while another scan of the same image is queued or running, and for items that are not container images.

Registry permissions are part of permissions in depth. Roles get these by default. Per-member denies and custom roles apply to them in the way that page describes: where custom roles are not available yet, the role defaults below are what counts.

Permission Lowest default role What it allows
Read (git.registry:read) Viewer See images, tags and statuses; download the public signing key and the signature material; see your own tokens and access state
Export (git.registry:export) Viewer Create and revoke your own pull token
Create (git.registry:create) Member Create and revoke your own push token; decides whether your registry account can push
Update (git.registry:update) Member Scan again and Sign again
Revoke (git.registry:revoke) Admin See and revoke other members’ tokens
Manage (git.registry:manage) Admin Create the CI push and runtime pull credentials
Manage repository settings (git.repo-settings:manage) Admin Manage a repository’s deploy keys, Actions secrets and variables, and webhooks (see Repositories)
Read security findings (security:read) Viewer See finding details, severity counts and the scan attestation; also decides who is notified about new findings and refused pushes
Respond to security findings (security:respond) Member Accept risk or mark a false positive

Auditors can read the registry, verify signatures offline, and create pull tokens, but cannot push.

Custom Registries (/gravity/registry/registries, reached from the Registry page’s own tab) connects a private Docker Registry v2 endpoint you already run - Harbor, GitLab’s container registry, or a plain Docker Registry v2 server - so you can browse it from inside Sencai without switching tools, and scan its images for known vulnerabilities. Images in an external registry are not signed by Sencai.

Add registry asks for a URL, an optional username (for basic auth - for a GitLab personal access token, set the username to oauth2), and an optional token. Only an organization admin can add or remove a custom registry. The URL must be https://, on port 443, at a public IPv4 address; see Scan images in your own registry for the full rules.

Once added:

  • Test connection checks reachability, the certificate, the login and whether the catalog can be read, and shows which of those it proved. The headline is Connected, Authentication failed or Connection error.
  • Opening a connected registry lists its repositories and lets you browse tags. If the registry doesn’t expose a browsable catalog, adding an API URL (GitLab-compatible) enables discovery through that API instead; otherwise you can look up a specific repository path directly to see its tags.
  • Test on a repository card (or Scan on a tag) scans that image now, and the Scheduled scans card repeats a scan every day, three days or week. Results appear on the scan page and under Security → Vulnerabilities.
  • Repositories can be starred as favourites, scoped to that registry.

Editing a registry lets you update its URL, username, or token at any time - leave the token field blank to keep the existing one. Changing the URL, username or token clears the last test result, so a registry you pointed at a wrong address is not shown as connected.

Sencai doesn’t currently offer an in-app retention or bulk-cleanup policy for images in your organization’s own registry - manage lifecycle through your CI pipeline (for example, tagging conventions and pipeline-driven deletion) for now. Deleting an image does not delete its history in Sencai’s audit log.