> 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-apps/local.md).

# Under Local

In the Local deployment method, the Seal CLI runs in local mode inside your CI/CD pipeline and reads [Local Sealing Rules](/using-platform/sealing-rules/local-rules.md) from `.seal-actions.yml` at the repository root. The everyday work involves editing that file — by hand, or by accepting a pull request from the Seal GitHub App — and merging the change.

## The recurring rhythm

The four steps from [Working with the platform](/using-platform/working-with-the-platform.md), specialized for Local:

1. **Review** the Vulnerable packages tab on the [Protection page](/discovering/protection-page.md). The Seal CLI uploads what it found to the platform on every run, so the UI is current.
2. **Decide what to seal.** For each row, add an entry to `.seal-actions.yml`. Two paths get this done:
   * In a source-control-connected Seal Project, open a pull request from the [Projects page](/getting-started/creating-a-seal-project.md) using the PR button next to the project (also available as a batch **Create pull request** action across selected projects). The Seal GitHub App generates the PR with the entry added. This action is available only for source-control-connected projects on the **Local** deployment method, plus connected projects whose deployment method is not yet determined (a freshly imported project that has not run the CLI once). Projects on the **Remote** or **Automatic Remediation** deployment method do not offer it, because those apply fixes in CI rather than through a source pull request.
   * Otherwise, edit the file directly. See the [Local Sealing Rules](/using-platform/sealing-rules/local-rules.md) schema reference.

<figure><img src="/files/1FyJvyRtTgov8PUyFQIu" alt="Projects page row with the PR button highlighted"><figcaption><p>The per-project PR button opens a pull request that edits <code>.seal-actions.yml</code>.</p></figcaption></figure>

3\. \*\*Let the next CI build run.\*\* Once the file change is merged, the next invocation of the Seal CLI in local mode reads the file, substitutes the sealed version, and reports back. 4. \*\*Verify.\*\* After the build, the row state moves to \*\*Sealed\*\*.

## Where rules live in your codebase

`.seal-actions.yml` is a regular file in your repository. It is reviewed and merged like any other code change. The benefits over remote rules are that the change history is in your VCS and the change goes through your normal review process; the cost is that an emergency change requires a PR rather than a UI click.

The file is per-repository — one Seal Project per file — and every entry names a specific package, version, and pinned `-sp[N]` substitute. Local mode does not support the safest-version (un-pinned) substitute or the "all packages" blanket rule. See [Local Sealing Rules](/using-platform/sealing-rules/local-rules.md) for the full constraints.

## 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 row's state reflects what is being done about those open vulnerabilities.

Take a Seal Project whose `.seal-actions.yml` entry pins `ejs@2.7.4` to `2.7.4-sp1`:

* The `ejs@2.7.4` row sits in **Sealed** — the package has open vulnerabilities, but the entry substitutes a sealed iteration. As long as a newer iteration than `sp1` is in use, the row stays in **Sealed**.
* `ejs@2.7.4-sp1` itself has no row on the Vulnerable packages tab as long as it has no open vulnerabilities. It appears on the [Sealed packages tab](/discovering/protection-page/sealed-packages-tab.md) instead.

When a new vulnerability is disclosed that affects `sp1`, `sp1` gains its own row on the Vulnerable packages tab. The state of that row tracks Seal's response:

* While Seal has not yet started a new sealed iteration, the row is in **Generate available** — a customer can trigger the backport with the Generate fix action.
* Once Seal publishes `sp2`, the row moves to **Ready to seal**.

To consume `sp2`, edit `.seal-actions.yml` to point at it. Two paths:

* If the **Seal GitHub App** is configured to open pull requests automatically, it opens a PR updating the entry to `sp2` when the iteration ships. Review and merge.
* Otherwise, open a PR on demand from the Projects page using the per-project PR button, or edit the file by hand.

Once the file change is merged and the next CI build pulls `sp2`, the `sp1` row returns to **Sealed** (because a newer sealed iteration is now in use). `sp2` does not get its own row unless it is itself flagged as vulnerable later, i.e., when `sp3` becomes necessary.

Until the file is updated, the next CI build keeps pulling `sp1`.

## Common situations

### A new vulnerability is disclosed in a package you already use

The row appears on the Vulnerable packages tab in whichever state matches Seal's progress on it: **Generate available**, **Version in progress**, or **Ready to seal**. Critical and high-severity vulnerabilities are typically picked up by Seal automatically within hours; lower-severity ones may sit in **Generate available** until a customer triggers them.

If you already had an entry in `.seal-actions.yml` pinning the package to a sealed iteration, that iteration keeps shipping with your build until you update the file. When the iteration that addresses the new vulnerability lands, update the file via PR (from the Projects page, automatically from the Seal GitHub App if it's configured, or by hand).

### A developer adds a new vulnerable dependency

The PR or merge build's CLI step discovers the new package. The row appears on the Vulnerable packages tab. Open a PR from the Projects page (or by hand) adding the entry to `.seal-actions.yml`. Until that change is merged, the next build leaves the dependency vulnerable; the build does not fail by default.

### CI fails after a `.seal-actions.yml` change

In the overwhelming majority of cases, a CI failure that follows shortly after a `.seal-actions.yml` change has nothing to do with the substitution. 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 version is the cause, revert the file change and re-run. If the build still fails, the substitution was not the source; treat it as any other regression. If the build succeeds without the entry but fails with it in place, contact your Seal account team with the build logs and the sealed version involved.

### When the substitution does not happen

The row stuck at **Pending deploy** after a build that otherwise succeeded is a narrow case. Most failure modes — a malformed `.seal-actions.yml` (the CLI refuses to load files that fail schema validation), a network outage, a wrong token — fail the CLI outright and therefore fail the CI; those are diagnosed from the CI logs, not from the row state. The cases where a build succeeds but the substitution is not applied are:

* The CLI step was not actually invoked for this build (skipped step, conditional that bypassed it, or earlier pipeline failure that fell through to a passing job).
* The build's checkout did not include `.seal-actions.yml`. A leading-dot filename is sometimes filtered by aggressive `.gitignore` patterns or by CI artifact filters; make sure the build sees the file.
* The CLI ran in the wrong fix mode. Local mode is required to read the file; running in remote or all mode does not fail the build, but the file is ignored.
* `SEAL_PROJECT` does not match the Seal Project that owns the file's entries. Project attribution comes entirely from `SEAL_PROJECT`; if the build's value points at a different project (or a typo the platform treats as a new project), the file's entries are still read, but the substitution is attributed somewhere other than the project you are watching.

## Related

* [Local Sealing Rules](/using-platform/sealing-rules/local-rules.md): the `.seal-actions.yml` schema and constraints.
* [Connecting GitHub](/discovering/connecting-source-control/github.md): the source-control integration that powers the PR flows.
* [Seal Apps via the Seal CLI in CI/CD](/setup-apps-os/cli-in-cicd.md): the setup chapter the Local rhythm assumes.
* [The CLI fix mode](/setup-apps-os/cli-in-cicd/cli-fix-mode.md): how to verify which mode the CI is invoking.
