> For the complete documentation index, see [llms.txt](https://docs.sealsecurity.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sealsecurity.io/using-platform/working-with-seal-os/in-cicd.md).

# In CI/CD

In CI/CD, `seal fix --os` runs inside a `Dockerfile` during `docker build`. The image build is the trigger for every step of the rhythm: discovery happens during the build, the substitution happens during the build, and the resulting image carries the sealed OS layer.

## The recurring rhythm

The four steps from [Working with the platform](/using-platform/working-with-the-platform.md), specialized for Seal OS in CI/CD:

1. **Review** the Vulnerable packages tab on the [Protection page](/discovering/protection-page.md), filtered to the Seal Project the image's OS scan is attributed to. Rows arrive after every image build; they reflect what Seal saw the last time the build ran.
2. **Decide what to seal.** Most teams run `seal fix --os` in **all** fix mode and let it seal everything sealable. Teams that prefer per-package control use Remote or Local rules; the create flows are the same as for Seal Apps (see [Remote Sealing Rules](/using-platform/sealing-rules/remote-rules.md) and [Local Sealing Rules](/using-platform/sealing-rules/local-rules.md)).
3. **Let the next image build run.** Every build that runs your `Dockerfile` invokes `seal fix --os`, picks up whatever sealed iterations Seal has published, and bakes them into the resulting image. There is no separate "deployment" of the seal step.
4. **Verify** by reading the row state on the Protection page. After the build, rows for the OS packages move to **Sealed**.

The cadence of the rhythm is the cadence of your image releases. Teams that build their images on every push pick up new sealed iterations the same day; teams that release weekly or monthly pick them up on that interval. There is no separate Seal-side trigger that bakes new sealed iterations into the image — the image build does it.

## When new vulnerabilities are disclosed against a sealed iteration

A package version has a row on the Vulnerable packages tab only when it is in use **and** has at least one open vulnerability. The mechanic is identical to Seal Apps; see [Working with Seal Apps under Remote](/using-platform/working-with-seal-apps/remote.md#when-new-vulnerabilities-are-disclosed-against-a-sealed-iteration) for the row-progression details.

The OS-specific twist is the cadence question: until your next image build, your running images keep shipping the iteration they were built with. If a critical OS-package vulnerability lands and you need the sealed iteration in production faster than your normal release cycle, you have to trigger an image rebuild — Seal does not push fixes into images that have already been published.

## Common situations

### A new vulnerability is disclosed in an OS package you use

A row appears on the Vulnerable packages tab once the next image build discovers it. The state matches Seal's response:

* If a sealed iteration is already available, the row is in **Ready to seal**. The next image build pulls it.
* Otherwise the row is in **Generate available** (lower-severity vulnerabilities Seal has not auto-prioritized) or **Version in progress** (Seal is actively building the iteration). When the iteration ships, the next image build picks it up.

### A base image change pulls in new vulnerable packages

When you bump the `FROM` line, the base layer's OS packages change. The next image build discovers the new set; rows appear for any new vulnerable packages, and `seal fix --os` (in all mode) seals them in the same build. In rule-driven modes (Remote / Local), packages the existing rules do not cover stay in **Ready to seal** until you create rules for them.

### A new `RUN apk add` / `apt-get install` / `dnf install` step adds a vulnerable package

Same as above: the next build sees the addition, the row appears, and `seal fix --os` substitutes the sealed version in the same build. The `Dockerfile` requirement is that `seal fix --os` runs **after** every OS-package install or upgrade step; otherwise the additions are not in scope at the time of the seal run. See [When in the build the CLI runs](/setup-apps-os/seal-os-cicd.md#when-in-the-build-the-cli-runs).

### CI fails after `seal fix --os` was added or changed

In the overwhelming majority of cases, a build failure that follows shortly after an OS-substitution change has nothing to do with the sealed packages — some other change in the same build cycle is the cause. Check your CI logs and your commit history first.

If you still suspect the sealed OS packages are the cause, the simplest test is to revert the `Dockerfile` to the previous `seal fix --os` invocation (or temporarily drop the seal step entirely) and re-build. If the build still fails, the seal step was not the source; treat it as any other regression. If the build succeeds without the seal step but fails with it in place, contact your Seal account team with the build logs and the sealed package versions involved.

A separate class of failure is the seal step itself erroring inside the build — a parsing error in `.seal-actions.yml`, a network issue reaching the Seal OS artifact server, a `USER` directive that dropped root before the seal step, or a missing / wrong `SEAL_TOKEN`. Those produce a clear error in the build log; the diagnosis is the log message.

### The image was built but the rows did not move

The narrow case of "build succeeded, rows stayed at **Pending deploy** or did not appear at all":

* The seal step was conditional in the Dockerfile or in CI, and the condition skipped it for this build.
* The CLI ran in the wrong fix mode for the configured rules (running in `local` mode when the rules live in the platform, or in `remote` mode when they live in `.seal-actions.yml`). The build does not fail; the substitution simply does not happen.
* `SEAL_PROJECT` is not the one whose Protection page you are watching. Project attribution comes entirely from `SEAL_PROJECT`; if the build passes a value pointing at a different (or freshly auto-created) project, the rows you expect to move are not the ones the run is touching.

## Related

* [Seal OS in CI/CD](/setup-apps-os/seal-os-cicd.md): the setup chapter the in-CI rhythm assumes.
* [Sealing OS packages in a Dockerfile](/setup-apps-os/seal-os-cicd/dockerfile.md): the per-distribution Dockerfile patterns.
* [`seal fix --os` reference](/setup-apps-os/seal-os-cicd/seal-fix-os-reference.md): the flag list.
* [Working with Seal OS on live hosts](/using-platform/working-with-seal-os/on-hosts.md): the other Seal OS deployment shape.
