Skip to content

Multi-instance on one host: applyContainerConfig CA files in shared tmpdir get clobbered across instances, breaking TLS in running containers #51

Description

@jonnychesthair-crypto

Summary

applyContainerConfig() writes the gateway CA material to fixed filenames in the shared system temp dir and bind-mounts those host paths into containers. When two OneCLI instances run on the same host (e.g. two self-hosted gateways for two isolated agent apps), each instance's container spawn overwrites the other instance's CA files in place. Because the files are bind-mounted, every running container of the other instance immediately loses TLS trust for its own MITM gateway: all proxied HTTPS starts failing with curl exit 60 (SSL certificate problem) until its next spawn rewrites the file back — which then breaks the first instance's containers. A ping-pong outage with no error on the writing side.

Affected code

src/container/ca.ts (verified identical in 2.2.1 and latest 2.7.0):

function writeCaCertificate(caCertificate) {
  const outPath = join(tmpdir(), "onecli-proxy-ca.pem");   // fixed name, shared /tmp
  ...
}
function buildCombinedCaBundle(caCertificate) {
  ...
  const outPath = join(tmpdir(), "onecli-combined-ca.pem"); // fixed name, shared /tmp
  ...
}

src/container/credentials.ts has the same pattern for credential stubs (tmpdir()/onecli-stubs/onecli-stub-<basename>), which additionally risks one instance's containers mounting another instance's credential stub content.

Reproduction

  1. Run two self-hosted OneCLI instances on one host (different ports, different CAs).
  2. App A (SDK pointed at instance A) spawns a container via applyContainerConfig — container gets /tmp/onecli-combined-ca.pem bind-mounted, HTTPS through gateway A works.
  3. While A's container is still running, App B (instance B) spawns a container.
  4. A's running container: any HTTPS call through gateway A now fails with curl exit 60 / effective HTTP 000. curl -k succeeds, isolating it to CA trust. Host file mtimes match B's spawn time.

Suggested fix

Any of:

  • Derive the filenames from the instance, e.g. onecli-proxy-ca-<sha1(baseUrl).slice(0,8)>.pem (container-side mount path can stay fixed).
  • Make the output directory configurable on the SDK constructor / applyContainerConfig options.
  • Write via unique temp name + keep per-config path.

Workaround

Set a distinct TMPDIR per host process (Node's os.tmpdir() honors it on POSIX, read per call). Verified working, but it's easy to miss until the collision bites — the failure appears only in the other app, minutes later, with no log on the writer's side.

Versions: SDK 2.2.1 (where hit) and 2.7.0 (code inspected, same pattern). Node v20.20.1, Linux.

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