@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.
- package/README.md +79 -0
- package/dist/envctl.d.ts +3 -0
- package/dist/envctl.d.ts.map +1 -0
- package/dist/envctl.js +36 -0
- package/dist/envctl.js.map +1 -0
- package/dist/lib/auth.d.ts +21 -0
- package/dist/lib/auth.d.ts.map +1 -0
- package/dist/lib/auth.js +148 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/check-firebase.d.ts +6 -0
- package/dist/lib/check-firebase.d.ts.map +1 -0
- package/dist/lib/check-firebase.js +81 -0
- package/dist/lib/check-firebase.js.map +1 -0
- package/dist/lib/check-live.d.ts +3 -0
- package/dist/lib/check-live.d.ts.map +1 -0
- package/dist/lib/check-live.js +50 -0
- package/dist/lib/check-live.js.map +1 -0
- package/dist/lib/check.d.ts +9 -0
- package/dist/lib/check.d.ts.map +1 -0
- package/dist/lib/check.js +165 -0
- package/dist/lib/check.js.map +1 -0
- package/dist/lib/cli/help.d.ts +4 -0
- package/dist/lib/cli/help.d.ts.map +1 -0
- package/dist/lib/cli/help.js +52 -0
- package/dist/lib/cli/help.js.map +1 -0
- package/dist/lib/cli/registry.d.ts +19 -0
- package/dist/lib/cli/registry.d.ts.map +1 -0
- package/dist/lib/cli/registry.js +111 -0
- package/dist/lib/cli/registry.js.map +1 -0
- package/dist/lib/cli/router.d.ts +22 -0
- package/dist/lib/cli/router.d.ts.map +1 -0
- package/dist/lib/cli/router.js +98 -0
- package/dist/lib/cli/router.js.map +1 -0
- package/dist/lib/cli/version.d.ts +2 -0
- package/dist/lib/cli/version.d.ts.map +1 -0
- package/dist/lib/cli/version.js +58 -0
- package/dist/lib/cli/version.js.map +1 -0
- package/dist/lib/commands/auth.d.ts +2 -0
- package/dist/lib/commands/auth.d.ts.map +1 -0
- package/dist/lib/commands/auth.js +33 -0
- package/dist/lib/commands/auth.js.map +1 -0
- package/dist/lib/commands/bootstrap-args.d.ts +11 -0
- package/dist/lib/commands/bootstrap-args.d.ts.map +1 -0
- package/dist/lib/commands/bootstrap-args.js +111 -0
- package/dist/lib/commands/bootstrap-args.js.map +1 -0
- package/dist/lib/commands/bootstrap.d.ts +5 -0
- package/dist/lib/commands/bootstrap.d.ts.map +1 -0
- package/dist/lib/commands/bootstrap.js +166 -0
- package/dist/lib/commands/bootstrap.js.map +1 -0
- package/dist/lib/commands/check.d.ts +3 -0
- package/dist/lib/commands/check.d.ts.map +1 -0
- package/dist/lib/commands/check.js +47 -0
- package/dist/lib/commands/check.js.map +1 -0
- package/dist/lib/commands/config-pull.d.ts +12 -0
- package/dist/lib/commands/config-pull.d.ts.map +1 -0
- package/dist/lib/commands/config-pull.js +161 -0
- package/dist/lib/commands/config-pull.js.map +1 -0
- package/dist/lib/commands/config-push-args.d.ts +9 -0
- package/dist/lib/commands/config-push-args.d.ts.map +1 -0
- package/dist/lib/commands/config-push-args.js +108 -0
- package/dist/lib/commands/config-push-args.js.map +1 -0
- package/dist/lib/commands/config-push.d.ts +6 -0
- package/dist/lib/commands/config-push.d.ts.map +1 -0
- package/dist/lib/commands/config-push.js +166 -0
- package/dist/lib/commands/config-push.js.map +1 -0
- package/dist/lib/commands/deployment-config.d.ts +9 -0
- package/dist/lib/commands/deployment-config.d.ts.map +1 -0
- package/dist/lib/commands/deployment-config.js +73 -0
- package/dist/lib/commands/deployment-config.js.map +1 -0
- package/dist/lib/commands/env-plan.d.ts +4 -0
- package/dist/lib/commands/env-plan.d.ts.map +1 -0
- package/dist/lib/commands/env-plan.js +85 -0
- package/dist/lib/commands/env-plan.js.map +1 -0
- package/dist/lib/commands/env.d.ts +4 -0
- package/dist/lib/commands/env.d.ts.map +1 -0
- package/dist/lib/commands/env.js +122 -0
- package/dist/lib/commands/env.js.map +1 -0
- package/dist/lib/commands/init.d.ts +3 -0
- package/dist/lib/commands/init.d.ts.map +1 -0
- package/dist/lib/commands/init.js +59 -0
- package/dist/lib/commands/init.js.map +1 -0
- package/dist/lib/commands/secrets-args.d.ts +13 -0
- package/dist/lib/commands/secrets-args.d.ts.map +1 -0
- package/dist/lib/commands/secrets-args.js +136 -0
- package/dist/lib/commands/secrets-args.js.map +1 -0
- package/dist/lib/commands/secrets-plan.d.ts +9 -0
- package/dist/lib/commands/secrets-plan.d.ts.map +1 -0
- package/dist/lib/commands/secrets-plan.js +109 -0
- package/dist/lib/commands/secrets-plan.js.map +1 -0
- package/dist/lib/commands/secrets.d.ts +7 -0
- package/dist/lib/commands/secrets.d.ts.map +1 -0
- package/dist/lib/commands/secrets.js +191 -0
- package/dist/lib/commands/secrets.js.map +1 -0
- package/dist/lib/deployments.d.ts +4 -0
- package/dist/lib/deployments.d.ts.map +1 -0
- package/dist/lib/deployments.js +83 -0
- package/dist/lib/deployments.js.map +1 -0
- package/dist/lib/environments.d.ts +4 -0
- package/dist/lib/environments.d.ts.map +1 -0
- package/dist/lib/environments.js +97 -0
- package/dist/lib/environments.js.map +1 -0
- package/dist/lib/firebase-credential.d.ts +28 -0
- package/dist/lib/firebase-credential.d.ts.map +1 -0
- package/dist/lib/firebase-credential.js +50 -0
- package/dist/lib/firebase-credential.js.map +1 -0
- package/dist/lib/firebase-invalidate.d.ts +4 -0
- package/dist/lib/firebase-invalidate.d.ts.map +1 -0
- package/dist/lib/firebase-invalidate.js +61 -0
- package/dist/lib/firebase-invalidate.js.map +1 -0
- package/dist/lib/firebase-vars.d.ts +14 -0
- package/dist/lib/firebase-vars.d.ts.map +1 -0
- package/dist/lib/firebase-vars.js +40 -0
- package/dist/lib/firebase-vars.js.map +1 -0
- package/dist/lib/firebase.d.ts +20 -0
- package/dist/lib/firebase.d.ts.map +1 -0
- package/dist/lib/firebase.js +189 -0
- package/dist/lib/firebase.js.map +1 -0
- package/dist/lib/gcp.d.ts +4 -0
- package/dist/lib/gcp.d.ts.map +1 -0
- package/dist/lib/gcp.js +53 -0
- package/dist/lib/gcp.js.map +1 -0
- package/dist/lib/generated-secrets.d.ts +16 -0
- package/dist/lib/generated-secrets.d.ts.map +1 -0
- package/dist/lib/generated-secrets.js +68 -0
- package/dist/lib/generated-secrets.js.map +1 -0
- package/dist/lib/logger.d.ts +7 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +60 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/manifest/index.d.ts +6 -0
- package/dist/lib/manifest/index.d.ts.map +1 -0
- package/dist/lib/manifest/index.js +15 -0
- package/dist/lib/manifest/index.js.map +1 -0
- package/dist/lib/manifest/parse.d.ts +11 -0
- package/dist/lib/manifest/parse.d.ts.map +1 -0
- package/dist/lib/manifest/parse.js +214 -0
- package/dist/lib/manifest/parse.js.map +1 -0
- package/dist/lib/manifest/resolve.d.ts +9 -0
- package/dist/lib/manifest/resolve.d.ts.map +1 -0
- package/dist/lib/manifest/resolve.js +34 -0
- package/dist/lib/manifest/resolve.js.map +1 -0
- package/dist/lib/manifest/types.d.ts +57 -0
- package/dist/lib/manifest/types.d.ts.map +1 -0
- package/dist/lib/manifest/types.js +12 -0
- package/dist/lib/manifest/types.js.map +1 -0
- package/dist/lib/manifest/write.d.ts +3 -0
- package/dist/lib/manifest/write.d.ts.map +1 -0
- package/dist/lib/manifest/write.js +110 -0
- package/dist/lib/manifest/write.js.map +1 -0
- package/dist/lib/project.d.ts +6 -0
- package/dist/lib/project.d.ts.map +1 -0
- package/dist/lib/project.js +56 -0
- package/dist/lib/project.js.map +1 -0
- package/dist/lib/providers/deployment.d.ts +19 -0
- package/dist/lib/providers/deployment.d.ts.map +1 -0
- package/dist/lib/providers/deployment.js +62 -0
- package/dist/lib/providers/deployment.js.map +1 -0
- package/dist/lib/providers/registry.d.ts +5 -0
- package/dist/lib/providers/registry.d.ts.map +1 -0
- package/dist/lib/providers/registry.js +31 -0
- package/dist/lib/providers/registry.js.map +1 -0
- package/dist/lib/providers/service.d.ts +35 -0
- package/dist/lib/providers/service.d.ts.map +1 -0
- package/dist/lib/providers/service.js +81 -0
- package/dist/lib/providers/service.js.map +1 -0
- package/dist/lib/rotation-preflight.d.ts +11 -0
- package/dist/lib/rotation-preflight.d.ts.map +1 -0
- package/dist/lib/rotation-preflight.js +47 -0
- package/dist/lib/rotation-preflight.js.map +1 -0
- package/dist/lib/rotation.d.ts +33 -0
- package/dist/lib/rotation.d.ts.map +1 -0
- package/dist/lib/rotation.js +168 -0
- package/dist/lib/rotation.js.map +1 -0
- package/dist/lib/sentry.d.ts +5 -0
- package/dist/lib/sentry.d.ts.map +1 -0
- package/dist/lib/sentry.js +132 -0
- package/dist/lib/sentry.js.map +1 -0
- package/dist/lib/subprocess.d.ts +8 -0
- package/dist/lib/subprocess.d.ts.map +1 -0
- package/dist/lib/subprocess.js +30 -0
- package/dist/lib/subprocess.js.map +1 -0
- package/dist/lib/targets.d.ts +3 -0
- package/dist/lib/targets.d.ts.map +1 -0
- package/dist/lib/targets.js +25 -0
- package/dist/lib/targets.js.map +1 -0
- package/dist/lib/vercel-api.d.ts +50 -0
- package/dist/lib/vercel-api.d.ts.map +1 -0
- package/dist/lib/vercel-api.js +176 -0
- package/dist/lib/vercel-api.js.map +1 -0
- package/package.json +53 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment.js","sourceRoot":"","sources":["../../../src/lib/providers/deployment.ts"],"names":[],"mappings":";;AAgIA,wEAIC;AApID,kCAA6C;AAC7C,gDAGwB;AACxB,sCAAuC;AACvC,wCAA2C;AAC3C,8CAIuB;AA2CvB,6EAA6E;AAC7E,8EAA8E;AAC9E,4EAA4E;AAC5E,aAAa;AACb,MAAM,wBAAwB;IACnB,QAAQ,GAAG,QAAQ,CAAC;IACpB,SAAS,CAAS;IAClB,MAAM,CAAqB;IACnB,MAAM,CAAe;IAEtC,YAAY,UAAkB;QAC5B,MAAM,KAAK,GAAG,IAAA,yBAAkB,GAAE,CAAC;QACnC,IAAI,CAAC,KAAK;YACR,MAAM,IAAI,mBAAU,CAClB,gFAAgF,CACjF,CAAC;QACJ,MAAM,OAAO,GAAG,IAAA,uBAAa,EAAC,UAAU,CAAC,CAAC;QAC1C,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;QACnC,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QAC7B,IAAI,CAAC,MAAM,GAAG,IAAI,yBAAY,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IAC3E,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;IACnC,CAAC;IACD,cAAc,CAAC,EAAU;QACvB,OAAO,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC,CAAC;IACxC,CAAC;IACD,UAAU,CACR,IAAoB,EACpB,GAAW,EACX,MAAc;QAEd,OAAO,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;IACnD,CAAC;IACD,YAAY,CACV,GAAW,EACX,KAAa,EACb,MAAc,EACd,OAAmB,OAAO;QAE1B,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC;IAC5D,CAAC;IACD,YAAY,CAAC,QAAsB,EAAE,KAAa;QAChD,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IACnD,CAAC;IACD,eAAe,CACb,GAAW,EACX,KAAa,EACb,MAAc,EACd,IAAoB,EACpB,IAAiB;QAEjB,yEAAyE;QACzE,uEAAuE;QACvE,OAAO,IAAI,KAAK,SAAS;YACvB,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC;YACvD,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAClE,CAAC;IACD,sBAAsB,CACpB,EAAU,EACV,eAAyB,EACzB,SAAiB;QAEjB,OAAO,IAAI,CAAC,MAAM,CAAC,sBAAsB,CAAC,EAAE,EAAE,eAAe,EAAE,SAAS,CAAC,CAAC;IAC5E,CAAC;IACD,2BAA2B,CAAC,SAAiB;QAC3C,OAAO,IAAA,yCAAe,EAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACjD,CAAC;IACD,yBAAyB;QACvB,OAAO,IAAA,uCAAe,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;CACF;AAED,SAAgB,8BAA8B,CAC5C,UAAkB;IAElB,OAAO,IAAI,wBAAwB,CAAC,UAAU,CAAC,CAAC;AAClD,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type DeploymentProvider } from "./deployment";
|
|
2
|
+
export declare const KNOWN_DEPLOYMENT_PROVIDERS: string[];
|
|
3
|
+
export declare function resolveDeploymentProvider(provider: string, workingDir: string): DeploymentProvider;
|
|
4
|
+
export declare function resolveProjectDeployment(deploymentDir: string, workingDir: string): DeploymentProvider;
|
|
5
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/registry.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,kBAAkB,EACxB,MAAM,cAAc,CAAC;AAYtB,eAAO,MAAM,0BAA0B,UAAoC,CAAC;AAI5E,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,kBAAkB,CAOpB;AAKD,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,GACjB,kBAAkB,CAGpB"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KNOWN_DEPLOYMENT_PROVIDERS = void 0;
|
|
4
|
+
exports.resolveDeploymentProvider = resolveDeploymentProvider;
|
|
5
|
+
exports.resolveProjectDeployment = resolveProjectDeployment;
|
|
6
|
+
const manifest_1 = require("../manifest");
|
|
7
|
+
const logger_1 = require("../logger");
|
|
8
|
+
const deployment_1 = require("./deployment");
|
|
9
|
+
// The deployment sinks envctl knows how to drive, keyed by the manifest
|
|
10
|
+
// `provider:` discriminant. Adding a hosting target is a new entry here plus its
|
|
11
|
+
// implementation — no edits threaded through config-push / rotation.
|
|
12
|
+
const DEPLOYMENT_PROVIDERS = {
|
|
13
|
+
vercel: deployment_1.createVercelDeploymentProvider,
|
|
14
|
+
};
|
|
15
|
+
exports.KNOWN_DEPLOYMENT_PROVIDERS = Object.keys(DEPLOYMENT_PROVIDERS);
|
|
16
|
+
// Resolve a deployment provider by its manifest `provider:` name, erroring with
|
|
17
|
+
// the offending value when it is not registered.
|
|
18
|
+
function resolveDeploymentProvider(provider, workingDir) {
|
|
19
|
+
const factory = DEPLOYMENT_PROVIDERS[provider];
|
|
20
|
+
if (!factory)
|
|
21
|
+
return (0, logger_1.err)(`Unknown deployment provider '${provider}' — envctl supports: ${exports.KNOWN_DEPLOYMENT_PROVIDERS.join(", ")}`);
|
|
22
|
+
return factory(workingDir);
|
|
23
|
+
}
|
|
24
|
+
// The deployment provider declared by the project's manifest — the first
|
|
25
|
+
// `deployments[]` entry's provider, defaulting to vercel for a legacy config
|
|
26
|
+
// (parseManifest synthesizes a vercel deployment when none is declared).
|
|
27
|
+
function resolveProjectDeployment(deploymentDir, workingDir) {
|
|
28
|
+
const provider = (0, manifest_1.parseManifest)(deploymentDir).deployments[0]?.provider;
|
|
29
|
+
return resolveDeploymentProvider(provider ?? "vercel", workingDir);
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/lib/providers/registry.ts"],"names":[],"mappings":";;;AAqBA,8DAUC;AAKD,4DAMC;AA1CD,0CAA4C;AAC5C,sCAAgC;AAChC,6CAGsB;AAEtB,wEAAwE;AACxE,iFAAiF;AACjF,qEAAqE;AACrE,MAAM,oBAAoB,GAGtB;IACF,MAAM,EAAE,2CAA8B;CACvC,CAAC;AAEW,QAAA,0BAA0B,GAAG,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;AAE5E,gFAAgF;AAChF,iDAAiD;AACjD,SAAgB,yBAAyB,CACvC,QAAgB,EAChB,UAAkB;IAElB,MAAM,OAAO,GAAG,oBAAoB,CAAC,QAAQ,CAAC,CAAC;IAC/C,IAAI,CAAC,OAAO;QACV,OAAO,IAAA,YAAG,EACR,gCAAgC,QAAQ,wBAAwB,kCAA0B,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CACxG,CAAC;IACJ,OAAO,OAAO,CAAC,UAAU,CAAC,CAAC;AAC7B,CAAC;AAED,yEAAyE;AACzE,6EAA6E;AAC7E,yEAAyE;AACzE,SAAgB,wBAAwB,CACtC,aAAqB,EACrB,UAAkB;IAElB,MAAM,QAAQ,GAAG,IAAA,wBAAa,EAAC,aAAa,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC;IACvE,OAAO,yBAAyB,CAAC,QAAQ,IAAI,QAAQ,EAAE,UAAU,CAAC,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type FirebaseCredentialSpec } from "../firebase-credential";
|
|
2
|
+
import type { DeploymentProvider } from "./deployment";
|
|
3
|
+
export interface ServiceContext {
|
|
4
|
+
targetEnv: string;
|
|
5
|
+
deployment: DeploymentProvider;
|
|
6
|
+
tempDir: string;
|
|
7
|
+
firebaseCredential: FirebaseCredentialSpec;
|
|
8
|
+
firebaseSaEmail?: string;
|
|
9
|
+
gcpProject?: string;
|
|
10
|
+
sentryOrg?: string;
|
|
11
|
+
sentryProject?: string;
|
|
12
|
+
/**
|
|
13
|
+
* The provider targets this service is scoped to (#89), from the manifest's
|
|
14
|
+
* `services[].environments`. Undefined ⇒ all environments (unscoped). init /
|
|
15
|
+
* rotate skip any target outside this set.
|
|
16
|
+
*/
|
|
17
|
+
allowedTargets?: string[];
|
|
18
|
+
}
|
|
19
|
+
export interface ServiceRotation {
|
|
20
|
+
invalidate(): Promise<void>;
|
|
21
|
+
retiredKeyWarnings(): string[];
|
|
22
|
+
}
|
|
23
|
+
export interface ServiceProvider {
|
|
24
|
+
readonly provider: string;
|
|
25
|
+
readonly displayName: string;
|
|
26
|
+
/** Which slot this provider fills in the fail-fast auth preflight. */
|
|
27
|
+
readonly authKey: "firebase" | "sentry";
|
|
28
|
+
/** Env-var keys whose presence in Vercel means this service is provisioned. */
|
|
29
|
+
presenceKeys(ctx: ServiceContext): string[];
|
|
30
|
+
init(ctx: ServiceContext): Promise<void>;
|
|
31
|
+
rotate(ctx: ServiceContext): Promise<ServiceRotation>;
|
|
32
|
+
}
|
|
33
|
+
export declare const serviceProviders: () => ServiceProvider[];
|
|
34
|
+
export declare function resolveServiceProvider(provider: string): ServiceProvider;
|
|
35
|
+
//# sourceMappingURL=service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../../../src/lib/providers/service.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,wBAAwB,CAAC;AAKhC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAKvD,MAAM,WAAW,cAAc;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,kBAAkB,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,kBAAkB,EAAE,sBAAsB,CAAC;IAC3C,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAKD,MAAM,WAAW,eAAe;IAC9B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,kBAAkB,IAAI,MAAM,EAAE,CAAC;CAChC;AAKD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,sEAAsE;IACtE,QAAQ,CAAC,OAAO,EAAE,UAAU,GAAG,QAAQ,CAAC;IACxC,+EAA+E;IAC/E,YAAY,CAAC,GAAG,EAAE,cAAc,GAAG,MAAM,EAAE,CAAC;IAC5C,IAAI,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACzC,MAAM,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;CACvD;AAqGD,eAAO,MAAM,gBAAgB,QAAO,eAAe,EACjB,CAAC;AAInC,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,eAAe,CAOxE"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.serviceProviders = void 0;
|
|
4
|
+
exports.resolveServiceProvider = resolveServiceProvider;
|
|
5
|
+
const firebase_credential_1 = require("../firebase-credential");
|
|
6
|
+
const firebase_1 = require("../firebase");
|
|
7
|
+
const firebase_invalidate_1 = require("../firebase-invalidate");
|
|
8
|
+
const logger_1 = require("../logger");
|
|
9
|
+
const sentry_1 = require("../sentry");
|
|
10
|
+
const firebaseServiceProvider = {
|
|
11
|
+
provider: "firebase",
|
|
12
|
+
displayName: "Firebase",
|
|
13
|
+
authKey: "firebase",
|
|
14
|
+
presenceKeys: (ctx) => (0, firebase_credential_1.firebasePresenceKeys)(ctx.firebaseCredential),
|
|
15
|
+
init: (ctx) => (0, firebase_1.initFirebase)(ctx.targetEnv, ctx.deployment, ctx.tempDir, ctx.firebaseSaEmail, ctx.gcpProject, ctx.firebaseCredential, ctx.allowedTargets),
|
|
16
|
+
rotate: async (ctx) => {
|
|
17
|
+
const { oldKeys, fp } = await (0, firebase_1.rotateFirebase)(ctx.targetEnv, ctx.deployment, ctx.tempDir, ctx.firebaseCredential, ctx.allowedTargets);
|
|
18
|
+
return {
|
|
19
|
+
invalidate: async () => {
|
|
20
|
+
if (fp)
|
|
21
|
+
await (0, firebase_invalidate_1.invalidateFirebaseKeys)(ctx.deployment, fp);
|
|
22
|
+
},
|
|
23
|
+
retiredKeyWarnings: () => oldKeys.map(({ vercelEnv, keyId, saEmail }) => `Old Firebase key to remove: ${keyId} (${vercelEnv}, account: ${saEmail})`),
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
};
|
|
27
|
+
// Resolve Sentry org/project from the context override or the environment —
|
|
28
|
+
// mirroring rotation's invalidation-time resolution.
|
|
29
|
+
function sentryOrgProject(ctx) {
|
|
30
|
+
return {
|
|
31
|
+
org: ctx.sentryOrg ?? process.env.SENTRY_ORG,
|
|
32
|
+
project: ctx.sentryProject ?? process.env.SENTRY_PROJECT,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
const sentryServiceProvider = {
|
|
36
|
+
provider: "sentry",
|
|
37
|
+
displayName: "Sentry",
|
|
38
|
+
authKey: "sentry",
|
|
39
|
+
presenceKeys: () => ["SENTRY_DSN", "NEXT_PUBLIC_SENTRY_DSN"],
|
|
40
|
+
init: (ctx) => (0, sentry_1.initSentry)(ctx.targetEnv, ctx.deployment, ctx.sentryOrg, ctx.sentryProject, ctx.allowedTargets),
|
|
41
|
+
rotate: async (ctx) => {
|
|
42
|
+
const oldKeyId = await (0, sentry_1.rotateSentry)(ctx.targetEnv, ctx.deployment, ctx.sentryOrg, ctx.sentryProject, ctx.allowedTargets);
|
|
43
|
+
return {
|
|
44
|
+
invalidate: async () => {
|
|
45
|
+
if (!oldKeyId)
|
|
46
|
+
return;
|
|
47
|
+
const { org, project } = sentryOrgProject(ctx);
|
|
48
|
+
if (!org || !project)
|
|
49
|
+
return (0, logger_1.err)("SENTRY_ORG and SENTRY_PROJECT are required for key invalidation");
|
|
50
|
+
await (0, sentry_1.invalidateSentryKey)(oldKeyId, org, project);
|
|
51
|
+
},
|
|
52
|
+
retiredKeyWarnings: () => {
|
|
53
|
+
if (!oldKeyId)
|
|
54
|
+
return [];
|
|
55
|
+
const { org, project } = sentryOrgProject(ctx);
|
|
56
|
+
return [
|
|
57
|
+
`Old Sentry key to remove: ${oldKeyId} (project: ${org}/${project})`,
|
|
58
|
+
];
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
// The secret sources envctl knows how to rotate, keyed by the manifest
|
|
64
|
+
// `services[].provider` discriminant. Order is significant: providers act in
|
|
65
|
+
// this order, so the fail-fast auth preflight and the rotation sequence stay
|
|
66
|
+
// Firebase-before-Sentry, matching the pre-registry behavior.
|
|
67
|
+
const SERVICE_PROVIDERS = {
|
|
68
|
+
firebase: firebaseServiceProvider,
|
|
69
|
+
sentry: sentryServiceProvider,
|
|
70
|
+
};
|
|
71
|
+
const serviceProviders = () => Object.values(SERVICE_PROVIDERS);
|
|
72
|
+
exports.serviceProviders = serviceProviders;
|
|
73
|
+
// Resolve a service provider by its manifest `provider:` name, erroring with the
|
|
74
|
+
// offending value when it is not registered.
|
|
75
|
+
function resolveServiceProvider(provider) {
|
|
76
|
+
const impl = SERVICE_PROVIDERS[provider];
|
|
77
|
+
if (!impl)
|
|
78
|
+
return (0, logger_1.err)(`Unknown service provider '${provider}' — envctl supports: ${Object.keys(SERVICE_PROVIDERS).join(", ")}`);
|
|
79
|
+
return impl;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/lib/providers/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface ProviderSet {
|
|
2
|
+
firebase: boolean;
|
|
3
|
+
sentry: boolean;
|
|
4
|
+
/** Sentry org slug — falls back to SENTRY_ORG env var. */
|
|
5
|
+
sentryOrg?: string;
|
|
6
|
+
/** Sentry project slug — falls back to SENTRY_PROJECT env var. */
|
|
7
|
+
sentryProject?: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function checkVercelPrereqs(token: string | undefined): asserts token is string;
|
|
10
|
+
export declare function assertProviderAuth(providers: ProviderSet): void;
|
|
11
|
+
//# sourceMappingURL=rotation-preflight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotation-preflight.d.ts","sourceRoot":"","sources":["../../src/lib/rotation-preflight.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,OAAO,CAAC;IAChB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,kEAAkE;IAClE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAID,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,GAAG,SAAS,GACxB,OAAO,CAAC,KAAK,IAAI,MAAM,CAazB;AAOD,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,WAAW,GAAG,IAAI,CAwB/D"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.checkVercelPrereqs = checkVercelPrereqs;
|
|
4
|
+
exports.assertProviderAuth = assertProviderAuth;
|
|
5
|
+
const auth_1 = require("./auth");
|
|
6
|
+
const logger_1 = require("./logger");
|
|
7
|
+
const subprocess_1 = require("./subprocess");
|
|
8
|
+
// Vercel is required for every flow: assert the CLI is installed, a token
|
|
9
|
+
// resolves, and the CLI session is authenticated, before any provider work.
|
|
10
|
+
function checkVercelPrereqs(token) {
|
|
11
|
+
if (!(0, subprocess_1.commandExists)("vercel"))
|
|
12
|
+
(0, logger_1.err)("Missing required tools: vercel");
|
|
13
|
+
if (!token)
|
|
14
|
+
(0, logger_1.err)("No Vercel token found. Set VERCEL_TOKEN or run 'vercel login' to authenticate.");
|
|
15
|
+
try {
|
|
16
|
+
(0, subprocess_1.run)("vercel", ["whoami"]);
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
(0, logger_1.err)("Vercel CLI not authenticated. Run: vercel login");
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// Fail-fast auth preflight (issue #91): before any mint/push, assert local auth
|
|
23
|
+
// for every provider that will be rotated/initialized, so an unauthenticated
|
|
24
|
+
// provider stops the run up front instead of after a sibling provider has
|
|
25
|
+
// already minted and pushed a new key — which would leave a partial, unverified
|
|
26
|
+
// state. Reports every missing provider at once with an actionable message.
|
|
27
|
+
function assertProviderAuth(providers) {
|
|
28
|
+
const missing = [];
|
|
29
|
+
if (providers.firebase && !(0, auth_1.gcpAuthState)().authenticated)
|
|
30
|
+
missing.push("gcp (Firebase) — install the gcloud CLI and run `gcloud auth login`");
|
|
31
|
+
if (providers.sentry) {
|
|
32
|
+
if (!(0, auth_1.sentryAuthState)().authenticated)
|
|
33
|
+
missing.push("sentry — set SENTRY_AUTH_TOKEN or run `sentry-cli login`");
|
|
34
|
+
const org = providers.sentryOrg ?? process.env.SENTRY_ORG;
|
|
35
|
+
const project = providers.sentryProject ?? process.env.SENTRY_PROJECT;
|
|
36
|
+
if (!org)
|
|
37
|
+
missing.push("sentry — set SENTRY_ORG (Sentry organization slug)");
|
|
38
|
+
if (!project)
|
|
39
|
+
missing.push("sentry — set SENTRY_PROJECT (Sentry project slug)");
|
|
40
|
+
}
|
|
41
|
+
if (missing.length > 0)
|
|
42
|
+
(0, logger_1.err)(`Not authenticated or configured for provider(s) required by this operation:\n` +
|
|
43
|
+
missing.map((m) => ` - ${m}`).join("\n") +
|
|
44
|
+
`\nProvide the required credentials (see \`envctl auth status\`), or scope ` +
|
|
45
|
+
`the run to a ready provider.`);
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=rotation-preflight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotation-preflight.js","sourceRoot":"","sources":["../../src/lib/rotation-preflight.ts"],"names":[],"mappings":";;AAiBA,gDAeC;AAOD,gDAwBC;AA/DD,iCAAuD;AACvD,qCAA+B;AAC/B,6CAA4D;AAa5D,0EAA0E;AAC1E,4EAA4E;AAC5E,SAAgB,kBAAkB,CAChC,KAAyB;IAEzB,IAAI,CAAC,IAAA,0BAAa,EAAC,QAAQ,CAAC;QAAE,IAAA,YAAG,EAAC,gCAAgC,CAAC,CAAC;IAEpE,IAAI,CAAC,KAAK;QACR,IAAA,YAAG,EACD,gFAAgF,CACjF,CAAC;IAEJ,IAAI,CAAC;QACH,IAAA,gBAAM,EAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/B,CAAC;IAAC,MAAM,CAAC;QACP,IAAA,YAAG,EAAC,iDAAiD,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAED,gFAAgF;AAChF,6EAA6E;AAC7E,0EAA0E;AAC1E,gFAAgF;AAChF,4EAA4E;AAC5E,SAAgB,kBAAkB,CAAC,SAAsB;IACvD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,SAAS,CAAC,QAAQ,IAAI,CAAC,IAAA,mBAAY,GAAE,CAAC,aAAa;QACrD,OAAO,CAAC,IAAI,CACV,qEAAqE,CACtE,CAAC;IACJ,IAAI,SAAS,CAAC,MAAM,EAAE,CAAC;QACrB,IAAI,CAAC,IAAA,sBAAe,GAAE,CAAC,aAAa;YAClC,OAAO,CAAC,IAAI,CAAC,0DAA0D,CAAC,CAAC;QAC3E,MAAM,GAAG,GAAG,SAAS,CAAC,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;QAC1D,MAAM,OAAO,GAAG,SAAS,CAAC,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;QACtE,IAAI,CAAC,GAAG;YACN,OAAO,CAAC,IAAI,CAAC,oDAAoD,CAAC,CAAC;QACrE,IAAI,CAAC,OAAO;YACV,OAAO,CAAC,IAAI,CAAC,mDAAmD,CAAC,CAAC;IACtE,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC;QACpB,IAAA,YAAG,EACD,+EAA+E;YAC7E,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YACzC,4EAA4E;YAC5E,8BAA8B,CACjC,CAAC;AACN,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type FirebaseCredentialSpec } from "./firebase-credential";
|
|
2
|
+
export declare function serviceScopeTargets(configDir: string, provider: string): string[] | undefined;
|
|
3
|
+
export interface RotationOptions {
|
|
4
|
+
targetEnv: string;
|
|
5
|
+
invalidateKeys: boolean;
|
|
6
|
+
/** Project root for `.vercel/project.json` detection. Defaults to CWD. */
|
|
7
|
+
workingDir?: string;
|
|
8
|
+
/** Deployment config directory (for resolving the deployment provider). */
|
|
9
|
+
deploymentDir?: string;
|
|
10
|
+
init?: "all" | "firebase" | "sentry";
|
|
11
|
+
/** SA email for --init firebase. Falls back to FIREBASE_SA_EMAIL env var. */
|
|
12
|
+
firebaseSaEmail?: string;
|
|
13
|
+
/** GCP project ID for --init firebase. Falls back to GCLOUD_PROJECT env var. */
|
|
14
|
+
gcpProject?: string;
|
|
15
|
+
/** Sentry org slug. Falls back to SENTRY_ORG env var. */
|
|
16
|
+
sentryOrg?: string;
|
|
17
|
+
/** Sentry project slug. Falls back to SENTRY_PROJECT env var. */
|
|
18
|
+
sentryProject?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Restrict a rotation to a single provider (mirrors `secrets init`'s
|
|
21
|
+
* positional). Undefined rotates every provider present in the project.
|
|
22
|
+
* Ignored for `init` flows, which scope via {@link RotationOptions.init}.
|
|
23
|
+
*/
|
|
24
|
+
provider?: "firebase" | "sentry";
|
|
25
|
+
/**
|
|
26
|
+
* The resolved Firebase credential contract (shape + var names) from the
|
|
27
|
+
* manifest (#97/#98). Defaults to the provider default (split + default names)
|
|
28
|
+
* when unset, so callers without a manifest keep today's behavior.
|
|
29
|
+
*/
|
|
30
|
+
firebaseCredential?: FirebaseCredentialSpec;
|
|
31
|
+
}
|
|
32
|
+
export declare function run(opts: RotationOptions): Promise<void>;
|
|
33
|
+
//# sourceMappingURL=rotation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotation.d.ts","sourceRoot":"","sources":["../../src/lib/rotation.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,uBAAuB,CAAC;AAiB/B,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,MAAM,EAAE,GAAG,SAAS,CAOtB;AAID,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,OAAO,CAAC;IACxB,0EAA0E;IAC1E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,2EAA2E;IAC3E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,IAAI,CAAC,EAAE,KAAK,GAAG,UAAU,GAAG,QAAQ,CAAC;IACrC,6EAA6E;IAC7E,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gFAAgF;IAChF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAC;IACjC;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,sBAAsB,CAAC;CAC7C;AAID,wBAAsB,GAAG,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAkI9D"}
|
|
@@ -0,0 +1,168 @@
|
|
|
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.serviceScopeTargets = serviceScopeTargets;
|
|
37
|
+
exports.run = run;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
const auth_1 = require("./auth");
|
|
42
|
+
const deployment_config_1 = require("./commands/deployment-config");
|
|
43
|
+
const firebase_credential_1 = require("./firebase-credential");
|
|
44
|
+
const logger_1 = require("./logger");
|
|
45
|
+
const manifest_1 = require("./manifest");
|
|
46
|
+
const registry_1 = require("./providers/registry");
|
|
47
|
+
const service_1 = require("./providers/service");
|
|
48
|
+
const rotation_preflight_1 = require("./rotation-preflight");
|
|
49
|
+
const targets_1 = require("./targets");
|
|
50
|
+
// The provider targets a service is scoped to (#89), from its manifest
|
|
51
|
+
// `services[].environments` declaration mapped through the env→target model.
|
|
52
|
+
// Undefined ⇒ the service is unscoped and applies to every environment.
|
|
53
|
+
function serviceScopeTargets(configDir, provider) {
|
|
54
|
+
const service = (0, manifest_1.parseManifest)(configDir).services.find((s) => s.provider === provider);
|
|
55
|
+
if (!service?.environments)
|
|
56
|
+
return undefined;
|
|
57
|
+
const resolveTarget = (0, targets_1.envTargetResolver)(configDir);
|
|
58
|
+
return [...new Set(service.environments.map((e) => resolveTarget(e)))];
|
|
59
|
+
}
|
|
60
|
+
// ─── Main orchestration ───────────────────────────────────────────────────────
|
|
61
|
+
async function run(opts) {
|
|
62
|
+
const token = (0, auth_1.resolveVercelToken)();
|
|
63
|
+
(0, rotation_preflight_1.checkVercelPrereqs)(token);
|
|
64
|
+
const workingDir = opts.workingDir ?? process.cwd();
|
|
65
|
+
const configDir = opts.deploymentDir ?? (0, deployment_config_1.deploymentDir)(workingDir);
|
|
66
|
+
const deployment = (0, registry_1.resolveProjectDeployment)(configDir, workingDir);
|
|
67
|
+
(0, logger_1.log)(`Project: ${deployment.projectId}${deployment.teamId ? ` (team: ${deployment.teamId})` : ""}`);
|
|
68
|
+
const ctx = {
|
|
69
|
+
targetEnv: opts.targetEnv,
|
|
70
|
+
deployment,
|
|
71
|
+
tempDir: "",
|
|
72
|
+
firebaseCredential: opts.firebaseCredential ?? (0, firebase_credential_1.resolveFirebaseCredential)(),
|
|
73
|
+
firebaseSaEmail: opts.firebaseSaEmail,
|
|
74
|
+
gcpProject: opts.gcpProject,
|
|
75
|
+
sentryOrg: opts.sentryOrg,
|
|
76
|
+
sentryProject: opts.sentryProject,
|
|
77
|
+
};
|
|
78
|
+
const allEnvs = await deployment.listEnvVars();
|
|
79
|
+
// Scope key-existence checks to the specific Vercel target so that
|
|
80
|
+
// successive per-env --init calls (e.g. preview then production) don't
|
|
81
|
+
// see secrets created for an earlier target and falsely error.
|
|
82
|
+
const scopedEnvs = opts.targetEnv === "all"
|
|
83
|
+
? allEnvs.envs
|
|
84
|
+
: allEnvs.envs.filter((e) => e.target.includes(opts.targetEnv));
|
|
85
|
+
const envKeys = scopedEnvs.map((e) => e.key);
|
|
86
|
+
const providers = (0, service_1.serviceProviders)();
|
|
87
|
+
const isPresent = (p) => p.presenceKeys(ctx).some((k) => envKeys.includes(k));
|
|
88
|
+
const willInit = (p) => opts.init === "all" || opts.init === p.provider;
|
|
89
|
+
// Environment scoping (#89): the provider targets this run covers, and each
|
|
90
|
+
// service's declared scope. A service whose scope does not intersect this
|
|
91
|
+
// run's targets is skipped entirely (silently — not acted on); a service that
|
|
92
|
+
// partially overlaps acts only on its in-scope targets (enforced per-target
|
|
93
|
+
// inside init/rotate via `allowedTargets`).
|
|
94
|
+
const runTargets = opts.targetEnv === "all"
|
|
95
|
+
? ["production", "preview", "development"]
|
|
96
|
+
: [opts.targetEnv];
|
|
97
|
+
const scopeFor = (p) => serviceScopeTargets(configDir, p.provider);
|
|
98
|
+
const inScope = (p) => {
|
|
99
|
+
const scope = scopeFor(p);
|
|
100
|
+
return scope === undefined || scope.some((t) => runTargets.includes(t));
|
|
101
|
+
};
|
|
102
|
+
// Guards, iterating the registry rather than naming providers:
|
|
103
|
+
// - init: erroring if a selected provider's secret already exists
|
|
104
|
+
// - scoped rotate: erroring if the named provider is absent
|
|
105
|
+
// - unscoped rotate: erroring if nothing is present to rotate
|
|
106
|
+
if (opts.init) {
|
|
107
|
+
for (const p of providers) {
|
|
108
|
+
if (willInit(p) && isPresent(p))
|
|
109
|
+
(0, logger_1.err)(`${p.displayName} keys already exist in this Vercel project — use \`envctl secrets rotate\` to update them, not \`envctl secrets init\`.`);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
else if (opts.provider) {
|
|
113
|
+
const scoped = (0, service_1.resolveServiceProvider)(opts.provider);
|
|
114
|
+
if (!isPresent(scoped))
|
|
115
|
+
(0, logger_1.err)(`No ${scoped.displayName} keys found in this Vercel project — nothing to rotate for \`${opts.provider}\`. To push them for the first time, use \`envctl secrets init ${opts.provider}\`.`);
|
|
116
|
+
}
|
|
117
|
+
else if (!providers.some(isPresent)) {
|
|
118
|
+
(0, logger_1.err)(`No ${providers.map((p) => p.displayName).join(" or ")} keys found in this Vercel project — nothing to rotate. To push secrets for the first time, use \`envctl secrets init\`.`);
|
|
119
|
+
}
|
|
120
|
+
// Which providers this run acts on: for init, whichever `opts.init` selects;
|
|
121
|
+
// for rotate, whichever are present and not excluded by a provider scope.
|
|
122
|
+
const acting = providers.filter((p) => inScope(p) &&
|
|
123
|
+
(opts.init
|
|
124
|
+
? willInit(p)
|
|
125
|
+
: isPresent(p) &&
|
|
126
|
+
(opts.provider === undefined || opts.provider === p.provider)));
|
|
127
|
+
// Fail fast if a provider we would mint/push for is not authenticated, before
|
|
128
|
+
// any key is created — so a rotation can never leave a partial state (#91).
|
|
129
|
+
(0, rotation_preflight_1.assertProviderAuth)({
|
|
130
|
+
firebase: acting.some((p) => p.authKey === "firebase"),
|
|
131
|
+
sentry: acting.some((p) => p.authKey === "sentry"),
|
|
132
|
+
sentryOrg: opts.sentryOrg,
|
|
133
|
+
sentryProject: opts.sentryProject,
|
|
134
|
+
});
|
|
135
|
+
(0, logger_1.log)(`Target: ${opts.targetEnv} | ${opts.init ? "Initializing" : `Invalidate after redeployment: ${opts.invalidateKeys}`}`);
|
|
136
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "rotate-keys-"));
|
|
137
|
+
ctx.tempDir = tempDir;
|
|
138
|
+
try {
|
|
139
|
+
if (opts.init) {
|
|
140
|
+
for (const p of acting)
|
|
141
|
+
await p.init({ ...ctx, allowedTargets: scopeFor(p) });
|
|
142
|
+
await deployment.triggerAndWaitRedeployments(opts.targetEnv);
|
|
143
|
+
(0, logger_1.log)("Key initialization complete.");
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
const rotations = [];
|
|
147
|
+
for (const p of acting)
|
|
148
|
+
rotations.push(await p.rotate({ ...ctx, allowedTargets: scopeFor(p) }));
|
|
149
|
+
await deployment.triggerAndWaitRedeployments(opts.targetEnv);
|
|
150
|
+
if (opts.invalidateKeys) {
|
|
151
|
+
(0, logger_1.log)("Invalidating old keys...");
|
|
152
|
+
for (const rotation of rotations)
|
|
153
|
+
await rotation.invalidate();
|
|
154
|
+
}
|
|
155
|
+
else {
|
|
156
|
+
(0, logger_1.log)("Skipping key invalidation (--no-invalidate)");
|
|
157
|
+
for (const rotation of rotations)
|
|
158
|
+
for (const message of rotation.retiredKeyWarnings())
|
|
159
|
+
(0, logger_1.warn)(message);
|
|
160
|
+
}
|
|
161
|
+
(0, logger_1.log)("Key rotation complete.");
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
finally {
|
|
165
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=rotation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rotation.js","sourceRoot":"","sources":["../../src/lib/rotation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { DeploymentProvider } from "./providers/deployment";
|
|
2
|
+
export declare function rotateSentry(targetEnv: string, client: DeploymentProvider, sentryOrgOverride?: string, sentryProjectOverride?: string, allowedTargets?: string[]): Promise<string>;
|
|
3
|
+
export declare function initSentry(targetEnv: string, client: DeploymentProvider, sentryOrgOverride?: string, sentryProjectOverride?: string, allowedTargets?: string[]): Promise<void>;
|
|
4
|
+
export declare function invalidateSentryKey(oldKeyId: string, org: string, project: string): Promise<void>;
|
|
5
|
+
//# sourceMappingURL=sentry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sentry.d.ts","sourceRoot":"","sources":["../../src/lib/sentry.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAgDjE,wBAAsB,YAAY,CAChC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,kBAAkB,EAC1B,iBAAiB,CAAC,EAAE,MAAM,EAC1B,qBAAqB,CAAC,EAAE,MAAM,EAC9B,cAAc,CAAC,EAAE,MAAM,EAAE,GACxB,OAAO,CAAC,MAAM,CAAC,CA+EjB;AAID,wBAAsB,UAAU,CAC9B,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,kBAAkB,EAC1B,iBAAiB,CAAC,EAAE,MAAM,EAC1B,qBAAqB,CAAC,EAAE,MAAM,EAC9B,cAAc,CAAC,EAAE,MAAM,EAAE,GACxB,OAAO,CAAC,IAAI,CAAC,CAoCf;AAID,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAiBf"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.rotateSentry = rotateSentry;
|
|
4
|
+
exports.initSentry = initSentry;
|
|
5
|
+
exports.invalidateSentryKey = invalidateSentryKey;
|
|
6
|
+
const auth_1 = require("./auth");
|
|
7
|
+
const logger_1 = require("./logger");
|
|
8
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
9
|
+
function targetEnvs(targetEnv) {
|
|
10
|
+
if (targetEnv === "all")
|
|
11
|
+
return ["production", "preview", "development"];
|
|
12
|
+
return [targetEnv];
|
|
13
|
+
}
|
|
14
|
+
async function sentryRequest(path, method = "GET", body) {
|
|
15
|
+
const token = (0, auth_1.resolveSentryToken)();
|
|
16
|
+
if (!token)
|
|
17
|
+
(0, logger_1.err)("Sentry auth token is required for Sentry key rotation — set SENTRY_AUTH_TOKEN or run `sentry-cli login`");
|
|
18
|
+
const base = process.env.SENTRY_URL ?? "https://sentry.io";
|
|
19
|
+
const res = await fetch(`${base}/api/0${path}`, {
|
|
20
|
+
method,
|
|
21
|
+
headers: {
|
|
22
|
+
Authorization: `Bearer ${token}`,
|
|
23
|
+
"Content-Type": "application/json",
|
|
24
|
+
},
|
|
25
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
26
|
+
});
|
|
27
|
+
if (!res.ok) {
|
|
28
|
+
const text = await res.text();
|
|
29
|
+
throw new Error(`Sentry API ${method} ${path} failed (${res.status}): ${text}`);
|
|
30
|
+
}
|
|
31
|
+
if (method === "DELETE")
|
|
32
|
+
return undefined;
|
|
33
|
+
return res.json();
|
|
34
|
+
}
|
|
35
|
+
// ─── Sentry rotation ──────────────────────────────────────────────────────────
|
|
36
|
+
async function rotateSentry(targetEnv, client, sentryOrgOverride, sentryProjectOverride, allowedTargets) {
|
|
37
|
+
(0, logger_1.log)("Rotating Sentry client key...");
|
|
38
|
+
if (!(0, auth_1.resolveSentryToken)())
|
|
39
|
+
(0, logger_1.err)("Sentry auth token is required for Sentry rotation — set SENTRY_AUTH_TOKEN or run `sentry-cli login`");
|
|
40
|
+
const org = sentryOrgOverride ?? process.env.SENTRY_ORG;
|
|
41
|
+
const project = sentryProjectOverride ?? process.env.SENTRY_PROJECT;
|
|
42
|
+
if (!org)
|
|
43
|
+
(0, logger_1.err)("SENTRY_ORG is required for Sentry rotation");
|
|
44
|
+
if (!project)
|
|
45
|
+
(0, logger_1.err)("SENTRY_PROJECT is required for Sentry rotation");
|
|
46
|
+
const allEnvs = await client.listEnvVars();
|
|
47
|
+
let dsnKeyName = "";
|
|
48
|
+
let currentDsnId = "";
|
|
49
|
+
for (const candidate of ["NEXT_PUBLIC_SENTRY_DSN", "SENTRY_DSN"]) {
|
|
50
|
+
const found = allEnvs.envs.find((e) => e.key === candidate);
|
|
51
|
+
if (found) {
|
|
52
|
+
dsnKeyName = candidate;
|
|
53
|
+
currentDsnId = found.id;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (!dsnKeyName)
|
|
58
|
+
(0, logger_1.err)("Could not find SENTRY_DSN or NEXT_PUBLIC_SENTRY_DSN in Vercel");
|
|
59
|
+
(0, logger_1.log)(` DSN env var: ${dsnKeyName}`);
|
|
60
|
+
const currentDsn = await client.getEnvVarValue(currentDsnId);
|
|
61
|
+
const currentKeys = await sentryRequest(`/projects/${org}/${project}/keys/`);
|
|
62
|
+
const dsnPublicKey = currentDsn.replace(/https?:\/\/([^@]+)@.*/, "$1");
|
|
63
|
+
const oldKey = currentKeys.find((k) => new RegExp(dsnPublicKey, "i").test(k.dsn.public));
|
|
64
|
+
if (!oldKey) {
|
|
65
|
+
(0, logger_1.warn)("Could not match current DSN to a Sentry project key — old key will not be invalidated");
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
(0, logger_1.log)(` Current Sentry key ID: ${oldKey.id}`);
|
|
69
|
+
}
|
|
70
|
+
(0, logger_1.log)(" Creating new Sentry project key...");
|
|
71
|
+
const label = `rotated-${new Date().toISOString().slice(0, 10).replace(/-/g, "")}`;
|
|
72
|
+
const newKey = await sentryRequest(`/projects/${org}/${project}/keys/`, "POST", {
|
|
73
|
+
name: label,
|
|
74
|
+
});
|
|
75
|
+
(0, logger_1.log)(` New Sentry key ID: ${newKey.id}`);
|
|
76
|
+
for (const vercelEnv of targetEnvs(targetEnv)) {
|
|
77
|
+
if (allowedTargets && !allowedTargets.includes(vercelEnv))
|
|
78
|
+
continue;
|
|
79
|
+
const currentEnvs = await client.listEnvVars();
|
|
80
|
+
if (targetEnv === "all") {
|
|
81
|
+
const existing = currentEnvs.envs.find((e) => e.key === dsnKeyName && e.target.includes(vercelEnv));
|
|
82
|
+
if (!existing) {
|
|
83
|
+
(0, logger_1.log)(` [${vercelEnv}] No existing ${dsnKeyName} — skipping (use --env ${vercelEnv} to explicitly add)`);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
await client.setEnvForTarget(dsnKeyName, newKey.dsn.public, vercelEnv, currentEnvs.envs);
|
|
88
|
+
}
|
|
89
|
+
(0, logger_1.log)("Sentry key rotation complete.");
|
|
90
|
+
return oldKey?.id ?? "";
|
|
91
|
+
}
|
|
92
|
+
// ─── Sentry init ──────────────────────────────────────────────────────────────
|
|
93
|
+
async function initSentry(targetEnv, client, sentryOrgOverride, sentryProjectOverride, allowedTargets) {
|
|
94
|
+
(0, logger_1.log)("Initializing Sentry DSN...");
|
|
95
|
+
if (!(0, auth_1.resolveSentryToken)())
|
|
96
|
+
(0, logger_1.err)("Sentry auth token is required for --init sentry — set SENTRY_AUTH_TOKEN or run `sentry-cli login`");
|
|
97
|
+
const org = sentryOrgOverride ?? process.env.SENTRY_ORG;
|
|
98
|
+
const project = sentryProjectOverride ?? process.env.SENTRY_PROJECT;
|
|
99
|
+
if (!org)
|
|
100
|
+
(0, logger_1.err)("SENTRY_ORG is required for --init sentry");
|
|
101
|
+
if (!project)
|
|
102
|
+
(0, logger_1.err)("SENTRY_PROJECT is required for --init sentry");
|
|
103
|
+
const dsnKeyName = "NEXT_PUBLIC_SENTRY_DSN";
|
|
104
|
+
(0, logger_1.log)(" Creating new Sentry project key...");
|
|
105
|
+
const label = `init-${new Date().toISOString().slice(0, 10).replace(/-/g, "")}`;
|
|
106
|
+
const newKey = await sentryRequest(`/projects/${org}/${project}/keys/`, "POST", { name: label });
|
|
107
|
+
(0, logger_1.log)(` New Sentry key ID: ${newKey.id}`);
|
|
108
|
+
const currentEnvs = await client.listEnvVars();
|
|
109
|
+
for (const vercelEnv of targetEnvs(targetEnv)) {
|
|
110
|
+
if (allowedTargets && !allowedTargets.includes(vercelEnv))
|
|
111
|
+
continue;
|
|
112
|
+
await client.setEnvForTarget(dsnKeyName, newKey.dsn.public, vercelEnv, currentEnvs.envs);
|
|
113
|
+
(0, logger_1.log)(` [${vercelEnv}] Pushed ${dsnKeyName}`);
|
|
114
|
+
}
|
|
115
|
+
(0, logger_1.log)("Sentry initialization complete.");
|
|
116
|
+
}
|
|
117
|
+
// ─── Sentry key invalidation ──────────────────────────────────────────────────
|
|
118
|
+
async function invalidateSentryKey(oldKeyId, org, project) {
|
|
119
|
+
if (!oldKeyId) {
|
|
120
|
+
(0, logger_1.warn)("No old Sentry key ID recorded — skipping Sentry invalidation");
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
(0, logger_1.log)(`Invalidating old Sentry key: ${oldKeyId}`);
|
|
124
|
+
try {
|
|
125
|
+
await sentryRequest(`/projects/${org}/${project}/keys/${oldKeyId}/`, "DELETE");
|
|
126
|
+
(0, logger_1.log)(" Old Sentry key deleted.");
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
(0, logger_1.warn)(`Failed to delete Sentry key ${oldKeyId} — remove it manually in Sentry project settings.`);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=sentry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sentry.js","sourceRoot":"","sources":["../../src/lib/sentry.ts"],"names":[],"mappings":"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"}
|