mirror of
https://github.com/Studio-Saelix/sencho.git
synced 2026-07-27 20:29:10 +00:00
421177e4a6
* feat(stacks): add compose-vs-runtime drift engine Add a read-only engine that compares a stack's on-disk compose model against the live Docker runtime and reports where the two diverge. GET /api/stacks/:stackName/drift returns a per-stack report with a status (in-sync, drifted, missing-runtime, unreachable) and typed, service-scoped findings: a declared service with no running container, a running container not declared in compose, an image mismatch, and a published-port mismatch. The report is computed at request time with no persistence and is available on every tier. The check reuses the existing compose parser and Docker dependency snapshot; the compose parser now also captures each service's declared image. Boundaries fail closed: an unreadable compose file reports drifted and an unreachable Docker daemon reports unreachable, never a false in-sync. * fix(stacks): keep drift hasContainers accurate on compose parse error assembleStackDrift hardcoded hasContainers: false on the parse-error path, contradicting the field's contract when the runtime actually has running containers. Compute it once from the container set and reuse it across all return paths. Also add a route test that exercises the successful 200 path for an existing stack on the Community tier (stubbing only the Docker boundary), so a tier gate or handler regression after the existence check is caught. * feat(stacks): add a drift detection tab to the stack view Surface the compose-vs-runtime drift report on the per-stack Anatomy panel as a read-only Drift tab. It shows the stack's status (in sync, drifted, not running, unreachable) and, when drifted, the specific service-scoped reasons with the declared and running values side by side. A re-check action reruns the comparison. The tab lives in the shared anatomy panel, so it appears on both the desktop stack view and the mobile stack detail. Available on every tier. * fix(stacks): sanitize the logged error in the drift report builder The compose-read and Docker-snapshot catch blocks logged the raw error object, whose message can embed the user-controlled stack path (e.g. an ENOENT path). Log the error through the existing sanitizer so a crafted stack name cannot forge log lines, matching the pattern used elsewhere in the stacks router.
58 lines
3.8 KiB
Plaintext
58 lines
3.8 KiB
Plaintext
---
|
|
title: Drift Detection
|
|
description: See at a glance whether a stack's running containers still match the Compose file on disk, with specific, actionable reasons when they have diverged.
|
|
---
|
|
|
|
The **Drift** tab in the right-hand **Anatomy** panel answers a single day-two question: does what is actually running still match the Compose file on disk? Sencho treats your Compose file as the source of truth, so it compares the file against the live Docker runtime and reports exactly where the two have diverged.
|
|
|
|
The check is read-only. It tells you what changed and never alters a stack on its own, so you can trust the report before deciding what to do about it. The report is built fresh each time you open the tab, with no separate state to maintain.
|
|
|
|
## Status
|
|
|
|
Every stack resolves to one of four states, shown as a badge at the top of the tab:
|
|
|
|
| Status | Meaning |
|
|
|--------|---------|
|
|
| **In sync** | The running containers match the Compose file: same services, images, and published ports. |
|
|
| **Drifted** | Something running differs from the file. The specific reasons are listed below the badge. |
|
|
| **Not running** | The stack is defined on disk but no containers are running. |
|
|
| **Unreachable** | Docker could not be reached, so drift cannot be assessed right now. |
|
|
|
|
## Findings
|
|
|
|
When a stack is drifted, each reason is listed against the service it affects:
|
|
|
|
| Finding | What it means |
|
|
|---------|---------------|
|
|
| **Service missing** | The Compose file declares a service, but it has no running container. |
|
|
| **Undeclared** | A container is running for the stack, but no matching service exists in the Compose file. |
|
|
| **Image** | A running container uses a different image than the Compose file declares. The expected and running values are shown side by side. |
|
|
| **Ports** | The published ports of a service differ from what the Compose file declares. |
|
|
|
|
Image references are compared after normalizing the implicit Docker Hub registry and a missing tag to `:latest`, so `nginx` and `docker.io/library/nginx:latest` are treated as the same image. A running container pinned to a digest is compared against the declared tag as written.
|
|
|
|
## Accessing the Drift tab
|
|
|
|
1. Click any stack in the left sidebar to open it.
|
|
2. Switch to the **Drift** tab in the Anatomy panel header.
|
|
3. Read the status badge and any findings. Use **re-check** to run the comparison again after you deploy or change something.
|
|
|
|
On a phone, the same report appears under the **Compose** section of the stack detail.
|
|
|
|
## Troubleshooting
|
|
|
|
<AccordionGroup>
|
|
<Accordion title="A stack I deliberately stopped shows as 'Not running'">
|
|
That is expected. Drift compares the file on disk against what is actually running, so a stack with no running containers reports **Not running** even when you stopped it on purpose. Deploy it to return it to **In sync**.
|
|
</Accordion>
|
|
<Accordion title="The image finding flags a stack I just updated">
|
|
Open **re-check** after the deploy finishes. During a rolling update, replicas can briefly run different images, and the report is a snapshot of that moment. Once every container is on the declared image, the finding clears.
|
|
</Accordion>
|
|
<Accordion title="A stack that uses a published port range shows a ports finding">
|
|
A Compose port range such as `8000-8002:8000-8002` is compared conservatively and can read as a ports difference even when the deployment is correct. Sencho errs toward surfacing a possible difference rather than hiding one. The status reflects this as drift you can confirm against the file.
|
|
</Accordion>
|
|
<Accordion title="The status says 'Unreachable'">
|
|
Sencho could not reach Docker on the active node, so it cannot compare the runtime. Confirm the Docker engine is running and the node is online, then use **re-check**. Other stacks on the same node will show the same state until Docker responds.
|
|
</Accordion>
|
|
</AccordionGroup>
|