@celilo/e2e 0.20.5 → 0.20.6

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.
@@ -124,6 +124,36 @@ ENV NODE_EXTRA_CA_CERTS=/etc/ssl/certs/ca-certificates.crt
124
124
  # fall through to Bun's normal resolution.
125
125
  RUN printf '[install.scopes]\n"@celilo" = "http://npm-registry.lab"\n' > /root/.bunfig.toml
126
126
 
127
+ # --- The fleet browser runtime (managed-browser-runtime) ----------------------
128
+ #
129
+ # Browser-driven health checks (celilo-web-console is the first) resolve
130
+ # `/var/lib/celilo/browsers/current/chrome` and a descriptor describing what
131
+ # was installed. This image provisions that runtime the way the celilo-mgmt
132
+ # role does on a real management host (`modules/celilo-mgmt/ansible/roles/
133
+ # celilo-mgmt/tasks/debian.yml`), pinned to the SAME playwright version that
134
+ # role declares — the fleet's single browser-version declaration. A module
135
+ # bundling a different client is a pin-drift finding, not a failure: the
136
+ # consumer passes the stable path explicitly.
137
+ #
138
+ # Revision comes from the pinned client itself (`install --dry-run`), never
139
+ # from a hand-maintained version→revision table — same reasoning as the role.
140
+ ARG PLAYWRIGHT_VERSION=1.60.0
141
+ RUN set -eux; \
142
+ REVISION="$(PLAYWRIGHT_BROWSERS_PATH=/var/lib/celilo/browsers bun x "playwright-core@${PLAYWRIGHT_VERSION}" install --dry-run chromium-headless-shell \
143
+ | grep -oE 'chromium_headless_shell-[0-9]+' | head -1 | cut -d- -f2)"; \
144
+ PLAYWRIGHT_BROWSERS_PATH=/var/lib/celilo/browsers bun x "playwright-core@${PLAYWRIGHT_VERSION}" install chromium-headless-shell; \
145
+ PLAYWRIGHT_BROWSERS_PATH=/var/lib/celilo/browsers bun x "playwright-core@${PLAYWRIGHT_VERSION}" install-deps chromium-headless-shell; \
146
+ BIN="$(find /var/lib/celilo/browsers/chromium_headless_shell-"${REVISION}" -type f \
147
+ \( -name chrome-headless-shell -o -name headless_shell \) | head -1)"; \
148
+ test -x "${BIN}"; \
149
+ mkdir -p /var/lib/celilo/browsers/current; \
150
+ ln -sf "${BIN}" /var/lib/celilo/browsers/current/chrome; \
151
+ BROWSER_VERSION="$(/var/lib/celilo/browsers/current/chrome --version | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | head -1)"; \
152
+ printf '{"schemaVersion":1,"browser":"chromium","flavor":"headless-shell","browserVersion":"%s","playwrightVersion":"%s","revision":"%s","writtenBy":"e2e management image"}' \
153
+ "${BROWSER_VERSION}" "${PLAYWRIGHT_VERSION}" "${REVISION}" \
154
+ > /var/lib/celilo/browsers/current/celilo-browser.json; \
155
+ cat /var/lib/celilo/browsers/current/celilo-browser.json
156
+
127
157
  # Standard modules pre-packaged as .netapp files — built by e2e-build.
128
158
  # Tests import from /netapps/<module>.netapp instead of the monorepo mount.
129
159
  COPY netapps/ /netapps/
@@ -18,6 +18,11 @@ RUN apt-get update && apt-get install -y \
18
18
  iproute2 \
19
19
  iputils-ping \
20
20
  dnsutils \
21
+ # wireguard-tools: the control-plane-vpn vantage. A browser that reaches
22
+ # celilo-web-console (secure-mgmt, VPN-only per D7) must enter as a real
23
+ # VPN peer — the proxy brings up a wg tunnel, it does not attach directly
24
+ # to the zone. Needs /dev/net/tun at `docker run` time (socks-proxy.ts).
25
+ wireguard-tools \
21
26
  && rm -rf /var/lib/apt/lists/*
22
27
 
23
28
  COPY config/socks/danted.conf /etc/danted.conf
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@celilo/e2e",
3
- "version": "0.20.5",
3
+ "version": "0.20.6",
4
4
  "description": "E2E test infrastructure for Celilo-deployed applications. Provides a simulated internet with DNS hierarchy, ACME server, firewalls, and target machines in Docker.",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -38,7 +38,7 @@
38
38
  "README.md"
39
39
  ],
40
40
  "dependencies": {
41
- "@celilo/capabilities": "^5.1.1",
41
+ "@celilo/capabilities": "^6.0.0",
42
42
  "@celilo/cli-display": "^0.2.0",
43
43
  "@celilo/event-bus": "^0.7.0",
44
44
  "@celilo/terraform-fake": "^0.3.1",
@@ -3,6 +3,7 @@ import { existsSync } from 'node:fs';
3
3
  import { createConnection } from 'node:net';
4
4
  import { join } from 'node:path';
5
5
  import { progress } from './progress';
6
+ import type { ExecResult, SocksProxyHandle } from './types';
6
7
 
7
8
  /** Package root — `docker/` and `config/` live here. */
8
9
  const PACKAGE_ROOT = join(__dirname, '..');
@@ -37,17 +38,6 @@ export interface SocksProxyOptions {
37
38
  nameserver?: string;
38
39
  }
39
40
 
40
- export interface SocksProxyHandle {
41
- /** URL the host can use to reach the proxy, e.g. 'socks5://127.0.0.1:54321' */
42
- hostUrl: string;
43
- /** The published host port (the second half of hostUrl) */
44
- hostPort: number;
45
- /** Container name (deterministic per project + vantage) */
46
- containerName: string;
47
- /** Tear down the proxy. Idempotent. */
48
- stop(): Promise<void>;
49
- }
50
-
51
41
  /**
52
42
  * Custom image with dante-server + an entrypoint that fixes routing
53
43
  * and DNS for the chosen vantage. Built from
@@ -139,6 +129,11 @@ export async function startSocksProxy(
139
129
  `--network ${networkName}`,
140
130
  `--ip ${cfg.ip}`,
141
131
  '--cap-add NET_ADMIN',
132
+ // wireguard-tools in the image plus the TUN device let the proxy bring
133
+ // up a real WireGuard tunnel, which is how a browser enters the
134
+ // topology as a control-plane-vpn peer (celilo-web-console's only
135
+ // client path, D7). Harmless for the plain vantages.
136
+ '--device /dev/net/tun',
142
137
  `-e VANTAGE=${vantage}`,
143
138
  ...(options.nameserver ? [`-e NAMESERVER_OVERRIDE=${options.nameserver}`] : []),
144
139
  '-p 127.0.0.1::1080',
@@ -224,6 +219,32 @@ function makeHandle(containerName: string, port: number): SocksProxyHandle {
224
219
  hostUrl: `socks5://127.0.0.1:${port}`,
225
220
  hostPort: port,
226
221
  containerName,
222
+ /**
223
+ * Run a command inside the proxy container.
224
+ *
225
+ * The proxy is started with `docker run`, not compose, so
226
+ * `net.exec` (a `docker compose exec`) cannot reach it. The
227
+ * control-plane-vpn test uses this to bring the proxy's WireGuard
228
+ * tunnel up after the tunnel has deployed — the peer is the proxy,
229
+ * so the browser behind it enters the topology the way a real
230
+ * admin laptop does.
231
+ */
232
+ async exec(cmd, timeoutMs = 60_000): Promise<ExecResult> {
233
+ try {
234
+ const stdout = execSync(`docker exec ${containerName} bash -c ${JSON.stringify(cmd)}`, {
235
+ timeout: timeoutMs,
236
+ stdio: 'pipe',
237
+ }).toString();
238
+ return { stdout, stderr: '', exitCode: 0 };
239
+ } catch (err: unknown) {
240
+ const e = err as { stdout?: Buffer; stderr?: Buffer; status?: number };
241
+ return {
242
+ stdout: e.stdout?.toString() ?? '',
243
+ stderr: e.stderr?.toString() ?? String(err),
244
+ exitCode: e.status ?? 1,
245
+ };
246
+ }
247
+ },
227
248
  async stop(): Promise<void> {
228
249
  if (stopped) return;
229
250
  stopped = true;
package/src/types.ts CHANGED
@@ -220,6 +220,14 @@ export interface SocksProxyHandle {
220
220
  hostPort: number;
221
221
  /** Container name (deterministic per project + vantage) */
222
222
  containerName: string;
223
+ /**
224
+ * Run a command inside the proxy container (raw `docker exec`).
225
+ *
226
+ * The proxy is started with `docker run`, not compose, so `net.exec`
227
+ * cannot reach it. The control-plane-vpn browser test uses this to bring
228
+ * the proxy's WireGuard tunnel up after the tunnel has deployed.
229
+ */
230
+ exec(cmd: string, timeoutMs?: number): Promise<ExecResult>;
223
231
  /** Tear down the proxy. Idempotent. */
224
232
  stop(): Promise<void>;
225
233
  }