@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.
- package/config/socks/startup.sh +7 -0
- package/package.json +3 -3
- package/registry-server/package.json +1 -1
- package/scripts/stage-apt-repo.ts +3 -1
- package/src/module-host.ts +0 -1
- package/src/router-swap.ts +16 -2
- package/src/socks-proxy.ts +31 -3
- package/src/types.ts +14 -0
package/config/socks/startup.sh
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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(
|
package/src/module-host.ts
CHANGED
|
@@ -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) {
|
package/src/router-swap.ts
CHANGED
|
@@ -102,7 +102,21 @@ export function forwardedPorts(listing: string): string[] {
|
|
|
102
102
|
return [...new Set(ports)].sort();
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
/**
|
|
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
|
}
|
package/src/socks-proxy.ts
CHANGED
|
@@ -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
|
-
|
|
73
|
-
|
|
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 {
|