@rmartz/envctl 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/README.md +79 -0
  2. package/dist/envctl.d.ts +3 -0
  3. package/dist/envctl.d.ts.map +1 -0
  4. package/dist/envctl.js +36 -0
  5. package/dist/envctl.js.map +1 -0
  6. package/dist/lib/auth.d.ts +21 -0
  7. package/dist/lib/auth.d.ts.map +1 -0
  8. package/dist/lib/auth.js +148 -0
  9. package/dist/lib/auth.js.map +1 -0
  10. package/dist/lib/check-firebase.d.ts +6 -0
  11. package/dist/lib/check-firebase.d.ts.map +1 -0
  12. package/dist/lib/check-firebase.js +81 -0
  13. package/dist/lib/check-firebase.js.map +1 -0
  14. package/dist/lib/check-live.d.ts +3 -0
  15. package/dist/lib/check-live.d.ts.map +1 -0
  16. package/dist/lib/check-live.js +50 -0
  17. package/dist/lib/check-live.js.map +1 -0
  18. package/dist/lib/check.d.ts +9 -0
  19. package/dist/lib/check.d.ts.map +1 -0
  20. package/dist/lib/check.js +165 -0
  21. package/dist/lib/check.js.map +1 -0
  22. package/dist/lib/cli/help.d.ts +4 -0
  23. package/dist/lib/cli/help.d.ts.map +1 -0
  24. package/dist/lib/cli/help.js +52 -0
  25. package/dist/lib/cli/help.js.map +1 -0
  26. package/dist/lib/cli/registry.d.ts +19 -0
  27. package/dist/lib/cli/registry.d.ts.map +1 -0
  28. package/dist/lib/cli/registry.js +111 -0
  29. package/dist/lib/cli/registry.js.map +1 -0
  30. package/dist/lib/cli/router.d.ts +22 -0
  31. package/dist/lib/cli/router.d.ts.map +1 -0
  32. package/dist/lib/cli/router.js +98 -0
  33. package/dist/lib/cli/router.js.map +1 -0
  34. package/dist/lib/cli/version.d.ts +2 -0
  35. package/dist/lib/cli/version.d.ts.map +1 -0
  36. package/dist/lib/cli/version.js +58 -0
  37. package/dist/lib/cli/version.js.map +1 -0
  38. package/dist/lib/commands/auth.d.ts +2 -0
  39. package/dist/lib/commands/auth.d.ts.map +1 -0
  40. package/dist/lib/commands/auth.js +33 -0
  41. package/dist/lib/commands/auth.js.map +1 -0
  42. package/dist/lib/commands/bootstrap-args.d.ts +11 -0
  43. package/dist/lib/commands/bootstrap-args.d.ts.map +1 -0
  44. package/dist/lib/commands/bootstrap-args.js +111 -0
  45. package/dist/lib/commands/bootstrap-args.js.map +1 -0
  46. package/dist/lib/commands/bootstrap.d.ts +5 -0
  47. package/dist/lib/commands/bootstrap.d.ts.map +1 -0
  48. package/dist/lib/commands/bootstrap.js +166 -0
  49. package/dist/lib/commands/bootstrap.js.map +1 -0
  50. package/dist/lib/commands/check.d.ts +3 -0
  51. package/dist/lib/commands/check.d.ts.map +1 -0
  52. package/dist/lib/commands/check.js +47 -0
  53. package/dist/lib/commands/check.js.map +1 -0
  54. package/dist/lib/commands/config-pull.d.ts +12 -0
  55. package/dist/lib/commands/config-pull.d.ts.map +1 -0
  56. package/dist/lib/commands/config-pull.js +161 -0
  57. package/dist/lib/commands/config-pull.js.map +1 -0
  58. package/dist/lib/commands/config-push-args.d.ts +9 -0
  59. package/dist/lib/commands/config-push-args.d.ts.map +1 -0
  60. package/dist/lib/commands/config-push-args.js +108 -0
  61. package/dist/lib/commands/config-push-args.js.map +1 -0
  62. package/dist/lib/commands/config-push.d.ts +6 -0
  63. package/dist/lib/commands/config-push.d.ts.map +1 -0
  64. package/dist/lib/commands/config-push.js +166 -0
  65. package/dist/lib/commands/config-push.js.map +1 -0
  66. package/dist/lib/commands/deployment-config.d.ts +9 -0
  67. package/dist/lib/commands/deployment-config.d.ts.map +1 -0
  68. package/dist/lib/commands/deployment-config.js +73 -0
  69. package/dist/lib/commands/deployment-config.js.map +1 -0
  70. package/dist/lib/commands/env-plan.d.ts +4 -0
  71. package/dist/lib/commands/env-plan.d.ts.map +1 -0
  72. package/dist/lib/commands/env-plan.js +85 -0
  73. package/dist/lib/commands/env-plan.js.map +1 -0
  74. package/dist/lib/commands/env.d.ts +4 -0
  75. package/dist/lib/commands/env.d.ts.map +1 -0
  76. package/dist/lib/commands/env.js +122 -0
  77. package/dist/lib/commands/env.js.map +1 -0
  78. package/dist/lib/commands/init.d.ts +3 -0
  79. package/dist/lib/commands/init.d.ts.map +1 -0
  80. package/dist/lib/commands/init.js +59 -0
  81. package/dist/lib/commands/init.js.map +1 -0
  82. package/dist/lib/commands/secrets-args.d.ts +13 -0
  83. package/dist/lib/commands/secrets-args.d.ts.map +1 -0
  84. package/dist/lib/commands/secrets-args.js +136 -0
  85. package/dist/lib/commands/secrets-args.js.map +1 -0
  86. package/dist/lib/commands/secrets-plan.d.ts +9 -0
  87. package/dist/lib/commands/secrets-plan.d.ts.map +1 -0
  88. package/dist/lib/commands/secrets-plan.js +109 -0
  89. package/dist/lib/commands/secrets-plan.js.map +1 -0
  90. package/dist/lib/commands/secrets.d.ts +7 -0
  91. package/dist/lib/commands/secrets.d.ts.map +1 -0
  92. package/dist/lib/commands/secrets.js +191 -0
  93. package/dist/lib/commands/secrets.js.map +1 -0
  94. package/dist/lib/deployments.d.ts +4 -0
  95. package/dist/lib/deployments.d.ts.map +1 -0
  96. package/dist/lib/deployments.js +83 -0
  97. package/dist/lib/deployments.js.map +1 -0
  98. package/dist/lib/environments.d.ts +4 -0
  99. package/dist/lib/environments.d.ts.map +1 -0
  100. package/dist/lib/environments.js +97 -0
  101. package/dist/lib/environments.js.map +1 -0
  102. package/dist/lib/firebase-credential.d.ts +28 -0
  103. package/dist/lib/firebase-credential.d.ts.map +1 -0
  104. package/dist/lib/firebase-credential.js +50 -0
  105. package/dist/lib/firebase-credential.js.map +1 -0
  106. package/dist/lib/firebase-invalidate.d.ts +4 -0
  107. package/dist/lib/firebase-invalidate.d.ts.map +1 -0
  108. package/dist/lib/firebase-invalidate.js +61 -0
  109. package/dist/lib/firebase-invalidate.js.map +1 -0
  110. package/dist/lib/firebase-vars.d.ts +14 -0
  111. package/dist/lib/firebase-vars.d.ts.map +1 -0
  112. package/dist/lib/firebase-vars.js +40 -0
  113. package/dist/lib/firebase-vars.js.map +1 -0
  114. package/dist/lib/firebase.d.ts +20 -0
  115. package/dist/lib/firebase.d.ts.map +1 -0
  116. package/dist/lib/firebase.js +189 -0
  117. package/dist/lib/firebase.js.map +1 -0
  118. package/dist/lib/gcp.d.ts +4 -0
  119. package/dist/lib/gcp.d.ts.map +1 -0
  120. package/dist/lib/gcp.js +53 -0
  121. package/dist/lib/gcp.js.map +1 -0
  122. package/dist/lib/generated-secrets.d.ts +16 -0
  123. package/dist/lib/generated-secrets.d.ts.map +1 -0
  124. package/dist/lib/generated-secrets.js +68 -0
  125. package/dist/lib/generated-secrets.js.map +1 -0
  126. package/dist/lib/logger.d.ts +7 -0
  127. package/dist/lib/logger.d.ts.map +1 -0
  128. package/dist/lib/logger.js +60 -0
  129. package/dist/lib/logger.js.map +1 -0
  130. package/dist/lib/manifest/index.d.ts +6 -0
  131. package/dist/lib/manifest/index.d.ts.map +1 -0
  132. package/dist/lib/manifest/index.js +15 -0
  133. package/dist/lib/manifest/index.js.map +1 -0
  134. package/dist/lib/manifest/parse.d.ts +11 -0
  135. package/dist/lib/manifest/parse.d.ts.map +1 -0
  136. package/dist/lib/manifest/parse.js +214 -0
  137. package/dist/lib/manifest/parse.js.map +1 -0
  138. package/dist/lib/manifest/resolve.d.ts +9 -0
  139. package/dist/lib/manifest/resolve.d.ts.map +1 -0
  140. package/dist/lib/manifest/resolve.js +34 -0
  141. package/dist/lib/manifest/resolve.js.map +1 -0
  142. package/dist/lib/manifest/types.d.ts +57 -0
  143. package/dist/lib/manifest/types.d.ts.map +1 -0
  144. package/dist/lib/manifest/types.js +12 -0
  145. package/dist/lib/manifest/types.js.map +1 -0
  146. package/dist/lib/manifest/write.d.ts +3 -0
  147. package/dist/lib/manifest/write.d.ts.map +1 -0
  148. package/dist/lib/manifest/write.js +110 -0
  149. package/dist/lib/manifest/write.js.map +1 -0
  150. package/dist/lib/project.d.ts +6 -0
  151. package/dist/lib/project.d.ts.map +1 -0
  152. package/dist/lib/project.js +56 -0
  153. package/dist/lib/project.js.map +1 -0
  154. package/dist/lib/providers/deployment.d.ts +19 -0
  155. package/dist/lib/providers/deployment.d.ts.map +1 -0
  156. package/dist/lib/providers/deployment.js +62 -0
  157. package/dist/lib/providers/deployment.js.map +1 -0
  158. package/dist/lib/providers/registry.d.ts +5 -0
  159. package/dist/lib/providers/registry.d.ts.map +1 -0
  160. package/dist/lib/providers/registry.js +31 -0
  161. package/dist/lib/providers/registry.js.map +1 -0
  162. package/dist/lib/providers/service.d.ts +35 -0
  163. package/dist/lib/providers/service.d.ts.map +1 -0
  164. package/dist/lib/providers/service.js +81 -0
  165. package/dist/lib/providers/service.js.map +1 -0
  166. package/dist/lib/rotation-preflight.d.ts +11 -0
  167. package/dist/lib/rotation-preflight.d.ts.map +1 -0
  168. package/dist/lib/rotation-preflight.js +47 -0
  169. package/dist/lib/rotation-preflight.js.map +1 -0
  170. package/dist/lib/rotation.d.ts +33 -0
  171. package/dist/lib/rotation.d.ts.map +1 -0
  172. package/dist/lib/rotation.js +168 -0
  173. package/dist/lib/rotation.js.map +1 -0
  174. package/dist/lib/sentry.d.ts +5 -0
  175. package/dist/lib/sentry.d.ts.map +1 -0
  176. package/dist/lib/sentry.js +132 -0
  177. package/dist/lib/sentry.js.map +1 -0
  178. package/dist/lib/subprocess.d.ts +8 -0
  179. package/dist/lib/subprocess.d.ts.map +1 -0
  180. package/dist/lib/subprocess.js +30 -0
  181. package/dist/lib/subprocess.js.map +1 -0
  182. package/dist/lib/targets.d.ts +3 -0
  183. package/dist/lib/targets.d.ts.map +1 -0
  184. package/dist/lib/targets.js +25 -0
  185. package/dist/lib/targets.js.map +1 -0
  186. package/dist/lib/vercel-api.d.ts +50 -0
  187. package/dist/lib/vercel-api.d.ts.map +1 -0
  188. package/dist/lib/vercel-api.js +176 -0
  189. package/dist/lib/vercel-api.js.map +1 -0
  190. package/package.json +53 -0
package/README.md ADDED
@@ -0,0 +1,79 @@
1
+ # envctl
2
+
3
+ A personal, `gh`-style command-line tool for managing deployment configuration and atomically rotating provider secrets across projects and their environments. The hosting/secret providers (Vercel, Firebase, …) sit behind the tool as pluggable backends.
4
+
5
+ See the [Vision](https://github.com/rmartz/envctl/issues/1) for the design and desired functionality.
6
+
7
+ ## Install
8
+
9
+ envctl is published to GitHub Packages as `@rmartz/envctl` and installed as a personal global CLI — never a per-project dependency.
10
+
11
+ **One-time setup.** GitHub Packages requires authentication (even for public packages), so add to your `~/.npmrc`:
12
+
13
+ ```
14
+ @rmartz:registry=https://npm.pkg.github.com
15
+ //npm.pkg.github.com/:_authToken=<a GitHub token with the read:packages scope>
16
+ ```
17
+
18
+ **Install and update:**
19
+
20
+ ```bash
21
+ pnpm add -g @rmartz/envctl # install
22
+ pnpm add -g @rmartz/envctl@latest # update to the newest release
23
+ ```
24
+
25
+ Then, from any project directory:
26
+
27
+ ```bash
28
+ envctl --version
29
+ envctl config push --dry-run # preview the public-var sync for the current project
30
+ envctl config pull # write .env.local from the development environment
31
+ envctl secrets rotate # atomically rotate Firebase/Sentry secrets and redeploy
32
+ envctl secrets init firebase # bootstrap secrets for a fresh project (auto-detects if omitted)
33
+ ```
34
+
35
+ `secrets rotate` mints each new credential, redeploys, then invalidates the old
36
+ one, so the project is never left without a working credential. It relies on the
37
+ same auth as the rest of the CLI — `VERCEL_TOKEN` or `vercel login`,
38
+ `SENTRY_AUTH_TOKEN`, and an authenticated `gcloud` for Firebase key minting (run
39
+ `envctl auth status` to check). Pass `--no-invalidate` to keep the old keys or
40
+ `--refresh-previews` to redeploy active PR previews afterward.
41
+
42
+ New to a project, or unsure which command to reach for? Start with the
43
+ **[Vercel deploy runbook](docs/runbook-vercel-deploy.md)** — a scenario-driven
44
+ playbook (cold-start, mint, rotate, add a provider, public-var change, local
45
+ pull) with copy-pasteable sequences and a "how you know it worked" check for
46
+ each. For mechanism detail, see the
47
+ [secrets rotation engine](docs/secrets-rotation.md) for the full mint → deploy →
48
+ verify → invalidate flow, and the [docs index](docs/index.md) for the
49
+ [config-push](docs/config-push.md) and [environments](docs/env.md) subsystems.
50
+
51
+ ## Bootstrap a blank environment
52
+
53
+ Bring a linked but otherwise empty Vercel project fully online in one step:
54
+
55
+ ```bash
56
+ envctl bootstrap
57
+ ```
58
+
59
+ **Prerequisites:**
60
+
61
+ 1. A linked Vercel project (`.vercel/project.json`, created by `vercel link`)
62
+ 2. An authenticated `gcloud` with a **pre-existing** Firebase project and service account — if the project uses Firebase (envctl mints keys for existing resources; creating the service account from scratch is tracked in [#70](https://github.com/rmartz/envctl/issues/70))
63
+ 3. A Sentry token (`SENTRY_AUTH_TOKEN` or `sentry-cli login`) and a **pre-existing** Sentry project — if the project uses Sentry
64
+
65
+ `bootstrap` runs four phases in order: push public variables (`config push`), initialize any missing provider secrets (`secrets init`), pull a local dotenv file (`config pull`), and trigger redeployments so running environments pick up the pushed vars (`triggerAndWaitRedeployments` — skipped with a log message on a zero-deployment project). It is idempotent — safe to re-run after a partial failure, and existing secrets are never rotated. Pass `--dry-run` to preview every phase without making changes.
66
+
67
+ See the [Bootstrap subsystem docs](docs/bootstrap.md) for the full option reference.
68
+
69
+ ## Development
70
+
71
+ ```bash
72
+ pnpm install
73
+ pnpm build # tsc → dist/
74
+ pnpm run test:ts # vitest
75
+ ```
76
+
77
+ ## Releases
78
+
79
+ Releases are automated with [semantic-release](https://semantic-release.gitbook.io/): a merge to `main` computes the next version from the Conventional Commit history, tags it, creates a GitHub release, and publishes `@rmartz/envctl` to GitHub Packages.
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=envctl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envctl.d.ts","sourceRoot":"","sources":["../src/envctl.ts"],"names":[],"mappings":""}
package/dist/envctl.js ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const logger_1 = require("./lib/logger");
5
+ const help_1 = require("./lib/cli/help");
6
+ const registry_1 = require("./lib/cli/registry");
7
+ const router_1 = require("./lib/cli/router");
8
+ const version_1 = require("./lib/cli/version");
9
+ async function main() {
10
+ const registry = (0, registry_1.buildRegistry)();
11
+ const { workingDir, rest } = (0, router_1.extractGlobalArgs)(process.argv.slice(2), process.cwd());
12
+ const result = (0, router_1.route)(rest, registry);
13
+ switch (result.kind) {
14
+ case "version":
15
+ console.log((0, version_1.readPackageVersion)(__dirname));
16
+ return;
17
+ case "help":
18
+ console.log(result.group ? (0, help_1.renderGroupHelp)(result.group) : (0, help_1.renderTopHelp)(registry));
19
+ return;
20
+ case "error":
21
+ console.error(result.message);
22
+ process.exitCode = 1;
23
+ return;
24
+ case "run":
25
+ await result.command.run({ workingDir }, result.args);
26
+ return;
27
+ }
28
+ }
29
+ main().catch((error) => {
30
+ if (error instanceof logger_1.FatalError) {
31
+ console.error(error.message);
32
+ process.exit(1);
33
+ }
34
+ throw error;
35
+ });
36
+ //# sourceMappingURL=envctl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envctl.js","sourceRoot":"","sources":["../src/envctl.ts"],"names":[],"mappings":";;;AACA,yCAA0C;AAC1C,yCAAgE;AAChE,iDAAmD;AACnD,6CAA4D;AAC5D,+CAAuD;AAEvD,KAAK,UAAU,IAAI;IACjB,MAAM,QAAQ,GAAG,IAAA,wBAAa,GAAE,CAAC;IACjC,MAAM,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,IAAA,0BAAiB,EAC5C,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EACrB,OAAO,CAAC,GAAG,EAAE,CACd,CAAC;IACF,MAAM,MAAM,GAAG,IAAA,cAAK,EAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAErC,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,SAAS;YACZ,OAAO,CAAC,GAAG,CAAC,IAAA,4BAAkB,EAAC,SAAS,CAAC,CAAC,CAAC;YAC3C,OAAO;QACT,KAAK,MAAM;YACT,OAAO,CAAC,GAAG,CACT,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAA,sBAAe,EAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAA,oBAAa,EAAC,QAAQ,CAAC,CACvE,CAAC;YACF,OAAO;QACT,KAAK,OAAO;YACV,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YAC9B,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;YACrB,OAAO;QACT,KAAK,KAAK;YACR,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,UAAU,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;YACtD,OAAO;IACX,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,KAAc,EAAE,EAAE;IAC9B,IAAI,KAAK,YAAY,mBAAU,EAAE,CAAC;QAChC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,MAAM,KAAK,CAAC;AACd,CAAC,CAAC,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Returns the Vercel API token to use, preferring VERCEL_TOKEN env var and
3
+ * falling back to the token stored by the Vercel CLI (vercel login).
4
+ *
5
+ * Returns undefined if no token is available.
6
+ */
7
+ export declare function resolveVercelToken(): string | undefined;
8
+ /**
9
+ * Returns the Sentry auth token, preferring SENTRY_AUTH_TOKEN and falling back
10
+ * to the token stored by sentry-cli (`sentry-cli login` → ~/.sentryclirc).
11
+ * Returns undefined if none is available.
12
+ */
13
+ export declare function resolveSentryToken(): string | undefined;
14
+ export interface AuthState {
15
+ authenticated: boolean;
16
+ source?: string;
17
+ }
18
+ export declare function vercelAuthState(): AuthState;
19
+ export declare function sentryAuthState(): AuthState;
20
+ export declare function gcpAuthState(): AuthState;
21
+ //# sourceMappingURL=auth.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AA+DA;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAEvD;AAqBD;;;;GAIG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,GAAG,SAAS,CAGvD;AAKD,MAAM,WAAW,SAAS;IACxB,aAAa,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,eAAe,IAAI,SAAS,CAK3C;AAED,wBAAgB,eAAe,IAAI,SAAS,CAM3C;AAID,wBAAgB,YAAY,IAAI,SAAS,CAcxC"}
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.resolveVercelToken = resolveVercelToken;
37
+ exports.resolveSentryToken = resolveSentryToken;
38
+ exports.vercelAuthState = vercelAuthState;
39
+ exports.sentryAuthState = sentryAuthState;
40
+ exports.gcpAuthState = gcpAuthState;
41
+ const fs = __importStar(require("fs"));
42
+ const os = __importStar(require("os"));
43
+ const path = __importStar(require("path"));
44
+ const subprocess_1 = require("./subprocess");
45
+ function vercelCliAuthPath() {
46
+ if (process.env.__VERCEL_CLI_AUTH_PATH)
47
+ return process.env.__VERCEL_CLI_AUTH_PATH;
48
+ switch (process.platform) {
49
+ case "darwin":
50
+ return path.join(os.homedir(), "Library", "Application Support", "com.vercel.cli", "auth.json");
51
+ case "win32":
52
+ return path.join(process.env.APPDATA ?? os.homedir(), "com.vercel.cli", "auth.json");
53
+ default:
54
+ return path.join(process.env.XDG_DATA_HOME ?? path.join(os.homedir(), ".local", "share"), "com.vercel.cli", "auth.json");
55
+ }
56
+ }
57
+ function readCliToken() {
58
+ const authPath = vercelCliAuthPath();
59
+ let raw;
60
+ try {
61
+ raw = fs.readFileSync(authPath, "utf-8");
62
+ }
63
+ catch {
64
+ return undefined;
65
+ }
66
+ let auth;
67
+ try {
68
+ auth = JSON.parse(raw);
69
+ }
70
+ catch {
71
+ return undefined;
72
+ }
73
+ if (!auth.token)
74
+ return undefined;
75
+ if (auth.expiresAt !== undefined && Date.now() / 1000 > auth.expiresAt) {
76
+ return undefined;
77
+ }
78
+ return auth.token;
79
+ }
80
+ /**
81
+ * Returns the Vercel API token to use, preferring VERCEL_TOKEN env var and
82
+ * falling back to the token stored by the Vercel CLI (vercel login).
83
+ *
84
+ * Returns undefined if no token is available.
85
+ */
86
+ function resolveVercelToken() {
87
+ return process.env.VERCEL_TOKEN ?? readCliToken() ?? undefined;
88
+ }
89
+ function sentryClircPath() {
90
+ return (process.env.__SENTRY_CLIRC_PATH ?? path.join(os.homedir(), ".sentryclirc"));
91
+ }
92
+ // Reads the `token = …` value from sentry-cli's ~/.sentryclirc (INI-style).
93
+ // Graceful: a missing or unparseable file yields undefined.
94
+ function readSentryClircToken() {
95
+ let raw;
96
+ try {
97
+ raw = fs.readFileSync(sentryClircPath(), "utf-8");
98
+ }
99
+ catch {
100
+ return undefined;
101
+ }
102
+ const match = /^\s*token\s*=\s*(\S+)\s*$/m.exec(raw);
103
+ return match ? match[1] : undefined;
104
+ }
105
+ /**
106
+ * Returns the Sentry auth token, preferring SENTRY_AUTH_TOKEN and falling back
107
+ * to the token stored by sentry-cli (`sentry-cli login` → ~/.sentryclirc).
108
+ * Returns undefined if none is available.
109
+ */
110
+ function resolveSentryToken() {
111
+ // `||` (not `??`) so a blank SENTRY_AUTH_TOKEN falls through to the CLI store.
112
+ return process.env.SENTRY_AUTH_TOKEN || readSentryClircToken() || undefined;
113
+ }
114
+ function vercelAuthState() {
115
+ if (process.env.VERCEL_TOKEN)
116
+ return { authenticated: true, source: "VERCEL_TOKEN env var" };
117
+ if (readCliToken())
118
+ return { authenticated: true, source: "vercel login" };
119
+ return { authenticated: false };
120
+ }
121
+ function sentryAuthState() {
122
+ if (process.env.SENTRY_AUTH_TOKEN)
123
+ return { authenticated: true, source: "SENTRY_AUTH_TOKEN env var" };
124
+ if (readSentryClircToken())
125
+ return { authenticated: true, source: "sentry-cli login (~/.sentryclirc)" };
126
+ return { authenticated: false };
127
+ }
128
+ // GCP auth is owned entirely by the gcloud CLI; report the active account via a
129
+ // local, side-effect-free `gcloud auth list` query (no token minting).
130
+ function gcpAuthState() {
131
+ if (!(0, subprocess_1.commandExists)("gcloud"))
132
+ return { authenticated: false };
133
+ try {
134
+ const account = (0, subprocess_1.run)("gcloud", [
135
+ "auth",
136
+ "list",
137
+ "--filter=status:ACTIVE",
138
+ "--format=value(account)",
139
+ ]).trim();
140
+ if (account)
141
+ return { authenticated: true, source: `gcloud: ${account}` };
142
+ }
143
+ catch {
144
+ // gcloud present but the query failed — treat as unauthenticated.
145
+ }
146
+ return { authenticated: false };
147
+ }
148
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { type Finding } from "./check";
2
+ import type { DeploymentProvider } from "./providers/deployment";
3
+ import type { VercelEnvVar } from "./vercel-api";
4
+ export declare function checkFirebaseSaDrift(deployment: DeploymentProvider, configDir: string, liveEnvs: VercelEnvVar[]): Promise<Finding[]>;
5
+ export declare function checkFirebaseProjectDrift(deployment: DeploymentProvider, configDir: string, liveEnvs: VercelEnvVar[]): Promise<Finding[]>;
6
+ //# sourceMappingURL=check-firebase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-firebase.d.ts","sourceRoot":"","sources":["../../src/lib/check-firebase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAQ3D,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAEjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAUjD,wBAAsB,oBAAoB,CACxC,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,YAAY,EAAE,GACvB,OAAO,CAAC,OAAO,EAAE,CAAC,CAqCpB;AAaD,wBAAsB,yBAAyB,CAC7C,UAAU,EAAE,kBAAkB,EAC9B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,YAAY,EAAE,GACvB,OAAO,CAAC,OAAO,EAAE,CAAC,CAkCpB"}
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkFirebaseSaDrift = checkFirebaseSaDrift;
4
+ exports.checkFirebaseProjectDrift = checkFirebaseProjectDrift;
5
+ const check_1 = require("./check");
6
+ const environments_1 = require("./environments");
7
+ const firebase_credential_1 = require("./firebase-credential");
8
+ const firebase_vars_1 = require("./firebase-vars");
9
+ const manifest_1 = require("./manifest");
10
+ const targets_1 = require("./targets");
11
+ // #103: `FIREBASE_SA_EMAIL` is a deprecated committed var that duplicates the
12
+ // service-account identity the app already reads from the credential's
13
+ // `clientEmail`. This flags a project that still declares it against the live
14
+ // credential — an **error** when the two name different service accounts (the
15
+ // drift class #97/#98 were created to kill: envctl would mint keys for one SA
16
+ // while the app authenticates as another), a deprecation **warning** when it
17
+ // merely duplicates the credential. Part of `envctl check --live`, since the
18
+ // credential's value lives in the provider, not in git.
19
+ async function checkFirebaseSaDrift(deployment, configDir, liveEnvs) {
20
+ const manifest = (0, manifest_1.parseManifest)(configDir);
21
+ const spec = (0, firebase_credential_1.resolveFirebaseCredential)(manifest.services.find((s) => s.provider === "firebase"));
22
+ const resolveTarget = (0, targets_1.envTargetResolver)(configDir);
23
+ const findings = [];
24
+ const seen = new Set();
25
+ for (const env of manifest.environments) {
26
+ const declared = (0, environments_1.parseDeploymentEnv)(configDir, env).FIREBASE_SA_EMAIL;
27
+ if (!declared)
28
+ continue;
29
+ const target = resolveTarget(env);
30
+ const seenKey = `${target}|${declared}`;
31
+ if (seen.has(seenKey))
32
+ continue;
33
+ seen.add(seenKey);
34
+ if (!(0, firebase_vars_1.hasFirebaseCredentialForEnv)(liveEnvs, spec.names, target))
35
+ continue;
36
+ const sa = await (0, firebase_vars_1.getFirebaseSaForEnv)(target, liveEnvs, spec.names, deployment);
37
+ if (!sa?.email)
38
+ continue;
39
+ findings.push(sa.email === declared
40
+ ? (0, check_1.mkWarning)(`FIREBASE_SA_EMAIL for '${env}' duplicates the credential's ${spec.names.clientEmail} — it is deprecated; remove it and let envctl derive the service account from the credential.`)
41
+ : (0, check_1.mkError)(`FIREBASE_SA_EMAIL for '${env}' (${declared}) disagrees with the credential's ${spec.names.clientEmail} (${sa.email}) on the '${target}' target — they name different service accounts. Remove the deprecated FIREBASE_SA_EMAIL and let envctl derive the identity from the credential.`));
42
+ }
43
+ return findings;
44
+ }
45
+ // #121: the committed `FIREBASE_PROJECT_ID` (a public var in `deployment/{env}.yml`)
46
+ // is the target's own GCP project — the project envctl mints keys in at init, and
47
+ // the same project the app's credential authenticates against (the credential's
48
+ // `projectId` var). If the two disagree, envctl would mint keys in one GCP
49
+ // project while the app runs against another — the projectId analog of the
50
+ // SA-email drift #103 addressed. Unlike `FIREBASE_SA_EMAIL`, `FIREBASE_PROJECT_ID`
51
+ // is **not** deprecated: #127 established that init must resolve the project
52
+ // strictly from the target's own declared value, so a matching committed value is
53
+ // correct and required — only a mismatch (drift) is flagged, as an error. Part of
54
+ // `envctl check --live` (the credential's value lives in the provider, not git);
55
+ // deferred to this follow-up by #127.
56
+ async function checkFirebaseProjectDrift(deployment, configDir, liveEnvs) {
57
+ const manifest = (0, manifest_1.parseManifest)(configDir);
58
+ const spec = (0, firebase_credential_1.resolveFirebaseCredential)(manifest.services.find((s) => s.provider === "firebase"));
59
+ const resolveTarget = (0, targets_1.envTargetResolver)(configDir);
60
+ const findings = [];
61
+ const seen = new Set();
62
+ for (const env of manifest.environments) {
63
+ const declared = (0, environments_1.parseDeploymentEnv)(configDir, env).FIREBASE_PROJECT_ID;
64
+ if (!declared)
65
+ continue;
66
+ const target = resolveTarget(env);
67
+ const seenKey = `${target}|${declared}`;
68
+ if (seen.has(seenKey))
69
+ continue;
70
+ seen.add(seenKey);
71
+ if (!(0, firebase_vars_1.hasFirebaseCredentialForEnv)(liveEnvs, spec.names, target))
72
+ continue;
73
+ const sa = await (0, firebase_vars_1.getFirebaseSaForEnv)(target, liveEnvs, spec.names, deployment);
74
+ if (!sa?.gcpProject)
75
+ continue;
76
+ if (sa.gcpProject !== declared)
77
+ findings.push((0, check_1.mkError)(`FIREBASE_PROJECT_ID for '${env}' (${declared}) disagrees with the credential's ${spec.names.projectId} (${sa.gcpProject}) on the '${target}' target — envctl would mint keys in one GCP project while the app authenticates against another. Reconcile the committed FIREBASE_PROJECT_ID with the live credential.`));
78
+ }
79
+ return findings;
80
+ }
81
+ //# sourceMappingURL=check-firebase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-firebase.js","sourceRoot":"","sources":["../../src/lib/check-firebase.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { type Finding } from "./check";
2
+ export declare function checkLive(workingDir: string): Promise<Finding[]>;
3
+ //# sourceMappingURL=check-live.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-live.d.ts","sourceRoot":"","sources":["../../src/lib/check-live.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,OAAO,EAAE,MAAM,SAAS,CAAC;AAmB3D,wBAAsB,SAAS,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CA4CtE"}
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkLive = checkLive;
4
+ const check_1 = require("./check");
5
+ const check_firebase_1 = require("./check-firebase");
6
+ const deployment_config_1 = require("./commands/deployment-config");
7
+ const environments_1 = require("./environments");
8
+ const manifest_1 = require("./manifest");
9
+ const registry_1 = require("./providers/registry");
10
+ const targets_1 = require("./targets");
11
+ // Live reconciliation (`envctl check --live`): compares the public config vars
12
+ // the project declares against what is actually present on the deployment
13
+ // provider, surfacing drift. Requires network + auth, which is why it is behind
14
+ // a flag. Secrets (Firebase/Sentry credentials, generated values) are owned by
15
+ // the rotation engine and deliberately out of scope here — this checks the
16
+ // public variables `config push` manages, so declared-vs-live stays apples to
17
+ // apples.
18
+ async function checkLive(workingDir) {
19
+ const configDir = (0, deployment_config_1.deploymentDir)(workingDir);
20
+ let deployment;
21
+ try {
22
+ deployment = (0, registry_1.resolveProjectDeployment)(configDir, workingDir);
23
+ }
24
+ catch (e) {
25
+ return [
26
+ (0, check_1.mkError)(`--live check skipped: ${e instanceof Error ? e.message : String(e)}`),
27
+ ];
28
+ }
29
+ const manifest = (0, manifest_1.parseManifest)(configDir);
30
+ const resolveTarget = (0, targets_1.envTargetResolver)(configDir);
31
+ const live = (await deployment.listEnvVars()).envs;
32
+ const findings = [];
33
+ for (const env of manifest.environments) {
34
+ const target = resolveTarget(env);
35
+ const declared = (0, environments_1.parseDeploymentEnv)(configDir, env);
36
+ for (const key of Object.keys(declared)) {
37
+ const present = live.some((e) => e.key === key && e.target.includes(target));
38
+ if (!present)
39
+ findings.push((0, check_1.mkWarning)(`declared variable '${key}' for '${env}' is not present on the '${target}' target (drift).`));
40
+ }
41
+ }
42
+ // The deprecated FIREBASE_SA_EMAIL must agree with the credential's live
43
+ // clientEmail (#103).
44
+ findings.push(...(await (0, check_firebase_1.checkFirebaseSaDrift)(deployment, configDir, live)));
45
+ // The committed FIREBASE_PROJECT_ID must agree with the credential's live
46
+ // projectId (#121).
47
+ findings.push(...(await (0, check_firebase_1.checkFirebaseProjectDrift)(deployment, configDir, live)));
48
+ return findings;
49
+ }
50
+ //# sourceMappingURL=check-live.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-live.js","sourceRoot":"","sources":["../../src/lib/check-live.ts"],"names":[],"mappings":";;AAmBA,8BA4CC;AA/DD,mCAA2D;AAC3D,qDAG0B;AAC1B,oEAA6D;AAC7D,iDAAoD;AACpD,yCAA2C;AAE3C,mDAAgE;AAChE,uCAA8C;AAE9C,+EAA+E;AAC/E,0EAA0E;AAC1E,gFAAgF;AAChF,+EAA+E;AAC/E,2EAA2E;AAC3E,8EAA8E;AAC9E,UAAU;AACH,KAAK,UAAU,SAAS,CAAC,UAAkB;IAChD,MAAM,SAAS,GAAG,IAAA,iCAAa,EAAC,UAAU,CAAC,CAAC;IAE5C,IAAI,UAA8B,CAAC;IACnC,IAAI,CAAC;QACH,UAAU,GAAG,IAAA,mCAAwB,EAAC,SAAS,EAAE,UAAU,CAAC,CAAC;IAC/D,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO;YACL,IAAA,eAAO,EACL,yBAAyB,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CACtE;SACF,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,IAAA,wBAAa,EAAC,SAAS,CAAC,CAAC;IAC1C,MAAM,aAAa,GAAG,IAAA,2BAAiB,EAAC,SAAS,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,CAAC,MAAM,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC;IAEnD,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,KAAK,MAAM,GAAG,IAAI,QAAQ,CAAC,YAAY,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;QAClC,MAAM,QAAQ,GAAG,IAAA,iCAAkB,EAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QACpD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;YACxC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CACvB,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAClD,CAAC;YACF,IAAI,CAAC,OAAO;gBACV,QAAQ,CAAC,IAAI,CACX,IAAA,iBAAS,EACP,sBAAsB,GAAG,UAAU,GAAG,4BAA4B,MAAM,mBAAmB,CAC5F,CACF,CAAC;QACN,CAAC;IACH,CAAC;IAED,yEAAyE;IACzE,sBAAsB;IACtB,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,IAAA,qCAAoB,EAAC,UAAU,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5E,0EAA0E;IAC1E,oBAAoB;IACpB,QAAQ,CAAC,IAAI,CACX,GAAG,CAAC,MAAM,IAAA,0CAAyB,EAAC,UAAU,EAAE,SAAS,EAAE,IAAI,CAAC,CAAC,CAClE,CAAC;IACF,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,9 @@
1
+ export type Severity = "error" | "warning";
2
+ export interface Finding {
3
+ readonly severity: Severity;
4
+ readonly message: string;
5
+ }
6
+ export declare const mkError: (message: string) => Finding;
7
+ export declare const mkWarning: (message: string) => Finding;
8
+ export declare function checkStatic(workingDir: string): Finding[];
9
+ //# sourceMappingURL=check.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/lib/check.ts"],"names":[],"mappings":"AAoBA,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,SAAS,CAAC;AAC3C,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B;AAED,eAAO,MAAM,OAAO,GAAI,SAAS,MAAM,KAAG,OAGxC,CAAC;AACH,eAAO,MAAM,SAAS,GAAI,SAAS,MAAM,KAAG,OAG1C,CAAC;AAKH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,EAAE,CAmCzD"}