@wpelevator/tug 0.3.0 → 0.5.0

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.
package/README.md CHANGED
@@ -6,15 +6,15 @@ Deploy Docker Compose projects to one or more ordinary Linux VPSes through a sma
6
6
 
7
7
  ## Features
8
8
 
9
- - Control API with bearer-token auth, scoped `read`/`deploy`/`admin` API tokens for CI and teammates, an audit trail naming who acted, and SQLite metadata.
10
- - Nodes join over SSH (`node-install`) or enroll themselves with a single `docker run` (`node-enroll`), with per-node agent and registry tokens. Agents only dial out, so nodes behind NAT work.
11
- - Agents pull desired state from control, apply a generated per-node Compose file, run TCP/HTTP/Docker health checks and report status. An outbound WebSocket wakes them as soon as control queues work and carries live `exec`, followed logs, `ps` and `inspect` sessions, with long-poll and periodic-poll fallbacks for ordinary work.
9
+ - Control API with bearer-token auth, scoped `read`/`deploy`/`admin` API tokens for CI and teammates, an audit trail naming who acted, and SQLite metadata through Node's built-in driver.
10
+ - Nodes join over SSH (`node-install`) or enroll themselves with a single `docker run` (`node-enroll`), with one agent token per node. Agents only dial out, so nodes behind NAT work.
11
+ - Agents pull desired state from control, reconcile containers through the Docker Engine API, run TCP/HTTP/Docker health checks and report status. An outbound WebSocket wakes them as soon as control queues work and carries live `exec`, followed logs, `ps` and `inspect` sessions, with long-poll and periodic-poll fallbacks for ordinary work.
12
12
  - `x-tug` placement of services and volumes on nodes, with immutable desired-state records per deployment.
13
- - Build application images on control from uploaded source, or locally with `deploy --build-local`. Agents download saved images directly from control by default; a bring-your-own registry is optional.
13
+ - Build application images on control from uploaded source, or locally with `deploy --build-local`. Agents download saved images directly from control. Published images are pinned to registry digests at deployment creation.
14
14
  - Secrets encrypted at rest, released only to the nodes whose services reference them, with targeted service recreation when only a secret changes.
15
15
  - Deployment convergence, per-project operation locks, cancellation, rollback, per-service rollout events and log fetching through the agents.
16
16
  - Opt-in zero-downtime rolling rollouts for ingress-fronted services (`x-tug.rollout`) and automatic rollback of failed deployments (`x-tug.rollback: auto`). See [Compose extensions](docs/compose.md#rolling-rollouts).
17
- - Per-node registry pull tokens enforced by an htpasswd-backed registry you provide, with rotation and revocation.
17
+ - Private published images use encrypted project credentials for digest resolution and Engine API pulls.
18
18
  - Optional WireGuard mesh between nodes, health-aware cross-node service names and a managed Caddy ingress with automatic HTTPS, each opt-in. See [Networking](docs/networking.md).
19
19
  - Private-by-default published ports: generated Compose binds them to the overlay IP, loopback or the node address, never every interface unless you write `0.0.0.0`. See [Networking](docs/networking.md#published-ports-private-by-default).
20
20
  - Control-plane backup and restore, and `tug doctor` diagnostics.
@@ -31,7 +31,6 @@ Deploy Docker Compose projects to one or more ordinary Linux VPSes through a sma
31
31
  | Control API (role-checked) |
32
32
  | SQLite: desired states, secrets |
33
33
  | image builds, saved images |
34
- | registry (optional) |
35
34
  +-------------------------------------+
36
35
  ^ ^
37
36
  | agents dial out: work, status,
@@ -72,7 +71,7 @@ The CLI installs the matching `ghcr.io/wpelevator/tug:<version>` image on your h
72
71
 
73
72
  - [Architecture](docs/architecture.md): components, reconciliation, workflow diagrams, secrets and runtime paths.
74
73
  - [Compose extensions](docs/compose.md): `x-tug` placement, health checks, volumes and limitations.
75
- - [Control plane](docs/control-plane.md): install, TLS, registry credentials, backup and restore.
74
+ - [Control plane](docs/control-plane.md): install, TLS, image delivery, backup and restore.
76
75
  - [Backups](docs/backups.md): interim WordPress backup sidecar with restic, per-node and NFS variants, and a restore drill until `x-tug.backup` (M11).
77
76
  - [Access control](docs/access-control.md): scoped API tokens, roles, audit trail and a GitHub Actions deploy example.
78
77
  - [Networking](docs/networking.md): WireGuard mesh, service DNS, ingress and TLS, firewall notes.
@@ -80,7 +79,7 @@ The CLI installs the matching `ghcr.io/wpelevator/tug:<version>` image on your h
80
79
  - [CLI reference](docs/cli.md): every `tug` command and option.
81
80
  - [Configuration](docs/configuration.md): CLI, control and agent environment variables.
82
81
  - [Development](docs/development.md): local setup, CI, Compose stack, host mode and the integration test.
83
- - [Testing](docs/testing.md): test layers, the numbers rollouts are held to, and the backlog of mocked tests.
82
+ - [Testing](docs/testing.md): test layers, rollout metrics, mocked test backlog, and the [Caddy/PHP and static-file benchmark](docs/testing.md#caddy-proxy-overhead-benchmark).
84
83
  - [Observability](docs/observability.md): what can be observed today, and the proposed logs, metrics and alerting.
85
84
  - [Releases](docs/releases.md): changesets, npm and Docker image publishing.
86
85
  - [Standalone binary](docs/standalone-binary.md): proposed Bun-compiled CLI binaries and Homebrew distribution.
package/dist/agent.d.ts CHANGED
@@ -1,12 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import { WebSocket } from 'ws';
3
+ import type { ContainerSummary, DockerApi } from './docker-api.ts';
3
4
  import type { AgentLiveCommand, AgentLiveFrame } from './protocol.ts';
4
5
  import type { LiveEngineOptions } from './live.ts';
5
6
  import { parseDuration } from './util.ts';
6
- import type { DockerRunner, HostRunner, HttpClient } from './runners.ts';
7
+ import type { HostRunner, HttpClient } from './runners.ts';
7
8
  import type { Command, CommandResult, DesiredState, HealthCheck, ProjectStatus, ImageArtifact, PortBinding, ServiceEndpoint } from './protocol.ts';
8
9
  export interface AgentContext {
9
- docker: DockerRunner;
10
+ docker: DockerApi;
10
11
  http: HttpClient;
11
12
  nodeName: string;
12
13
  stateDir: string;
@@ -57,25 +58,23 @@ export declare class AgentLiveOperations {
57
58
  private readonly emit;
58
59
  private readonly engine;
59
60
  private readonly sessions;
60
- constructor(ctx: AgentContext, emit: (frame: AgentLiveOutputFrame) => void, options?: Omit<LiveEngineOptions, 'emit'>);
61
+ constructor(ctx: AgentContext, emit: (frame: AgentLiveOutputFrame) => void, options?: Omit<LiveEngineOptions, 'emit' | 'docker'>);
61
62
  handle(frame: AgentLiveControlFrame): Promise<void>;
62
63
  dispose(): void;
63
64
  private fail;
64
65
  private open;
65
66
  }
66
- export declare function containerIp(ctx: AgentContext, project: string, service: string, cwd: string, composeFile?: string): Promise<string>;
67
- export declare function waitForHealth(ctx: AgentContext, project: string, service: string, health: HealthCheck | null | undefined, cwd: string, composeFile?: string): Promise<void>;
67
+ /** The container's address on the project network, which health checks dial. */
68
+ export declare function containerIp(ctx: AgentContext, project: string, container: string): Promise<string>;
69
+ export declare function waitForHealth(ctx: AgentContext, project: string, container: string, service: string, health: HealthCheck | null | undefined): Promise<void>;
68
70
  export { parseDuration };
69
71
  export interface PublicListener {
70
72
  project: string;
71
73
  container: string;
72
74
  listen: string;
73
75
  }
74
- /**
75
- * Containers of Tug projects (`projects`, plus their rolling revision projects `<project>-…`) that
76
- * listen on all interfaces or on a public IP, from `docker ps --format '{{.Label "com.docker.compose.project"}}\t{{.Names}}\t{{.Ports}}'`.
77
- */
78
- export declare function publicListeners(psOutput: string, projects: readonly string[]): PublicListener[];
76
+ /** Containers of Tug projects (`projects`) that publish a port on all interfaces or on a public IP. */
77
+ export declare function publicListeners(containers: ContainerSummary[], projects: readonly string[]): PublicListener[];
79
78
  export declare function executeCommand(command: Command, ctx?: AgentContext): Promise<CommandResult>;
80
79
  export declare function ensureArtifact(ctx: AgentContext, artifact: ImageArtifact): Promise<void>;
81
80
  export declare function pruneManagedImages(ctx: AgentContext, retained: string[]): Promise<void>;
@@ -94,8 +93,6 @@ interface Creds {
94
93
  agentToken: string;
95
94
  nodeName?: string;
96
95
  controlUrl?: string;
97
- registry?: string | null;
98
- registryToken?: string | null;
99
96
  }
100
97
  export declare function loadOrEnroll(): Promise<Creds>;
101
98
  export declare function main(): Promise<void>;