@celilo/e2e 0.2.1 → 0.3.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.
@@ -2,14 +2,14 @@ $ORIGIN iamtheinternet.org.
2
2
  $TTL 300
3
3
 
4
4
  @ IN SOA ns1.iamtheinternet.org. admin.iamtheinternet.org. (
5
- 2024010764 300 60 604800 300
5
+ 2024010769 300 60 604800 300
6
6
  )
7
7
 
8
8
  @ IN NS ns1.iamtheinternet.org.
9
9
  ns1 IN A 100.64.0.55
10
10
  @ IN A 0.0.0.0
11
11
  caddy IN A 100.100.0.100
12
- www IN A 10.0.10.10
12
+ www IN A 100.100.0.100
13
13
  deathstar IN A 100.100.0.100
14
14
  test IN A 0.0.0.0
15
15
  auth IN A 100.100.0.100
@@ -22,9 +22,12 @@ RUN update-ca-certificates
22
22
  # Point apt at the simulated apt cache proxy (for runtime apt usage)
23
23
  RUN echo 'Acquire::http::Proxy "http://100.64.0.2:3142";' > /etc/apt/apt.conf.d/00proxy
24
24
 
25
+ # Install celilo CLI from npm — provides the `celilo` command
26
+ RUN bun add -g @celilo/cli@0.1.4
27
+
25
28
  COPY config/ssh/generate-keys.sh /config/ssh/generate-keys.sh
26
29
  COPY config/routing/management-routes.sh /startup.sh
27
30
  RUN chmod +x /startup.sh /config/ssh/generate-keys.sh
28
31
 
29
- WORKDIR /celilo/apps/celilo
32
+ WORKDIR /root
30
33
  CMD ["/startup.sh"]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@celilo/e2e",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
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",
@@ -13,7 +13,12 @@ const PACKAGE_ROOT = join(__dirname, '..');
13
13
  * Find the Celilo project root by walking up from the package directory.
14
14
  * Looks for apps/celilo/ as the marker.
15
15
  */
16
- function findCeliloRoot(): string {
16
+ /**
17
+ * Try to find the Celilo project root by walking up from the package directory.
18
+ * Returns undefined if not found — the CLI is pre-installed in Docker so this
19
+ * is only needed for development (mounting local source).
20
+ */
21
+ function findCeliloRoot(): string | undefined {
17
22
  let dir = PACKAGE_ROOT;
18
23
  for (let i = 0; i < 10; i++) {
19
24
  if (existsSync(join(dir, 'apps', 'celilo'))) {
@@ -23,10 +28,7 @@ function findCeliloRoot(): string {
23
28
  if (parent === dir) break;
24
29
  dir = parent;
25
30
  }
26
- throw new Error(
27
- 'Could not find Celilo project root (directory containing apps/celilo/).\n' +
28
- 'Set it explicitly: network().celilo("/path/to/infra").start()',
29
- );
31
+ return undefined;
30
32
  }
31
33
 
32
34
  const COMPOSE_TIMEOUT = 120_000;
@@ -218,7 +220,7 @@ export async function startNetwork(config: NetworkConfig): Promise<NetworkHandle
218
220
 
219
221
  // Build and start per-test containers only
220
222
  console.log('[progress:start] building Docker images | images built');
221
- run(`docker compose -f ${COMPOSE_FILE} -p ${projectName} build`, { cwd: composeDir, timeout: 300_000 });
223
+ run(`docker compose -f ${COMPOSE_FILE} -p ${projectName} build`, { cwd: composeDir, timeout: 600_000 });
222
224
 
223
225
  console.log('[progress:start] starting containers | containers running');
224
226
  run(`docker compose -f ${COMPOSE_FILE} -p ${projectName} up -d`, { cwd: composeDir, timeout: 120_000 });
@@ -296,7 +298,7 @@ export async function startNetwork(config: NetworkConfig): Promise<NetworkHandle
296
298
  // Initialize celilo
297
299
  console.log('[progress:start] initializing celilo | celilo initialized');
298
300
  const initResult = dockerExec(projectName, composeDir, 'management',
299
- `cd /celilo/apps/celilo && bun run src/cli/index.ts system init --accept-defaults \
301
+ `celilo system init --accept-defaults \
300
302
  network.dmz.subnet=10.0.10.0/24 \
301
303
  network.app.subnet=10.0.20.0/24 \
302
304
  network.secure.subnet=10.0.30.0/24 \
@@ -317,7 +319,7 @@ export async function startNetwork(config: NetworkConfig): Promise<NetworkHandle
317
319
  const timeoutMs = typeof optsOrTimeout === 'number' ? optsOrTimeout : (optsOrTimeout?.timeoutMs ?? 120_000);
318
320
 
319
321
  const result = await dockerExecAsync(projectName, composeDir, 'management',
320
- `cd /celilo/apps/celilo && bun run src/cli/index.ts ${cmd}`, timeoutMs);
322
+ `celilo ${cmd}`, timeoutMs);
321
323
 
322
324
  if (check && result.exitCode !== 0) {
323
325
  throw new CeliloCommandError(cmd, result);
@@ -227,7 +227,7 @@ export function generateSharedInfraYaml(): string {
227
227
  * References the shared infrastructure's isp-external network as external.
228
228
  * Creates its own internal, dmz, app, secure networks.
229
229
  */
230
- export function generateTestComposeYaml(config: NetworkConfig, celiloRoot = '..'): string {
230
+ export function generateTestComposeYaml(config: NetworkConfig, celiloRoot?: string): string {
231
231
  const networks: Record<string, unknown> = {
232
232
  internal: networkDef('192.168.0.0/24', '192.168.0.250'),
233
233
  dmz: networkDef('10.0.10.0/24', '10.0.10.250'),
@@ -259,7 +259,7 @@ export function generateTestComposeYaml(config: NetworkConfig, celiloRoot = '..'
259
259
  networks: { internal: { ipv4_address: '192.168.0.100' } },
260
260
  cap_add: ['NET_ADMIN'],
261
261
  volumes: [
262
- `${celiloRoot}:/celilo`,
262
+ ...(celiloRoot ? [`${celiloRoot}:/celilo`] : []),
263
263
  'ssh-keys:/ssh-keys',
264
264
  ...(config.managementVolumes ?? []),
265
265
  ],
@@ -371,7 +371,7 @@ export function generateComposeYaml(config: NetworkConfig, celiloRoot = '..'): s
371
371
  networks: { internal: { ipv4_address: '192.168.0.100' } },
372
372
  cap_add: ['NET_ADMIN'],
373
373
  volumes: [
374
- `${celiloRoot}:/celilo`,
374
+ ...(celiloRoot ? [`${celiloRoot}:/celilo`] : []),
375
375
  'ssh-keys:/ssh-keys',
376
376
  ...(config.managementVolumes ?? []),
377
377
  ],
@@ -1,6 +1,36 @@
1
+ import { execSync } from 'node:child_process';
2
+ import { existsSync } from 'node:fs';
3
+ import { join } from 'node:path';
1
4
  import { startNetwork } from './container-manager';
2
5
  import type { NetworkConfig, NetworkHandle, TopologyPreset } from './types';
3
6
 
7
+ /**
8
+ * If a mounted path looks like a celilo module (has scripts/package.json),
9
+ * ensure its dependencies are installed on the host before Docker starts.
10
+ */
11
+ async function ensureModuleDeps(hostPath: string): Promise<void> {
12
+ // Check common locations for a module's scripts dir
13
+ for (const scriptsDir of [
14
+ join(hostPath, 'scripts'),
15
+ join(hostPath, 'celilo', 'scripts'),
16
+ ]) {
17
+ const pkgJson = join(scriptsDir, 'package.json');
18
+ const nodeModules = join(scriptsDir, 'node_modules');
19
+ if (existsSync(pkgJson) && !existsSync(nodeModules)) {
20
+ console.log(`[progress:start] installing deps in ${scriptsDir} | deps installed`);
21
+ try {
22
+ execSync('bun install', { cwd: scriptsDir, timeout: 30_000, stdio: 'pipe' });
23
+ } catch (err) {
24
+ const msg = err instanceof Error ? err.message : String(err);
25
+ throw new Error(
26
+ `Failed to install module dependencies in ${scriptsDir}:\n${msg}\n\n` +
27
+ `Fix: cd ${scriptsDir} && bun install`,
28
+ );
29
+ }
30
+ }
31
+ }
32
+ }
33
+
4
34
  export class NetworkBuilder {
5
35
  private config: NetworkConfig = {
6
36
  topology: 'default',
@@ -82,6 +112,13 @@ export class NetworkBuilder {
82
112
  }
83
113
 
84
114
  async start(): Promise<NetworkHandle> {
115
+ // Pre-flight: ensure mounted module directories have deps installed.
116
+ // Without this, `module import` tries to `bun install` inside Docker
117
+ // through the simulated internet, which is slow or fails.
118
+ for (const vol of this.config.managementVolumes) {
119
+ const [hostPath] = vol.split(':');
120
+ await ensureModuleDeps(hostPath);
121
+ }
85
122
  return startNetwork(this.config);
86
123
  }
87
124
  }
package/src/runner.ts CHANGED
@@ -505,15 +505,6 @@ async function main() {
505
505
  console.log(`${bold}╚══════════════════════════════════════════════════════════════╝${reset}`);
506
506
  console.log();
507
507
 
508
- // Shared infra check
509
- console.log(`${bold}Shared Infrastructure${reset}`);
510
- if (isSharedInfraHealthy()) {
511
- console.log(` ${green}✔ already running (DNS healthy)${reset}`);
512
- } else {
513
- console.log(` ${dim}Will start on first test...${reset}`);
514
- }
515
- console.log();
516
-
517
508
  const suiteStart = Date.now();
518
509
  const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
519
510
  const resultsDir = join(testDir, 'results', timestamp);