@celilo/e2e 0.16.1 → 0.17.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.
@@ -34,6 +34,13 @@ esac
34
34
  ip route del default 2>/dev/null || true
35
35
  ip route add default via "$GATEWAY"
36
36
 
37
+ # An explicit resolver from the caller wins over the vantage default. The proxy
38
+ # is what resolves names for a SOCKS5 client — a browser hands it the hostname
39
+ # and never resolves it itself — so a test driving a browser at a name only the
40
+ # fleet's own resolver knows has to say so here. Modelling a real device: one
41
+ # on the internal zone is handed the fleet's resolver, not a fixed stub.
42
+ NAMESERVER="${NAMESERVER_OVERRIDE:-$NAMESERVER}"
43
+
37
44
  # Bypass docker's embedded resolver — point directly at the in-network
38
45
  # DNS so split-horizon and the namecheap simulator both behave correctly.
39
46
  echo "nameserver $NAMESERVER" > /etc/resolv.conf
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@celilo/e2e",
3
- "version": "0.16.1",
3
+ "version": "0.17.1",
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",
@@ -37,10 +37,10 @@
37
37
  "README.md"
38
38
  ],
39
39
  "dependencies": {
40
- "@celilo/capabilities": "^2.0.0",
40
+ "@celilo/capabilities": "^2.4.0",
41
41
  "@celilo/cli-display": "^0.2.0",
42
42
  "@celilo/event-bus": "^0.6.0",
43
- "@celilo/terraform-fake": "^0.3.0",
43
+ "@celilo/terraform-fake": "^0.3.1",
44
44
  "yaml": "^2.8.0",
45
45
  "zod": "^3.24.1"
46
46
  },
@@ -8,7 +8,7 @@
8
8
  "start": "bun run src/index.ts",
9
9
  "dev": "bun --watch src/index.ts",
10
10
  "build:binary": "bun build --compile --target=bun-linux-x64 --outfile=dist/celilo-registry-server src/index.ts",
11
- "test": "bun test"
11
+ "test": "bun test --timeout 30000"
12
12
  },
13
13
  "devDependencies": {
14
14
  "bun-types": "latest",
@@ -98,7 +98,9 @@ export function stageAptRepo(repoRoot: string, pkgDir: string): boolean {
98
98
 
99
99
  const debs = readdirSync(distDir).filter((f) => f.endsWith('.deb') && f.includes(version));
100
100
  for (const deb of debs) {
101
- cpSync(join(distDir, deb), join(pool, deb));
101
+ // `force` explicit: a rebuilt .deb at the same version must replace the
102
+ // one already pooled, or build-infra serves stale bytes.
103
+ cpSync(join(distDir, deb), join(pool, deb), { force: true });
102
104
  }
103
105
 
104
106
  console.log(
@@ -48,7 +48,6 @@ export function parseModuleHost(statusOutput: string): ModuleHost | null {
48
48
  // both, and a raw match silently finds nothing.
49
49
  const lines = statusOutput
50
50
  .split('\n')
51
- // biome-ignore lint/suspicious/noControlCharactersInRegex: stripping ANSI is the point
52
51
  .map((line) => line.replace(/\x1b\[[0-9;]*m/g, '').replace(/^[\s│|]+/, ''));
53
52
 
54
53
  for (const line of lines) {
@@ -102,7 +102,21 @@ export function forwardedPorts(listing: string): string[] {
102
102
  return [...new Set(ports)].sort();
103
103
  }
104
104
 
105
- /** The DHCP pool's advertised DNS servers, read back off the device. */
105
+ /**
106
+ * The DHCP pool's advertised DNS servers, read back off the device.
107
+ *
108
+ * Queries the pool INSTANCE (`…Pool.1.`), not the collection (`…Pool.`). The
109
+ * simulator answers the collection form with `{"Objects":[]}` — no error, just
110
+ * an empty list — so the collection form reads as "the router advertises no DNS
111
+ * servers" whatever is actually configured. Both `greenwave` and `axon` write
112
+ * through `Device.DHCPv4.Server.Pool.1.`
113
+ * (`modules/greenwave/scripts/isp-router-functions.ts:153`), so this reads back
114
+ * exactly where the module wrote.
115
+ *
116
+ * Nothing called this until `e2e/tests/provider-arrival-backfill.test.ts`, which
117
+ * is how the mismatch survived: against the collection form an assertion fails
118
+ * identically whether the router was configured or not.
119
+ */
106
120
  export async function routerDhcpDnsServers(
107
121
  net: NetworkHandle,
108
122
  device: RouterDevice,
@@ -115,7 +129,7 @@ export async function routerDhcpDnsServers(
115
129
  );
116
130
  const listed = await net.exec(
117
131
  'fw-isp',
118
- `curl -sk 'https://${greenwaveRouterIp()}/cgi/cgi_get?Object=Device.DHCPv4.Server.Pool.' -b /tmp/dhcp-cookies`,
132
+ `curl -sk 'https://${greenwaveRouterIp()}/cgi/cgi_get?Object=Device.DHCPv4.Server.Pool.1.' -b /tmp/dhcp-cookies`,
119
133
  );
120
134
  return listed.stdout;
121
135
  }
@@ -22,6 +22,19 @@ export interface SocksProxyOptions {
22
22
  * zones via the firewall.
23
23
  */
24
24
  vantage?: SocksProxyVantage;
25
+ /**
26
+ * Resolver the proxy should use instead of the vantage's baked default.
27
+ *
28
+ * The PROXY resolves names for a SOCKS5 client: chromium configured with
29
+ * `socks5://` sends the hostname and never resolves it itself. A test driving
30
+ * a browser at a name only the fleet's own resolver knows — anything on a
31
+ * private ingress — therefore has to point the proxy at that resolver.
32
+ *
33
+ * More faithful rather than less: the rig's baked stub answers a fixed
34
+ * split-horizon table, whereas a device on the internal zone is handed the
35
+ * fleet's resolver. Pass the deployed resolver's DNS-ingress address.
36
+ */
37
+ nameserver?: string;
25
38
  }
26
39
 
27
40
  export interface SocksProxyHandle {
@@ -69,8 +82,22 @@ const VANTAGE_CONFIGS: Record<SocksProxyVantage, VantageConfig> = {
69
82
  },
70
83
  };
71
84
 
72
- function containerNameFor(projectName: string, vantage: SocksProxyVantage): string {
73
- return `${projectName}-socks-${vantage}`;
85
+ /**
86
+ * Deterministic per (project, vantage, resolver).
87
+ *
88
+ * The resolver is part of the identity because a proxy is REUSED by name: two
89
+ * calls differing only in `nameserver` would otherwise silently share one
90
+ * container, and the second would resolve through the first's resolver. That
91
+ * failure looks like a DNS bug in the fleet, which is the worst possible place
92
+ * for it to look like anything.
93
+ */
94
+ function containerNameFor(
95
+ projectName: string,
96
+ vantage: SocksProxyVantage,
97
+ nameserver?: string,
98
+ ): string {
99
+ const suffix = nameserver ? `-dns-${nameserver.replace(/\./g, '-')}` : '';
100
+ return `${projectName}-socks-${vantage}${suffix}`;
74
101
  }
75
102
 
76
103
  /**
@@ -85,7 +112,7 @@ export async function startSocksProxy(
85
112
  const vantage = options.vantage ?? 'isp-external';
86
113
  const cfg = VANTAGE_CONFIGS[vantage];
87
114
  const networkName = `${projectName}_${cfg.network}`;
88
- const containerName = containerNameFor(projectName, vantage);
115
+ const containerName = containerNameFor(projectName, vantage, options.nameserver);
89
116
 
90
117
  // Reuse existing container if one is running for this project + vantage
91
118
  const existing = inspectContainer(containerName);
@@ -113,6 +140,7 @@ export async function startSocksProxy(
113
140
  `--ip ${cfg.ip}`,
114
141
  '--cap-add NET_ADMIN',
115
142
  `-e VANTAGE=${vantage}`,
143
+ ...(options.nameserver ? [`-e NAMESERVER_OVERRIDE=${options.nameserver}`] : []),
116
144
  '-p 127.0.0.1::1080',
117
145
  PROXY_IMAGE,
118
146
  ].join(' '),
package/src/types.ts CHANGED
@@ -182,6 +182,20 @@ export class CeliloCommandError extends Error {
182
182
  */
183
183
  export interface ProxyOptions {
184
184
  vantage?: 'isp-external' | 'internal';
185
+ /**
186
+ * Resolver the proxy should use, overriding the vantage's baked default.
187
+ *
188
+ * The proxy is what actually resolves names: a browser configured with
189
+ * `socks5://` hands the HOSTNAME to the proxy and never resolves it itself.
190
+ * So a test driving a browser at a name only the fleet's own resolver knows
191
+ * — anything on a private ingress — must point the proxy at that resolver.
192
+ *
193
+ * This is more faithful, not less: the rig's baked stub answers a fixed
194
+ * split-horizon table, whereas a real device on the internal zone is handed
195
+ * the fleet's resolver by DHCP. Pass the deployed resolver's DNS-ingress
196
+ * address here to model that.
197
+ */
198
+ nameserver?: string;
185
199
  }
186
200
 
187
201
  export interface SocksProxyHandle {