@celilo/e2e 0.17.1 → 0.18.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/bin/e2e-status +1 -1
- package/config/namecheap/ddns-tls.crt +21 -0
- package/config/namecheap/ddns-tls.key +28 -0
- package/config/namecheap/namecheap-ca.crt +20 -0
- package/config/routing/management-routes.sh +0 -3
- package/docker/Dockerfile.management +6 -0
- package/docker/Dockerfile.namecheap-dns +6 -0
- package/package.json +2 -2
- package/simulators/namecheap-ddns/server.ts +22 -1
- package/src/container-manager.ts +5 -0
- package/src/docker-compose-generator.ts +0 -2
- package/src/simulator-ips.ts +1 -1
- package/src/types.ts +13 -1
package/bin/e2e-status
CHANGED
|
@@ -32,4 +32,4 @@ done
|
|
|
32
32
|
echo ""
|
|
33
33
|
echo "=== DDNS Simulator ==="
|
|
34
34
|
echo -n " Status: "
|
|
35
|
-
docker compose -p "$PROJECT_NAME" exec -T namecheap-dns curl -s
|
|
35
|
+
docker compose -p "$PROJECT_NAME" exec -T namecheap-dns curl -s --cacert /etc/ssl/namecheap-sim/namecheap-ca.crt https://dynamicdns.park-your-domain.com/status --resolve dynamicdns.park-your-domain.com:443:127.0.0.1 2>/dev/null || echo "(not running)"
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIDfTCCAmWgAwIBAgIUdjRGJDcAnXSrb8e8pgTGItaituQwDQYJKoZIhvcNAQEL
|
|
3
|
+
BQAwJjEkMCIGA1UEAwwbY2VsaWxvIGUyZSBOYW1lY2hlYXAgc2ltIENBMCAXDTI2
|
|
4
|
+
MDgyMTA2NDEyNFoYDzIxMjYwNzI4MDY0MTI0WjAqMSgwJgYDVQQDDB9keW5hbWlj
|
|
5
|
+
ZG5zLnBhcmsteW91ci1kb21haW4uY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
|
6
|
+
MIIBCgKCAQEAqWyqjNCSLxfJLhgwJBT78SzmLb9sRdHCrXYrxeqBF3dHR3aM5/oj
|
|
7
|
+
CuiwT1l8P87cCauTbfHXSpOKRa0HDaQ5ArCQgBOxcK0Q4FzeUKRUtfbA9QR+b7ym
|
|
8
|
+
FQDSV7nYG8oOFnQybr/uKpfRaficzGQQJZDZ3mEXC24J5LLc0PYc6kgASZMy8QY6
|
|
9
|
+
PkCVdzX8viu0J3jGL780W/7AkNuLyzBmBs9SOyWy8vETY4MsRgm0Umv/Rh0MD33P
|
|
10
|
+
n/D5EFYb8bbKAWnEXbpY7p7N7o2Er1IrNq1SD4TCkmR9VLeNm+pdYt6RKBaFoAYd
|
|
11
|
+
Jbhk5YjnefqvlCPYyW2jyHOkh2I6up/P4QIDAQABo4GcMIGZMCoGA1UdEQQjMCGC
|
|
12
|
+
H2R5bmFtaWNkbnMucGFyay15b3VyLWRvbWFpbi5jb20wCQYDVR0TBAIwADALBgNV
|
|
13
|
+
HQ8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFMpDRmoxUAwc
|
|
14
|
+
WJg/0WKwllOse/y7MB8GA1UdIwQYMBaAFNLIv6wf7Q7vOHzctgjyYKGapXkwMA0G
|
|
15
|
+
CSqGSIb3DQEBCwUAA4IBAQAgp2bS+l/5mcoHVTlpt7pKbSx/LNzKAoatbchIQuoI
|
|
16
|
+
uaEy77r6XhLC1BAcqQRIQ38zBDHSQHcR6bI4nSY24HnczZHxM9r6LoJ8MKvXuuH+
|
|
17
|
+
rllrJb3qqvQECO9y4N3bvoK2RT6EjkwqNRsuvn0qtfSOkY2StJrMBdIlFjlAO0FZ
|
|
18
|
+
Bu1+ZBYeqRP+AoTidjzSuU7JgGhGEHLdKJnoBlo4o9FbHgGBw8wgQiUUnWUfcHhw
|
|
19
|
+
Uy+6f2RvK8jrPh2baWnqxpLRBBZdfmN4yu7JKs88uMBpRA9lD29essb/Q9MP8F/H
|
|
20
|
+
2N0zizK46OSkimSMKACbI5U/f2E7JCuQukZV6VotrchC
|
|
21
|
+
-----END CERTIFICATE-----
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
-----BEGIN PRIVATE KEY-----
|
|
2
|
+
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCpbKqM0JIvF8ku
|
|
3
|
+
GDAkFPvxLOYtv2xF0cKtdivF6oEXd0dHdozn+iMK6LBPWXw/ztwJq5Nt8ddKk4pF
|
|
4
|
+
rQcNpDkCsJCAE7FwrRDgXN5QpFS19sD1BH5vvKYVANJXudgbyg4WdDJuv+4ql9Fp
|
|
5
|
+
+JzMZBAlkNneYRcLbgnkstzQ9hzqSABJkzLxBjo+QJV3Nfy+K7QneMYvvzRb/sCQ
|
|
6
|
+
24vLMGYGz1I7JbLy8RNjgyxGCbRSa/9GHQwPfc+f8PkQVhvxtsoBacRduljuns3u
|
|
7
|
+
jYSvUis2rVIPhMKSZH1Ut42b6l1i3pEoFoWgBh0luGTliOd5+q+UI9jJbaPIc6SH
|
|
8
|
+
Yjq6n8/hAgMBAAECggEAMUj3qgPoaoOgVeTaaDykd6mIgglb3UmiOKSWIjpP+DwO
|
|
9
|
+
A6dkYP0eYYeD9mlBICy0TKnZNtPxvXOC9zbYxOqfXP1w45kW9oCZ1rKdR1cuf0p7
|
|
10
|
+
Iit+/lEh/R0ikztwNtFF3NlLbHUvurs0Q3/7WOfI3Kyw/CRBOGV3wkwXuT/G9I2p
|
|
11
|
+
PzPc5eB0XThMXw5TfpcQfRedCOTjGelVk/fDF7cqRuK/g9f77XTfZ76ftLFBREvv
|
|
12
|
+
/7v8rJMoljL08fpU30r1xAFRNQHLfkUVLQxB1l3g9BJ91VieSUHgWljdS4hGDvf/
|
|
13
|
+
djfSIzq4bpkkoYVt8jGOA9+7peahVhWzCEdjVFTlKwKBgQDSi4v+1SCllgqoLSRe
|
|
14
|
+
FvFlWEwMeJWGN2qqxrXfWURgK8ODMgDxYjvwtFr5kO+JfWFrsT5DLYduWOyUkU/O
|
|
15
|
+
b8Qw3Sd2MAgU2cO/ejf/xDIgyIVao+Mg+x2pAADm6NFknUiBHOvZ0MbLZHUpa7uD
|
|
16
|
+
Z0fFXDqhKyIAGC0DvKqD8qp26wKBgQDOAHSZ1kfic074FmUU136I82pwdViVrEHA
|
|
17
|
+
OMNmNaqnrU9HkKqrwIqHrOTdEMNQnkB+OMmJNK6H4N54PILze+TR+EYu6d1BiTWK
|
|
18
|
+
3TAyhaA/eNGa3NuVyg8/wLFPxHj7QLUpv7JsqBKg45/GlPyXU5HtDX0Bsi3COlfX
|
|
19
|
+
YlQi70y5YwKBgHFnwMxON/t4ydy0E/aqHPQdjzjYapGUn9vElIntJys152VvNZrO
|
|
20
|
+
8sJAIxBxxNQluKetHIBKsbv6IdQUQQxMnzxCotLCJFg2w30Lc8ZMA0QtPccIp3pI
|
|
21
|
+
SD2TRukZVk//d+IzlcYI8krznTfmU2X/52SivOG6veGXJAfzQ1U3DCJpAoGAde4Q
|
|
22
|
+
0li3gk3csW2wpEPRbnlbP9INynF4mqBkTEkAz0kKD8Aj1Hs/UviJdHy6M5bE+P1t
|
|
23
|
+
cpy0JZl4AoExvk346rMlCopbXb885ahGhUW2PV/fLratBo1MOYUIfM/PKpcanzHc
|
|
24
|
+
5RM6xtxIhZiZGdB/w6NrIuNsCrr3upfR7sXruF0CgYEAskixy85n2KZzr8kEz3Vb
|
|
25
|
+
ji7zwB9Nl5qSYThc73dmaDCeLGeStfvpjg6TZNHtB9IXzpCo11D1jN04uHigMhAt
|
|
26
|
+
N5hvFmI5eLGLL6EEpMusms9EVPkclybMnS/ykjOX4YNxwTn5fi28ITN36VSulFN/
|
|
27
|
+
OWZYLOMmP6gMqfNJ7ktAA5o=
|
|
28
|
+
-----END PRIVATE KEY-----
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIDLzCCAhegAwIBAgIUeuo47ZC6Ka3Zfq7a36MZPnASRQwwDQYJKoZIhvcNAQEL
|
|
3
|
+
BQAwJjEkMCIGA1UEAwwbY2VsaWxvIGUyZSBOYW1lY2hlYXAgc2ltIENBMCAXDTI2
|
|
4
|
+
MDgyMTA2NDEyNFoYDzIxMjYwNzI4MDY0MTI0WjAmMSQwIgYDVQQDDBtjZWxpbG8g
|
|
5
|
+
ZTJlIE5hbWVjaGVhcCBzaW0gQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
|
6
|
+
AoIBAQC2W2bH5m1J6SAkRTT7vspz22V9mWlv1TzWOqVuuRBFQ4IrBlSKrCrgOdi6
|
|
7
|
+
/IAu9rkY2DJsgt3ts4L4IhJnA3VRGU+UltdAwPuo5eOHGq9aLPwaa/Rb7q4Act+a
|
|
8
|
+
53wVp3eLDAEvY4fk+dHUay87Ar2sXC+8WgwVZwUGoOpRE7/IWab9Q98a3hDYMQ1h
|
|
9
|
+
B71z2Ecz1g1z1w/zBqjiR4IMwgVV2VZ9yCmXBSad2mVCPf/51rWuY9ooZw73MbRc
|
|
10
|
+
PByejx0Fa8jigfFszG/oE2i7alO3ISmJzODgX8AuqqO3yVokKGTUY1DsJxas1U27
|
|
11
|
+
vhlHtYfVEhnUXgWyZphWvr38DslLAgMBAAGjUzBRMB0GA1UdDgQWBBTSyL+sH+0O
|
|
12
|
+
7zh83LYI8mChmqV5MDAfBgNVHSMEGDAWgBTSyL+sH+0O7zh83LYI8mChmqV5MDAP
|
|
13
|
+
BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQA4BF303aKFEXpTHrPY
|
|
14
|
+
L3zopaL6EYTL6fzU8dhB5ZwCXfCJUa5Rx860kIFSjSaUd3rCfJ/70MTe9SQUGKVF
|
|
15
|
+
dt659/PA8olQtZQJsNOSjduQxAgwGe3T8V3G/qDogGDTAJKWGMQCWYSEwBjr30pQ
|
|
16
|
+
keyX1ahBzWwSg3FmdEOt35SfhvFQ4S/TAoEM33QARq+jJfMBupPNSIETgcr+Rimn
|
|
17
|
+
YWbshg1zfXuQnju9qV3R1bEST7ZSH+CjXhPu6CCbu/jTT3lPRIB04w2Yw5IAi1Kh
|
|
18
|
+
SzCF3TlQEUXpkPhlYpglhW0q3wgfp7QmnquNLHo6E8I+PyBjkSkg+Xq2cw14bE0i
|
|
19
|
+
MWHp
|
|
20
|
+
-----END CERTIFICATE-----
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
set -e
|
|
3
3
|
|
|
4
4
|
# System-wide environment for all processes (hooks, ansible, etc.)
|
|
5
|
-
echo 'DDNS_ENDPOINT=http://100.64.0.55:8080/update' >> /etc/environment
|
|
6
|
-
export DDNS_ENDPOINT="http://100.64.0.55:8080/update"
|
|
7
5
|
|
|
8
6
|
# Generate SSH keys if needed
|
|
9
7
|
/config/ssh/generate-keys.sh /ssh-keys
|
|
@@ -105,7 +103,6 @@ cat > /root/.zshrc << ZSHRC
|
|
|
105
103
|
export PATH="/root/.bun/bin:/usr/local/bin:\$PATH"
|
|
106
104
|
|
|
107
105
|
# Simulated network overrides
|
|
108
|
-
export DDNS_ENDPOINT="http://100.64.0.55:8080/update"
|
|
109
106
|
|
|
110
107
|
# History
|
|
111
108
|
HISTFILE=/root/.zsh_history
|
|
@@ -96,6 +96,12 @@ COPY config/pebble/pebble-ca.crt /usr/local/share/ca-certificates/pebble-ca.crt
|
|
|
96
96
|
# external_web's authoritative post-publish check HTTPS-GETs the route from
|
|
97
97
|
# here, which is why mgmt in particular must trust it.
|
|
98
98
|
COPY config/cpanel-host/cpanel-host-ca.crt /usr/local/share/ca-certificates/cpanel-host-ca.crt
|
|
99
|
+
# Trust the Namecheap DDNS sim's CA. Its cert is likewise PRE-INSTALLED rather
|
|
100
|
+
# than Pebble-issued: celilo does not own a third-party API's TLS. This is what
|
|
101
|
+
# lets namecheap's hooks call the REAL endpoint URL over real TLS, instead of
|
|
102
|
+
# being redirected at an http://ip:port by an environment variable that an
|
|
103
|
+
# allow-listed hook environment no longer carries.
|
|
104
|
+
COPY config/namecheap/namecheap-ca.crt /usr/local/share/ca-certificates/namecheap-ca.crt
|
|
99
105
|
RUN update-ca-certificates
|
|
100
106
|
|
|
101
107
|
# Tell bun (and Node-compat code) to merge the system CA bundle with
|
|
@@ -14,6 +14,12 @@ RUN apt-get update && apt-get install -y \
|
|
|
14
14
|
RUN curl -fsSL https://bun.sh/install | bash
|
|
15
15
|
ENV PATH="/root/.bun/bin:$PATH"
|
|
16
16
|
|
|
17
|
+
# The endpoint's own certificate, PRE-INSTALLED the way a real third-party
|
|
18
|
+
# service's is (same pattern as the cPanel host sim). The CA rides along so the
|
|
19
|
+
# container can probe its own HTTPS endpoint without disabling verification.
|
|
20
|
+
COPY config/namecheap/ddns-tls.crt config/namecheap/ddns-tls.key config/namecheap/namecheap-ca.crt /etc/ssl/namecheap-sim/
|
|
21
|
+
RUN chmod 600 /etc/ssl/namecheap-sim/ddns-tls.key
|
|
22
|
+
|
|
17
23
|
COPY simulators/namecheap-ddns/ /simulator/
|
|
18
24
|
COPY config/routing/dns-routes.sh /dns-routes.sh
|
|
19
25
|
RUN chmod +x /dns-routes.sh
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@celilo/e2e",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.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",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"README.md"
|
|
38
38
|
],
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@celilo/capabilities": "^
|
|
40
|
+
"@celilo/capabilities": "^3.0.0",
|
|
41
41
|
"@celilo/cli-display": "^0.2.0",
|
|
42
42
|
"@celilo/event-bus": "^0.6.0",
|
|
43
43
|
"@celilo/terraform-fake": "^0.3.1",
|
|
@@ -46,7 +46,24 @@ const PASSWORD_MAP: Record<string, string> = (() => {
|
|
|
46
46
|
return {};
|
|
47
47
|
})();
|
|
48
48
|
const FALLBACK_PASSWORD = process.env.DDNS_PASSWORD || 'test123';
|
|
49
|
-
|
|
49
|
+
/**
|
|
50
|
+
* The real Namecheap DDNS endpoint is `https://dynamicdns.park-your-domain.com`,
|
|
51
|
+
* so that is what this serves: port 443, with a certificate for that name.
|
|
52
|
+
*
|
|
53
|
+
* It used to listen on plain HTTP at 8080 and the rig pointed the module at
|
|
54
|
+
* `http://100.64.0.55:8080/update` through a `DDNS_ENDPOINT` environment
|
|
55
|
+
* variable. That bypassed both the DNS chain the rig had already built (the
|
|
56
|
+
* `park-your-domain.com` zone has always been there) and TLS, and it stopped
|
|
57
|
+
* working when hooks became subprocesses with an allow-listed environment
|
|
58
|
+
* (openspec/changes/hook-process-boundary, design D5).
|
|
59
|
+
*
|
|
60
|
+
* The certificate is PRE-INSTALLED rather than issued by Pebble, the same way
|
|
61
|
+
* the cPanel host simulator's is, and for the same reason: celilo does not own
|
|
62
|
+
* this service's TLS. A real third-party API has a certificate from a real CA
|
|
63
|
+
* long before celilo talks to it, and there is no ACME exchange to model.
|
|
64
|
+
*/
|
|
65
|
+
const PORT = Number(process.env.DDNS_PORT) || 443;
|
|
66
|
+
const TLS_DIR = process.env.DDNS_TLS_DIR || '/etc/ssl/namecheap-sim';
|
|
50
67
|
|
|
51
68
|
function expectedPasswordFor(domain: string): string {
|
|
52
69
|
return PASSWORD_MAP[domain] ?? FALLBACK_PASSWORD;
|
|
@@ -107,6 +124,10 @@ function normalizeIp(address: string): string {
|
|
|
107
124
|
|
|
108
125
|
const server = Bun.serve({
|
|
109
126
|
port: PORT,
|
|
127
|
+
tls: {
|
|
128
|
+
cert: Bun.file(`${TLS_DIR}/ddns-tls.crt`),
|
|
129
|
+
key: Bun.file(`${TLS_DIR}/ddns-tls.key`),
|
|
130
|
+
},
|
|
110
131
|
fetch(req, server) {
|
|
111
132
|
const url = new URL(req.url);
|
|
112
133
|
|
package/src/container-manager.ts
CHANGED
|
@@ -813,6 +813,11 @@ function buildNetworkHandle(
|
|
|
813
813
|
await handle.celilo(`module config set iptables firewall_ip ${firewallIp}`);
|
|
814
814
|
await handle.celilo(`module config set iptables nat_ip ${natIp}`);
|
|
815
815
|
await handle.celilo(`module config set iptables zones '${JSON.stringify(declaredZones)}'`);
|
|
816
|
+
// Caller-supplied settings last, so a suite can turn on an opt-in policy
|
|
817
|
+
// the way an operator would rather than assert against the default.
|
|
818
|
+
for (const [key, value] of Object.entries(opts.config ?? {})) {
|
|
819
|
+
await handle.celilo(`module config set iptables ${key} ${value}`);
|
|
820
|
+
}
|
|
816
821
|
// `check: false` returns the failed deploy instead of throwing, so a test
|
|
817
822
|
// can assert on WHAT the refusal said. Interface classification refuses
|
|
818
823
|
// by design (D12 onboarding), and a refusal is only useful if it names
|
|
@@ -595,7 +595,6 @@ export function generateTestComposeYaml(config: NetworkConfig, celiloRoot?: stri
|
|
|
595
595
|
...(config.managementVolumes ?? []),
|
|
596
596
|
],
|
|
597
597
|
environment: {
|
|
598
|
-
DDNS_ENDPOINT: `http://${SIMULATOR_IPS.NAMECHEAP_DNS}:8080/update`,
|
|
599
598
|
// On its own control-plane network the only router in reach is fw-main's
|
|
600
599
|
// leg there — both for the default route and for the segmented zones.
|
|
601
600
|
DEFAULT_GATEWAY: zone === 'secure-mgmt' ? SECURE_MGMT_GATEWAY : managementDefaultGw,
|
|
@@ -821,7 +820,6 @@ export function generateComposeYaml(config: NetworkConfig, celiloRoot = '..'): s
|
|
|
821
820
|
...(config.managementVolumes ?? []),
|
|
822
821
|
],
|
|
823
822
|
environment: {
|
|
824
|
-
DDNS_ENDPOINT: `http://${SIMULATOR_IPS.NAMECHEAP_DNS}:8080/update`,
|
|
825
823
|
DEFAULT_GATEWAY: managementDefaultGw,
|
|
826
824
|
CELILO_REGISTRY_URL: 'http://e2e-registry.lab',
|
|
827
825
|
},
|
package/src/simulator-ips.ts
CHANGED
|
@@ -23,7 +23,7 @@ export const SIMULATOR_IPS = {
|
|
|
23
23
|
ROOT_DNS: '100.64.0.53',
|
|
24
24
|
/** Authoritative TLD DNS for `com.`, `org.`, `net.`. */
|
|
25
25
|
TLD_DNS: '100.64.0.54',
|
|
26
|
-
/** Authoritative DNS for the customer domains; also serves the DDNS update endpoint at
|
|
26
|
+
/** Authoritative DNS for the customer domains; also serves the DDNS update endpoint at https://dynamicdns.park-your-domain.com. */
|
|
27
27
|
NAMECHEAP_DNS: '100.64.0.55',
|
|
28
28
|
/** Internal e2e module registry (replaces production celilo.computer in tests). */
|
|
29
29
|
REGISTRY: '100.64.0.56',
|
package/src/types.ts
CHANGED
|
@@ -449,7 +449,19 @@ export interface NetworkHandle {
|
|
|
449
449
|
*
|
|
450
450
|
* @param opts.natIp - NAT IP for port-forwarded traffic (default 10.226.1.253)
|
|
451
451
|
*/
|
|
452
|
-
|
|
452
|
+
/**
|
|
453
|
+
* @param opts.config - Extra `module config set iptables <key> <value>` pairs,
|
|
454
|
+
* applied after the topology-derived ones and before the deploy. For
|
|
455
|
+
* settings whose whole point is that they are OPT-IN: the harness deploys a
|
|
456
|
+
* DEFAULT firewall, so a suite testing an opt-in policy has to turn it on
|
|
457
|
+
* the way an operator would, and asserting on a default deploy would only
|
|
458
|
+
* ever measure the default.
|
|
459
|
+
*/
|
|
460
|
+
deployFirewall(opts?: {
|
|
461
|
+
natIp?: string;
|
|
462
|
+
check?: boolean;
|
|
463
|
+
config?: Record<string, string>;
|
|
464
|
+
}): Promise<ExecResult>;
|
|
453
465
|
|
|
454
466
|
/**
|
|
455
467
|
* Deploy the `greenwave` module against the ISP router (`fw-isp`) — the box
|