@distrohelena/canton-typescript-sdk 0.1.17 → 0.1.19
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/README.md +43 -0
- package/dist/client/canton-client-options.d.ts +2 -0
- package/dist/client/canton-client-options.js +2 -0
- package/dist/transports/grpc/grpc-call-options-factory.d.ts +1 -1
- package/dist/transports/grpc/grpc-call-options-factory.js +8 -4
- package/dist/transports/grpc/grpc-channel-factory.js +1 -1
- package/node/start-local.sh +189 -2
- package/node/stop-local.sh +26 -1
- package/node/test-start-local.sh +108 -4
- package/node/test-stop-local.sh +10 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -127,6 +127,49 @@ already be a Ledger API user with the appropriate rights on each participant.
|
|
|
127
127
|
Extra participants use the existing shared-secret onboarding flow; the current
|
|
128
128
|
OAuth2-plus-extras limitation still applies.
|
|
129
129
|
|
|
130
|
+
### Optional localnet TLS
|
|
131
|
+
|
|
132
|
+
Set `LOCALNET_TLS=1` to enable TLS on every participant Ledger API and Admin API
|
|
133
|
+
listener, including generated extra participants. TLS is disabled by default,
|
|
134
|
+
so `LOCALNET_TLS=0` preserves the existing Quickstart behavior. The launcher
|
|
135
|
+
uses direct Compose mode when TLS is enabled so it can apply the generated
|
|
136
|
+
configuration overlay.
|
|
137
|
+
|
|
138
|
+
By default, development-only material is generated in
|
|
139
|
+
`.generated/localnet-tls`: `ca.crt`, `server.crt`, and `server.key`. Set
|
|
140
|
+
`LOCALNET_TLS_ROTATE=1` to replace it. To provide your own material, set all
|
|
141
|
+
three variables together:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
LOCALNET_TLS=1 \
|
|
145
|
+
LOCALNET_TLS_CERT_CHAIN_PATH=/path/to/server-chain.pem \
|
|
146
|
+
LOCALNET_TLS_PRIVATE_KEY_PATH=/path/to/server-key.pem \
|
|
147
|
+
LOCALNET_TLS_CA_CERT_PATH=/path/to/root-ca.pem \
|
|
148
|
+
canton-localnet-start
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
The server certificate must cover the hostname used by the client, normally
|
|
152
|
+
`localhost` for host-side SDK calls. Client certificate authentication is not
|
|
153
|
+
enabled; authentication remains controlled by the existing Quickstart
|
|
154
|
+
`AUTH_MODE` and optional ES256 settings.
|
|
155
|
+
|
|
156
|
+
The SDK gRPC channels remain TLS by default. For generated localnet material,
|
|
157
|
+
pass the generated CA to the client:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { readFileSync } from "node:fs";
|
|
161
|
+
|
|
162
|
+
const client = new CantonClient(new CantonClientOptions({
|
|
163
|
+
transportKind: TransportKind.grpc,
|
|
164
|
+
ledgerEndpoint: "localhost:3901",
|
|
165
|
+
ledgerAdminEndpoint: "localhost:3902",
|
|
166
|
+
participantAdminEndpoint: "localhost:3902",
|
|
167
|
+
grpcTlsRootCertificates: readFileSync(
|
|
168
|
+
".generated/localnet-tls/ca.crt",
|
|
169
|
+
),
|
|
170
|
+
}));
|
|
171
|
+
```
|
|
172
|
+
|
|
130
173
|
The live suite runs single-worker with an extended timeout because it mutates and reads a shared localnet.
|
|
131
174
|
|
|
132
175
|
Prerequisites:
|
|
@@ -9,6 +9,7 @@ export declare class CantonClientOptions {
|
|
|
9
9
|
readonly ledgerAdminEndpoint?: string;
|
|
10
10
|
readonly participantAdminEndpoint?: string;
|
|
11
11
|
readonly grpcChannelSecurity: GrpcChannelSecurity;
|
|
12
|
+
readonly grpcTlsRootCertificates?: Uint8Array;
|
|
12
13
|
readonly ledgerGrpcChannelSecurity?: GrpcChannelSecurity;
|
|
13
14
|
readonly ledgerAdminGrpcChannelSecurity?: GrpcChannelSecurity;
|
|
14
15
|
readonly participantAdminGrpcChannelSecurity?: GrpcChannelSecurity;
|
|
@@ -25,6 +26,7 @@ export declare class CantonClientOptions {
|
|
|
25
26
|
ledgerAdminEndpoint?: string;
|
|
26
27
|
participantAdminEndpoint?: string;
|
|
27
28
|
grpcChannelSecurity?: GrpcChannelSecurity;
|
|
29
|
+
grpcTlsRootCertificates?: Uint8Array;
|
|
28
30
|
ledgerGrpcChannelSecurity?: GrpcChannelSecurity;
|
|
29
31
|
ledgerAdminGrpcChannelSecurity?: GrpcChannelSecurity;
|
|
30
32
|
participantAdminGrpcChannelSecurity?: GrpcChannelSecurity;
|
|
@@ -5,6 +5,7 @@ export class CantonClientOptions {
|
|
|
5
5
|
ledgerAdminEndpoint;
|
|
6
6
|
participantAdminEndpoint;
|
|
7
7
|
grpcChannelSecurity;
|
|
8
|
+
grpcTlsRootCertificates;
|
|
8
9
|
ledgerGrpcChannelSecurity;
|
|
9
10
|
ledgerAdminGrpcChannelSecurity;
|
|
10
11
|
participantAdminGrpcChannelSecurity;
|
|
@@ -22,6 +23,7 @@ export class CantonClientOptions {
|
|
|
22
23
|
this.participantAdminEndpoint = init.participantAdminEndpoint;
|
|
23
24
|
this.grpcChannelSecurity =
|
|
24
25
|
init.grpcChannelSecurity ?? GrpcChannelSecurity.tls;
|
|
26
|
+
this.grpcTlsRootCertificates = init.grpcTlsRootCertificates;
|
|
25
27
|
this.ledgerGrpcChannelSecurity = init.ledgerGrpcChannelSecurity;
|
|
26
28
|
this.ledgerAdminGrpcChannelSecurity =
|
|
27
29
|
init.ledgerAdminGrpcChannelSecurity;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IAuthProvider } from "../../core/auth/auth-provider.interface.js";
|
|
2
2
|
import { RequestOptions } from "../../core/types/request-options.js";
|
|
3
3
|
import { GrpcChannelSecurity } from "../../core/types/grpc-channel-security.js";
|
|
4
|
-
export declare function createGrpcChannelCredentials(security: GrpcChannelSecurity): import("@grpc/grpc-js").ChannelCredentials;
|
|
4
|
+
export declare function createGrpcChannelCredentials(security: GrpcChannelSecurity, tlsRootCertificates?: Uint8Array): import("@grpc/grpc-js").ChannelCredentials;
|
|
5
5
|
export declare function buildGrpcCallOptionsAsync(authProvider?: IAuthProvider, defaultTimeoutMs?: number, options?: RequestOptions): Promise<{
|
|
6
6
|
meta: Record<string, string>;
|
|
7
7
|
timeout?: number;
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { credentials } from "@grpc/grpc-js";
|
|
2
|
+
import { Buffer } from "node:buffer";
|
|
2
3
|
import { resolveRequestTimeoutMs } from "../../core/types/request-timeout.js";
|
|
3
4
|
import { GrpcChannelSecurity } from "../../core/types/grpc-channel-security.js";
|
|
4
|
-
export function createGrpcChannelCredentials(security) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
5
|
+
export function createGrpcChannelCredentials(security, tlsRootCertificates) {
|
|
6
|
+
if (security === GrpcChannelSecurity.insecure) {
|
|
7
|
+
return credentials.createInsecure();
|
|
8
|
+
}
|
|
9
|
+
return tlsRootCertificates === undefined
|
|
10
|
+
? credentials.createSsl()
|
|
11
|
+
: credentials.createSsl(Buffer.from(tlsRootCertificates));
|
|
8
12
|
}
|
|
9
13
|
export async function buildGrpcCallOptionsAsync(authProvider, defaultTimeoutMs, options) {
|
|
10
14
|
const timeout = resolveRequestTimeoutMs(defaultTimeoutMs, options);
|
|
@@ -32,7 +32,7 @@ import { buildGrpcCallOptionsAsync, createGrpcChannelCredentials, } from "./grpc
|
|
|
32
32
|
export function createGrpcOperations(options, endpoint, grpcChannelSecurity, dependencies = {}) {
|
|
33
33
|
const rpcTransport = new ProtobufGrpcTransport({
|
|
34
34
|
host: normalizeGrpcHost(endpoint),
|
|
35
|
-
channelCredentials: createGrpcChannelCredentials(grpcChannelSecurity),
|
|
35
|
+
channelCredentials: createGrpcChannelCredentials(grpcChannelSecurity, options.grpcTlsRootCertificates),
|
|
36
36
|
clientOptions: options.grpcConnectTimeoutMs === undefined
|
|
37
37
|
? undefined
|
|
38
38
|
: {
|
package/node/start-local.sh
CHANGED
|
@@ -98,6 +98,158 @@ es256_runtime_dir() {
|
|
|
98
98
|
printf '%s\n' "${START_LOCAL_ES256_RUNTIME_DIR:-$REPO_ROOT/.generated/localnet-es256}"
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
+
resolve_tls_enabled() {
|
|
102
|
+
local value="${LOCALNET_TLS:-0}"
|
|
103
|
+
if [[ "$value" != "0" && "$value" != "1" ]]; then
|
|
104
|
+
echo "LOCALNET_TLS must be 0 or 1." >&2
|
|
105
|
+
return 1
|
|
106
|
+
fi
|
|
107
|
+
printf '%s\n' "$value"
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
resolve_tls_rotate() {
|
|
111
|
+
local value="${LOCALNET_TLS_ROTATE:-0}"
|
|
112
|
+
if [[ "$value" != "0" && "$value" != "1" ]]; then
|
|
113
|
+
echo "LOCALNET_TLS_ROTATE must be 0 or 1." >&2
|
|
114
|
+
return 1
|
|
115
|
+
fi
|
|
116
|
+
printf '%s\n' "$value"
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
tls_runtime_dir() {
|
|
120
|
+
printf '%s\n' "${START_LOCAL_TLS_RUNTIME_DIR:-$REPO_ROOT/.generated/localnet-tls}"
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
prepare_tls_runtime_files() {
|
|
124
|
+
local enabled
|
|
125
|
+
enabled="$(resolve_tls_enabled)"
|
|
126
|
+
if [[ "$enabled" != "1" ]]; then
|
|
127
|
+
return 0
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
local runtime_dir
|
|
131
|
+
runtime_dir="$(tls_runtime_dir)"
|
|
132
|
+
local ca_key_path="$runtime_dir/ca.key"
|
|
133
|
+
local ca_certificate_path="$runtime_dir/ca.crt"
|
|
134
|
+
local server_key_path="$runtime_dir/server.key"
|
|
135
|
+
local server_certificate_path="$runtime_dir/server.crt"
|
|
136
|
+
local compose_file="$runtime_dir/compose-localnet.yaml"
|
|
137
|
+
local tls_fragment_file="$runtime_dir/canton-tls.conf"
|
|
138
|
+
local canton_config_file="$runtime_dir/canton-localnet.conf"
|
|
139
|
+
local supplied_count=0
|
|
140
|
+
|
|
141
|
+
[[ -n "${LOCALNET_TLS_CERT_CHAIN_PATH:-}" ]] && ((supplied_count += 1))
|
|
142
|
+
[[ -n "${LOCALNET_TLS_PRIVATE_KEY_PATH:-}" ]] && ((supplied_count += 1))
|
|
143
|
+
[[ -n "${LOCALNET_TLS_CA_CERT_PATH:-}" ]] && ((supplied_count += 1))
|
|
144
|
+
|
|
145
|
+
mkdir -p "$runtime_dir"
|
|
146
|
+
if (( supplied_count > 0 )); then
|
|
147
|
+
if (( supplied_count != 3 )); then
|
|
148
|
+
echo "LOCALNET_TLS_CERT_CHAIN_PATH, LOCALNET_TLS_PRIVATE_KEY_PATH, and LOCALNET_TLS_CA_CERT_PATH must be set together." >&2
|
|
149
|
+
return 1
|
|
150
|
+
fi
|
|
151
|
+
server_certificate_path="$LOCALNET_TLS_CERT_CHAIN_PATH"
|
|
152
|
+
server_key_path="$LOCALNET_TLS_PRIVATE_KEY_PATH"
|
|
153
|
+
ca_certificate_path="$LOCALNET_TLS_CA_CERT_PATH"
|
|
154
|
+
if [[ ! -r "$server_certificate_path" || ! -r "$server_key_path" || ! -r "$ca_certificate_path" ]]; then
|
|
155
|
+
echo "Supplied TLS certificate, private key, or CA certificate is not readable." >&2
|
|
156
|
+
return 1
|
|
157
|
+
fi
|
|
158
|
+
if ! openssl x509 -in "$server_certificate_path" -noout >/dev/null 2>&1 \
|
|
159
|
+
|| ! openssl pkey -in "$server_key_path" -noout >/dev/null 2>&1 \
|
|
160
|
+
|| ! openssl x509 -in "$ca_certificate_path" -noout >/dev/null 2>&1 \
|
|
161
|
+
|| ! openssl verify -CAfile "$ca_certificate_path" "$server_certificate_path" >/dev/null 2>&1; then
|
|
162
|
+
echo "Supplied TLS material is not valid PEM certificate/key material." >&2
|
|
163
|
+
return 1
|
|
164
|
+
fi
|
|
165
|
+
local certificate_public_key private_public_key
|
|
166
|
+
if ! certificate_public_key="$(openssl x509 -in "$server_certificate_path" -pubkey -noout | openssl pkey -pubin -outform DER | sha256sum | awk '{print $1}')" \
|
|
167
|
+
|| ! private_public_key="$(openssl pkey -in "$server_key_path" -pubout | openssl pkey -pubin -outform DER | sha256sum | awk '{print $1}')" \
|
|
168
|
+
|| [[ "$certificate_public_key" != "$private_public_key" ]]; then
|
|
169
|
+
echo "Supplied TLS private key does not match the server certificate." >&2
|
|
170
|
+
return 1
|
|
171
|
+
fi
|
|
172
|
+
else
|
|
173
|
+
if [[ "$(resolve_tls_rotate)" == "1" ]]; then
|
|
174
|
+
rm -f "$ca_key_path" "$ca_certificate_path" "$server_key_path" "$server_certificate_path"
|
|
175
|
+
fi
|
|
176
|
+
if [[ ! -e "$ca_key_path" || ! -e "$ca_certificate_path" ]]; then
|
|
177
|
+
rm -f "$ca_key_path" "$ca_certificate_path"
|
|
178
|
+
openssl genrsa -out "$ca_key_path" 2048 >/dev/null 2>&1
|
|
179
|
+
chmod 600 "$ca_key_path"
|
|
180
|
+
openssl req -x509 -new -sha256 -days 3650 -key "$ca_key_path" \
|
|
181
|
+
-subj "/CN=localnet-tls-ca" -out "$ca_certificate_path" >/dev/null 2>&1
|
|
182
|
+
fi
|
|
183
|
+
if [[ ! -e "$server_key_path" || ! -e "$server_certificate_path" ]]; then
|
|
184
|
+
rm -f "$server_key_path" "$server_certificate_path"
|
|
185
|
+
local csr_path="$runtime_dir/server.csr"
|
|
186
|
+
local extensions_path="$runtime_dir/server-extensions.cnf"
|
|
187
|
+
openssl genrsa -out "$server_key_path" 2048 >/dev/null 2>&1
|
|
188
|
+
chmod 600 "$server_key_path"
|
|
189
|
+
openssl req -new -sha256 -key "$server_key_path" -subj "/CN=localhost" -out "$csr_path" >/dev/null 2>&1
|
|
190
|
+
cat > "$extensions_path" <<'EOF'
|
|
191
|
+
[server_ext]
|
|
192
|
+
basicConstraints = CA:FALSE
|
|
193
|
+
keyUsage = digitalSignature, keyEncipherment
|
|
194
|
+
extendedKeyUsage = serverAuth
|
|
195
|
+
subjectAltName = DNS:localhost, DNS:canton, IP:127.0.0.1
|
|
196
|
+
EOF
|
|
197
|
+
openssl x509 -req -sha256 -days 3650 -in "$csr_path" \
|
|
198
|
+
-CA "$ca_certificate_path" -CAkey "$ca_key_path" -CAcreateserial \
|
|
199
|
+
-out "$server_certificate_path" -extfile "$extensions_path" -extensions server_ext >/dev/null 2>&1
|
|
200
|
+
rm -f "$csr_path" "$extensions_path" "$ca_certificate_path.srl"
|
|
201
|
+
fi
|
|
202
|
+
if ! openssl x509 -in "$server_certificate_path" -noout >/dev/null 2>&1 \
|
|
203
|
+
|| ! openssl pkey -in "$server_key_path" -noout >/dev/null 2>&1 \
|
|
204
|
+
|| ! openssl x509 -in "$ca_certificate_path" -noout >/dev/null 2>&1; then
|
|
205
|
+
echo "Generated TLS material is invalid." >&2
|
|
206
|
+
return 1
|
|
207
|
+
fi
|
|
208
|
+
fi
|
|
209
|
+
|
|
210
|
+
: > "$tls_fragment_file"
|
|
211
|
+
local participant profile
|
|
212
|
+
for participant in app-provider app-user sv; do
|
|
213
|
+
case "$participant" in
|
|
214
|
+
app-provider) profile="$APP_PROVIDER_PROFILE" ;;
|
|
215
|
+
app-user) profile="$APP_USER_PROFILE" ;;
|
|
216
|
+
sv) profile="$SV_PROFILE" ;;
|
|
217
|
+
esac
|
|
218
|
+
if [[ "$profile" != "off" ]]; then
|
|
219
|
+
cat >> "$tls_fragment_file" <<EOF
|
|
220
|
+
canton.participants.${participant}.ledger-api.tls {
|
|
221
|
+
cert-chain-file = "/app/localnet-tls/server.crt"
|
|
222
|
+
private-key-file = "/app/localnet-tls/server.key"
|
|
223
|
+
trust-collection-file = "/app/localnet-tls/ca.crt"
|
|
224
|
+
}
|
|
225
|
+
canton.participants.${participant}.admin-api.tls {
|
|
226
|
+
cert-chain-file = "/app/localnet-tls/server.crt"
|
|
227
|
+
private-key-file = "/app/localnet-tls/server.key"
|
|
228
|
+
trust-collection-file = "/app/localnet-tls/ca.crt"
|
|
229
|
+
}
|
|
230
|
+
EOF
|
|
231
|
+
fi
|
|
232
|
+
done
|
|
233
|
+
cat > "$canton_config_file" <<'EOF'
|
|
234
|
+
include file("/app/base-app.conf")
|
|
235
|
+
include file("/app/localnet-tls.conf")
|
|
236
|
+
EOF
|
|
237
|
+
cat > "$compose_file" <<EOF
|
|
238
|
+
services:
|
|
239
|
+
canton:
|
|
240
|
+
volumes:
|
|
241
|
+
- "${LOCALNET_DIR}/conf/canton/app.conf:/app/base-app.conf:ro"
|
|
242
|
+
- "$canton_config_file:/app/app.conf:ro"
|
|
243
|
+
- "$tls_fragment_file:/app/localnet-tls.conf:ro"
|
|
244
|
+
- "$server_certificate_path:/app/localnet-tls/server.crt:ro"
|
|
245
|
+
- "$server_key_path:/app/localnet-tls/server.key:ro"
|
|
246
|
+
- "$ca_certificate_path:/app/localnet-tls/ca.crt:ro"
|
|
247
|
+
EOF
|
|
248
|
+
export LOCALNET_TLS_COMPOSE_FILE="$compose_file"
|
|
249
|
+
export LOCALNET_TLS_FRAGMENT_FILE="$tls_fragment_file"
|
|
250
|
+
export LOCALNET_TLS_CA_CERT_PATH="$ca_certificate_path"
|
|
251
|
+
}
|
|
252
|
+
|
|
101
253
|
prepare_es256_runtime_files() {
|
|
102
254
|
local runtime_dir
|
|
103
255
|
runtime_dir="$(es256_runtime_dir)"
|
|
@@ -150,6 +302,8 @@ prepare_es256_runtime_files() {
|
|
|
150
302
|
cat > "$canton_config_file" <<EOF
|
|
151
303
|
include file("/app/base-app.conf")
|
|
152
304
|
|
|
305
|
+
$(if [[ "$(resolve_tls_enabled)" == "1" ]]; then printf 'include file("/app/localnet-tls.conf")\n'; fi)
|
|
306
|
+
|
|
153
307
|
EOF
|
|
154
308
|
local participant profile
|
|
155
309
|
for participant in app-provider app-user sv; do
|
|
@@ -195,6 +349,13 @@ append_es256_args() {
|
|
|
195
349
|
fi
|
|
196
350
|
}
|
|
197
351
|
|
|
352
|
+
append_tls_args() {
|
|
353
|
+
local -n compose_args_ref="$1"
|
|
354
|
+
if [[ "$(resolve_tls_enabled)" == "1" ]]; then
|
|
355
|
+
compose_args_ref+=( -f "$LOCALNET_TLS_COMPOSE_FILE" )
|
|
356
|
+
fi
|
|
357
|
+
}
|
|
358
|
+
|
|
198
359
|
resolve_docker_compose_cmd() {
|
|
199
360
|
if (( ${#DOCKER_COMPOSE_CMD[@]} > 0 )); then
|
|
200
361
|
return 0
|
|
@@ -414,6 +575,25 @@ canton.participants.extra-${index}.ledger-api.auth-services = [
|
|
|
414
575
|
}
|
|
415
576
|
]
|
|
416
577
|
|
|
578
|
+
EOF
|
|
579
|
+
done
|
|
580
|
+
fi
|
|
581
|
+
|
|
582
|
+
if [[ "$(resolve_tls_enabled)" == "1" ]]; then
|
|
583
|
+
local index
|
|
584
|
+
for ((index = 1; index <= count; index++)); do
|
|
585
|
+
cat >> "$canton_config_file" <<EOF
|
|
586
|
+
canton.participants.extra-${index}.ledger-api.tls {
|
|
587
|
+
cert-chain-file = "/app/localnet-tls/server.crt"
|
|
588
|
+
private-key-file = "/app/localnet-tls/server.key"
|
|
589
|
+
trust-collection-file = "/app/localnet-tls/ca.crt"
|
|
590
|
+
}
|
|
591
|
+
canton.participants.extra-${index}.admin-api.tls {
|
|
592
|
+
cert-chain-file = "/app/localnet-tls/server.crt"
|
|
593
|
+
private-key-file = "/app/localnet-tls/server.key"
|
|
594
|
+
trust-collection-file = "/app/localnet-tls/ca.crt"
|
|
595
|
+
}
|
|
596
|
+
|
|
417
597
|
EOF
|
|
418
598
|
done
|
|
419
599
|
fi
|
|
@@ -795,6 +975,7 @@ grant_localnet_validator_read_rights() {
|
|
|
795
975
|
|
|
796
976
|
start_ledger_stack() {
|
|
797
977
|
local auth_mode="${1:-shared-secret}"
|
|
978
|
+
export AUTH_MODE="$auth_mode"
|
|
798
979
|
local modules_dir="$QUICKSTART_DIR/docker/modules"
|
|
799
980
|
local localnet_dir="$modules_dir/localnet"
|
|
800
981
|
local splice_version
|
|
@@ -808,6 +989,7 @@ start_ledger_stack() {
|
|
|
808
989
|
export SV_PROFILE=on
|
|
809
990
|
export PQS_SV_PROFILE=on
|
|
810
991
|
load_localnet_common_env "$localnet_dir/env/common.env"
|
|
992
|
+
prepare_tls_runtime_files
|
|
811
993
|
prepare_es256_runtime_files
|
|
812
994
|
local extra_participants
|
|
813
995
|
extra_participants="$(resolve_extra_participants)"
|
|
@@ -841,6 +1023,7 @@ start_ledger_stack() {
|
|
|
841
1023
|
fi
|
|
842
1024
|
|
|
843
1025
|
append_extra_participant_args "$extra_participants" "$auth_mode" compose_args
|
|
1026
|
+
append_tls_args compose_args
|
|
844
1027
|
append_es256_args compose_args
|
|
845
1028
|
docker_compose "${compose_args[@]}" down -v --remove-orphans
|
|
846
1029
|
mapfile -t startup_services < <(prerequisite_services "$auth_mode")
|
|
@@ -873,12 +1056,16 @@ if [[ ! -f .env.local ]]; then
|
|
|
873
1056
|
make setup
|
|
874
1057
|
fi
|
|
875
1058
|
|
|
876
|
-
if [[ "$(resolve_es256_enabled)" != "1" ]] && make_target_exists start-local-ledger; then
|
|
1059
|
+
if [[ "$(resolve_es256_enabled)" != "1" && "$(resolve_tls_enabled)" != "1" ]] && make_target_exists start-local-ledger; then
|
|
877
1060
|
make start-local-ledger
|
|
878
1061
|
else
|
|
879
1062
|
auth_mode="$(read_env_value AUTH_MODE || true)"
|
|
880
1063
|
auth_mode="${auth_mode:-shared-secret}"
|
|
881
|
-
|
|
1064
|
+
if [[ "$(resolve_es256_enabled)" == "1" || "$(resolve_tls_enabled)" == "1" ]]; then
|
|
1065
|
+
echo "Generated localnet transport overlay enabled. Starting ledger-only compose stack directly."
|
|
1066
|
+
else
|
|
1067
|
+
echo "start-local-ledger target not found. Starting ledger-only compose stack directly."
|
|
1068
|
+
fi
|
|
882
1069
|
start_ledger_stack "$auth_mode"
|
|
883
1070
|
if [[ "$(resolve_es256_enabled)" == "1" ]]; then
|
|
884
1071
|
echo "ES256 bearer token written to $LOCALNET_ES256_TOKEN_PATH"
|
package/node/stop-local.sh
CHANGED
|
@@ -92,6 +92,19 @@ es256_runtime_dir() {
|
|
|
92
92
|
printf '%s\n' "${START_LOCAL_ES256_RUNTIME_DIR:-$REPO_ROOT/.generated/localnet-es256}"
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
resolve_tls_enabled() {
|
|
96
|
+
local value="${LOCALNET_TLS:-0}"
|
|
97
|
+
if [[ "$value" != "0" && "$value" != "1" ]]; then
|
|
98
|
+
echo "LOCALNET_TLS must be 0 or 1." >&2
|
|
99
|
+
return 1
|
|
100
|
+
fi
|
|
101
|
+
printf '%s\n' "$value"
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
tls_runtime_dir() {
|
|
105
|
+
printf '%s\n' "${START_LOCAL_TLS_RUNTIME_DIR:-$REPO_ROOT/.generated/localnet-tls}"
|
|
106
|
+
}
|
|
107
|
+
|
|
95
108
|
append_es256_args() {
|
|
96
109
|
local -n compose_args_ref="$1"
|
|
97
110
|
if [[ "$(resolve_es256_enabled)" == "1" ]]; then
|
|
@@ -102,6 +115,16 @@ append_es256_args() {
|
|
|
102
115
|
fi
|
|
103
116
|
}
|
|
104
117
|
|
|
118
|
+
append_tls_args() {
|
|
119
|
+
local -n compose_args_ref="$1"
|
|
120
|
+
if [[ "$(resolve_tls_enabled)" == "1" ]]; then
|
|
121
|
+
local compose_file="$(tls_runtime_dir)/compose-localnet.yaml"
|
|
122
|
+
if [[ -f "$compose_file" ]]; then
|
|
123
|
+
compose_args_ref+=( -f "$compose_file" )
|
|
124
|
+
fi
|
|
125
|
+
fi
|
|
126
|
+
}
|
|
127
|
+
|
|
105
128
|
resolve_docker_compose_cmd() {
|
|
106
129
|
if (( ${#DOCKER_COMPOSE_CMD[@]} > 0 )); then
|
|
107
130
|
return 0
|
|
@@ -141,6 +164,7 @@ append_existing_extra_participant_args() {
|
|
|
141
164
|
|
|
142
165
|
stop_ledger_stack() {
|
|
143
166
|
local auth_mode="${1:-shared-secret}"
|
|
167
|
+
export AUTH_MODE="$auth_mode"
|
|
144
168
|
local modules_dir="$QUICKSTART_DIR/docker/modules"
|
|
145
169
|
local localnet_dir="$modules_dir/localnet"
|
|
146
170
|
local splice_version
|
|
@@ -177,6 +201,7 @@ stop_ledger_stack() {
|
|
|
177
201
|
fi
|
|
178
202
|
|
|
179
203
|
append_existing_extra_participant_args compose_args
|
|
204
|
+
append_tls_args compose_args
|
|
180
205
|
append_es256_args compose_args
|
|
181
206
|
docker_compose "${compose_args[@]}" down -v --remove-orphans
|
|
182
207
|
}
|
|
@@ -190,7 +215,7 @@ if [[ ! -f .env.local ]]; then
|
|
|
190
215
|
exit 0
|
|
191
216
|
fi
|
|
192
217
|
|
|
193
|
-
if [[ "$(resolve_es256_enabled)" != "1" ]] && make_target_exists stop-local-ledger; then
|
|
218
|
+
if [[ "$(resolve_es256_enabled)" != "1" && "$(resolve_tls_enabled)" != "1" ]] && make_target_exists stop-local-ledger; then
|
|
194
219
|
make stop-local-ledger
|
|
195
220
|
else
|
|
196
221
|
auth_mode="$(read_env_value AUTH_MODE || true)"
|
package/node/test-start-local.sh
CHANGED
|
@@ -32,12 +32,17 @@ run_case() {
|
|
|
32
32
|
local cn_quickstart_dir_override="${6:-}"
|
|
33
33
|
local repo_root_env_contents="${7:-}"
|
|
34
34
|
local es256_enabled="${8:-0}"
|
|
35
|
+
local tls_enabled="${9:-0}"
|
|
36
|
+
local tls_cert_chain_path="${10:-}"
|
|
37
|
+
local tls_private_key_path="${11:-}"
|
|
38
|
+
local tls_ca_cert_path="${12:-}"
|
|
39
|
+
local expected_status="${13:-0}"
|
|
35
40
|
local quickstart_dir="$tmpdir/quickstart"
|
|
36
41
|
local quickstart_root_dir="$tmpdir/cn-quickstart"
|
|
37
42
|
local stubbin="$tmpdir/bin"
|
|
38
43
|
local generated_dir="$tmpdir/generated"
|
|
39
44
|
|
|
40
|
-
rm -rf "$quickstart_dir" "$quickstart_root_dir" "$stubbin" "$generated_dir"
|
|
45
|
+
rm -rf "$quickstart_dir" "$quickstart_root_dir" "$stubbin" "$generated_dir" "$tmpdir/tls"
|
|
41
46
|
mkdir -p \
|
|
42
47
|
"$quickstart_root_dir" \
|
|
43
48
|
"$quickstart_dir/docker/modules/localnet/env" \
|
|
@@ -84,6 +89,7 @@ printf 'stub env APP_PROVIDER_PROFILE=%s\n' "${APP_PROVIDER_PROFILE:-}"
|
|
|
84
89
|
printf 'stub env APP_USER_PROFILE=%s\n' "${APP_USER_PROFILE:-}"
|
|
85
90
|
printf 'stub env SV_PROFILE=%s\n' "${SV_PROFILE:-}"
|
|
86
91
|
printf 'stub env PQS_SV_PROFILE=%s\n' "${PQS_SV_PROFILE:-}"
|
|
92
|
+
printf 'stub env AUTH_MODE=%s\n' "${AUTH_MODE:-}"
|
|
87
93
|
if [[ "${1:-}" == "inspect" ]]; then
|
|
88
94
|
printf 'healthy\n'
|
|
89
95
|
exit 0
|
|
@@ -145,6 +151,7 @@ EOF
|
|
|
145
151
|
chmod +x "$stubbin/docker-compose"
|
|
146
152
|
|
|
147
153
|
local output
|
|
154
|
+
local status=0
|
|
148
155
|
output="$(
|
|
149
156
|
if [[ -n "$repo_root_env_contents" ]]; then
|
|
150
157
|
printf '%s\n' "$repo_root_env_contents" > "$REPO_ENV_FILE"
|
|
@@ -158,20 +165,39 @@ EOF
|
|
|
158
165
|
TERM="${TERM:-dumb}" \
|
|
159
166
|
START_LOCAL_GENERATED_DIR="$generated_dir" \
|
|
160
167
|
START_LOCAL_ES256_RUNTIME_DIR="$tmpdir/es256" \
|
|
168
|
+
START_LOCAL_TLS_RUNTIME_DIR="$tmpdir/tls" \
|
|
161
169
|
LOCALNET_ES256_JWT="$es256_enabled" \
|
|
170
|
+
LOCALNET_TLS="$tls_enabled" \
|
|
171
|
+
LOCALNET_TLS_CERT_CHAIN_PATH="$tls_cert_chain_path" \
|
|
172
|
+
LOCALNET_TLS_PRIVATE_KEY_PATH="$tls_private_key_path" \
|
|
173
|
+
LOCALNET_TLS_CA_CERT_PATH="$tls_ca_cert_path" \
|
|
162
174
|
EXTRA_PARTICIPANTS="$extra_participants" \
|
|
163
175
|
PATH="$stubbin:$PATH" \
|
|
164
|
-
bash ./start-local.sh
|
|
176
|
+
bash ./start-local.sh 2>&1
|
|
165
177
|
else
|
|
166
178
|
CN_QUICKSTART_DIR="${cn_quickstart_dir_override:-$quickstart_dir}" \
|
|
167
179
|
START_LOCAL_GENERATED_DIR="$generated_dir" \
|
|
168
180
|
START_LOCAL_ES256_RUNTIME_DIR="$tmpdir/es256" \
|
|
181
|
+
START_LOCAL_TLS_RUNTIME_DIR="$tmpdir/tls" \
|
|
169
182
|
LOCALNET_ES256_JWT="$es256_enabled" \
|
|
183
|
+
LOCALNET_TLS="$tls_enabled" \
|
|
184
|
+
LOCALNET_TLS_CERT_CHAIN_PATH="$tls_cert_chain_path" \
|
|
185
|
+
LOCALNET_TLS_PRIVATE_KEY_PATH="$tls_private_key_path" \
|
|
186
|
+
LOCALNET_TLS_CA_CERT_PATH="$tls_ca_cert_path" \
|
|
170
187
|
EXTRA_PARTICIPANTS="$extra_participants" \
|
|
171
188
|
PATH="$stubbin:$PATH" \
|
|
172
|
-
bash ./start-local.sh
|
|
189
|
+
bash ./start-local.sh 2>&1
|
|
173
190
|
fi
|
|
174
|
-
)"
|
|
191
|
+
)" || status=$?
|
|
192
|
+
|
|
193
|
+
if [[ "$expected_status" == "0" && "$status" != "0" ]]; then
|
|
194
|
+
printf 'expected successful start-local case, got status %s and output:\n%s\n' "$status" "$output" >&2
|
|
195
|
+
exit 1
|
|
196
|
+
fi
|
|
197
|
+
if [[ "$expected_status" != "0" && "$status" == "0" ]]; then
|
|
198
|
+
printf 'expected failing start-local case, got success and output:\n%s\n' "$output" >&2
|
|
199
|
+
exit 1
|
|
200
|
+
fi
|
|
175
201
|
|
|
176
202
|
if ! grep -Fxq "$expected_output" <<<"$output"; then
|
|
177
203
|
printf 'expected output line %q, got:\n%s\n' "$expected_output" "$output" >&2
|
|
@@ -190,6 +216,28 @@ assert_file_contains() {
|
|
|
190
216
|
fi
|
|
191
217
|
}
|
|
192
218
|
|
|
219
|
+
assert_file_contains_text() {
|
|
220
|
+
local path="$1"
|
|
221
|
+
local expected="$2"
|
|
222
|
+
|
|
223
|
+
if ! grep -Fq "$expected" "$path"; then
|
|
224
|
+
printf 'expected file %s to contain text %q, got:\n' "$path" "$expected" >&2
|
|
225
|
+
cat "$path" >&2
|
|
226
|
+
exit 1
|
|
227
|
+
fi
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
assert_file_mode() {
|
|
231
|
+
local path="$1"
|
|
232
|
+
local expected="$2"
|
|
233
|
+
local actual
|
|
234
|
+
actual="$(stat -c '%a' "$path")"
|
|
235
|
+
if [[ "$actual" != "$expected" ]]; then
|
|
236
|
+
printf 'expected file %s mode %s, got %s\n' "$path" "$expected" "$actual" >&2
|
|
237
|
+
exit 1
|
|
238
|
+
fi
|
|
239
|
+
}
|
|
240
|
+
|
|
193
241
|
run_repo_root_env_case() {
|
|
194
242
|
local quickstart_dir="$tmpdir/quickstart"
|
|
195
243
|
local quickstart_root_dir="$tmpdir/custom-quickstart-root"
|
|
@@ -247,6 +295,7 @@ printf 'stub env APP_PROVIDER_PROFILE=%s\n' "${APP_PROVIDER_PROFILE:-}"
|
|
|
247
295
|
printf 'stub env APP_USER_PROFILE=%s\n' "${APP_USER_PROFILE:-}"
|
|
248
296
|
printf 'stub env SV_PROFILE=%s\n' "${SV_PROFILE:-}"
|
|
249
297
|
printf 'stub env PQS_SV_PROFILE=%s\n' "${PQS_SV_PROFILE:-}"
|
|
298
|
+
printf 'stub env AUTH_MODE=%s\n' "${AUTH_MODE:-}"
|
|
250
299
|
if [[ "${1:-}" == "inspect" ]]; then
|
|
251
300
|
printf 'healthy\n'
|
|
252
301
|
exit 0
|
|
@@ -284,6 +333,7 @@ run_case $'.PHONY: start\nstart:\n' 'stub env IMAGE_TAG=0.6.5'
|
|
|
284
333
|
run_case $'.PHONY: start\nstart:\n' 'stub env APP_USER_PROFILE=off'
|
|
285
334
|
run_case $'.PHONY: start\nstart:\n' 'stub env SV_PROFILE=on'
|
|
286
335
|
run_case $'.PHONY: start\nstart:\n' 'stub env PQS_SV_PROFILE=on'
|
|
336
|
+
run_case $'.PHONY: start\nstart:\n' 'stub env AUTH_MODE=oauth2' oauth2
|
|
287
337
|
run_case $'.PHONY: start\nstart:\n' 'stub docker compose -f compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/localnet/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/splice-onboarding/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/pqs/compose.yaml --env-file .env --env-file .env.local --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/compose.env --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/env/common.env --env-file '"$tmpdir"'/quickstart/docker/modules/pqs/compose.env --profile app-provider --profile pqs-app-provider --profile pqs-sv down -v --remove-orphans'
|
|
288
338
|
run_case $'.PHONY: start\nstart:\n' 'stub docker compose -f compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/localnet/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/splice-onboarding/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/pqs/compose.yaml --env-file .env --env-file .env.local --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/compose.env --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/env/common.env --env-file '"$tmpdir"'/quickstart/docker/modules/pqs/compose.env --profile app-provider --profile pqs-app-provider --profile pqs-sv up -d --no-recreate postgres canton'
|
|
289
339
|
run_case $'.PHONY: start\nstart:\n' 'stub docker compose -f compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/localnet/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/splice-onboarding/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/pqs/compose.yaml --env-file .env --env-file .env.local --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/compose.env --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/env/common.env --env-file '"$tmpdir"'/quickstart/docker/modules/pqs/compose.env --profile app-provider --profile pqs-app-provider --profile pqs-sv -f '"$tmpdir"'/quickstart/docker/modules/keycloak/compose.yaml --env-file '"$tmpdir"'/quickstart/docker/modules/keycloak/compose.env --profile keycloak down -v --remove-orphans' oauth2
|
|
@@ -351,4 +401,58 @@ assert_file_contains "$tmpdir/generated/additional-config.extra-validators.conf"
|
|
|
351
401
|
assert_file_contains "$tmpdir/generated/additional-config.extra-validators.conf" ' validator-party-hint = "${EXTRA_VALIDATOR_1_PARTY_HINT}"'
|
|
352
402
|
assert_file_contains "$tmpdir/generated/additional-config.extra-validators.conf" ' domains.global.buy-extra-traffic {'
|
|
353
403
|
assert_file_contains "$tmpdir/generated/additional-config.extra-validators.conf" 'canton.sv-apps.sv.expected-validator-onboardings += { secret = "${EXTRA_VALIDATOR_3_ONBOARDING_SECRET}" }'
|
|
404
|
+
run_case $'.PHONY: start-local-ledger\nstart-local-ledger:\n' 'stub docker compose -f compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/localnet/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/splice-onboarding/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/pqs/compose.yaml --env-file .env --env-file .env.local --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/compose.env --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/env/common.env --env-file '"$tmpdir"'/quickstart/docker/modules/pqs/compose.env --profile app-provider --profile pqs-app-provider --profile pqs-sv -f '"$tmpdir"'/tls/compose-localnet.yaml down -v --remove-orphans' shared-secret default 0 '' '' 0 1
|
|
405
|
+
assert_file_contains_text "$tmpdir/tls/canton-tls.conf" 'canton.participants.app-provider.ledger-api.tls {'
|
|
406
|
+
assert_file_contains_text "$tmpdir/tls/canton-tls.conf" 'canton.participants.app-provider.admin-api.tls {'
|
|
407
|
+
assert_file_contains_text "$tmpdir/tls/canton-tls.conf" 'canton.participants.sv.admin-api.tls {'
|
|
408
|
+
if grep -Fq 'canton.participants.app-user.ledger-api.tls {' "$tmpdir/tls/canton-tls.conf" \
|
|
409
|
+
|| grep -Fq 'canton.participants.app-user.admin-api.tls {' "$tmpdir/tls/canton-tls.conf"; then
|
|
410
|
+
echo "unexpected TLS configuration for inactive app-user participant" >&2
|
|
411
|
+
exit 1
|
|
412
|
+
fi
|
|
413
|
+
assert_file_contains_text "$tmpdir/tls/compose-localnet.yaml" '/app/localnet-tls/server.key:ro'
|
|
414
|
+
assert_file_contains_text "$tmpdir/tls/compose-localnet.yaml" '/app/localnet-tls/ca.crt:ro'
|
|
415
|
+
assert_file_mode "$tmpdir/tls/server.key" 600
|
|
416
|
+
assert_file_mode "$tmpdir/tls/ca.key" 600
|
|
417
|
+
run_case $'.PHONY: start\nstart:\n' 'stub docker compose -f compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/localnet/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/splice-onboarding/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/pqs/compose.yaml --env-file .env --env-file .env.local --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/compose.env --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/env/common.env --env-file '"$tmpdir"'/quickstart/docker/modules/pqs/compose.env --profile app-provider --profile pqs-app-provider --profile pqs-sv -f '"$tmpdir"'/generated/compose-extra-participants.yaml --env-file '"$tmpdir"'/generated/extra-participants.env -f '"$tmpdir"'/tls/compose-localnet.yaml down -v --remove-orphans' shared-secret default 2 '' '' 0 1
|
|
418
|
+
assert_file_contains_text "$tmpdir/generated/additional-config.extra-participants.conf" 'canton.participants.extra-1.ledger-api.tls {'
|
|
419
|
+
assert_file_contains_text "$tmpdir/generated/additional-config.extra-participants.conf" 'canton.participants.extra-2.admin-api.tls {'
|
|
420
|
+
|
|
421
|
+
mkdir -p "$tmpdir/supplied"
|
|
422
|
+
openssl genrsa -out "$tmpdir/supplied/ca.key" 2048 >/dev/null 2>&1
|
|
423
|
+
openssl req -x509 -new -sha256 -days 3650 \
|
|
424
|
+
-key "$tmpdir/supplied/ca.key" \
|
|
425
|
+
-subj '/CN=supplied-localnet-ca' \
|
|
426
|
+
-addext 'basicConstraints=critical,CA:TRUE' \
|
|
427
|
+
-addext 'keyUsage=critical,keyCertSign,cRLSign' \
|
|
428
|
+
-out "$tmpdir/supplied/ca.crt" >/dev/null 2>&1
|
|
429
|
+
openssl genrsa -out "$tmpdir/supplied/server.key" 2048 >/dev/null 2>&1
|
|
430
|
+
openssl req -new -sha256 -key "$tmpdir/supplied/server.key" \
|
|
431
|
+
-subj '/CN=localhost' -out "$tmpdir/supplied/server.csr" >/dev/null 2>&1
|
|
432
|
+
printf '%s\n' \
|
|
433
|
+
'[server_ext]' \
|
|
434
|
+
'basicConstraints = CA:FALSE' \
|
|
435
|
+
'keyUsage = digitalSignature, keyEncipherment' \
|
|
436
|
+
'extendedKeyUsage = serverAuth' \
|
|
437
|
+
'subjectAltName = DNS:localhost, DNS:canton, IP:127.0.0.1' \
|
|
438
|
+
> "$tmpdir/supplied/server-extensions.cnf"
|
|
439
|
+
openssl x509 -req -sha256 -days 3650 \
|
|
440
|
+
-in "$tmpdir/supplied/server.csr" \
|
|
441
|
+
-CA "$tmpdir/supplied/ca.crt" -CAkey "$tmpdir/supplied/ca.key" -CAcreateserial \
|
|
442
|
+
-out "$tmpdir/supplied/server.crt" \
|
|
443
|
+
-extfile "$tmpdir/supplied/server-extensions.cnf" -extensions server_ext >/dev/null 2>&1
|
|
444
|
+
run_case $'.PHONY: start\nstart:\n' 'stub docker compose -f compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/localnet/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/splice-onboarding/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/pqs/compose.yaml --env-file .env --env-file .env.local --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/compose.env --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/env/common.env --env-file '"$tmpdir"'/quickstart/docker/modules/pqs/compose.env --profile app-provider --profile pqs-app-provider --profile pqs-sv -f '"$tmpdir"'/tls/compose-localnet.yaml down -v --remove-orphans' shared-secret default 0 '' '' 0 1 "$tmpdir/supplied/server.crt" "$tmpdir/supplied/server.key" "$tmpdir/supplied/ca.crt"
|
|
445
|
+
if [[ -e "$tmpdir/tls/server.key" || -e "$tmpdir/tls/ca.key" ]]; then
|
|
446
|
+
echo 'supplied TLS mode unexpectedly generated private material' >&2
|
|
447
|
+
exit 1
|
|
448
|
+
fi
|
|
449
|
+
assert_file_contains_text "$tmpdir/tls/compose-localnet.yaml" "$tmpdir/supplied/server.key:/app/localnet-tls/server.key:ro"
|
|
450
|
+
openssl genrsa -out "$tmpdir/supplied/mismatch.key" 2048 >/dev/null 2>&1
|
|
451
|
+
run_case $'.PHONY: start\nstart:\n' 'Supplied TLS private key does not match the server certificate.' shared-secret default 0 '' '' 0 1 "$tmpdir/supplied/server.crt" "$tmpdir/supplied/mismatch.key" "$tmpdir/supplied/ca.crt" 1
|
|
452
|
+
run_case $'.PHONY: start\nstart:\n' 'LOCALNET_TLS_CERT_CHAIN_PATH, LOCALNET_TLS_PRIVATE_KEY_PATH, and LOCALNET_TLS_CA_CERT_PATH must be set together.' shared-secret default 0 '' '' 0 1 "$tmpdir/supplied/server.crt" '' '' 1
|
|
453
|
+
run_case $'.PHONY: start\nstart:\n' 'LOCALNET_TLS must be 0 or 1.' shared-secret default 0 '' '' 0 invalid '' '' '' 1
|
|
454
|
+
run_case $'.PHONY: start\nstart:\n' 'ES256 bearer token written to '"$tmpdir"'/es256/ledger-api-user.token' shared-secret default 0 '' '' 1 1
|
|
455
|
+
assert_file_contains_text "$tmpdir/es256/canton-es256.conf" 'include file("/app/localnet-tls.conf")'
|
|
456
|
+
assert_file_contains_text "$tmpdir/es256/compose-es256.yaml" '/app/es256-certificate.pem:ro'
|
|
457
|
+
assert_file_contains_text "$tmpdir/tls/compose-localnet.yaml" '/app/localnet-tls/server.crt:ro'
|
|
354
458
|
run_repo_root_env_case
|
package/node/test-stop-local.sh
CHANGED
|
@@ -14,6 +14,7 @@ run_case() {
|
|
|
14
14
|
local expected_output="$2"
|
|
15
15
|
local auth_mode="${3:-shared-secret}"
|
|
16
16
|
local docker_mode="${4:-compose-v2}"
|
|
17
|
+
local tls_enabled="${5:-0}"
|
|
17
18
|
local quickstart_dir="$tmpdir/quickstart"
|
|
18
19
|
local stubbin="$tmpdir/bin"
|
|
19
20
|
local generated_dir="$tmpdir/generated-stop"
|
|
@@ -26,6 +27,10 @@ run_case() {
|
|
|
26
27
|
"$quickstart_dir/docker/modules/keycloak" \
|
|
27
28
|
"$stubbin" \
|
|
28
29
|
"$generated_dir"
|
|
30
|
+
if [[ "$tls_enabled" == "1" ]]; then
|
|
31
|
+
mkdir -p "$tmpdir/tls"
|
|
32
|
+
printf 'services:\n' > "$tmpdir/tls/compose-localnet.yaml"
|
|
33
|
+
fi
|
|
29
34
|
|
|
30
35
|
printf '%s\n' "$makefile_targets" > "$quickstart_dir/Makefile"
|
|
31
36
|
printf 'DOCKER_NETWORK=quickstart\nSPLICE_VERSION=0.6.5\n' > "$quickstart_dir/.env"
|
|
@@ -64,6 +69,7 @@ printf 'stub env APP_PROVIDER_PROFILE=%s\n' "${APP_PROVIDER_PROFILE:-}"
|
|
|
64
69
|
printf 'stub env APP_USER_PROFILE=%s\n' "${APP_USER_PROFILE:-}"
|
|
65
70
|
printf 'stub env SV_PROFILE=%s\n' "${SV_PROFILE:-}"
|
|
66
71
|
printf 'stub env PQS_SV_PROFILE=%s\n' "${PQS_SV_PROFILE:-}"
|
|
72
|
+
printf 'stub env AUTH_MODE=%s\n' "${AUTH_MODE:-}"
|
|
67
73
|
if [[ "${1:-}" == "compose" && "${2:-}" == "version" ]]; then
|
|
68
74
|
if [[ "$docker_mode" == "compose-v2" ]]; then
|
|
69
75
|
exit 0
|
|
@@ -95,6 +101,8 @@ EOF
|
|
|
95
101
|
cd "$SCRIPT_DIR"
|
|
96
102
|
CN_QUICKSTART_DIR="$quickstart_dir" \
|
|
97
103
|
START_LOCAL_GENERATED_DIR="$generated_dir" \
|
|
104
|
+
START_LOCAL_TLS_RUNTIME_DIR="$tmpdir/tls" \
|
|
105
|
+
LOCALNET_TLS="$tls_enabled" \
|
|
98
106
|
PATH="$stubbin:$PATH" \
|
|
99
107
|
bash ./stop-local.sh
|
|
100
108
|
)"
|
|
@@ -108,5 +116,6 @@ EOF
|
|
|
108
116
|
run_case $'.PHONY: stop-local-ledger\nstop-local-ledger:\n' 'stub make stop-local-ledger'
|
|
109
117
|
run_case $'.PHONY: stop\nstop:\n' 'stub docker compose -f compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/localnet/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/splice-onboarding/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/pqs/compose.yaml --env-file .env --env-file .env.local --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/compose.env --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/env/common.env --env-file '"$tmpdir"'/quickstart/docker/modules/pqs/compose.env --profile app-provider --profile pqs-app-provider --profile pqs-sv down -v --remove-orphans'
|
|
110
118
|
run_case $'.PHONY: stop\nstop:\n' 'stub docker compose -f compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/localnet/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/splice-onboarding/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/pqs/compose.yaml --env-file .env --env-file .env.local --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/compose.env --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/env/common.env --env-file '"$tmpdir"'/quickstart/docker/modules/pqs/compose.env --profile app-provider --profile pqs-app-provider --profile pqs-sv -f '"$tmpdir"'/quickstart/docker/modules/keycloak/compose.yaml --env-file '"$tmpdir"'/quickstart/docker/modules/keycloak/compose.env --profile keycloak down -v --remove-orphans' oauth2
|
|
119
|
+
run_case $'.PHONY: stop\nstop:\n' 'stub env AUTH_MODE=oauth2' oauth2
|
|
111
120
|
run_case $'.PHONY: stop\nstop:\n' 'stub docker-compose -f compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/localnet/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/splice-onboarding/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/pqs/compose.yaml --env-file .env --env-file .env.local --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/compose.env --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/env/common.env --env-file '"$tmpdir"'/quickstart/docker/modules/pqs/compose.env --profile app-provider --profile pqs-app-provider --profile pqs-sv down -v --remove-orphans' shared-secret compose-v1
|
|
112
|
-
|
|
121
|
+
run_case $'.PHONY: stop-local-ledger\nstop-local-ledger:\n' 'stub docker compose -f compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/localnet/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/splice-onboarding/compose.yaml -f '"$tmpdir"'/quickstart/docker/modules/pqs/compose.yaml --env-file .env --env-file .env.local --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/compose.env --env-file '"$tmpdir"'/quickstart/docker/modules/localnet/env/common.env --env-file '"$tmpdir"'/quickstart/docker/modules/pqs/compose.env --profile app-provider --profile pqs-app-provider --profile pqs-sv -f '"$tmpdir"'/tls/compose-localnet.yaml down -v --remove-orphans' shared-secret compose-v2 1
|