@smoothbricks/cli 0.11.16 → 0.11.18

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.
Files changed (79) hide show
  1. package/README.md +65 -4
  2. package/dist/cli.d.ts.map +1 -1
  3. package/dist/cli.js +47 -0
  4. package/dist/github-ci/index.d.ts +1 -1
  5. package/dist/github-ci/index.d.ts.map +1 -1
  6. package/dist/github-ci/index.js +7 -10
  7. package/dist/lib/secret-names.d.ts +35 -0
  8. package/dist/lib/secret-names.d.ts.map +1 -0
  9. package/dist/lib/secret-names.js +61 -0
  10. package/dist/monorepo/ci-workflow.d.ts +56 -0
  11. package/dist/monorepo/ci-workflow.d.ts.map +1 -1
  12. package/dist/monorepo/ci-workflow.js +214 -8
  13. package/dist/monorepo/managed-files.d.ts +23 -0
  14. package/dist/monorepo/managed-files.d.ts.map +1 -1
  15. package/dist/monorepo/managed-files.js +39 -1
  16. package/dist/monorepo/publish-workflow.d.ts +10 -1
  17. package/dist/monorepo/publish-workflow.d.ts.map +1 -1
  18. package/dist/monorepo/publish-workflow.js +58 -20
  19. package/dist/release/github-release.d.ts +10 -0
  20. package/dist/release/github-release.d.ts.map +1 -1
  21. package/dist/release/github-release.js +11 -5
  22. package/dist/release/index.d.ts.map +1 -1
  23. package/dist/release/index.js +4 -5
  24. package/dist/secrets/commands.d.ts +84 -0
  25. package/dist/secrets/commands.d.ts.map +1 -0
  26. package/dist/secrets/commands.js +375 -0
  27. package/dist/secrets/index.d.ts +103 -0
  28. package/dist/secrets/index.d.ts.map +1 -0
  29. package/dist/secrets/index.js +255 -0
  30. package/dist/secrets/repository.d.ts +60 -0
  31. package/dist/secrets/repository.d.ts.map +1 -0
  32. package/dist/secrets/repository.js +145 -0
  33. package/dist/wrangler/cloudflare.d.ts +7 -0
  34. package/dist/wrangler/cloudflare.d.ts.map +1 -1
  35. package/dist/wrangler/cloudflare.js +10 -0
  36. package/dist/wrangler/deploy-stage.d.ts +13 -2
  37. package/dist/wrangler/deploy-stage.d.ts.map +1 -1
  38. package/dist/wrangler/deploy-stage.js +89 -78
  39. package/dist/wrangler/deployed-version.d.ts +44 -0
  40. package/dist/wrangler/deployed-version.d.ts.map +1 -0
  41. package/dist/wrangler/deployed-version.js +87 -0
  42. package/dist/wrangler/live-version.d.ts +146 -0
  43. package/dist/wrangler/live-version.d.ts.map +1 -0
  44. package/dist/wrangler/live-version.js +326 -0
  45. package/dist/wrangler/stage-secrets.d.ts +57 -0
  46. package/dist/wrangler/stage-secrets.d.ts.map +1 -0
  47. package/dist/wrangler/stage-secrets.js +178 -0
  48. package/managed/raw/tooling/direnv/devenv.smoo.nix +9 -1
  49. package/managed/raw/tooling/git-hooks/pre-push.sh +30 -29
  50. package/package.json +2 -2
  51. package/src/cli.ts +69 -1
  52. package/src/github-ci/index.test.ts +92 -8
  53. package/src/github-ci/index.ts +7 -10
  54. package/src/lib/secret-names.ts +70 -0
  55. package/src/monorepo/__tests__/ci-workflow.test.ts +188 -2
  56. package/src/monorepo/__tests__/publish-workflow.test.ts +33 -15
  57. package/src/monorepo/ci-workflow.ts +294 -8
  58. package/src/monorepo/managed-files.test.ts +28 -1
  59. package/src/monorepo/managed-files.ts +56 -2
  60. package/src/monorepo/package-policy.test.ts +1 -1
  61. package/src/monorepo/publish-workflow.ts +65 -19
  62. package/src/monorepo/secret-references.test.ts +1 -1
  63. package/src/release/__tests__/github-release.test.ts +8 -4
  64. package/src/release/__tests__/private-npm-status.test.ts +2 -2
  65. package/src/release/github-release.ts +13 -5
  66. package/src/release/index.ts +4 -4
  67. package/src/secrets/commands.test.ts +28 -0
  68. package/src/secrets/commands.ts +412 -0
  69. package/src/secrets/index.test.ts +209 -0
  70. package/src/secrets/index.ts +287 -0
  71. package/src/secrets/repository.test.ts +98 -0
  72. package/src/secrets/repository.ts +164 -0
  73. package/src/wrangler/cloudflare.ts +18 -0
  74. package/src/wrangler/deploy-stage.test.ts +448 -23
  75. package/src/wrangler/deploy-stage.ts +142 -83
  76. package/src/wrangler/deployed-version.test.ts +150 -0
  77. package/src/wrangler/deployed-version.ts +130 -0
  78. package/src/wrangler/live-version.ts +363 -0
  79. package/src/wrangler/stage-secrets.ts +146 -0
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Reconciles the three places a repository's secrets are described, all of
3
+ * which smoo already owns:
4
+ *
5
+ * 1. **Workers declare names.** `.dev.vars.example` per wrangler project — the
6
+ * file `wrangler types --env-file` reads and `prepare-env` prompts from.
7
+ * 2. **Workflows declare where values come from.** `smoo.github.deploySecrets`
8
+ * and `e2eSecrets` map an env name to a repository secret, and the managed
9
+ * workflows render exactly those into the job environment.
10
+ * 3. **A developer shell declares how to fetch one locally.** `smoo.secrets`
11
+ * names a command whose stdout is the value.
12
+ *
13
+ * Nothing joined them, so a Worker could declare a secret no workflow supplies
14
+ * and no repository holds. That fails at deploy time, on a stage, with a
15
+ * fail-closed message about the value rather than about the missing
16
+ * declaration — the shape that costs an afternoon: a Worker declares
17
+ * `STRIPE_PUBLISHABLE_KEY`, `ci.yml` passes `secrets.STRIPE_PUBLISHABLE_KEY`,
18
+ * the repository holds no such secret, and the empty value surfaces as the
19
+ * payment library's own `publishable_key_mismatch` refusal.
20
+ */
21
+ /** Where an env name is described, which repository secret carries it, and whether that exists. */
22
+ export interface SecretRow {
23
+ name: string;
24
+ /** The repository secret this env name reads from, by convention or declaration. */
25
+ repositorySecret: string;
26
+ /** Wrangler projects whose `.dev.vars.example` declares it. */
27
+ declaredByWorkers: string[];
28
+ /** True when a managed workflow renders `secrets.<name>` into a job. */
29
+ suppliedByWorkflow: boolean;
30
+ /** True when `smoo.secrets` can fetch it for a developer shell. */
31
+ fetchableLocally: boolean;
32
+ /** True when the repository holds a secret of this name. */
33
+ onRepository: boolean;
34
+ /**
35
+ * GitHub Environments holding their own value for this name. A job bound to
36
+ * an environment reads that value in preference to the repository's, which
37
+ * is how one name carries test credentials on a preview stage and live ones
38
+ * in production.
39
+ */
40
+ heldByEnvironment: string[];
41
+ }
42
+ export interface SecretSources {
43
+ /** Worker label -> env names it declares. */
44
+ workerSecrets: Record<string, readonly string[]>;
45
+ /** Env names a managed workflow passes into a job. */
46
+ workflowSecrets: readonly string[];
47
+ /** Env name -> repository secret, by convention with declared exceptions. */
48
+ secretNames: Readonly<Record<string, string>>;
49
+ /** Env names `smoo.secrets` can fetch locally. */
50
+ localCommands: readonly string[];
51
+ /** Repository secret names GitHub currently holds. */
52
+ repositorySecrets: readonly string[];
53
+ /** Environment name -> secret names that environment holds. */
54
+ environmentSecrets?: Readonly<Record<string, readonly string[]>>;
55
+ }
56
+ /**
57
+ * One row per name known to any source, sorted, so a reader sees the whole
58
+ * picture rather than one source's view of it.
59
+ */
60
+ export declare function reconcileSecrets(sources: SecretSources): SecretRow[];
61
+ /**
62
+ * The rows a CI deploy cannot satisfy: a Worker declares the name, a workflow
63
+ * promises to pass it, and the repository has no value to pass. Reported
64
+ * separately from "declared but not wired into any workflow", because the
65
+ * remedies differ — set a secret, versus declare it in `smoo.github`.
66
+ */
67
+ export declare function unsatisfiedSecrets(rows: readonly SecretRow[], boundEnvironments?: readonly string[]): SecretRow[];
68
+ /** Bound environments that lack their own value and cannot fall back to the repository. */
69
+ export declare function environmentsMissing(row: SecretRow, boundEnvironments: readonly string[]): string[];
70
+ /** Worker-declared names no managed workflow passes: a CI deploy will run without them. */
71
+ export declare function unwiredSecrets(rows: readonly SecretRow[]): SecretRow[];
72
+ /** Env names the managed workflows pass into a job, from the declarations that render them. */
73
+ export declare function workflowSecretNames(root: string): string[];
74
+ /**
75
+ * GitHub Environments the rendered workflows bind, read from the workflow
76
+ * files rather than from config: a binding may be hand-authored inside a
77
+ * `smoo-local` block, and the file is what GitHub executes either way. A job
78
+ * bound to an environment resolves `secrets.X` from that environment first and
79
+ * from the repository second, so these names are the scopes a value can live
80
+ * in. Expressions are skipped - a computed environment names no fixed scope.
81
+ */
82
+ export declare function workflowEnvironments(root: string): string[];
83
+ /**
84
+ * Env name -> repository secret for every name in play, following the naming
85
+ * convention and honouring the declared exceptions a repository still needs.
86
+ */
87
+ export declare function secretNameMapping(root: string, envNames: readonly string[]): Record<string, string>;
88
+ /** Every wrangler project's declared secret names, keyed by the project directory. */
89
+ export declare function workerSecretNames(root: string, workspaceDirs: readonly string[]): Record<string, string[]>;
90
+ /** Names `smoo.secrets` declares a fetch command for. */
91
+ export declare function localSecretCommandNames(root: string): string[];
92
+ /**
93
+ * Resolve one declared secret through its command. The value is returned, never
94
+ * logged: callers hand it to `gh secret set` over stdin.
95
+ */
96
+ export declare function fetchLocalSecret(root: string, name: string): {
97
+ ok: true;
98
+ value: string;
99
+ } | {
100
+ ok: false;
101
+ reason: string;
102
+ };
103
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/secrets/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AASH,mGAAmG;AACnG,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,oFAAoF;IACpF,gBAAgB,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,wEAAwE;IACxE,kBAAkB,EAAE,OAAO,CAAC;IAC5B,mEAAmE;IACnE,gBAAgB,EAAE,OAAO,CAAC;IAC1B,4DAA4D;IAC5D,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAED,MAAM,WAAW,aAAa;IAC5B,6CAA6C;IAC7C,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC;IACjD,sDAAsD;IACtD,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,6EAA6E;IAC7E,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC9C,kDAAkD;IAClD,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,sDAAsD;IACtD,iBAAiB,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,+DAA+D;IAC/D,kBAAkB,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;CAClE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,GAAG,SAAS,EAAE,CAoCpE;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,SAAS,SAAS,EAAE,EAAE,iBAAiB,GAAE,SAAS,MAAM,EAAO,GAAG,SAAS,EAAE,CAUrH;AAED,2FAA2F;AAC3F,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,SAAS,EAAE,iBAAiB,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAGlG;AAED,2FAA2F;AAC3F,wBAAgB,cAAc,CAAC,IAAI,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,EAAE,CAEtE;AAED,+FAA+F;AAC/F,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAkB1D;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAW3D;AAoDD;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMnG;AAED,sFAAsF;AACtF,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAS1G;AAED,yDAAyD;AACzD,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAG9D;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAqB7D"}
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Reconciles the three places a repository's secrets are described, all of
3
+ * which smoo already owns:
4
+ *
5
+ * 1. **Workers declare names.** `.dev.vars.example` per wrangler project — the
6
+ * file `wrangler types --env-file` reads and `prepare-env` prompts from.
7
+ * 2. **Workflows declare where values come from.** `smoo.github.deploySecrets`
8
+ * and `e2eSecrets` map an env name to a repository secret, and the managed
9
+ * workflows render exactly those into the job environment.
10
+ * 3. **A developer shell declares how to fetch one locally.** `smoo.secrets`
11
+ * names a command whose stdout is the value.
12
+ *
13
+ * Nothing joined them, so a Worker could declare a secret no workflow supplies
14
+ * and no repository holds. That fails at deploy time, on a stage, with a
15
+ * fail-closed message about the value rather than about the missing
16
+ * declaration — the shape that costs an afternoon: a Worker declares
17
+ * `STRIPE_PUBLISHABLE_KEY`, `ci.yml` passes `secrets.STRIPE_PUBLISHABLE_KEY`,
18
+ * the repository holds no such secret, and the empty value surfaces as the
19
+ * payment library's own `publishable_key_mismatch` refusal.
20
+ */
21
+ import { spawnSync } from 'node:child_process';
22
+ import { existsSync, readdirSync, readFileSync } from 'node:fs';
23
+ import { join } from 'node:path';
24
+ import { repositoryOwnerFromUrl, repositorySecretMapping } from '../lib/secret-names.js';
25
+ import { readPackageJsonObject, repositoryInfo } from '../lib/workspace.js';
26
+ import { parseDevVarsExample } from '../wrangler/prepare-env.js';
27
+ /**
28
+ * One row per name known to any source, sorted, so a reader sees the whole
29
+ * picture rather than one source's view of it.
30
+ */
31
+ export function reconcileSecrets(sources) {
32
+ const declaredByAnyWorker = Object.values(sources.workerSecrets).flatMap((names) => [...names]);
33
+ const names = new Set([...declaredByAnyWorker, ...sources.workflowSecrets, ...sources.localCommands]);
34
+ // A repository secret that already carries a known env name is that name's
35
+ // row, not a row of its own: listing ACME_GITHUB_CLIENT_SECRET beside
36
+ // GITHUB_CLIENT_SECRET would report one value as two secrets, one of them
37
+ // permanently "declared by nothing".
38
+ const carriesKnownEnvName = new Set(names.size > 0 ? [...names].map((name) => sources.secretNames[name] ?? name) : []);
39
+ // A value only an environment holds is still a value: leaving it out of the
40
+ // rows is how an operator ends up hunting for a secret that is already set.
41
+ const addUndeclared = (secret) => {
42
+ if (!carriesKnownEnvName.has(secret))
43
+ names.add(secret);
44
+ };
45
+ for (const secret of sources.repositorySecrets)
46
+ addUndeclared(secret);
47
+ for (const held of Object.values(sources.environmentSecrets ?? {})) {
48
+ for (const secret of held)
49
+ addUndeclared(secret);
50
+ }
51
+ return [...names]
52
+ .sort((left, right) => left.localeCompare(right))
53
+ .map((name) => ({
54
+ name,
55
+ repositorySecret: sources.secretNames[name] ?? name,
56
+ declaredByWorkers: Object.entries(sources.workerSecrets)
57
+ .filter(([, declared]) => declared.includes(name))
58
+ .map(([label]) => label)
59
+ .sort((left, right) => left.localeCompare(right)),
60
+ suppliedByWorkflow: sources.workflowSecrets.includes(name),
61
+ fetchableLocally: sources.localCommands.includes(name),
62
+ onRepository: sources.repositorySecrets.includes(sources.secretNames[name] ?? name),
63
+ heldByEnvironment: Object.entries(sources.environmentSecrets ?? {})
64
+ .filter(([, held]) => held.includes(sources.secretNames[name] ?? name))
65
+ .map(([environment]) => environment)
66
+ .sort((left, right) => left.localeCompare(right)),
67
+ }));
68
+ }
69
+ /**
70
+ * The rows a CI deploy cannot satisfy: a Worker declares the name, a workflow
71
+ * promises to pass it, and the repository has no value to pass. Reported
72
+ * separately from "declared but not wired into any workflow", because the
73
+ * remedies differ — set a secret, versus declare it in `smoo.github`.
74
+ */
75
+ export function unsatisfiedSecrets(rows, boundEnvironments = []) {
76
+ return rows.filter((row) => {
77
+ if (!row.suppliedByWorkflow)
78
+ return false;
79
+ if (row.onRepository)
80
+ return false;
81
+ // With no environment bound, the repository is the only scope a job reads.
82
+ // With environments bound, each one can carry the value instead - so the
83
+ // name is satisfied only when every bound environment holds it.
84
+ if (boundEnvironments.length === 0)
85
+ return true;
86
+ return !boundEnvironments.every((environment) => row.heldByEnvironment.includes(environment));
87
+ });
88
+ }
89
+ /** Bound environments that lack their own value and cannot fall back to the repository. */
90
+ export function environmentsMissing(row, boundEnvironments) {
91
+ if (row.onRepository)
92
+ return [];
93
+ return boundEnvironments.filter((environment) => !row.heldByEnvironment.includes(environment));
94
+ }
95
+ /** Worker-declared names no managed workflow passes: a CI deploy will run without them. */
96
+ export function unwiredSecrets(rows) {
97
+ return rows.filter((row) => row.declaredByWorkers.length > 0 && !row.suppliedByWorkflow);
98
+ }
99
+ /** Env names the managed workflows pass into a job, from the declarations that render them. */
100
+ export function workflowSecretNames(root) {
101
+ const manifest = readPackageJsonObject(join(root, 'package.json'));
102
+ const smoo = manifest?.smoo;
103
+ const github = smoo?.github;
104
+ const names = new Set([
105
+ ...Object.keys(github?.deploySecrets ?? {}),
106
+ ...Object.keys(github?.e2eSecrets ?? {}),
107
+ ]);
108
+ if (smoo?.remoteCache?.tokenSecret)
109
+ names.add(smoo.remoteCache.tokenSecret);
110
+ for (const origin of github?.cargoCredentials?.gitOrigins ?? []) {
111
+ if (origin.tokenEnv)
112
+ names.add(origin.tokenEnv);
113
+ }
114
+ for (const source of github?.sourceCheckouts ?? []) {
115
+ if (source.tokenEnv)
116
+ names.add(source.tokenEnv);
117
+ }
118
+ if (smoo?.privateNpm?.readTokenEnv)
119
+ names.add(smoo.privateNpm.readTokenEnv);
120
+ if (smoo?.privateNpm?.publishTokenEnv)
121
+ names.add(smoo.privateNpm.publishTokenEnv);
122
+ return [...names].sort((left, right) => left.localeCompare(right));
123
+ }
124
+ /**
125
+ * GitHub Environments the rendered workflows bind, read from the workflow
126
+ * files rather than from config: a binding may be hand-authored inside a
127
+ * `smoo-local` block, and the file is what GitHub executes either way. A job
128
+ * bound to an environment resolves `secrets.X` from that environment first and
129
+ * from the repository second, so these names are the scopes a value can live
130
+ * in. Expressions are skipped - a computed environment names no fixed scope.
131
+ */
132
+ export function workflowEnvironments(root) {
133
+ const directory = join(root, '.github', 'workflows');
134
+ if (!existsSync(directory))
135
+ return [];
136
+ const environments = new Set();
137
+ for (const entry of readdirSync(directory)) {
138
+ if (!entry.endsWith('.yml') && !entry.endsWith('.yaml'))
139
+ continue;
140
+ for (const bound of environmentBindings(readFileSync(join(directory, entry), 'utf8'))) {
141
+ environments.add(bound);
142
+ }
143
+ }
144
+ return [...environments].sort((left, right) => left.localeCompare(right));
145
+ }
146
+ /**
147
+ * The environments one workflow file binds, in both spellings GitHub accepts:
148
+ * `environment: staging`, and the block form whose `name:` sits under it when
149
+ * the job also records a deployment URL. Only a `name:` indented inside an
150
+ * `environment:` block is a binding - a workflow's, a job's and a step's are
151
+ * not, and reading those as environments would send an operator to set
152
+ * secrets in scopes that do not exist.
153
+ */
154
+ function environmentBindings(text) {
155
+ const lines = text.split('\n');
156
+ const bound = [];
157
+ for (let index = 0; index < lines.length; index += 1) {
158
+ const binding = /^(\s*)environment:(.*)$/.exec(lines[index] ?? '');
159
+ if (!binding)
160
+ continue;
161
+ const indent = (binding[1] ?? '').length;
162
+ const value = binding[2] ?? '';
163
+ // Nothing but a comment after the colon is the block form; anything else
164
+ // is the value itself.
165
+ if (!/^\s*(?:#.*)?$/.test(value)) {
166
+ const name = literalEnvironmentName(value);
167
+ if (name !== null)
168
+ bound.push(name);
169
+ continue;
170
+ }
171
+ for (let next = index + 1; next < lines.length; next += 1) {
172
+ const line = lines[next] ?? '';
173
+ const content = line.trimStart();
174
+ if (content.length === 0 || content.startsWith('#'))
175
+ continue;
176
+ if (line.length - content.length <= indent)
177
+ break;
178
+ const named = /^name:(.*)$/.exec(content);
179
+ if (!named)
180
+ continue;
181
+ const name = literalEnvironmentName(named[1] ?? '');
182
+ if (name !== null)
183
+ bound.push(name);
184
+ break;
185
+ }
186
+ }
187
+ return bound;
188
+ }
189
+ /**
190
+ * The fixed name a YAML value denotes, or null when it denotes no fixed scope:
191
+ * an expression is computed per run, and a flow mapping or a list is not a
192
+ * name. Names may contain spaces, which is why the renderer quotes them.
193
+ */
194
+ function literalEnvironmentName(value) {
195
+ const scalar = value.replace(/\s+#.*$/, '').trim();
196
+ if (scalar.length === 0 || scalar.includes('${{'))
197
+ return null;
198
+ const unquoted = /^(['"])(.*)\1$/.exec(scalar)?.[2] ?? scalar;
199
+ return /^[A-Za-z0-9._-][A-Za-z0-9._ -]*$/.test(unquoted) ? unquoted : null;
200
+ }
201
+ /**
202
+ * Env name -> repository secret for every name in play, following the naming
203
+ * convention and honouring the declared exceptions a repository still needs.
204
+ */
205
+ export function secretNameMapping(root, envNames) {
206
+ const manifest = readPackageJsonObject(join(root, 'package.json'));
207
+ const declared = { ...(manifest?.smoo?.github?.deploySecrets ?? {}), ...(manifest?.smoo?.github?.e2eSecrets ?? {}) };
208
+ const repository = manifest ? repositoryInfo(manifest) : null;
209
+ const owner = repository ? (repositoryOwnerFromUrl(repository.url) ?? '') : '';
210
+ return repositorySecretMapping(envNames, owner, declared);
211
+ }
212
+ /** Every wrangler project's declared secret names, keyed by the project directory. */
213
+ export function workerSecretNames(root, workspaceDirs) {
214
+ const byWorker = {};
215
+ for (const dir of workspaceDirs) {
216
+ const examplePath = join(root, dir, '.dev.vars.example');
217
+ if (!existsSync(examplePath))
218
+ continue;
219
+ const names = parseDevVarsExample(readFileSync(examplePath, 'utf8'));
220
+ if (names.length > 0)
221
+ byWorker[dir] = names;
222
+ }
223
+ return byWorker;
224
+ }
225
+ /** Names `smoo.secrets` declares a fetch command for. */
226
+ export function localSecretCommandNames(root) {
227
+ const manifest = readPackageJsonObject(join(root, 'package.json'));
228
+ return Object.keys(manifest?.smoo?.secrets ?? {}).sort((left, right) => left.localeCompare(right));
229
+ }
230
+ /**
231
+ * Resolve one declared secret through its command. The value is returned, never
232
+ * logged: callers hand it to `gh secret set` over stdin.
233
+ */
234
+ export function fetchLocalSecret(root, name) {
235
+ const manifest = readPackageJsonObject(join(root, 'package.json'));
236
+ const declared = manifest?.smoo?.secrets?.[name];
237
+ if (!declared) {
238
+ return { ok: false, reason: `smoo.secrets declares no command for ${name}` };
239
+ }
240
+ const [command, ...args] = declared.command;
241
+ const result = spawnSync(command, args, { encoding: 'utf8' });
242
+ if (result.status !== 0) {
243
+ // Name the command, never its output: a failing secret fetch prints
244
+ // credentials often enough that it is worth refusing to.
245
+ return {
246
+ ok: false,
247
+ reason: `${name}: \`${declared.command.join(' ')}\` exited ${result.status ?? 'without status'}`,
248
+ };
249
+ }
250
+ const value = result.stdout.replace(/\n$/, '');
251
+ if (value.length === 0) {
252
+ return { ok: false, reason: `${name}: \`${declared.command.join(' ')}\` produced no value` };
253
+ }
254
+ return { ok: true, value };
255
+ }
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Which GitHub repository `smoo secrets` reads and writes.
3
+ *
4
+ * `gh` refuses on a checkout with more than one remote ("multiple remotes
5
+ * detected"), which is exactly the public/private mirror layout this CLI's own
6
+ * users run — so the repository has to be resolved here, from the checkout,
7
+ * before `gh` is spawned. The current branch's upstream decides it: a branch
8
+ * that pushes to the private mirror is a branch whose secrets live there. That
9
+ * is a fact the checkout already records, not a preference to configure.
10
+ */
11
+ export interface RepositoryChoice {
12
+ /** `owner/name`, the form `gh --repo` takes. */
13
+ readonly repo: string;
14
+ /** Why this repository, for the operator to read back. */
15
+ readonly source: string;
16
+ }
17
+ /** `owner/name` from any git remote URL form, or null when it names no repository. */
18
+ export declare function repositorySlugFromUrl(url: string): string | null;
19
+ /**
20
+ * Pure resolution, so the precedence is testable without a checkout.
21
+ *
22
+ * A requested value is either a remote name or an `owner/name` slug; naming a
23
+ * remote is what an operator reaches for first (`-R private-repo`), and
24
+ * refusing it because it lacks a slash would be pedantry.
25
+ *
26
+ * With no request and no upstream - a branch pushed by explicit refspec, which
27
+ * is how the mirror layout is driven - the remote-tracking refs still record
28
+ * where this branch has been pushed. One remote carrying it is an answer; two
29
+ * is a genuine ambiguity worth refusing.
30
+ */
31
+ export declare function chooseRepository(inputs: {
32
+ readonly remotes: ReadonlyMap<string, string>;
33
+ readonly upstreamRemote: string | null;
34
+ /** Remotes that already carry the current branch, from its remote-tracking refs. */
35
+ readonly remotesCarryingBranch?: readonly string[];
36
+ /** Current branch name, for the refusal to say which branch decided nothing. */
37
+ readonly branch?: string | null;
38
+ readonly requested: string | undefined;
39
+ }): {
40
+ ok: true;
41
+ choice: RepositoryChoice;
42
+ } | {
43
+ ok: false;
44
+ reason: string;
45
+ };
46
+ /** Remote name -> URL, in config order. */
47
+ export declare function readRemotes(root: string): Map<string, string>;
48
+ /** Remotes with a remote-tracking ref for the current branch: where it has been pushed. */
49
+ export declare function readRemotesCarryingBranch(root: string, remotes: ReadonlyMap<string, string>): string[];
50
+ /** The remote the current branch tracks, or null when it tracks nothing. */
51
+ export declare function readUpstreamRemote(root: string): string | null;
52
+ /** The repository to operate on, resolved from the checkout. */
53
+ export declare function resolveRepository(root: string, requested: string | undefined): {
54
+ ok: true;
55
+ choice: RepositoryChoice;
56
+ } | {
57
+ ok: false;
58
+ reason: string;
59
+ };
60
+ //# sourceMappingURL=repository.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../../src/secrets/repository.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,MAAM,WAAW,gBAAgB;IAC/B,gDAAgD;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,sFAAsF;AACtF,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAehE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IACvC,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9C,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IACvC,oFAAoF;IACpF,QAAQ,CAAC,qBAAqB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnD,gFAAgF;IAChF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;CACxC,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAoDzE;AAOD,2CAA2C;AAC3C,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAS7D;AAED,2FAA2F;AAC3F,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,CAUtG;AAED,4EAA4E;AAC5E,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI9D;AAED,gEAAgE;AAChE,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,SAAS,EAAE,MAAM,GAAG,SAAS,GAC5B;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,gBAAgB,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAUxE"}
@@ -0,0 +1,145 @@
1
+ /**
2
+ * Which GitHub repository `smoo secrets` reads and writes.
3
+ *
4
+ * `gh` refuses on a checkout with more than one remote ("multiple remotes
5
+ * detected"), which is exactly the public/private mirror layout this CLI's own
6
+ * users run — so the repository has to be resolved here, from the checkout,
7
+ * before `gh` is spawned. The current branch's upstream decides it: a branch
8
+ * that pushes to the private mirror is a branch whose secrets live there. That
9
+ * is a fact the checkout already records, not a preference to configure.
10
+ */
11
+ import { spawnSync } from 'node:child_process';
12
+ /** `owner/name` from any git remote URL form, or null when it names no repository. */
13
+ export function repositorySlugFromUrl(url) {
14
+ const withoutProtocol = url
15
+ .trim()
16
+ .replace(/^[a-z+]+:\/\//i, '')
17
+ .replace(/^[^@/]+@/, '');
18
+ // A remainder starting with `/` or `.` carries no host, so it is a path on
19
+ // this machine - a valid git remote, never a GitHub repository.
20
+ if (withoutProtocol.startsWith('/') || withoutProtocol.startsWith('.'))
21
+ return null;
22
+ const path = withoutProtocol.replace(/^[^/:]+(?::\d+)?[/:]/, '');
23
+ const segments = path
24
+ .replace(/\.git$/i, '')
25
+ .split('/')
26
+ .filter((segment) => segment.length > 0);
27
+ if (segments.length < 2)
28
+ return null;
29
+ return `${segments[segments.length - 2]}/${segments[segments.length - 1]}`;
30
+ }
31
+ /**
32
+ * Pure resolution, so the precedence is testable without a checkout.
33
+ *
34
+ * A requested value is either a remote name or an `owner/name` slug; naming a
35
+ * remote is what an operator reaches for first (`-R private-repo`), and
36
+ * refusing it because it lacks a slash would be pedantry.
37
+ *
38
+ * With no request and no upstream - a branch pushed by explicit refspec, which
39
+ * is how the mirror layout is driven - the remote-tracking refs still record
40
+ * where this branch has been pushed. One remote carrying it is an answer; two
41
+ * is a genuine ambiguity worth refusing.
42
+ */
43
+ export function chooseRepository(inputs) {
44
+ const { remotes, upstreamRemote, requested } = inputs;
45
+ const remotesCarryingBranch = inputs.remotesCarryingBranch ?? [];
46
+ if (requested !== undefined && requested.length > 0) {
47
+ const url = remotes.get(requested);
48
+ if (url !== undefined) {
49
+ const slug = repositorySlugFromUrl(url);
50
+ if (slug === null)
51
+ return { ok: false, reason: `remote ${requested} (${url}) names no owner/name` };
52
+ return { ok: true, choice: { repo: slug, source: `remote ${requested}` } };
53
+ }
54
+ if (requested.includes('/'))
55
+ return { ok: true, choice: { repo: requested, source: 'requested' } };
56
+ return {
57
+ ok: false,
58
+ reason: `${requested} is neither a remote of this checkout nor an owner/name. ` +
59
+ `Remotes: ${[...remotes.keys()].join(', ') || 'none'}`,
60
+ };
61
+ }
62
+ if (upstreamRemote !== null) {
63
+ const url = remotes.get(upstreamRemote);
64
+ const slug = url === undefined ? null : repositorySlugFromUrl(url);
65
+ if (slug !== null) {
66
+ return { ok: true, choice: { repo: slug, source: `upstream of the current branch (${upstreamRemote})` } };
67
+ }
68
+ }
69
+ if (remotesCarryingBranch.length === 1) {
70
+ const name = remotesCarryingBranch[0] ?? '';
71
+ const url = remotes.get(name);
72
+ const slug = url === undefined ? null : repositorySlugFromUrl(url);
73
+ if (slug !== null) {
74
+ return { ok: true, choice: { repo: slug, source: `the only remote carrying this branch (${name})` } };
75
+ }
76
+ }
77
+ if (remotes.size === 1) {
78
+ const [name, url] = [...remotes][0];
79
+ const slug = repositorySlugFromUrl(url);
80
+ if (slug !== null)
81
+ return { ok: true, choice: { repo: slug, source: `the only remote (${name})` } };
82
+ }
83
+ const origin = remotes.get('origin');
84
+ const originSlug = origin === undefined ? null : repositorySlugFromUrl(origin);
85
+ if (originSlug !== null)
86
+ return { ok: true, choice: { repo: originSlug, source: 'remote origin' } };
87
+ const candidates = [...remotes].map(([name, url]) => `${name} -> ${repositorySlugFromUrl(url) ?? url}`).join(', ');
88
+ const branchClause = inputs.branch === undefined || inputs.branch === null
89
+ ? 'this checkout has no current branch'
90
+ : `branch ${inputs.branch} has no upstream and no remote carries it`;
91
+ return {
92
+ ok: false,
93
+ reason: `${branchClause}, and there is no origin, so the repository is ambiguous. ` +
94
+ `Pass -R with one of: ${candidates || 'no remotes at all'}`,
95
+ };
96
+ }
97
+ function git(root, args) {
98
+ const result = spawnSync('git', [...args], { cwd: root, encoding: 'utf8' });
99
+ return result.status === 0 ? result.stdout.trim() : null;
100
+ }
101
+ /** Remote name -> URL, in config order. */
102
+ export function readRemotes(root) {
103
+ const remotes = new Map();
104
+ const config = git(root, ['config', '--get-regexp', '^remote\\..*\\.url']);
105
+ if (config === null)
106
+ return remotes;
107
+ for (const line of config.split('\n')) {
108
+ const match = /^remote\.(.+)\.url\s+(.+)$/.exec(line.trim());
109
+ if (match !== null && match[1] !== undefined && match[2] !== undefined)
110
+ remotes.set(match[1], match[2]);
111
+ }
112
+ return remotes;
113
+ }
114
+ /** Remotes with a remote-tracking ref for the current branch: where it has been pushed. */
115
+ export function readRemotesCarryingBranch(root, remotes) {
116
+ const branch = git(root, ['rev-parse', '--abbrev-ref', 'HEAD']);
117
+ if (branch === null || branch === 'HEAD')
118
+ return [];
119
+ const carrying = [];
120
+ for (const name of remotes.keys()) {
121
+ if (git(root, ['rev-parse', '--verify', '--quiet', `refs/remotes/${name}/${branch}`]) !== null) {
122
+ carrying.push(name);
123
+ }
124
+ }
125
+ return carrying;
126
+ }
127
+ /** The remote the current branch tracks, or null when it tracks nothing. */
128
+ export function readUpstreamRemote(root) {
129
+ const branch = git(root, ['rev-parse', '--abbrev-ref', 'HEAD']);
130
+ if (branch === null || branch === 'HEAD')
131
+ return null;
132
+ return git(root, ['config', '--get', `branch.${branch}.remote`]);
133
+ }
134
+ /** The repository to operate on, resolved from the checkout. */
135
+ export function resolveRepository(root, requested) {
136
+ const remotes = readRemotes(root);
137
+ const branch = git(root, ['rev-parse', '--abbrev-ref', 'HEAD']);
138
+ return chooseRepository({
139
+ remotes,
140
+ upstreamRemote: readUpstreamRemote(root),
141
+ remotesCarryingBranch: readRemotesCarryingBranch(root, remotes),
142
+ branch: branch === 'HEAD' ? null : branch,
143
+ requested,
144
+ });
145
+ }
@@ -5,6 +5,10 @@ export interface R2Bucket {
5
5
  export interface WorkerScript {
6
6
  id: string;
7
7
  }
8
+ /** One secret bound to a Worker. Cloudflare answers names and types only; a value is never readable. */
9
+ export interface WorkerSecret {
10
+ name: string;
11
+ }
8
12
  export interface WorkerRoute {
9
13
  id: string;
10
14
  pattern: string;
@@ -40,6 +44,8 @@ export interface CloudflareClient {
40
44
  deleteR2Object(bucket: string, key: string): Promise<void>;
41
45
  deleteR2Bucket(name: string): Promise<void>;
42
46
  listWorkerScripts(): Promise<WorkerScript[]>;
47
+ /** Names only; the Worker's stored values are write-only from outside. */
48
+ listWorkerSecrets(workerName: string): Promise<string[]>;
43
49
  deleteWorkerScript(name: string): Promise<void>;
44
50
  listWorkerDomains(): Promise<WorkerDomain[]>;
45
51
  createWorkerDomain(hostname: string, workerName: string, zoneId: string): Promise<void>;
@@ -75,6 +81,7 @@ export declare class CloudflareRestClient implements CloudflareClient {
75
81
  deleteR2Object(bucket: string, key: string): Promise<void>;
76
82
  deleteR2Bucket(name: string): Promise<void>;
77
83
  listWorkerScripts(): Promise<WorkerScript[]>;
84
+ listWorkerSecrets(workerName: string): Promise<string[]>;
78
85
  deleteWorkerScript(name: string): Promise<void>;
79
86
  listWorkerDomains(): Promise<WorkerDomain[]>;
80
87
  createWorkerDomain(hostname: string, workerName: string, zoneId: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../src/wrangler/cloudflare.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cloudflare.d.ts","sourceRoot":"","sources":["../../src/wrangler/cloudflare.ts"],"names":[],"mappings":"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"}
@@ -29,6 +29,10 @@ const isWorkerScripts = (() => {
29
29
  const _io0 = input => "string" === typeof input.id;
30
30
  return input => Array.isArray(input) && input.every(elem => "object" === typeof elem && null !== elem && _io0(elem));
31
31
  })();
32
+ const isWorkerSecrets = (() => {
33
+ const _io0 = input => "string" === typeof input.name;
34
+ return input => Array.isArray(input) && input.every(elem => "object" === typeof elem && null !== elem && _io0(elem));
35
+ })();
32
36
  const isWorkerDomains = (() => {
33
37
  const _io0 = input => "string" === typeof input.id && "string" === typeof input.hostname && (undefined === input.service || "string" === typeof input.service);
34
38
  return input => Array.isArray(input) && input.every(elem => "object" === typeof elem && null !== elem && _io0(elem));
@@ -158,6 +162,12 @@ export class CloudflareRestClient {
158
162
  // `workers/scripts` takes no pagination parameters: the account's scripts arrive in one answer.
159
163
  return this.listOnce(`${this.accountPath}/workers/scripts`, isWorkerScripts);
160
164
  }
165
+ async listWorkerSecrets(workerName) {
166
+ // Unpaginated, like the script listing itself. A Worker that does not exist answers 404 rather
167
+ // than an empty list, so the caller must establish that the Worker is there before asking.
168
+ const secrets = await this.listOnce(`${this.accountPath}/workers/scripts/${encodeURIComponent(workerName)}/secrets`, isWorkerSecrets);
169
+ return secrets.map((secret) => secret.name);
170
+ }
161
171
  deleteWorkerScript(name) {
162
172
  return this.mutate(`${this.accountPath}/workers/scripts/${encodeURIComponent(name)}`, { method: 'DELETE' });
163
173
  }