signalk-container 1.18.0 → 1.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. package/README.md +87 -1
  2. package/dist/containers.d.ts +61 -0
  3. package/dist/containers.d.ts.map +1 -1
  4. package/dist/containers.js +159 -5
  5. package/dist/containers.js.map +1 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +53 -11
  8. package/dist/index.js.map +1 -1
  9. package/dist/jobs.d.ts.map +1 -1
  10. package/dist/jobs.js +6 -0
  11. package/dist/jobs.js.map +1 -1
  12. package/dist/types.d.ts +64 -0
  13. package/dist/types.d.ts.map +1 -1
  14. package/doc/plugin-developer-guide.md +22 -1
  15. package/package.json +1 -1
  16. package/public/chunks/_virtual_mf-localSharedImportMap___mfe_internal__signalk_container-B0qftSeN.js +1 -0
  17. package/public/chunks/hostInit-Co9yD_J1.js +1 -0
  18. package/public/chunks/{virtualExposes-BvqLyGjU.js → virtualExposes-B__J5cSP.js} +1 -1
  19. package/public/chunks/virtual_mf-REMOTE_ENTRY_ID___mfe_internal__signalk_container__remoteEntry_js-D6gSy08Y.js +4 -0
  20. package/public/chunks/{virtual_mf-exposes-ssr___mfe_internal__signalk_container__remoteEntry_js-BM72a-CN.js → virtual_mf-exposes-ssr___mfe_internal__signalk_container__remoteEntry_js-eOfXLU2V.js} +1 -1
  21. package/public/chunks/vite-preload-helper-L5lOfJxi.js +1 -0
  22. package/public/configpanel-entry.js +1 -1
  23. package/public/remoteEntry.js +1 -1
  24. package/public/remoteEntry.ssr.js +1 -1
  25. package/public/chunks/_virtual_mf-localSharedImportMap___mfe_internal__signalk_container-BEsDhqjG.js +0 -1
  26. package/public/chunks/dist-B5XYILWI.js +0 -4
  27. package/public/chunks/hostInit-B3-ZMCBI.js +0 -1
  28. package/public/chunks/vite-preload-helper-2rxlSZO5.js +0 -1
package/README.md CHANGED
@@ -14,7 +14,7 @@ Instead of each plugin implementing its own container orchestration, they delega
14
14
  - **Update detection** -- centralized "is there a newer image?" service for all consumer plugins. Auto-detects semver vs floating tags (`:latest`, `:main`), offline-tolerant with persistent cache, emits Signal K notifications, visible inline in the config panel. See the [developer guide](doc/plugin-developer-guide.md#update-detection).
15
15
  - **Resource limits editor** -- interactive UI in the config panel for setting CPU/memory/PID caps per container. Values are applied live via `podman update` when possible (no downtime), falls back to recreate when needed. Stored overrides are minimized against the consumer plugin's defaults so a future default bump flows through automatically. See the [developer guide](doc/plugin-developer-guide.md#resource-limits).
16
16
  - **Reset to plugin default** -- one-click restore of a container's original resource limits, clearing any user override.
17
- - **Per-process ulimits** -- `ContainerConfig.ulimits` pins per-process limits (`nofile`, `nproc`, …) on a container. A containerized process inherits these from the runtime, not the host sysctl, so raising the host `fs.file-max` alone does not lift a database's open-files limit; setting `ulimits` does. See the [developer guide](doc/plugin-developer-guide.md#per-process-ulimits-nofile-).
17
+ - **Per-process ulimits** -- `ContainerConfig.ulimits` pins per-process limits (`nofile`, `nproc`, …) on a container. A containerized process inherits these from the runtime, not the host sysctl, so raising the host `fs.file-max` alone does not lift a database's open-files limit; setting `ulimits` does. A `nofile` request over the host ceiling is clamped (not rejected) so the container still starts. See the [developer guide](doc/plugin-developer-guide.md#per-process-ulimits-nofile-) and, for raising the host limit, [Raising the open-files limit](#raising-the-open-files-limit-nofile).
18
18
  - **Image management** -- scheduled pruning of dangling images (weekly/monthly)
19
19
  - **Zero-config data dir sharing** -- `signalkDataMount` mounts the SignalK data directory into any managed container automatically, whether Signal K runs bare-metal, in Docker (named volume), or in Podman (named volume or bind mount). No host paths to configure.
20
20
  - **Zero-config config root sharing** -- `signalkConfigRootMount` mounts the entire SignalK installation config (`~/.signalk/`) — for backup, audit, or config-sync tools that need the whole tree, not the per-plugin subdirectory.
@@ -23,6 +23,7 @@ Instead of each plugin implementing its own container orchestration, they delega
23
23
  - **Per-volume host-source policy** -- volumes accept `{ source, ifMissing: "skip" | "abort" }` for user-managed (USB drives, NFS) or deployment-required (TLS certs) mounts. Plugins subscribe to `onVolumeIssue` events for `'skipped'`, `'aborted'`, and `'recovered'` actions; signalk-container auto-recreates the container when a previously-missing source reappears. See the [developer guide](doc/plugin-developer-guide.md#optional-and-required-volumes).
24
24
  - **Container log streaming** -- click **Logs** on any managed-container card to open a live-streaming popup of the container's stdout+stderr (combined, the same shape `podman logs <name>` produces). Plugin authors can also wire `onContainerLog` in `ensureRunning` options to forward the same stream into their plugin's `app.debug` channel — visible in the Signal K server log when debug is enabled. Multiple subscribers share a single underlying log stream. See the [developer guide](doc/plugin-developer-guide.md#streaming-container-logs-into-your-plugins-debug-channel).
25
25
  - **Host-UID ownership alignment** -- managed containers run by default under the Signal K host user's UID/GID (via `--user host:host` on Docker/rootful Podman, `--userns=keep-id` on rootless Podman). Files created on bind mounts are owned by the same identity that runs Signal K, with no `chmod` sweeps. Override per container via `ContainerConfig.user` for images with a non-root `USER` directive, or `user: false` to opt out. See the [developer guide](doc/plugin-developer-guide.md#host-uid-ownership).
26
+ - **Data-directory teardown** -- `containers.removeManagedData(name, hostPath)` removes a managed container _and_ deletes its bind-mount data, even on rootless Podman where a container process running as a non-root in-container UID writes files owned by a host **subuid** the Signal K user can't `rm`. The host-side delete is tried first (docker / rootful); on EACCES it falls back to an in-userns wipe using the container's own image (no extra pull). Use it for plugin uninstall cleanup. See the [developer guide](doc/plugin-developer-guide.md#removemanageddataname-hostpath-options-promisevoid).
26
27
  - **Image compliance probes** -- `containers.doctor.imageRunsAsUser(image, user?)` runs the image under the live UID mapping and verifies it can write `/tmp` as the host caller. Surfaces UID-compatibility problems _before_ a container wedges in a restart loop. See the [developer guide](doc/plugin-developer-guide.md#containersdoctorimagerunsasuserimage-user-promiseimageproberesult).
27
28
  - **Podman image qualification** -- automatically prefixes `docker.io/` for short image names
28
29
  - **Docker `host.containers.internal` parity** -- signalk-container adds the `host-gateway` mapping for Docker automatically (Podman has it natively). User-supplied `extraHosts` overrides are respected.
@@ -272,6 +273,91 @@ The deployment doctor at `/api/doctor/deployment` also detects this
272
273
  scenario and surfaces the same kernel-cmdline fix in its `remediation`
273
274
  array, so you don't have to guess which layer is broken first.
274
275
 
276
+ ### Raising the open-files limit (`nofile`)
277
+
278
+ Some managed containers ask for a high per-process open-files limit
279
+ (`RLIMIT_NOFILE`). QuestDB is the common case — it recommends
280
+ `nofile=1048576` and otherwise logs an open-files warning and risks WAL
281
+ corruption under heavy ingestion.
282
+
283
+ A containerized process inherits `nofile` from the **container runtime**,
284
+ not from the host's `fs.file-max` sysctl — so raising `fs.file-max` does
285
+ **not** help here. And under **rootless Podman** a container can never
286
+ raise its hard limit above the limit of the user that runs the runtime.
287
+ When a plugin requests more than the host allows, signalk-container clamps
288
+ the request to the host ceiling so the container still starts (you'll see
289
+ an advisory in the requesting plugin's config panel, e.g. QuestDB's
290
+ "open-files limit capped by the host"). To grant the full value, raise the
291
+ host limit.
292
+
293
+ **Check the limit the container actually got:**
294
+
295
+ ```bash
296
+ # podman, or `docker exec` on Docker
297
+ podman exec <sk-container> cat /proc/1/limits | grep -i "open files"
298
+ # Max open files 524288 524288 ← the per-process cap in effect
299
+ ```
300
+
301
+ **Rootless Podman** runs under the systemd user session, so the lever is the
302
+ user manager's open-files limit, which a rootless container can never exceed.
303
+ There are two places to set it; on stock Debian / Raspberry Pi OS you usually
304
+ need the **second**. Editing `/etc/security/limits.conf` does **not** help —
305
+ `pam_limits` only touches login shells, not the user manager that parents the
306
+ podman socket. `LimitNOFILE` takes a `soft:hard` form; a single number sets
307
+ soft = hard, and the container's hard ceiling is the user manager's _hard_
308
+ limit.
309
+
310
+ **1. Per-user-manager drop-in.** One-time, requires sudo:
311
+
312
+ ```bash
313
+ sudo mkdir -p /etc/systemd/system/user@.service.d
314
+ sudo tee /etc/systemd/system/user@.service.d/nofile.conf <<'EOF'
315
+ [Service]
316
+ LimitNOFILE=1048576
317
+ EOF
318
+ sudo systemctl daemon-reload
319
+ ```
320
+
321
+ The new limit only applies once the **user manager itself restarts** — and
322
+ `daemon-reload` does **not** restart an already-running `user@<uid>.service`.
323
+ On a headless boat the SK user has linger enabled (`loginctl enable-linger`),
324
+ so logging out and back in does not tear it down. Force a fresh user manager,
325
+ then restart the container:
326
+
327
+ ```bash
328
+ sudo systemctl restart user@$(id -u <sk-user>).service # or just reboot
329
+ ```
330
+
331
+ **2. System-wide default (Raspberry Pi OS / openplotter, and the reliable
332
+ fallback).** Stock Debian / Pi OS ships `/etc/systemd/system.conf` with a
333
+ commented `#DefaultLimitNOFILE=1024:524288` — that 524288 _hard_ default is
334
+ what bounds the per-unit request when step 1 doesn't take. Raise the system
335
+ (PID 1) manager's default directly:
336
+
337
+ ```bash
338
+ sudo sed -i 's/^#\?DefaultLimitNOFILE=.*/DefaultLimitNOFILE=1048576:1048576/' /etc/systemd/system.conf
339
+ sudo systemctl daemon-reexec # NOT daemon-reload — manager-global defaults
340
+ # are only re-read when PID 1 re-executes itself
341
+ sudo reboot # respawns the lingering user@.service + podman
342
+ # under the raised default
343
+ ```
344
+
345
+ **Rootful Podman / Docker** read the limit from the daemon's own service.
346
+ For Docker, set `LimitNOFILE=1048576` in a `docker.service` drop-in
347
+ (`/etc/systemd/system/docker.service.d/nofile.conf`), `daemon-reload`, and
348
+ restart the daemon.
349
+
350
+ The value cannot exceed the kernel's absolute per-process cap, `fs.nr_open`
351
+ (`cat /proc/sys/fs/nr_open` — typically ~1 billion, so not a practical limit).
352
+ Verify (either path):
353
+
354
+ ```bash
355
+ systemctl show user@$(id -u <sk-user>).service -p LimitNOFILE
356
+ # LimitNOFILE=1048576 ← the user manager now allows it
357
+ <runtime> exec <sk-container> cat /proc/1/limits | grep -i "open files"
358
+ # Max open files 1048576 1048576 ← the container actually got it
359
+ ```
360
+
275
361
  ### Watch out for systemd auto-restart (Quadlet / `Restart=always`)
276
362
 
277
363
  If you run Signal K via a podman Quadlet (`*.container` in
@@ -2,6 +2,7 @@ import type Docker from "dockerode";
2
2
  import { ContainerConfig, ContainerInfo, ContainerRuntimeInfo, ContainerState, EnsureRunningOptions, UlimitClamp, VolumeIssue, VolumeSpec } from "./types.js";
3
3
  import { StreamingProcessHandle } from "./runtime.js";
4
4
  import { type ContainerClient } from "./client.js";
5
+ import type { ErrorKind } from "./errors.js";
5
6
  /**
6
7
  * Build the value for a `-v <source>:<dest>[:flags]` argument with the
7
8
  * correct SELinux relabel suffix for the runtime.
@@ -464,6 +465,66 @@ prior?: ContainerConfig, _postRecreate?: boolean, _pull?: PullFn): Promise<void>
464
465
  export declare function startContainer(runtime: ContainerRuntimeInfo, name: string, client?: ContainerClient): Promise<void>;
465
466
  export declare function stopContainer(runtime: ContainerRuntimeInfo, name: string, client?: ContainerClient): Promise<void>;
466
467
  export declare function removeContainer(runtime: ContainerRuntimeInfo, name: string, client?: ContainerClient): Promise<void>;
468
+ /**
469
+ * Thrown by `removeContainer` when the runtime refuses to remove a container.
470
+ * Carries the classified `kind` so callers can distinguish a `permission`
471
+ * failure (a rootless container wedged unkillable in `Stopping`) — where
472
+ * keeping a healthy existing container beats failing startup — from other
473
+ * removal failures that should propagate.
474
+ */
475
+ export declare class ContainerRemovalError extends Error {
476
+ readonly kind: ErrorKind;
477
+ constructor(message: string, kind: ErrorKind);
478
+ }
479
+ /**
480
+ * Reject host paths that must never be recursively wiped. The guard is the
481
+ * cheap, always-correct floor (empty / `/` / a non-absolute path); the
482
+ * caller layers any deployment-specific "must be under the Signal K tree"
483
+ * check on top, where it has the data/config roots to compare against.
484
+ */
485
+ export declare function assertWipablePath(hostPath: string): void;
486
+ /**
487
+ * Result of one wipe-job run, mirroring the bits of `ContainerJobResult`
488
+ * that `removeManagedData` reasons about. Keeps `containers.ts` free of a
489
+ * `jobs.ts` import (jobs.ts already imports from here — the cycle would be
490
+ * real) while staying fully testable via an injected runner.
491
+ */
492
+ export interface WipeJobOutcome {
493
+ ok: boolean;
494
+ error?: string;
495
+ }
496
+ /**
497
+ * Delete a managed container's bind-mount data, working around the
498
+ * rootless-Podman subuid-ownership trap.
499
+ *
500
+ * Sequence:
501
+ * 1. Remove the container `name` (idempotent — a missing container is fine)
502
+ * so nothing holds the mount.
503
+ * 2. Try a direct host-side `fs.rm(hostPath, {recursive, force})`. On
504
+ * docker / rootful Podman the files are host-owned and this succeeds.
505
+ * 3. On EACCES/EPERM (the rootless-Podman case — files are owned by a
506
+ * subuid the host user can't touch) run `runWipeJob`: a one-shot helper
507
+ * that bind-mounts `hostPath` and `rm -rf`s its CONTENTS from inside the
508
+ * userns as in-container root, then retry the host-side delete to drop
509
+ * the now-empty host-owned parent dir.
510
+ *
511
+ * `runWipeJob(image, hostPath)` is injected so the runtime logic stays out
512
+ * of the `jobs.ts` import cycle and so unit tests can drive every branch
513
+ * without a real runtime. The wrapper in `index.ts` wires it to `runJob`
514
+ * with the container's own (already-present) image.
515
+ *
516
+ * `wipeImage` is the container's own image, captured from `inspect` BEFORE
517
+ * removal so the helper reuses bits already on disk — no registry pull on a
518
+ * possibly-offline boat. `null` when the container was already gone; the
519
+ * fallback then can't run, so a still-undeletable dir surfaces as an error.
520
+ */
521
+ export declare function removeManagedData(runtime: ContainerRuntimeInfo, name: string, hostPath: string, runWipeJob: (image: string, hostPath: string) => Promise<WipeJobOutcome>, client?: ContainerClient, onRemoved?: () => void): Promise<void>;
522
+ /**
523
+ * Container path the wipe helper mounts the data directory at — re-exported
524
+ * for the wrapper that builds the `runJob` config and for tests asserting the
525
+ * mount/command shape.
526
+ */
527
+ export declare const WIPE_MOUNT_PATH = "/sk-wipe-target";
467
528
  export declare function listContainers(runtime: ContainerRuntimeInfo, client?: ContainerClient): Promise<ContainerInfo[]>;
468
529
  export declare function pruneImages(runtime: ContainerRuntimeInfo, client?: ContainerClient): Promise<{
469
530
  imagesRemoved: number;
@@ -1 +1 @@
1
- {"version":3,"file":"containers.d.ts","sourceRoot":"","sources":["../src/containers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"containers.d.ts","sourceRoot":"","sources":["../src/containers.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,8 @@
1
1
  import * as net from "node:net";
2
+ import * as path from "node:path";
2
3
  import { PassThrough } from "node:stream";
3
4
  import { existsSync, readFileSync } from "node:fs";
5
+ import { rm } from "node:fs/promises";
4
6
  import { isContainerized, makeLineSplitter, userMappingFlags, } from "./runtime.js";
5
7
  import { demuxToText, demuxBufferToText, getClient, safe, safeInspect, } from "./client.js";
6
8
  import { resourcePayloadForRun } from "./resources.js";
@@ -1492,7 +1494,29 @@ prior, _postRecreate = false, _pull = pullImage) {
1492
1494
  if (drifted.length === 0)
1493
1495
  return false;
1494
1496
  debug(`Container ${fullName} config drift detected (${drifted.join(", ")}); recreating`);
1495
- await removeContainer(runtime, name, client);
1497
+ return recreateUnlessWedged(drifted.join(", "));
1498
+ };
1499
+ // Remove + recreate the container to apply a detected drift — but if removal
1500
+ // fails because the container is wedged unkillable in `Stopping` (the
1501
+ // rootless "sending SIGKILL … operation not permitted" condition) AND it is
1502
+ // still running, keep it and defer the recreate to the next start rather than
1503
+ // failing startup. Returns true if recreated, false if deferred. Shared by
1504
+ // the config-drift and digest-drift paths so both survive the wedge.
1505
+ const recreateUnlessWedged = async (driftDesc) => {
1506
+ try {
1507
+ await removeContainer(runtime, name, client);
1508
+ }
1509
+ catch (err) {
1510
+ if (err instanceof ContainerRemovalError &&
1511
+ err.kind === "permission" &&
1512
+ (await getContainerState(runtime, name, client)) === "running") {
1513
+ debug(`Container ${fullName} could not be removed to apply drift ` +
1514
+ `(${driftDesc}) — it is still running; keeping it and deferring ` +
1515
+ `the recreate. ${err.message}`);
1516
+ return false;
1517
+ }
1518
+ throw err;
1519
+ }
1496
1520
  await ensureRunning(runtime, name, config, debug, options, client, prior, true, _pull);
1497
1521
  return true;
1498
1522
  };
@@ -1533,9 +1557,7 @@ prior, _postRecreate = false, _pull = pullImage) {
1533
1557
  return false;
1534
1558
  }
1535
1559
  debug(`Container ${fullName} floating-tag digest drift detected (${liveId.slice(0, 19)}… → ${remoteId.slice(0, 19)}…); recreating`);
1536
- await removeContainer(runtime, name, client);
1537
- await ensureRunning(runtime, name, config, debug, options, client, prior, true, _pull);
1538
- return true;
1560
+ return recreateUnlessWedged(`digest ${liveId.slice(0, 19)}… → ${remoteId.slice(0, 19)}…`);
1539
1561
  };
1540
1562
  switch (state) {
1541
1563
  case "running": {
@@ -1700,9 +1722,141 @@ export async function removeContainer(runtime, name, client = getClient()) {
1700
1722
  const result = await safe(() => client.getContainer(fullName).remove({ force: true }));
1701
1723
  // 404 = already gone; that's success for a remove.
1702
1724
  if (!result.ok && result.error.kind !== "not-found") {
1703
- throw new Error(`Failed to remove ${fullName}: ${result.error.userMessage}`);
1725
+ // Surface the raw runtime error, not just the generic userMessage — a
1726
+ // hidden raw (e.g. podman's "sending SIGKILL … operation not permitted"
1727
+ // when a rootless container wedges in `Stopping`) is undiagnosable from
1728
+ // the report. Carry the kind so callers can react to a permission/wedge
1729
+ // failure (keep a healthy container running) vs hard-fail.
1730
+ throw new ContainerRemovalError(`Failed to remove ${fullName}: ${result.error.userMessage} (${result.error.raw})`, result.error.kind);
1731
+ }
1732
+ }
1733
+ /**
1734
+ * Thrown by `removeContainer` when the runtime refuses to remove a container.
1735
+ * Carries the classified `kind` so callers can distinguish a `permission`
1736
+ * failure (a rootless container wedged unkillable in `Stopping`) — where
1737
+ * keeping a healthy existing container beats failing startup — from other
1738
+ * removal failures that should propagate.
1739
+ */
1740
+ export class ContainerRemovalError extends Error {
1741
+ kind;
1742
+ constructor(message, kind) {
1743
+ super(message);
1744
+ this.kind = kind;
1745
+ this.name = "ContainerRemovalError";
1704
1746
  }
1705
1747
  }
1748
+ /**
1749
+ * Container path the wipe helper mounts the data directory at. Arbitrary —
1750
+ * the only requirement is that it not collide with image-baked paths the
1751
+ * helper's `rm` might depend on; a dedicated top-level dir avoids that.
1752
+ */
1753
+ const WIPE_MOUNT = "/sk-wipe-target";
1754
+ /** Posix error codes that signal "the host user can't delete this" and so
1755
+ * warrant the in-userns fallback rather than a hard failure. */
1756
+ const OWNERSHIP_ERROR_CODES = new Set(["EACCES", "EPERM"]);
1757
+ /** True for the EACCES/EPERM ownership errors that the in-userns wipe can fix.
1758
+ * Anything else (ENOENT, ENOTEMPTY from a live mount, …) is not an ownership
1759
+ * problem and should surface unchanged. */
1760
+ function isOwnershipError(err) {
1761
+ const code = err?.code;
1762
+ return code !== undefined && OWNERSHIP_ERROR_CODES.has(code);
1763
+ }
1764
+ /**
1765
+ * Reject host paths that must never be recursively wiped. The guard is the
1766
+ * cheap, always-correct floor (empty / `/` / a non-absolute path); the
1767
+ * caller layers any deployment-specific "must be under the Signal K tree"
1768
+ * check on top, where it has the data/config roots to compare against.
1769
+ */
1770
+ export function assertWipablePath(hostPath) {
1771
+ // Require an absolute path: a relative value would `path.resolve` to a
1772
+ // cwd-relative dir and quietly pass the root check, risking an rm -rf of
1773
+ // the wrong tree. The data/config sources signalk-container deals with are
1774
+ // always absolute, so reject anything else outright. Normalize first so a
1775
+ // root-equivalent like `/..` collapses to the root and is rejected too.
1776
+ const normalized = path.normalize(hostPath || "");
1777
+ if (!hostPath ||
1778
+ hostPath.trim() === "" ||
1779
+ !path.isAbsolute(hostPath) ||
1780
+ normalized === path.parse(normalized).root) {
1781
+ throw new Error(`removeManagedData: refusing to delete unsafe path ${JSON.stringify(hostPath)}`);
1782
+ }
1783
+ }
1784
+ /**
1785
+ * Delete a managed container's bind-mount data, working around the
1786
+ * rootless-Podman subuid-ownership trap.
1787
+ *
1788
+ * Sequence:
1789
+ * 1. Remove the container `name` (idempotent — a missing container is fine)
1790
+ * so nothing holds the mount.
1791
+ * 2. Try a direct host-side `fs.rm(hostPath, {recursive, force})`. On
1792
+ * docker / rootful Podman the files are host-owned and this succeeds.
1793
+ * 3. On EACCES/EPERM (the rootless-Podman case — files are owned by a
1794
+ * subuid the host user can't touch) run `runWipeJob`: a one-shot helper
1795
+ * that bind-mounts `hostPath` and `rm -rf`s its CONTENTS from inside the
1796
+ * userns as in-container root, then retry the host-side delete to drop
1797
+ * the now-empty host-owned parent dir.
1798
+ *
1799
+ * `runWipeJob(image, hostPath)` is injected so the runtime logic stays out
1800
+ * of the `jobs.ts` import cycle and so unit tests can drive every branch
1801
+ * without a real runtime. The wrapper in `index.ts` wires it to `runJob`
1802
+ * with the container's own (already-present) image.
1803
+ *
1804
+ * `wipeImage` is the container's own image, captured from `inspect` BEFORE
1805
+ * removal so the helper reuses bits already on disk — no registry pull on a
1806
+ * possibly-offline boat. `null` when the container was already gone; the
1807
+ * fallback then can't run, so a still-undeletable dir surfaces as an error.
1808
+ */
1809
+ export async function removeManagedData(runtime, name, hostPath, runWipeJob, client = getClient(),
1810
+ // Invoked exactly once, the instant the container is removed (before the data
1811
+ // delete). Lets the caller tear down container-scoped state (ports, log
1812
+ // broker) only when removal actually happened — not on a pre-removal failure
1813
+ // such as a non-404 inspect error, when the container is still running.
1814
+ onRemoved = () => { }) {
1815
+ assertWipablePath(hostPath);
1816
+ // Capture the image before removal so the in-userns fallback can reuse it
1817
+ // (guaranteed present locally — the container was just running it).
1818
+ const fullName = prefixedName(name);
1819
+ const info = await safeInspect(() => client.getContainer(fullName).inspect());
1820
+ const wipeImage = typeof info?.Config?.Image === "string" ? info.Config.Image : null;
1821
+ await removeContainer(runtime, name, client);
1822
+ onRemoved();
1823
+ // Docker / rootful Podman: bind-mount files are host-owned, plain rm works.
1824
+ try {
1825
+ await rm(hostPath, { recursive: true, force: true });
1826
+ return;
1827
+ }
1828
+ catch (err) {
1829
+ if (!isOwnershipError(err))
1830
+ throw err;
1831
+ }
1832
+ // Rootless-Podman subuid case: the host user can't delete subuid-owned
1833
+ // files. Wipe the dir contents from inside the userns (as in-container
1834
+ // root, which owns them) using the container's own image, then retry the
1835
+ // host-side delete to drop the now-empty host-owned parent.
1836
+ if (!wipeImage) {
1837
+ throw new Error(`removeManagedData: ${hostPath} is not deletable by the Signal K user ` +
1838
+ `and the container's image is unknown (it was already removed), so the ` +
1839
+ `in-userns cleanup helper cannot run. Delete ${hostPath} manually.`);
1840
+ }
1841
+ const wipe = await runWipeJob(wipeImage, hostPath);
1842
+ if (!wipe.ok) {
1843
+ throw new Error(`removeManagedData: in-userns wipe of ${hostPath} failed: ${wipe.error ?? "unknown error"}`);
1844
+ }
1845
+ try {
1846
+ await rm(hostPath, { recursive: true, force: true });
1847
+ }
1848
+ catch (err) {
1849
+ const code = err.code ?? "unknown";
1850
+ throw new Error(`removeManagedData: ${hostPath} still not removable after in-userns wipe (${code}). ` +
1851
+ `Delete it manually.`, { cause: err });
1852
+ }
1853
+ }
1854
+ /**
1855
+ * Container path the wipe helper mounts the data directory at — re-exported
1856
+ * for the wrapper that builds the `runJob` config and for tests asserting the
1857
+ * mount/command shape.
1858
+ */
1859
+ export const WIPE_MOUNT_PATH = WIPE_MOUNT;
1706
1860
  export async function listContainers(runtime, client = getClient()) {
1707
1861
  const result = await safe(() => client.listContainers({
1708
1862
  all: true,