Skip to content

update_stack restores [REDACTED] values from stale stack-file, not live service state #5

Description

@mrq1911

Summary

update_stack's [REDACTED] restoration reads its "original" values from client.getStackFile() (GET /api/stacks/:name/file — Swarmpit's stored stack-file record) rather than client.getStackCompose() (GET /api/stacks/:name/compose — the live, currently-running service state). If a secret/env var was ever changed on the live service through a path that doesn't touch the stack file (e.g. update_service_env, or editing directly in the Swarmpit UI), the stack file becomes stale relative to reality. Any later update_stack call that leaves that var as [REDACTED] will silently restore the stale stack-file value, overwriting the correct live value — with no error, no warning, and no diff shown.

Root cause

src/tools/stacks.ts, update_stack handler:

const current = await client.getStackFile(name).catch(() => ({ compose: "" }));
const restored = restoreRedactedValues(yaml, current.compose);

getStackFile (src/client.ts) hits /api/stacks/:name/file. getStackCompose (used by the get_stack_compose tool) hits /api/stacks/:name/compose — a different endpoint that reflects live service state. These two can diverge indefinitely; nothing keeps the stack file in sync with update_service/update_service_env changes.

Reproduction

  1. Fix a secret on a live service via update_service_env (bypasses the stack file entirely).
  2. Some time later, use update_stack for an unrelated change (e.g. adding a healthcheck), leaving the affected var as [REDACTED] in the submitted compose (the documented, expected usage per the tool's own description: "Leave [REDACTED] for unchanged secrets").
  3. The var reverts to whatever was in the stack file before step 1's fix — silently.

In our case this redirected a service's RPC_URL to a stale, wrong blockchain endpoint, with no error surfaced anywhere in the tool's response.

Suggested fix

Use getStackCompose (live state) instead of, or in addition to, getStackFile (stored record) as the restoration source in update_stack. If the two-endpoint distinction is intentional for other reasons, at minimum warn/diff when they disagree for a var being restored, since silent restoration of stale secrets is a correctness footgun with no error signal.

Related

Similar in spirit to #4 (update_service round-tripping [REDACTED] literally) — both are cases where the redaction/restoration layer's guarantee ("your secrets are safe to round-trip") doesn't actually hold under realistic multi-path update usage.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions