create-svc 0.1.70 → 0.1.72
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/package.json +1 -1
- package/src/service-runtime/cloudrun/cli.ts +14 -1
- package/src/service-runtime/cloudrun/config.ts +5 -0
- package/src/service-runtime/cloudrun/lib.ts +1 -1
- package/src/service-runtime/cloudrun/sdk.test.ts +16 -3
- package/src/service-runtime/cloudrun/temporal-config.test.ts +22 -0
- package/src/service-runtime/cloudrun/temporal-config.ts +11 -4
- package/templates/shared/service.jsonc +2 -1
package/package.json
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
formatError,
|
|
18
18
|
gcloud,
|
|
19
19
|
ensureProductionDomainMapping,
|
|
20
|
+
readVaultField,
|
|
20
21
|
requireCommand,
|
|
21
22
|
requireGcloudAuth,
|
|
22
23
|
resolveDeploymentTarget,
|
|
@@ -347,6 +348,7 @@ async function runSdk(args: string[]) {
|
|
|
347
348
|
const [subcommand] = args;
|
|
348
349
|
if (subcommand === "publish") {
|
|
349
350
|
requireCommand("buf");
|
|
351
|
+
ensureBufAuth();
|
|
350
352
|
run("buf", ["push"]);
|
|
351
353
|
const published = resolvePublishedSdk();
|
|
352
354
|
await writeSdkMode("remote", published);
|
|
@@ -371,6 +373,7 @@ async function runSdk(args: string[]) {
|
|
|
371
373
|
|
|
372
374
|
if (subcommand === "use-remote") {
|
|
373
375
|
requireCommand("buf");
|
|
376
|
+
ensureBufAuth();
|
|
374
377
|
const published = resolvePublishedSdk();
|
|
375
378
|
await writeSdkMode("remote", published);
|
|
376
379
|
return `Remote Buf SDK recorded for consumers: ${bufModule()}@${published.commit}`;
|
|
@@ -447,7 +450,17 @@ async function writeSdkMode(mode: "local" | "remote", published?: PublishedSdk)
|
|
|
447
450
|
}
|
|
448
451
|
|
|
449
452
|
function bufModule() {
|
|
450
|
-
return `buf.build/anmho/${config.serviceName}`;
|
|
453
|
+
return config.buf.module || `buf.build/anmho/${config.serviceName}`;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function ensureBufAuth() {
|
|
457
|
+
const token =
|
|
458
|
+
process.env.BUF_TOKEN?.trim() ||
|
|
459
|
+
readVaultField(config.buf.vaultMount, config.buf.vaultPath, ["BUF_TOKEN", "buf.api_token", "buf_token", "api_token", "token"]);
|
|
460
|
+
if (!token) {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
run("buf", ["registry", "login", "buf.build", "--token-stdin"], { input: `${token}\n` });
|
|
451
464
|
}
|
|
452
465
|
|
|
453
466
|
async function resolveLocalSdkPath() {
|
|
@@ -46,6 +46,11 @@ export const config = {
|
|
|
46
46
|
vaultMount: vault.mount || "secret",
|
|
47
47
|
vaultPath: vault.temporal_path || "prod/providers/temporal",
|
|
48
48
|
},
|
|
49
|
+
buf: {
|
|
50
|
+
module: serviceConfig.buf?.module || `buf.build/anmho/${serviceConfig.service_id}`,
|
|
51
|
+
vaultMount: vault.mount || "secret",
|
|
52
|
+
vaultPath: vault.buf_path || "prod/providers/buf",
|
|
53
|
+
},
|
|
49
54
|
neon: {
|
|
50
55
|
projectId: neon.project_id,
|
|
51
56
|
baseBranchId: neon.base_branch_id,
|
|
@@ -589,7 +589,7 @@ function renderTemporalMtlsEnv(temporal: ReturnType<typeof resolveTemporalRuntim
|
|
|
589
589
|
.join("\n");
|
|
590
590
|
}
|
|
591
591
|
|
|
592
|
-
function readVaultField(mount: string, path: string, fields: string[]) {
|
|
592
|
+
export function readVaultField(mount: string, path: string, fields: string[]) {
|
|
593
593
|
const vault = Bun.which("vault");
|
|
594
594
|
if (!vault || !path) {
|
|
595
595
|
return "";
|
|
@@ -37,6 +37,7 @@ test("service sdk publish pushes the named Buf module and selects remote SDK mod
|
|
|
37
37
|
const generatedRoot = join(root, "sdk-proof");
|
|
38
38
|
const fakeBin = join(root, "bin");
|
|
39
39
|
const bufLog = join(root, "buf.log");
|
|
40
|
+
const tokenLog = join(root, "buf-token.log");
|
|
40
41
|
|
|
41
42
|
await scaffoldProject(baseConfig(generatedRoot));
|
|
42
43
|
await mkdir(join(generatedRoot, "node_modules"));
|
|
@@ -46,10 +47,19 @@ test("service sdk publish pushes the named Buf module and selects remote SDK mod
|
|
|
46
47
|
[
|
|
47
48
|
"#!/bin/sh",
|
|
48
49
|
`echo "$@" >> "${bufLog}"`,
|
|
50
|
+
'if [ "$1 $2 $3 $4" = "registry login buf.build --token-stdin" ]; then',
|
|
51
|
+
` cat > "${tokenLog}"`,
|
|
52
|
+
" exit 0",
|
|
53
|
+
"fi",
|
|
49
54
|
'if [ "$1 $2 $3 $4" = "registry module commit list" ]; then',
|
|
50
55
|
' printf \'{"commits":[{"name":"buf.build/anmho/sdk-proof:commit-123","digest":"b5:abc123","create_time":"2026-05-25T12:00:00Z"}]}\'',
|
|
56
|
+
" exit 0",
|
|
51
57
|
"fi",
|
|
52
|
-
"
|
|
58
|
+
'if [ "$1" = "push" ]; then',
|
|
59
|
+
" exit 0",
|
|
60
|
+
"fi",
|
|
61
|
+
"echo unexpected buf command: $@ >&2",
|
|
62
|
+
"exit 1",
|
|
53
63
|
"",
|
|
54
64
|
].join("\n")
|
|
55
65
|
);
|
|
@@ -57,16 +67,19 @@ test("service sdk publish pushes the named Buf module and selects remote SDK mod
|
|
|
57
67
|
|
|
58
68
|
const result = Bun.spawnSync(["bun", join(import.meta.dir, "..", "..", "..", "index.ts"), "sdk", "publish"], {
|
|
59
69
|
cwd: generatedRoot,
|
|
60
|
-
env: { ...process.env, PATH: `${fakeBin}:${process.env.PATH ?? ""}` },
|
|
70
|
+
env: { ...process.env, BUF_TOKEN: "test-token", PATH: `${fakeBin}:${process.env.PATH ?? ""}` },
|
|
61
71
|
stdout: "pipe",
|
|
62
72
|
stderr: "pipe",
|
|
63
73
|
});
|
|
64
74
|
|
|
65
75
|
expect(result.success, [result.stdout.toString(), result.stderr.toString()].join("\n")).toBeTrue();
|
|
66
76
|
expect(result.stdout.toString()).toContain("recorded for consumers");
|
|
77
|
+
expect(result.stdout.toString()).not.toContain("test-token");
|
|
78
|
+
expect(result.stderr.toString()).not.toContain("test-token");
|
|
67
79
|
expect((await readFile(bufLog, "utf8")).trim()).toBe(
|
|
68
|
-
["push", "registry module commit list buf.build/anmho/sdk-proof --format json --page-size 1"].join("\n")
|
|
80
|
+
["registry login buf.build --token-stdin", "push", "registry module commit list buf.build/anmho/sdk-proof --format json --page-size 1"].join("\n")
|
|
69
81
|
);
|
|
82
|
+
expect((await readFile(tokenLog, "utf8")).trim()).toBe("test-token");
|
|
70
83
|
const sdkState = JSON.parse(await Bun.file(join(generatedRoot, ".service", "sdk.json")).text());
|
|
71
84
|
expect(sdkState).toMatchObject({
|
|
72
85
|
mode: "remote",
|
|
@@ -62,6 +62,28 @@ test("resolveTemporalRuntimeConfigValues reads self-hosted mTLS config from Vaul
|
|
|
62
62
|
});
|
|
63
63
|
});
|
|
64
64
|
|
|
65
|
+
test("resolveTemporalRuntimeConfigValues renders configured mTLS secret names without raw credentials", () => {
|
|
66
|
+
const resolved = resolveTemporalRuntimeConfigValues(
|
|
67
|
+
{ ...baseConfig, address: "temporal-grpc.anmho.com:7233" },
|
|
68
|
+
{},
|
|
69
|
+
() => ({
|
|
70
|
+
namespace: "default",
|
|
71
|
+
})
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
expect(resolved).toMatchObject({
|
|
75
|
+
enabled: true,
|
|
76
|
+
address: "temporal-grpc.anmho.com:7233",
|
|
77
|
+
namespace: "default",
|
|
78
|
+
tlsCaCertSecretName: "orders-temporal-ca-cert",
|
|
79
|
+
tlsCertSecretName: "orders-temporal-client-cert",
|
|
80
|
+
tlsKeySecretName: "orders-temporal-client-key",
|
|
81
|
+
tlsCaCert: "",
|
|
82
|
+
tlsCert: "",
|
|
83
|
+
tlsKey: "",
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
65
87
|
test("resolveTemporalRuntimeConfigValues prefers explicit environment overrides", () => {
|
|
66
88
|
const resolved = resolveTemporalRuntimeConfigValues(
|
|
67
89
|
baseConfig,
|
|
@@ -75,6 +75,13 @@ export function resolveTemporalRuntimeConfigValues(
|
|
|
75
75
|
env.TEMPORAL_TLS_CERT_SECRET?.trim() || (tlsCert ? config.tlsCertSecretName || `${config.taskQueue}-temporal-client-cert` : "");
|
|
76
76
|
const tlsKeySecretName =
|
|
77
77
|
env.TEMPORAL_TLS_KEY_SECRET?.trim() || (tlsKey ? config.tlsKeySecretName || `${config.taskQueue}-temporal-client-key` : "");
|
|
78
|
+
const configuredTLSSecretNames = Boolean(config.tlsCaCertSecretName && config.tlsCertSecretName && config.tlsKeySecretName);
|
|
79
|
+
const shouldRenderTLSSecretNames = Boolean(tlsCaCert || (!apiKey && configuredTLSSecretNames));
|
|
80
|
+
const resolvedTLSSecretNames = {
|
|
81
|
+
ca: shouldRenderTLSSecretNames ? tlsCaCertSecretName || config.tlsCaCertSecretName || "" : "",
|
|
82
|
+
cert: shouldRenderTLSSecretNames ? tlsCertSecretName || config.tlsCertSecretName || "" : "",
|
|
83
|
+
key: shouldRenderTLSSecretNames ? tlsKeySecretName || config.tlsKeySecretName || "" : "",
|
|
84
|
+
};
|
|
78
85
|
|
|
79
86
|
if (isLocalTemporalAddress(address)) {
|
|
80
87
|
throw new Error(
|
|
@@ -95,7 +102,7 @@ export function resolveTemporalRuntimeConfigValues(
|
|
|
95
102
|
`Temporal mTLS is partially configured; set TEMPORAL_TLS_CA_CERT, TEMPORAL_TLS_CERT, and TEMPORAL_TLS_KEY together in env or Vault at ${config.vaultMount}/${config.vaultPath}`
|
|
96
103
|
);
|
|
97
104
|
}
|
|
98
|
-
if (!apiKey && !tlsCaCert) {
|
|
105
|
+
if (!apiKey && !apiKeySecretName && !tlsCaCert && !configuredTLSSecretNames) {
|
|
99
106
|
throw new Error(
|
|
100
107
|
`Temporal is enabled but no credentials were found; set TEMPORAL_API_KEY or TEMPORAL_TLS_CA_CERT/TEMPORAL_TLS_CERT/TEMPORAL_TLS_KEY in env or Vault at ${config.vaultMount}/${config.vaultPath}`
|
|
101
108
|
);
|
|
@@ -108,9 +115,9 @@ export function resolveTemporalRuntimeConfigValues(
|
|
|
108
115
|
taskQueue,
|
|
109
116
|
apiKeySecretName,
|
|
110
117
|
apiKey,
|
|
111
|
-
tlsCaCertSecretName,
|
|
112
|
-
tlsCertSecretName,
|
|
113
|
-
tlsKeySecretName,
|
|
118
|
+
tlsCaCertSecretName: resolvedTLSSecretNames.ca,
|
|
119
|
+
tlsCertSecretName: resolvedTLSSecretNames.cert,
|
|
120
|
+
tlsKeySecretName: resolvedTLSSecretNames.key,
|
|
114
121
|
tlsCaCert,
|
|
115
122
|
tlsCert,
|
|
116
123
|
tlsKey,
|
|
@@ -70,7 +70,8 @@
|
|
|
70
70
|
"cloudflare_path": "prod/providers/cloudflare",
|
|
71
71
|
"grafana_path": "prod/providers/grafana",
|
|
72
72
|
"clerk_m2m_path": "prod/providers/clerk-m2m",
|
|
73
|
-
"temporal_path": "prod/providers/temporal"
|
|
73
|
+
"temporal_path": "prod/providers/temporal",
|
|
74
|
+
"buf_path": "prod/providers/buf"
|
|
74
75
|
}
|
|
75
76
|
},
|
|
76
77
|
|