vercel 59.5.0 → 59.7.0
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/dist/chunks/{add-Z5FM6TFI.js → add-7O4TM33A.js} +12 -12
- package/dist/chunks/{add-MH3WV6PV.js → add-UT6ZPA4F.js} +11 -11
- package/dist/chunks/{add-W3FFMTX4.js → add-UVMFKSSY.js} +11 -11
- package/dist/chunks/{build-VYYFBJL7.js → build-SKKT3DIB.js} +11 -11
- package/dist/chunks/{chunk-LLM3ZNXJ.js → chunk-2EH6SZRG.js} +2 -2
- package/dist/chunks/{chunk-UUVMIXT4.js → chunk-2T3IZZTJ.js} +4 -4
- package/dist/chunks/{chunk-RZ5NP6HN.js → chunk-2YRAWYGE.js} +1 -1
- package/dist/chunks/{chunk-TDXNNIZ6.js → chunk-3PA7LXYM.js} +2 -2
- package/dist/chunks/{chunk-KQRVZWJU.js → chunk-3T7WSWZH.js} +1 -1
- package/dist/chunks/{chunk-R6IGDGX3.js → chunk-5XECIWME.js} +1 -1
- package/dist/chunks/{chunk-PBHBX6UL.js → chunk-63OX2DER.js} +3 -3
- package/dist/chunks/{chunk-V4YLY44R.js → chunk-67IIZBBY.js} +2 -2
- package/dist/chunks/{chunk-AWSLWAOC.js → chunk-6JPVTPTU.js} +3 -3
- package/dist/chunks/{chunk-HT2XWSAJ.js → chunk-7AEEQOD4.js} +2 -29
- package/dist/chunks/{chunk-QG4PCM45.js → chunk-7HE63HCR.js} +102 -15
- package/dist/chunks/{chunk-FA3MO56Q.js → chunk-7IDPPWDN.js} +5 -5
- package/dist/chunks/{chunk-MRMNMFMD.js → chunk-7KSICC3A.js} +1 -1
- package/dist/chunks/{chunk-XBN2O34P.js → chunk-7ST552E3.js} +17 -4
- package/dist/chunks/{chunk-TAZ5ZAKG.js → chunk-AFKB6VMO.js} +2 -2
- package/dist/chunks/{chunk-CV4S27SS.js → chunk-ASBP32T6.js} +1 -1
- package/dist/chunks/{chunk-CQJRLNTX.js → chunk-AYLY3ZVL.js} +2 -2
- package/dist/chunks/{chunk-AWCID36T.js → chunk-BMKU5KEL.js} +1 -1
- package/dist/chunks/{chunk-E6LFKMI2.js → chunk-BQG777JE.js} +794 -124
- package/dist/chunks/{chunk-VWYNSJXI.js → chunk-CBHLLOGZ.js} +8 -8
- package/dist/chunks/{chunk-CSCSGSQG.js → chunk-CMRZ4KI4.js} +5 -5
- package/dist/chunks/{chunk-TIWAL2YU.js → chunk-DG6IMLCF.js} +6 -6
- package/dist/chunks/{chunk-YIHOS3ZF.js → chunk-FRAXI2WT.js} +1 -1
- package/dist/chunks/{chunk-7XX4ZEOV.js → chunk-FWKSJYDV.js} +1 -1
- package/dist/chunks/{chunk-OHER4DGX.js → chunk-FXD67VN5.js} +25 -9
- package/dist/chunks/{chunk-GUWPUX2Y.js → chunk-GK3RE3AC.js} +4 -4
- package/dist/chunks/{chunk-JNU3DTEV.js → chunk-IFNCPWH5.js} +9 -9
- package/dist/chunks/{chunk-PIMIKY4X.js → chunk-IJ4X426J.js} +1 -1
- package/dist/chunks/{chunk-NSU2BTRS.js → chunk-KD2N44NG.js} +4 -4
- package/dist/chunks/{chunk-TVXCXIRO.js → chunk-L3UXB2CW.js} +1 -1
- package/dist/chunks/{chunk-JJQP3PYM.js → chunk-MHCGKUI7.js} +5 -5
- package/dist/chunks/{chunk-47VQ6H2S.js → chunk-MUMITVZP.js} +2 -2
- package/dist/chunks/{chunk-L7CEMAJG.js → chunk-NGGLYKNU.js} +27 -5
- package/dist/chunks/{chunk-ZKUHCL6O.js → chunk-NJCM5JJN.js} +5 -5
- package/dist/chunks/{chunk-5LX2JDZP.js → chunk-O75LSD3C.js} +1 -1
- package/dist/chunks/{chunk-OX7KI3LF.js → chunk-QFAS4OVW.js} +18 -0
- package/dist/chunks/{chunk-4JTF6RD7.js → chunk-SSBYESJ5.js} +4 -4
- package/dist/chunks/{chunk-G75NFPIT.js → chunk-WNAKOXGK.js} +1 -1
- package/dist/chunks/{chunk-PPUWG2UB.js → chunk-WVPMR7XV.js} +58 -25
- package/dist/chunks/{chunk-CYNB6LL4.js → chunk-XNFHNTS2.js} +1 -1
- package/dist/chunks/{chunk-M3OSDZPY.js → chunk-XSYZDMUP.js} +16 -7
- package/dist/chunks/{chunk-VLPLCJZC.js → chunk-ZSFEACZU.js} +1 -1
- package/dist/chunks/{clear-TNGRDA7D.js → clear-X7M4WGBC.js} +11 -11
- package/dist/chunks/{compile-vercel-config-ERLXKKWW.js → compile-vercel-config-FBOZBWJC.js} +7 -7
- package/dist/chunks/{config-7EDKML5Q.js → config-KGW667XC.js} +9 -9
- package/dist/chunks/{config-H22EE765.js → config-RYPSCAR7.js} +11 -11
- package/dist/chunks/{delete-LORYIZHY.js → delete-OXYXXPHR.js} +8 -8
- package/dist/chunks/{delete-Q4S5F2AI.js → delete-VK6FTDBI.js} +9 -9
- package/dist/chunks/{disable-HKWCBDJC.js → disable-XRJTKNX4.js} +8 -8
- package/dist/chunks/{discard-UCCRF2JQ.js → discard-NAPSPR6Y.js} +8 -8
- package/dist/chunks/{edit-AWL35PYQ.js → edit-34GDLPQG.js} +10 -10
- package/dist/chunks/{edit-6IM6VRBR.js → edit-WLG4GLU3.js} +10 -10
- package/dist/chunks/{enable-GN3D3L3V.js → enable-IDKKVXKB.js} +8 -8
- package/dist/chunks/{exec-CNBOV577.js → exec-XH4K34JM.js} +3 -3
- package/dist/chunks/{export-HHRVFALV.js → export-MPMU3FYY.js} +8 -8
- package/dist/chunks/{image-4DCU4VPP.js → image-RZ2A4FWP.js} +6 -6
- package/dist/chunks/{import-builders-DVG3HOTF.js → import-builders-GZPE5N44.js} +9 -9
- package/dist/chunks/{inspect-B3OWUFLH.js → inspect-56S2DKPO.js} +11 -11
- package/dist/chunks/{inspect-VPME6UC7.js → inspect-EVDBNPP4.js} +11 -11
- package/dist/chunks/{inspect-TGOJDKIT.js → inspect-KGEMHV2T.js} +9 -9
- package/dist/chunks/{inspect-VLGKNHJW.js → inspect-OOV2ORKD.js} +11 -11
- package/dist/chunks/{inspect-TUW67CFZ.js → inspect-X2Y5FDKR.js} +10 -10
- package/dist/chunks/{list-K552ITMK.js → list-FWLSZYMO.js} +9 -9
- package/dist/chunks/{list-2DPKDHRV.js → list-H357CF7M.js} +10 -10
- package/dist/chunks/{list-TK2JO7BK.js → list-TWSOAQRB.js} +8 -8
- package/dist/chunks/{login-HRWEKW5P.js → login-54OPNB5E.js} +21 -12
- package/dist/chunks/{ls-JSV2WZVF.js → ls-6JHFSJBJ.js} +11 -11
- package/dist/chunks/{ls-O2WYF5UL.js → ls-DU3S2GBJ.js} +11 -11
- package/dist/chunks/{ls-IOXGXEY4.js → ls-VDFNIR5H.js} +10 -10
- package/dist/chunks/{ls-M5TYGFP5.js → ls-WFMTVJOO.js} +11 -11
- package/dist/chunks/{ls-YIF3KLF3.js → ls-WGIRTAVM.js} +11 -11
- package/dist/chunks/{ls-TM6NTZEB.js → ls-ZMR5RMU4.js} +9 -9
- package/dist/chunks/{open-FWAVEWGU.js → open-RCSCNKHF.js} +9 -9
- package/dist/chunks/{permissions-DPFYL47Z.js → permissions-XNN37R4N.js} +7 -7
- package/dist/chunks/{publish-63CGFKQR.js → publish-PLXEACYY.js} +8 -8
- package/dist/chunks/{push-T5ZTBW3P.js → push-EFYSB52Q.js} +11 -11
- package/dist/chunks/{query-B6O3EMEV.js → query-EKTXDOL7.js} +11 -11
- package/dist/chunks/{reorder-ANV4NMKH.js → reorder-OSA7D2RG.js} +8 -8
- package/dist/chunks/{reply-C73KGOCG.js → reply-6M2IYKLK.js} +10 -10
- package/dist/chunks/{resolve-IHSIVPEE.js → resolve-MCX5STKN.js} +9 -9
- package/dist/chunks/{restore-GSUNXP2O.js → restore-52OEP3NL.js} +8 -8
- package/dist/chunks/{rm-M7IJC2WZ.js → rm-2VAJFK25.js} +11 -11
- package/dist/chunks/{rm-RV5SQFQA.js → rm-4BJN2LJX.js} +11 -13
- package/dist/chunks/{rm-4O74PS4Q.js → rm-IYEDZOMN.js} +11 -11
- package/dist/chunks/{rm-PRINF4OU.js → rm-QW35WHSK.js} +11 -11
- package/dist/chunks/{rm-YDTK5ESZ.js → rm-TXV4GB4L.js} +10 -10
- package/dist/chunks/{routes-SZI2G4SE.js → routes-2OLIBRYX.js} +3 -3
- package/dist/chunks/{rule-inspect-ZZC53FLP.js → rule-inspect-WOBAN3Y2.js} +10 -10
- package/dist/chunks/{rules-SAOSSGFI.js → rules-CUJRAZYO.js} +10 -10
- package/dist/chunks/{schema-23ZFAKDU.js → schema-45SJNY5L.js} +4 -4
- package/dist/chunks/{schema-2Q3QRMRO.js → schema-VCGEJAOG.js} +9 -9
- package/dist/chunks/{set-L47ZCZBJ.js → set-2QSXMDVF.js} +9 -9
- package/dist/chunks/{tags-2TWLM77N.js → tags-NHX2VQ7E.js} +5 -5
- package/dist/chunks/{types-G3PEUIJH.js → types-JGANJ5EQ.js} +3 -3
- package/dist/chunks/{update-SZH2VBD6.js → update-EOHXTT4N.js} +12 -12
- package/dist/commands/build/builder-worker.cjs +281 -0
- package/dist/commands/build/index.js +798 -236
- package/dist/commands/deploy/index.js +103 -31
- package/dist/commands/dev/index.js +983 -176
- package/dist/commands/env/index.js +1167 -542
- package/dist/commands/link/index.js +10 -10
- package/dist/commands/list/index.js +10 -10
- package/dist/commands-bulk.js +2002 -962
- package/dist/index.js +16 -16
- package/dist/version.mjs +1 -1
- package/package.json +48 -48
- package/dist/chunks/chunk-HGRWPPYB.js +0 -18
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
getCustomEnvironments,
|
|
10
10
|
readStandardInput,
|
|
11
11
|
require_dist as require_dist3
|
|
12
|
-
} from "../../chunks/chunk-
|
|
12
|
+
} from "../../chunks/chunk-ZSFEACZU.js";
|
|
13
13
|
import {
|
|
14
14
|
getInvalidSubcommand
|
|
15
15
|
} from "../../chunks/chunk-VGIMO3ZK.js";
|
|
@@ -21,14 +21,15 @@ import {
|
|
|
21
21
|
} from "../../chunks/chunk-OQ3C5VXZ.js";
|
|
22
22
|
import "../../chunks/chunk-XRWOTCDO.js";
|
|
23
23
|
import {
|
|
24
|
+
isGuidanceEnabled,
|
|
24
25
|
suggestNextCommands
|
|
25
|
-
} from "../../chunks/chunk-
|
|
26
|
+
} from "../../chunks/chunk-7ST552E3.js";
|
|
26
27
|
import {
|
|
27
28
|
formatEnvironment
|
|
28
|
-
} from "../../chunks/chunk-
|
|
29
|
+
} from "../../chunks/chunk-67IIZBBY.js";
|
|
29
30
|
import {
|
|
30
31
|
validateLsArgs
|
|
31
|
-
} from "../../chunks/chunk-
|
|
32
|
+
} from "../../chunks/chunk-O75LSD3C.js";
|
|
32
33
|
import {
|
|
33
34
|
validateJsonOutput
|
|
34
35
|
} from "../../chunks/chunk-KXDWXXJH.js";
|
|
@@ -37,7 +38,7 @@ import {
|
|
|
37
38
|
} from "../../chunks/chunk-YPQSDAEW.js";
|
|
38
39
|
import {
|
|
39
40
|
getCommandAliases
|
|
40
|
-
} from "../../chunks/chunk-
|
|
41
|
+
} from "../../chunks/chunk-7HE63HCR.js";
|
|
41
42
|
import "../../chunks/chunk-7Q45OKWR.js";
|
|
42
43
|
import "../../chunks/chunk-GY5I4AYD.js";
|
|
43
44
|
import "../../chunks/chunk-CJV7J7B5.js";
|
|
@@ -52,33 +53,53 @@ import "../../chunks/chunk-DWIC7MRV.js";
|
|
|
52
53
|
import "../../chunks/chunk-XM3LOQIX.js";
|
|
53
54
|
import "../../chunks/chunk-XDGOOW3K.js";
|
|
54
55
|
import "../../chunks/chunk-VP5Y3SZG.js";
|
|
55
|
-
import {
|
|
56
|
-
require_execa
|
|
57
|
-
} from "../../chunks/chunk-R6IGDGX3.js";
|
|
58
56
|
import {
|
|
59
57
|
autoInstallVercelPlugin
|
|
60
|
-
} from "../../chunks/chunk-
|
|
58
|
+
} from "../../chunks/chunk-7AEEQOD4.js";
|
|
59
|
+
import {
|
|
60
|
+
require_execa
|
|
61
|
+
} from "../../chunks/chunk-5XECIWME.js";
|
|
61
62
|
import {
|
|
62
63
|
stamp_default
|
|
63
64
|
} from "../../chunks/chunk-64IF634X.js";
|
|
64
65
|
import "../../chunks/chunk-VXYGCOKL.js";
|
|
65
|
-
import "../../chunks/chunk-
|
|
66
|
+
import "../../chunks/chunk-FWKSJYDV.js";
|
|
66
67
|
import {
|
|
67
68
|
help
|
|
68
|
-
} from "../../chunks/chunk-
|
|
69
|
+
} from "../../chunks/chunk-2YRAWYGE.js";
|
|
69
70
|
import {
|
|
71
|
+
ENV_VISIBILITY_DEPRECATION_MESSAGE,
|
|
72
|
+
SENSITIVE_ENV_VALUE_PLACEHOLDER,
|
|
70
73
|
STANDARD_ENVIRONMENTS,
|
|
71
74
|
formatProject,
|
|
75
|
+
formatVisibilityLabel,
|
|
76
|
+
getApiPublicPrefix,
|
|
77
|
+
getEnvKeyWarnings,
|
|
72
78
|
getEnvRecords,
|
|
79
|
+
getFrameworkPublicPrefix,
|
|
80
|
+
getLocalSecretFallbackMessage,
|
|
81
|
+
getLocalSvelteKitPublicPrefixes,
|
|
82
|
+
getPublicPrefix,
|
|
83
|
+
getPublicPrefixSecretVisibilityError,
|
|
73
84
|
getTeamById,
|
|
85
|
+
getUnavailableSecretValuesMessage,
|
|
86
|
+
isFlagsSecretNeedingSplit,
|
|
87
|
+
isSecretEnvVar,
|
|
88
|
+
looksLikeSecret,
|
|
89
|
+
looksLikeSecretValue,
|
|
90
|
+
normalizeStdinEnvValue,
|
|
74
91
|
param,
|
|
75
92
|
parseTarget,
|
|
76
93
|
printAlignedLabel,
|
|
77
94
|
pull,
|
|
78
95
|
pullEnvRecords,
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
96
|
+
removePublicPrefix,
|
|
97
|
+
resolveEnvVarTypeOption,
|
|
98
|
+
resolveEnvVarVisibility,
|
|
99
|
+
resolveProjectContext,
|
|
100
|
+
shouldConfirmRotationBeforeDelete,
|
|
101
|
+
validateEnvValue
|
|
102
|
+
} from "../../chunks/chunk-BQG777JE.js";
|
|
82
103
|
import {
|
|
83
104
|
addSubcommand,
|
|
84
105
|
envCommand,
|
|
@@ -91,11 +112,11 @@ import {
|
|
|
91
112
|
removeSubcommand,
|
|
92
113
|
runSubcommand,
|
|
93
114
|
updateSubcommand
|
|
94
|
-
} from "../../chunks/chunk-
|
|
115
|
+
} from "../../chunks/chunk-FXD67VN5.js";
|
|
95
116
|
import {
|
|
96
117
|
TelemetryClient,
|
|
97
118
|
require_dist as require_dist2
|
|
98
|
-
} from "../../chunks/chunk-
|
|
119
|
+
} from "../../chunks/chunk-XNFHNTS2.js";
|
|
99
120
|
import {
|
|
100
121
|
buildCommandWithYes,
|
|
101
122
|
buildEnvAddCommandWithPreservedArgs,
|
|
@@ -105,21 +126,24 @@ import {
|
|
|
105
126
|
getPreservedArgsForEnvRm,
|
|
106
127
|
getPreservedArgsForEnvUpdate,
|
|
107
128
|
outputActionRequired,
|
|
108
|
-
outputAgentError
|
|
109
|
-
|
|
129
|
+
outputAgentError,
|
|
130
|
+
quoteArg,
|
|
131
|
+
redactEnvValueArgs,
|
|
132
|
+
withGlobalFlags
|
|
133
|
+
} from "../../chunks/chunk-NGGLYKNU.js";
|
|
110
134
|
import {
|
|
111
135
|
require_ms
|
|
112
136
|
} from "../../chunks/chunk-GGP5R3FU.js";
|
|
113
137
|
import {
|
|
114
138
|
printError
|
|
115
|
-
} from "../../chunks/chunk-
|
|
139
|
+
} from "../../chunks/chunk-AYLY3ZVL.js";
|
|
116
140
|
import {
|
|
117
141
|
parseArguments
|
|
118
142
|
} from "../../chunks/chunk-57RHXXXG.js";
|
|
119
143
|
import "../../chunks/chunk-RKDCNQ4S.js";
|
|
120
144
|
import {
|
|
121
145
|
isAPIError
|
|
122
|
-
} from "../../chunks/chunk-
|
|
146
|
+
} from "../../chunks/chunk-BMKU5KEL.js";
|
|
123
147
|
import {
|
|
124
148
|
getCommandName,
|
|
125
149
|
getCommandNamePlain,
|
|
@@ -134,7 +158,7 @@ import {
|
|
|
134
158
|
output_manager_default,
|
|
135
159
|
prependEmoji,
|
|
136
160
|
require_dist
|
|
137
|
-
} from "../../chunks/chunk-
|
|
161
|
+
} from "../../chunks/chunk-QFAS4OVW.js";
|
|
138
162
|
import {
|
|
139
163
|
require_source
|
|
140
164
|
} from "../../chunks/chunk-S7KYDPEM.js";
|
|
@@ -212,180 +236,6 @@ function isKnownError(error) {
|
|
|
212
236
|
return knownErrorsCodes.has(code.toUpperCase());
|
|
213
237
|
}
|
|
214
238
|
|
|
215
|
-
// src/util/env/validate-env.ts
|
|
216
|
-
var import_frameworks = __toESM(require_frameworks(), 1);
|
|
217
|
-
function getEnvValueWarnings(value) {
|
|
218
|
-
const warnings = [];
|
|
219
|
-
const normalized = value.replace(/\n$/, "");
|
|
220
|
-
if (/^[ \t]+/.test(normalized)) {
|
|
221
|
-
warnings.push({
|
|
222
|
-
message: "starts with whitespace",
|
|
223
|
-
requiresConfirmation: false
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
if (/[ \t]+$/.test(normalized)) {
|
|
227
|
-
warnings.push({
|
|
228
|
-
message: "ends with whitespace",
|
|
229
|
-
requiresConfirmation: false
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
if (normalized.includes("\r") || normalized.includes("\n")) {
|
|
233
|
-
warnings.push({
|
|
234
|
-
message: "contains newlines",
|
|
235
|
-
requiresConfirmation: false
|
|
236
|
-
});
|
|
237
|
-
}
|
|
238
|
-
if (value.includes("\0")) {
|
|
239
|
-
warnings.push({
|
|
240
|
-
message: "contains null characters",
|
|
241
|
-
requiresConfirmation: false
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
if (value === "") {
|
|
245
|
-
warnings.push({
|
|
246
|
-
message: "is empty",
|
|
247
|
-
requiresConfirmation: true
|
|
248
|
-
});
|
|
249
|
-
}
|
|
250
|
-
if (value.length > 2 && (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'"))) {
|
|
251
|
-
warnings.push({
|
|
252
|
-
message: "includes surrounding quotes (these will be stored literally)",
|
|
253
|
-
requiresConfirmation: false
|
|
254
|
-
});
|
|
255
|
-
}
|
|
256
|
-
return warnings;
|
|
257
|
-
}
|
|
258
|
-
function formatWarnings(warnings) {
|
|
259
|
-
if (warnings.length === 0)
|
|
260
|
-
return null;
|
|
261
|
-
const messages = warnings.map((w) => w.message);
|
|
262
|
-
const startsIdx = messages.indexOf("starts with whitespace");
|
|
263
|
-
const endsIdx = messages.indexOf("ends with whitespace");
|
|
264
|
-
if (startsIdx !== -1 && endsIdx !== -1) {
|
|
265
|
-
messages.splice(Math.max(startsIdx, endsIdx), 1);
|
|
266
|
-
messages[Math.min(startsIdx, endsIdx)] = "starts and ends with whitespace";
|
|
267
|
-
}
|
|
268
|
-
if (messages.length === 1) {
|
|
269
|
-
return `Value ${messages[0]}`;
|
|
270
|
-
}
|
|
271
|
-
if (messages.length === 2) {
|
|
272
|
-
return `Value ${messages[0]} and ${messages[1]}`;
|
|
273
|
-
}
|
|
274
|
-
const last = messages.pop();
|
|
275
|
-
return `Value ${messages.join(", ")}, and ${last}`;
|
|
276
|
-
}
|
|
277
|
-
var PUBLIC_PREFIXES = [
|
|
278
|
-
...new Set(
|
|
279
|
-
import_frameworks.frameworkList.map((f) => f.envPrefix).filter((p) => !!p)
|
|
280
|
-
)
|
|
281
|
-
];
|
|
282
|
-
var SENSITIVE_PATTERN = /(?:^|_)(password|secret|private|token|key|auth|jwt|signature)(?:_|$)/i;
|
|
283
|
-
function hasOnlyWhitespaceWarnings(warnings) {
|
|
284
|
-
return warnings.length > 0 && warnings.every(
|
|
285
|
-
(w) => w.message === "starts with whitespace" || w.message === "ends with whitespace"
|
|
286
|
-
);
|
|
287
|
-
}
|
|
288
|
-
function trimValue(value) {
|
|
289
|
-
return value.replace(/\n$/, "").trim();
|
|
290
|
-
}
|
|
291
|
-
function normalizeStdinEnvValue(value) {
|
|
292
|
-
let valueWithoutTrailingNewline = value;
|
|
293
|
-
if (value.endsWith("\r\n")) {
|
|
294
|
-
valueWithoutTrailingNewline = value.slice(0, -2);
|
|
295
|
-
} else if (value.endsWith("\n")) {
|
|
296
|
-
valueWithoutTrailingNewline = value.slice(0, -1);
|
|
297
|
-
} else {
|
|
298
|
-
return {
|
|
299
|
-
value,
|
|
300
|
-
strippedTrailingNewline: false
|
|
301
|
-
};
|
|
302
|
-
}
|
|
303
|
-
if (valueWithoutTrailingNewline.includes("\n") || valueWithoutTrailingNewline.includes("\r")) {
|
|
304
|
-
return {
|
|
305
|
-
value,
|
|
306
|
-
strippedTrailingNewline: false
|
|
307
|
-
};
|
|
308
|
-
}
|
|
309
|
-
return {
|
|
310
|
-
value: valueWithoutTrailingNewline,
|
|
311
|
-
strippedTrailingNewline: true
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
function getPublicPrefix(key) {
|
|
315
|
-
const upperKey = key.toUpperCase();
|
|
316
|
-
return PUBLIC_PREFIXES.find((p) => upperKey.startsWith(p)) || null;
|
|
317
|
-
}
|
|
318
|
-
function removePublicPrefix(key) {
|
|
319
|
-
const prefix = getPublicPrefix(key);
|
|
320
|
-
if (!prefix)
|
|
321
|
-
return key;
|
|
322
|
-
return key.slice(prefix.length);
|
|
323
|
-
}
|
|
324
|
-
async function validateEnvValue(opts) {
|
|
325
|
-
let finalValue = opts.initialValue;
|
|
326
|
-
let alreadyConfirmed = false;
|
|
327
|
-
if (!opts.skipConfirm) {
|
|
328
|
-
let valueAccepted = false;
|
|
329
|
-
while (!valueAccepted) {
|
|
330
|
-
const valueWarnings = getEnvValueWarnings(finalValue);
|
|
331
|
-
const warningMessage = formatWarnings(valueWarnings);
|
|
332
|
-
if (!warningMessage) {
|
|
333
|
-
valueAccepted = true;
|
|
334
|
-
break;
|
|
335
|
-
}
|
|
336
|
-
opts.showWarning(warningMessage);
|
|
337
|
-
const canTrim = hasOnlyWhitespaceWarnings(valueWarnings);
|
|
338
|
-
const choices = canTrim ? [
|
|
339
|
-
{ name: "Leave as is", value: "c" },
|
|
340
|
-
{ name: "Re-enter", value: "r" },
|
|
341
|
-
{ name: "Trim whitespace", value: "t" }
|
|
342
|
-
] : [
|
|
343
|
-
{ name: "Leave as is", value: "c" },
|
|
344
|
-
{ name: "Re-enter", value: "r" }
|
|
345
|
-
];
|
|
346
|
-
const action = await opts.selectAction(choices);
|
|
347
|
-
if (action === "c") {
|
|
348
|
-
valueAccepted = true;
|
|
349
|
-
if (valueWarnings.some((w) => w.requiresConfirmation)) {
|
|
350
|
-
alreadyConfirmed = true;
|
|
351
|
-
}
|
|
352
|
-
} else if (action === "t") {
|
|
353
|
-
finalValue = trimValue(finalValue);
|
|
354
|
-
opts.showLog("Trimmed whitespace");
|
|
355
|
-
} else {
|
|
356
|
-
finalValue = await opts.promptForValue();
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
} else {
|
|
360
|
-
const valueWarnings = getEnvValueWarnings(finalValue);
|
|
361
|
-
const warningMessage = formatWarnings(valueWarnings);
|
|
362
|
-
if (warningMessage) {
|
|
363
|
-
opts.showWarning(warningMessage);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
return { finalValue, alreadyConfirmed };
|
|
367
|
-
}
|
|
368
|
-
function getEnvKeyWarnings(key) {
|
|
369
|
-
const warnings = [];
|
|
370
|
-
const matchingPrefix = getPublicPrefix(key);
|
|
371
|
-
if (matchingPrefix) {
|
|
372
|
-
const sensitiveMatch = SENSITIVE_PATTERN.exec(key);
|
|
373
|
-
const nameWithoutPrefix = key.slice(matchingPrefix.length);
|
|
374
|
-
if (sensitiveMatch) {
|
|
375
|
-
warnings.push({
|
|
376
|
-
message: `The ${matchingPrefix} prefix will make ${nameWithoutPrefix} visible to anyone visiting your site`,
|
|
377
|
-
requiresConfirmation: true
|
|
378
|
-
});
|
|
379
|
-
} else {
|
|
380
|
-
warnings.push({
|
|
381
|
-
message: `${matchingPrefix} variables can be seen by anyone visiting your site`,
|
|
382
|
-
requiresConfirmation: false
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
return warnings;
|
|
387
|
-
}
|
|
388
|
-
|
|
389
239
|
// src/util/telemetry/commands/env/add.ts
|
|
390
240
|
var EnvAddTelemetryClient = class extends TelemetryClient {
|
|
391
241
|
trackCliArgumentName(name) {
|
|
@@ -438,6 +288,15 @@ var EnvAddTelemetryClient = class extends TelemetryClient {
|
|
|
438
288
|
});
|
|
439
289
|
}
|
|
440
290
|
}
|
|
291
|
+
trackCliOptionType(type) {
|
|
292
|
+
if (type) {
|
|
293
|
+
const validTypes = ["config", "secret"];
|
|
294
|
+
this.trackCliOption({
|
|
295
|
+
option: "type",
|
|
296
|
+
value: validTypes.includes(type) ? type : this.redactedValue
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
441
300
|
trackCliFlagSensitive(sensitive) {
|
|
442
301
|
if (sensitive) {
|
|
443
302
|
this.trackCliFlag("sensitive");
|
|
@@ -468,100 +327,42 @@ var EnvAddTelemetryClient = class extends TelemetryClient {
|
|
|
468
327
|
// src/commands/env/add.ts
|
|
469
328
|
import { determineAgent } from "@vercel/detect-agent";
|
|
470
329
|
|
|
471
|
-
// src/util/env/
|
|
472
|
-
function
|
|
473
|
-
|
|
474
|
-
if (resolved === "config") {
|
|
475
|
-
return "Config";
|
|
476
|
-
}
|
|
477
|
-
if (resolved === "secret") {
|
|
478
|
-
return "Secret";
|
|
479
|
-
}
|
|
480
|
-
return void 0;
|
|
330
|
+
// src/util/env/secret-storage-guidance.ts
|
|
331
|
+
function includesDevelopment(targets) {
|
|
332
|
+
return targets.length === 0 || targets.includes("development");
|
|
481
333
|
}
|
|
482
|
-
function
|
|
483
|
-
if (
|
|
484
|
-
|
|
334
|
+
function getProductionSecretPolicyErrorKind(message) {
|
|
335
|
+
if (/production secrets?.*different value|different value.*production secrets?/i.test(
|
|
336
|
+
message
|
|
337
|
+
)) {
|
|
338
|
+
return "different-values";
|
|
485
339
|
}
|
|
486
|
-
if (
|
|
487
|
-
|
|
340
|
+
if (/production secrets?.*(?:own environment group|separat)|(?:own environment group|separat).*production secrets?/i.test(
|
|
341
|
+
message
|
|
342
|
+
)) {
|
|
343
|
+
return "separate-environments";
|
|
488
344
|
}
|
|
489
|
-
return
|
|
345
|
+
return null;
|
|
490
346
|
}
|
|
491
|
-
function
|
|
492
|
-
return
|
|
347
|
+
function getProductionSecretPolicyRecovery(kind) {
|
|
348
|
+
return kind === "different-values" ? "Use different Secret values for Production and non-Production." : "Create separate Production and non-Production variables with different values.";
|
|
493
349
|
}
|
|
494
|
-
function
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
}
|
|
499
|
-
const wouldBeSecret = options.visibility === "secret" || options.type === "sensitive";
|
|
500
|
-
if (!wouldBeSecret) {
|
|
501
|
-
return null;
|
|
502
|
-
}
|
|
503
|
-
const prefixLabel = publicPrefix.replace(/_$/, "");
|
|
504
|
-
if (hasNonDevelopmentTarget(options.envTargets)) {
|
|
505
|
-
return `Environment variables with a public framework prefix (${prefixLabel}) cannot use secret visibility on Production or Preview. Target Development only, rename to remove the public prefix, or use \`--visibility config\` with \`--no-sensitive\` on Development.`;
|
|
506
|
-
}
|
|
507
|
-
return `Environment variables with a public framework prefix (${prefixLabel}) cannot use secret visibility. Rename to remove the public prefix or use \`--visibility config\` with \`--no-sensitive\`.`;
|
|
350
|
+
function getSecretStorageChoice(targets, recommendedReason) {
|
|
351
|
+
const availability = includesDevelopment(targets) ? "hidden in the dashboard; Development values can be pulled" : "hidden in the dashboard and unavailable to pulls";
|
|
352
|
+
const recommendation = recommendedReason ? `; recommended ${recommendedReason}` : "";
|
|
353
|
+
return `Secret (${availability}${recommendation})`;
|
|
508
354
|
}
|
|
509
|
-
function
|
|
510
|
-
if (
|
|
511
|
-
return
|
|
512
|
-
}
|
|
513
|
-
if (!hasNonDevelopmentTarget(envTargets)) {
|
|
514
|
-
return false;
|
|
355
|
+
function getDefaultSecretStorageGuidance(targets) {
|
|
356
|
+
if (includesDevelopment(targets)) {
|
|
357
|
+
return "Stored as Secret by default. This value is hidden in the dashboard; Development values can be pulled. Use `--type config` for other values you need to read later.";
|
|
515
358
|
}
|
|
516
|
-
return
|
|
517
|
-
}
|
|
518
|
-
function resolveEnvVarVisibility(options) {
|
|
519
|
-
if (options.explicitVisibility !== void 0) {
|
|
520
|
-
if (options.explicitVisibility !== "config" && options.explicitVisibility !== "secret") {
|
|
521
|
-
return {
|
|
522
|
-
error: "The `--visibility` flag must be either `config` or `secret`."
|
|
523
|
-
};
|
|
524
|
-
}
|
|
525
|
-
const publicPrefixError2 = getPublicPrefixSecretVisibilityError(
|
|
526
|
-
options.key,
|
|
527
|
-
{
|
|
528
|
-
visibility: options.explicitVisibility,
|
|
529
|
-
type: options.type,
|
|
530
|
-
envTargets: options.envTargets
|
|
531
|
-
}
|
|
532
|
-
);
|
|
533
|
-
if (publicPrefixError2) {
|
|
534
|
-
return { error: publicPrefixError2 };
|
|
535
|
-
}
|
|
536
|
-
return { visibility: options.explicitVisibility };
|
|
537
|
-
}
|
|
538
|
-
const inferred = visibilityFromEnvType(options.type);
|
|
539
|
-
if (inferred === void 0) {
|
|
540
|
-
return {};
|
|
541
|
-
}
|
|
542
|
-
if (shouldOmitInferredVisibility(
|
|
543
|
-
options.key,
|
|
544
|
-
options.envTargets,
|
|
545
|
-
options.teamSensitivePolicyOn
|
|
546
|
-
)) {
|
|
547
|
-
return {};
|
|
548
|
-
}
|
|
549
|
-
const publicPrefixError = getPublicPrefixSecretVisibilityError(options.key, {
|
|
550
|
-
visibility: inferred,
|
|
551
|
-
type: options.type,
|
|
552
|
-
envTargets: options.envTargets
|
|
553
|
-
});
|
|
554
|
-
if (publicPrefixError) {
|
|
555
|
-
return { error: publicPrefixError };
|
|
556
|
-
}
|
|
557
|
-
return { visibility: inferred };
|
|
359
|
+
return "Stored as Secret by default. This value is hidden in the dashboard and unavailable to pulls; use `--type config` for values you need to read later.";
|
|
558
360
|
}
|
|
559
361
|
|
|
560
362
|
// src/commands/env/add.ts
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
)}`;
|
|
363
|
+
function looksLikeCredentialName(key, publicPrefix = getPublicPrefix(key)) {
|
|
364
|
+
return looksLikeSecret(publicPrefix ? key.slice(publicPrefix.length) : key);
|
|
365
|
+
}
|
|
565
366
|
function filterEnvChoicesForSensitivity(choices, opts) {
|
|
566
367
|
if (opts.policyOn) {
|
|
567
368
|
return choices.filter((c) => c.value === "development");
|
|
@@ -592,19 +393,13 @@ function resolveFinalType(envTargets, isSensitive, opts) {
|
|
|
592
393
|
}
|
|
593
394
|
function fillEnvAddTemplate(template, opts) {
|
|
594
395
|
const targetPlaceholder = getEnvTargetPlaceholder();
|
|
595
|
-
return template.replace(/<name>/g, opts.envName
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
i++;
|
|
603
|
-
} else if (redacted[i].startsWith("--value=")) {
|
|
604
|
-
redacted[i] = '--value="<value>"';
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
return redacted;
|
|
396
|
+
return template.replace(/<name>/g, opts.envName ? quoteArg(opts.envName) : "<name>").split(targetPlaceholder).join(opts.envTargetArg ? quoteArg(opts.envTargetArg) : targetPlaceholder).replace(
|
|
397
|
+
/<git-branch>/g,
|
|
398
|
+
opts.envGitBranch ? quoteArg(opts.envGitBranch) : "<git-branch>"
|
|
399
|
+
).replace(
|
|
400
|
+
/<gitbranch>/g,
|
|
401
|
+
opts.envGitBranch ? quoteArg(opts.envGitBranch) : "<gitbranch>"
|
|
402
|
+
).replace(/<value>/g, "<value>");
|
|
608
403
|
}
|
|
609
404
|
function multiTargetSuggestion(argv, envName, targets, addNoSensitive) {
|
|
610
405
|
const flag = addNoSensitive ? " --no-sensitive" : "";
|
|
@@ -637,9 +432,6 @@ function formatEnvironmentTarget(target, customEnvironments) {
|
|
|
637
432
|
function formatEnvironmentTargets(envTargets, customEnvironments) {
|
|
638
433
|
return envTargets.map((target) => formatEnvironmentTarget(target, customEnvironments)).join(", ");
|
|
639
434
|
}
|
|
640
|
-
function typeLabel(type) {
|
|
641
|
-
return type === "sensitive" ? "Sensitive" : "Non-sensitive";
|
|
642
|
-
}
|
|
643
435
|
function printEnvAddResult(link, envName, envTargets, envGitBranch, customEnvironments, finalType, force, visibility) {
|
|
644
436
|
output_manager_default.print("\n");
|
|
645
437
|
printAlignedLabel(force ? "Overrode" : "Added", envName, { gutter: "\u2713" });
|
|
@@ -651,10 +443,9 @@ function printEnvAddResult(link, envName, envTargets, envGitBranch, customEnviro
|
|
|
651
443
|
if (envGitBranch) {
|
|
652
444
|
printAlignedLabel("Branch", envGitBranch);
|
|
653
445
|
}
|
|
654
|
-
printAlignedLabel("Type", typeLabel(finalType));
|
|
655
446
|
const visibilityLabel = formatVisibilityLabel(visibility, finalType);
|
|
656
447
|
if (visibilityLabel) {
|
|
657
|
-
printAlignedLabel("
|
|
448
|
+
printAlignedLabel("Type", visibilityLabel);
|
|
658
449
|
}
|
|
659
450
|
}
|
|
660
451
|
function printEnvAddWarning(message) {
|
|
@@ -667,6 +458,13 @@ function promptEnvValue(client, opts) {
|
|
|
667
458
|
...opts.isSensitive ? { transformer: (value) => "*".repeat(value.length) } : {}
|
|
668
459
|
});
|
|
669
460
|
}
|
|
461
|
+
function buildHumanEnvAddCommand(argv, commandTemplate) {
|
|
462
|
+
const globalFlags = getGlobalFlagsFromArgs(argv.slice(2), {
|
|
463
|
+
preserveProject: true
|
|
464
|
+
}).filter((flag) => !flag.startsWith("--non-interactive"));
|
|
465
|
+
const suffix = globalFlags.length > 0 ? ` ${globalFlags.map(quoteArg).join(" ")}` : "";
|
|
466
|
+
return getCommandNamePlain(`${commandTemplate}${suffix}`);
|
|
467
|
+
}
|
|
670
468
|
async function add(client, argv) {
|
|
671
469
|
let parsedArgs;
|
|
672
470
|
const flagsSpecification = getFlagsSpecification(addSubcommand.options);
|
|
@@ -694,6 +492,14 @@ async function add(client, argv) {
|
|
|
694
492
|
const positionalGitBranch = args[2];
|
|
695
493
|
const optionGitBranch = typeof opts["--git-branch"] === "string" ? opts["--git-branch"] : void 0;
|
|
696
494
|
let envGitBranch = optionGitBranch ?? positionalGitBranch;
|
|
495
|
+
const forceSensitive = Boolean(opts["--sensitive"]);
|
|
496
|
+
const forceEncrypted = Boolean(opts["--no-sensitive"]);
|
|
497
|
+
const typeOption = resolveEnvVarTypeOption({
|
|
498
|
+
type: typeof opts["--type"] === "string" ? opts["--type"] : void 0,
|
|
499
|
+
visibility: typeof opts["--visibility"] === "string" ? opts["--visibility"] : void 0
|
|
500
|
+
});
|
|
501
|
+
let explicitType = typeOption.explicitVisibility;
|
|
502
|
+
let typeSource = explicitType || forceSensitive || forceEncrypted ? "argv" : void 0;
|
|
697
503
|
const telemetryClient = new EnvAddTelemetryClient({
|
|
698
504
|
opts: {
|
|
699
505
|
store: client.telemetryEventStore
|
|
@@ -711,10 +517,47 @@ async function add(client, argv) {
|
|
|
711
517
|
telemetryClient.trackCliFlagForce(opts["--force"]);
|
|
712
518
|
telemetryClient.trackCliFlagGuidance(opts["--guidance"]);
|
|
713
519
|
telemetryClient.trackCliFlagYes(opts["--yes"]);
|
|
520
|
+
telemetryClient.trackCliOptionType(
|
|
521
|
+
typeof opts["--type"] === "string" ? opts["--type"] : void 0
|
|
522
|
+
);
|
|
714
523
|
telemetryClient.trackCliOptionVisibility(
|
|
715
524
|
typeof opts["--visibility"] === "string" ? opts["--visibility"] : void 0
|
|
716
525
|
);
|
|
717
526
|
telemetryClient.trackCliOptionProject(opts["--project"]);
|
|
527
|
+
if (typeOption.error) {
|
|
528
|
+
if (client.nonInteractive) {
|
|
529
|
+
outputAgentError(
|
|
530
|
+
client,
|
|
531
|
+
{
|
|
532
|
+
status: "error",
|
|
533
|
+
reason: typeOption.errorReason ?? "invalid_type",
|
|
534
|
+
message: typeOption.error
|
|
535
|
+
},
|
|
536
|
+
1
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
output_manager_default.fatal(typeOption.error);
|
|
540
|
+
return 1;
|
|
541
|
+
}
|
|
542
|
+
if (typeOption.usedDeprecatedVisibility) {
|
|
543
|
+
printEnvAddWarning(ENV_VISIBILITY_DEPRECATION_MESSAGE);
|
|
544
|
+
}
|
|
545
|
+
const typeConflictMessage = forceSensitive ? forceEncrypted ? "`--sensitive` and `--no-sensitive` cannot be used together. Pick one." : explicitType === "config" ? "`--type config` cannot be used with `--sensitive`. Pick one." : null : forceEncrypted && explicitType === "secret" ? "`--type secret` cannot be used with `--no-sensitive`. Pick one." : null;
|
|
546
|
+
if (typeConflictMessage) {
|
|
547
|
+
if (client.nonInteractive) {
|
|
548
|
+
outputAgentError(
|
|
549
|
+
client,
|
|
550
|
+
{
|
|
551
|
+
status: "error",
|
|
552
|
+
reason: "conflicting_type_flags",
|
|
553
|
+
message: typeConflictMessage
|
|
554
|
+
},
|
|
555
|
+
1
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
output_manager_default.fatal(typeConflictMessage);
|
|
559
|
+
return 1;
|
|
560
|
+
}
|
|
718
561
|
if (positionalGitBranch && optionGitBranch) {
|
|
719
562
|
output_manager_default.error(
|
|
720
563
|
"Git branch was provided twice. Use either `--git-branch <git-branch>` or the legacy third argument."
|
|
@@ -738,6 +581,7 @@ async function add(client, argv) {
|
|
|
738
581
|
return 1;
|
|
739
582
|
}
|
|
740
583
|
let envTargets = envTargetArg ? parseEnvTargetArg(envTargetArg) : [];
|
|
584
|
+
let resolvedLink;
|
|
741
585
|
if (client.nonInteractive) {
|
|
742
586
|
const link2 = await resolveProjectContext({
|
|
743
587
|
client,
|
|
@@ -788,9 +632,9 @@ async function add(client, argv) {
|
|
|
788
632
|
{
|
|
789
633
|
status: "error",
|
|
790
634
|
reason: "not_linked",
|
|
791
|
-
message: `Your codebase isn't linked to a project on Vercel. Run
|
|
635
|
+
message: `Your codebase isn't linked to a project on Vercel. Run \`${getCommandNamePlain(
|
|
792
636
|
"link"
|
|
793
|
-
)} to begin. Use
|
|
637
|
+
)}\` to begin. Use \`--yes\` for non-interactive mode; use \`--scope\` or \`--project\` to specify a team or project. Then run your \`env add\` command.`,
|
|
794
638
|
next: [
|
|
795
639
|
{ command: buildCommandWithYes(linkArgv) },
|
|
796
640
|
{ command: buildCommandWithYes(envAddRetryArgv) }
|
|
@@ -801,6 +645,7 @@ async function add(client, argv) {
|
|
|
801
645
|
}
|
|
802
646
|
if (link2.status !== "linked")
|
|
803
647
|
return 1;
|
|
648
|
+
resolvedLink = link2;
|
|
804
649
|
const { project: project2 } = link2;
|
|
805
650
|
const org = link2.org;
|
|
806
651
|
client.config.currentTeam = org.type === "team" ? org.id : void 0;
|
|
@@ -922,7 +767,7 @@ async function add(client, argv) {
|
|
|
922
767
|
status: "action_required",
|
|
923
768
|
reason: "missing_requirements",
|
|
924
769
|
missing,
|
|
925
|
-
message: `Provide all required inputs for non-interactive mode: ${parts.join("; ")}. Example:
|
|
770
|
+
message: `Provide all required inputs for non-interactive mode: ${parts.join("; ")}. Example: \`${filledTemplate}\``,
|
|
926
771
|
next
|
|
927
772
|
},
|
|
928
773
|
1
|
|
@@ -935,147 +780,246 @@ async function add(client, argv) {
|
|
|
935
780
|
validate: (val) => val ? true : "Name cannot be empty"
|
|
936
781
|
});
|
|
937
782
|
}
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
783
|
+
if (!resolvedLink) {
|
|
784
|
+
const link2 = await resolveProjectContext({
|
|
785
|
+
client,
|
|
786
|
+
projectNameOrId: opts["--project"]
|
|
787
|
+
});
|
|
788
|
+
if (link2.status === "error") {
|
|
789
|
+
return link2.exitCode;
|
|
790
|
+
} else if (link2.status === "not_linked") {
|
|
791
|
+
if (client.nonInteractive) {
|
|
792
|
+
const preserved = getPreservedArgsForEnvAdd(client.argv);
|
|
793
|
+
const linkPreserved = preserved.filter((a, i) => {
|
|
794
|
+
if (a === "--value")
|
|
795
|
+
return false;
|
|
796
|
+
if (a.startsWith("--value="))
|
|
797
|
+
return false;
|
|
798
|
+
if (i > 0 && preserved[i - 1] === "--value")
|
|
799
|
+
return false;
|
|
800
|
+
return true;
|
|
801
|
+
});
|
|
802
|
+
const linkArgv = [
|
|
803
|
+
...client.argv.slice(0, 2),
|
|
804
|
+
"link",
|
|
805
|
+
"--scope",
|
|
806
|
+
"<scope>",
|
|
807
|
+
...linkPreserved
|
|
808
|
+
];
|
|
809
|
+
outputAgentError(
|
|
810
|
+
client,
|
|
811
|
+
{
|
|
812
|
+
status: "error",
|
|
813
|
+
reason: "not_linked",
|
|
814
|
+
message: `Your codebase isn't linked to a project on Vercel. Run ${getCommandNamePlain(
|
|
815
|
+
"link"
|
|
816
|
+
)} to begin. Use --yes for non-interactive; use --scope or --project to specify team or project. Then run your env add command.`,
|
|
817
|
+
next: [
|
|
818
|
+
{ command: buildCommandWithYes(linkArgv) },
|
|
819
|
+
{ command: buildCommandWithYes(redactEnvValueArgs(client.argv)) }
|
|
820
|
+
]
|
|
821
|
+
},
|
|
822
|
+
1
|
|
823
|
+
);
|
|
824
|
+
} else {
|
|
825
|
+
output_manager_default.error(
|
|
826
|
+
`Your codebase isn\u2019t linked to a project on Vercel. Run ${getCommandName(
|
|
827
|
+
"link"
|
|
828
|
+
)} to begin.`
|
|
829
|
+
);
|
|
950
830
|
}
|
|
831
|
+
return 1;
|
|
832
|
+
}
|
|
833
|
+
resolvedLink = link2;
|
|
834
|
+
}
|
|
835
|
+
const link = resolvedLink;
|
|
836
|
+
client.config.currentTeam = link.org.type === "team" ? link.org.id : void 0;
|
|
837
|
+
const { project } = link;
|
|
838
|
+
if (explicitType === "secret" || forceSensitive) {
|
|
839
|
+
const publicPrefixError = getPublicPrefixSecretVisibilityError(envName, {
|
|
840
|
+
visibility: explicitType === "secret" ? "secret" : void 0,
|
|
841
|
+
type: "sensitive",
|
|
842
|
+
context: "add"
|
|
843
|
+
});
|
|
844
|
+
if (publicPrefixError) {
|
|
845
|
+
if (client.nonInteractive) {
|
|
846
|
+
outputAgentError(
|
|
847
|
+
client,
|
|
848
|
+
{
|
|
849
|
+
status: "error",
|
|
850
|
+
reason: "invalid_type",
|
|
851
|
+
message: publicPrefixError
|
|
852
|
+
},
|
|
853
|
+
1
|
|
854
|
+
);
|
|
855
|
+
}
|
|
856
|
+
output_manager_default.fatal(publicPrefixError);
|
|
857
|
+
return 1;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
let keyAccepted = false;
|
|
861
|
+
while (!keyAccepted) {
|
|
862
|
+
const apiPublicPrefix2 = getApiPublicPrefix(envName);
|
|
863
|
+
const frameworkPublicPrefix = getFrameworkPublicPrefix(
|
|
864
|
+
project.framework,
|
|
865
|
+
envName
|
|
866
|
+
);
|
|
867
|
+
const globallyKnownPrefix = getPublicPrefix(envName);
|
|
868
|
+
const deferFrameworkSecretError = frameworkPublicPrefix !== null && (explicitType === "secret" || forceSensitive);
|
|
869
|
+
const keyWarnings = deferFrameworkSecretError || globallyKnownPrefix !== null && apiPublicPrefix2 === null && frameworkPublicPrefix === null ? [] : getEnvKeyWarnings(envName);
|
|
870
|
+
const sensitiveWarning = keyWarnings.find((w) => w.requiresConfirmation);
|
|
871
|
+
if (!sensitiveWarning) {
|
|
872
|
+
for (const warning of keyWarnings) {
|
|
873
|
+
printEnvAddWarning(warning.message);
|
|
874
|
+
}
|
|
875
|
+
keyAccepted = true;
|
|
876
|
+
break;
|
|
877
|
+
}
|
|
878
|
+
const nameWithoutPrefix = removePublicPrefix(envName);
|
|
879
|
+
const publicPrefix = getPublicPrefix(envName);
|
|
880
|
+
if (typeSource === "argv") {
|
|
881
|
+
for (const warning of keyWarnings) {
|
|
882
|
+
printEnvAddWarning(warning.message);
|
|
883
|
+
}
|
|
884
|
+
keyAccepted = true;
|
|
885
|
+
break;
|
|
886
|
+
}
|
|
887
|
+
const privateCommand = buildEnvAddCommandWithPreservedArgs(
|
|
888
|
+
client.argv,
|
|
889
|
+
`env add ${nameWithoutPrefix} ${envTargetArg ?? getEnvTargetPlaceholder()} --type secret --value "<value>" --yes`
|
|
890
|
+
);
|
|
891
|
+
const publicCommand = buildEnvAddCommandWithPreservedArgs(
|
|
892
|
+
client.argv,
|
|
893
|
+
`env add ${envName} ${envTargetArg ?? getEnvTargetPlaceholder()} --type config --value "<value>" --yes`
|
|
894
|
+
);
|
|
895
|
+
const humanTargetArg = envTargetArg ? ` ${envTargetArg}` : "";
|
|
896
|
+
const privateHumanCommand = buildHumanEnvAddCommand(
|
|
897
|
+
client.argv,
|
|
898
|
+
`env add ${nameWithoutPrefix}${humanTargetArg} --type secret`
|
|
899
|
+
);
|
|
900
|
+
const publicHumanCommand = buildHumanEnvAddCommand(
|
|
901
|
+
client.argv,
|
|
902
|
+
`env add ${envName}${humanTargetArg} --type config`
|
|
903
|
+
);
|
|
904
|
+
const message = `\`${envName}\` looks like a credential, and \`${publicPrefix}\` exposes its value to anyone visiting your site. Choose explicitly: rename to \`${nameWithoutPrefix}\` with \`--type secret\` to keep it private, or keep the name with \`--type config\` to expose it.`;
|
|
905
|
+
if (client.nonInteractive || opts["--yes"] || !!stdInput) {
|
|
951
906
|
if (client.nonInteractive) {
|
|
952
|
-
const nameWithoutPrefix2 = removePublicPrefix(envName);
|
|
953
907
|
outputActionRequired(client, {
|
|
954
908
|
status: "action_required",
|
|
955
|
-
reason: "
|
|
956
|
-
message
|
|
909
|
+
reason: "public_prefix_requires_type",
|
|
910
|
+
message,
|
|
957
911
|
choices: [
|
|
958
|
-
{
|
|
959
|
-
|
|
912
|
+
{
|
|
913
|
+
id: "private",
|
|
914
|
+
name: `Keep private: rename to ${nameWithoutPrefix} and use Secret`
|
|
915
|
+
},
|
|
916
|
+
{
|
|
917
|
+
id: "public",
|
|
918
|
+
name: `Expose publicly: keep ${envName} as Config`
|
|
919
|
+
}
|
|
960
920
|
],
|
|
961
921
|
next: [
|
|
962
922
|
{
|
|
963
|
-
command:
|
|
964
|
-
|
|
965
|
-
`env add ${envName} ${getEnvTargetPlaceholder()} --value "<value>" --yes`
|
|
966
|
-
),
|
|
967
|
-
when: "Leave as is"
|
|
923
|
+
command: privateCommand,
|
|
924
|
+
when: "Keep it private; replace <value> before running"
|
|
968
925
|
},
|
|
969
926
|
{
|
|
970
|
-
command:
|
|
971
|
-
|
|
972
|
-
`env add ${nameWithoutPrefix2} ${getEnvTargetPlaceholder()} --value "<value>" --yes`
|
|
973
|
-
),
|
|
974
|
-
when: "Rename"
|
|
927
|
+
command: publicCommand,
|
|
928
|
+
when: "Expose it publicly; replace <value> before running"
|
|
975
929
|
}
|
|
976
930
|
]
|
|
977
931
|
});
|
|
978
932
|
}
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
];
|
|
988
|
-
const action = await client.input.select({
|
|
989
|
-
message: "Variable name?",
|
|
990
|
-
choices: choices2
|
|
991
|
-
});
|
|
992
|
-
if (action === "c") {
|
|
993
|
-
keyAccepted = true;
|
|
994
|
-
} else if (action === "p") {
|
|
995
|
-
envName = nameWithoutPrefix;
|
|
996
|
-
output_manager_default.log(`Renamed to ${envName}`);
|
|
997
|
-
} else {
|
|
998
|
-
envName = await client.input.text({
|
|
999
|
-
message: `Name?`,
|
|
1000
|
-
validate: (val) => val ? true : "Name cannot be empty"
|
|
1001
|
-
});
|
|
1002
|
-
}
|
|
933
|
+
output_manager_default.fatal(message);
|
|
934
|
+
output_manager_default.print(` Keep it private:
|
|
935
|
+
${privateHumanCommand}
|
|
936
|
+
`);
|
|
937
|
+
output_manager_default.print(` Expose it publicly:
|
|
938
|
+
${publicHumanCommand}
|
|
939
|
+
`);
|
|
940
|
+
return 1;
|
|
1003
941
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
942
|
+
for (const warning of keyWarnings) {
|
|
943
|
+
printEnvAddWarning(warning.message);
|
|
944
|
+
}
|
|
945
|
+
const action = await client.input.select({
|
|
946
|
+
message: "How should this variable be stored?",
|
|
947
|
+
choices: [
|
|
948
|
+
{
|
|
949
|
+
name: `Keep private: rename to ${nameWithoutPrefix} and use Secret`,
|
|
950
|
+
value: "p"
|
|
951
|
+
},
|
|
952
|
+
{
|
|
953
|
+
name: `Expose to anyone visiting your site: keep ${envName} as Config`,
|
|
954
|
+
value: "c"
|
|
955
|
+
},
|
|
956
|
+
{ name: "Enter a different name", value: "r" }
|
|
957
|
+
]
|
|
958
|
+
});
|
|
959
|
+
if (action === "p") {
|
|
960
|
+
envName = nameWithoutPrefix;
|
|
961
|
+
explicitType = "secret";
|
|
962
|
+
typeSource = "prompt";
|
|
963
|
+
output_manager_default.log(`Renamed to ${envName}`);
|
|
964
|
+
} else if (action === "c") {
|
|
965
|
+
explicitType = "config";
|
|
966
|
+
typeSource = "prompt";
|
|
967
|
+
keyAccepted = true;
|
|
968
|
+
} else {
|
|
969
|
+
envName = await client.input.text({
|
|
970
|
+
message: `Name?`,
|
|
971
|
+
validate: (val) => val ? true : "Name cannot be empty"
|
|
972
|
+
});
|
|
1008
973
|
}
|
|
1009
974
|
}
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
975
|
+
let customSveltePublicPrefix;
|
|
976
|
+
const apiPublicPrefix = getApiPublicPrefix(envName);
|
|
977
|
+
const matchingFrameworkPublicPrefix = getFrameworkPublicPrefix(
|
|
978
|
+
project.framework,
|
|
979
|
+
envName
|
|
980
|
+
);
|
|
981
|
+
if (matchingFrameworkPublicPrefix !== null && (explicitType === "secret" || forceSensitive)) {
|
|
982
|
+
const message = `\`${matchingFrameworkPublicPrefix}\` exposes this value to anyone visiting your site, so \`${envName}\` cannot be kept private as a Secret. Rename the variable without the framework's public prefix to keep it private, or use \`--type config\` only if the value is safe to expose.`;
|
|
1017
983
|
if (client.nonInteractive) {
|
|
1018
|
-
const preserved = getPreservedArgsForEnvAdd(client.argv);
|
|
1019
|
-
const linkPreserved = preserved.filter((a, i) => {
|
|
1020
|
-
if (a === "--value")
|
|
1021
|
-
return false;
|
|
1022
|
-
if (a.startsWith("--value="))
|
|
1023
|
-
return false;
|
|
1024
|
-
if (i > 0 && preserved[i - 1] === "--value")
|
|
1025
|
-
return false;
|
|
1026
|
-
return true;
|
|
1027
|
-
});
|
|
1028
|
-
const linkArgv = [
|
|
1029
|
-
...client.argv.slice(0, 2),
|
|
1030
|
-
"link",
|
|
1031
|
-
...link.status === "not_linked" ? ["--scope", "<scope>"] : [],
|
|
1032
|
-
...linkPreserved
|
|
1033
|
-
];
|
|
1034
|
-
let envAddRetryArgv = redactEnvValueArgs(client.argv);
|
|
1035
|
-
if (envTargetArg === "preview" && envGitBranch === void 0) {
|
|
1036
|
-
const argvArgs = client.argv.slice(2);
|
|
1037
|
-
const addIdx = argvArgs.indexOf("add");
|
|
1038
|
-
if (addIdx !== -1) {
|
|
1039
|
-
let pos = addIdx + 1;
|
|
1040
|
-
let positionals = 0;
|
|
1041
|
-
while (pos < argvArgs.length && positionals < 3 && !argvArgs[pos].startsWith("-")) {
|
|
1042
|
-
positionals++;
|
|
1043
|
-
pos++;
|
|
1044
|
-
}
|
|
1045
|
-
const insertAt = 2 + pos;
|
|
1046
|
-
envAddRetryArgv = redactEnvValueArgs([
|
|
1047
|
-
...client.argv.slice(0, insertAt),
|
|
1048
|
-
"<gitbranch>",
|
|
1049
|
-
...client.argv.slice(insertAt)
|
|
1050
|
-
]);
|
|
1051
|
-
}
|
|
1052
|
-
}
|
|
1053
984
|
outputAgentError(
|
|
1054
985
|
client,
|
|
1055
|
-
{
|
|
1056
|
-
status: "error",
|
|
1057
|
-
reason: "not_linked",
|
|
1058
|
-
message: `Your codebase isn't linked to a project on Vercel. Run ${getCommandNamePlain(
|
|
1059
|
-
"link"
|
|
1060
|
-
)} to begin. Use --yes for non-interactive; use --scope or --project to specify team or project. Then run your env add command.`,
|
|
1061
|
-
next: [
|
|
1062
|
-
{ command: buildCommandWithYes(linkArgv) },
|
|
1063
|
-
{ command: buildCommandWithYes(envAddRetryArgv) }
|
|
1064
|
-
]
|
|
1065
|
-
},
|
|
986
|
+
{ status: "error", reason: "invalid_type", message },
|
|
1066
987
|
1
|
|
1067
988
|
);
|
|
1068
|
-
}
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
989
|
+
}
|
|
990
|
+
output_manager_default.fatal(message);
|
|
991
|
+
return 1;
|
|
992
|
+
}
|
|
993
|
+
if (project.framework === "sveltekit" || project.framework === "sveltekit-1" || project.framework === "sveltekit-2") {
|
|
994
|
+
const localPublicPrefixes = await getLocalSvelteKitPublicPrefixes(
|
|
995
|
+
link.repoRoot ?? client.cwd,
|
|
996
|
+
project.rootDirectory
|
|
997
|
+
);
|
|
998
|
+
const matchingLocalPrefix = localPublicPrefixes?.find(
|
|
999
|
+
(prefix) => envName.startsWith(prefix)
|
|
1000
|
+
);
|
|
1001
|
+
if (matchingLocalPrefix !== void 0 && apiPublicPrefix === null && matchingFrameworkPublicPrefix === null) {
|
|
1002
|
+
customSveltePublicPrefix = matchingLocalPrefix;
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
if (customSveltePublicPrefix !== void 0 && (explicitType === "secret" || forceSensitive)) {
|
|
1006
|
+
const message = customSveltePublicPrefix === "" ? "This SvelteKit project uses an empty `publicPrefix`, so every Environment Variable is exposed to the browser and cannot be kept private as a Secret. Change the SvelteKit `publicPrefix`, or use `--type config` only if the value is safe to expose." : `\`${customSveltePublicPrefix}\` exposes this value to anyone visiting your site, so \`${envName}\` cannot be kept private as a Secret. Rename the variable without the configured public prefix, or use \`--type config\` only if the value is safe to expose.`;
|
|
1007
|
+
if (client.nonInteractive) {
|
|
1008
|
+
outputAgentError(
|
|
1009
|
+
client,
|
|
1010
|
+
{ status: "error", reason: "invalid_type", message },
|
|
1011
|
+
1
|
|
1073
1012
|
);
|
|
1074
1013
|
}
|
|
1014
|
+
output_manager_default.fatal(message);
|
|
1075
1015
|
return 1;
|
|
1076
1016
|
}
|
|
1077
|
-
|
|
1078
|
-
|
|
1017
|
+
if (customSveltePublicPrefix !== void 0) {
|
|
1018
|
+
printEnvAddWarning(
|
|
1019
|
+
customSveltePublicPrefix === "" ? "This SvelteKit project uses an empty `publicPrefix`, so every Environment Variable is exposed to the browser." : `\`${customSveltePublicPrefix}\` variables are exposed to the browser by this SvelteKit project.`
|
|
1020
|
+
);
|
|
1021
|
+
}
|
|
1022
|
+
const skipConfirm = opts["--yes"] || !!stdInput || valueFromFlag !== void 0;
|
|
1079
1023
|
const [{ envs }, customEnvironments] = await Promise.all([
|
|
1080
1024
|
getEnvRecords(client, project.id, "vercel-cli:env:add"),
|
|
1081
1025
|
getCustomEnvironments(client, project.id)
|
|
@@ -1163,50 +1107,54 @@ async function add(client, argv) {
|
|
|
1163
1107
|
);
|
|
1164
1108
|
return 1;
|
|
1165
1109
|
}
|
|
1166
|
-
const forceSensitive = Boolean(opts["--sensitive"]);
|
|
1167
|
-
const forceEncrypted = Boolean(opts["--no-sensitive"]);
|
|
1168
|
-
if (forceSensitive && forceEncrypted) {
|
|
1169
|
-
output_manager_default.error(
|
|
1170
|
-
`--sensitive and --no-sensitive cannot be used together. Pick one.`
|
|
1171
|
-
);
|
|
1172
|
-
return 1;
|
|
1173
|
-
}
|
|
1174
|
-
const explicitVisibility = typeof opts["--visibility"] === "string" ? opts["--visibility"] : void 0;
|
|
1175
|
-
if (explicitVisibility === "secret" && forceEncrypted) {
|
|
1176
|
-
output_manager_default.error(
|
|
1177
|
-
"`--visibility secret` cannot be used with `--no-sensitive`. Pick one."
|
|
1178
|
-
);
|
|
1179
|
-
return 1;
|
|
1180
|
-
}
|
|
1181
|
-
if (explicitVisibility === "config" && forceSensitive) {
|
|
1182
|
-
output_manager_default.error(
|
|
1183
|
-
"`--visibility config` cannot be used with `--sensitive`. Pick one."
|
|
1184
|
-
);
|
|
1185
|
-
return 1;
|
|
1186
|
-
}
|
|
1187
1110
|
const policyOn = false;
|
|
1188
1111
|
let teamSensitivePolicyOn = false;
|
|
1112
|
+
let disjunctiveProductionSecretPolicyOn = false;
|
|
1189
1113
|
if (link.org.type === "team") {
|
|
1190
1114
|
try {
|
|
1191
1115
|
const team = await getTeamById(client, link.org.id);
|
|
1192
1116
|
teamSensitivePolicyOn = team?.sensitiveEnvironmentVariablePolicy === "on";
|
|
1117
|
+
disjunctiveProductionSecretPolicyOn = team?.disjunctiveProductionSecretPolicy === "on";
|
|
1193
1118
|
} catch {
|
|
1194
1119
|
}
|
|
1195
1120
|
}
|
|
1121
|
+
const userWasExplicit = forceSensitive || forceEncrypted || !!explicitType;
|
|
1122
|
+
const skipSensitivePrompt = userWasExplicit || client.nonInteractive || skipConfirm;
|
|
1196
1123
|
const isDevelopmentOnlyTarget = envTargets.length === 1 && envTargets[0] === "development";
|
|
1197
|
-
const userWasExplicit = forceSensitive || forceEncrypted;
|
|
1198
|
-
const skipSensitivePrompt = userWasExplicit || client.nonInteractive || skipConfirm || isDevelopmentOnlyTarget;
|
|
1199
1124
|
let isSensitive;
|
|
1200
1125
|
if (forceSensitive) {
|
|
1201
1126
|
isSensitive = true;
|
|
1202
1127
|
} else if (forceEncrypted) {
|
|
1203
1128
|
isSensitive = false;
|
|
1129
|
+
} else if (explicitType) {
|
|
1130
|
+
isSensitive = explicitType === "secret";
|
|
1131
|
+
} else if (apiPublicPrefix || matchingFrameworkPublicPrefix || customSveltePublicPrefix !== void 0) {
|
|
1132
|
+
isSensitive = false;
|
|
1133
|
+
explicitType = "config";
|
|
1134
|
+
typeSource = "inferred";
|
|
1204
1135
|
} else if (isDevelopmentOnlyTarget) {
|
|
1205
1136
|
isSensitive = false;
|
|
1137
|
+
typeSource = "inferred";
|
|
1206
1138
|
} else if (skipSensitivePrompt) {
|
|
1207
1139
|
isSensitive = true;
|
|
1140
|
+
typeSource = "default";
|
|
1208
1141
|
} else {
|
|
1209
|
-
|
|
1142
|
+
const selectedType = await client.input.select({
|
|
1143
|
+
message: "Environment Variable type?",
|
|
1144
|
+
choices: [
|
|
1145
|
+
{
|
|
1146
|
+
name: getSecretStorageChoice(
|
|
1147
|
+
envTargets,
|
|
1148
|
+
looksLikeCredentialName(envName) ? "because this name looks like a credential" : void 0
|
|
1149
|
+
),
|
|
1150
|
+
value: "secret"
|
|
1151
|
+
},
|
|
1152
|
+
{ name: "Config (can be revealed after saving)", value: "config" }
|
|
1153
|
+
]
|
|
1154
|
+
});
|
|
1155
|
+
isSensitive = selectedType === "secret";
|
|
1156
|
+
explicitType = selectedType;
|
|
1157
|
+
typeSource = "prompt";
|
|
1210
1158
|
}
|
|
1211
1159
|
if (envTargets.length > 0) {
|
|
1212
1160
|
const compatibilityError = getTargetCompatibilityError(
|
|
@@ -1286,7 +1234,7 @@ async function add(client, argv) {
|
|
|
1286
1234
|
}
|
|
1287
1235
|
envValue = await promptEnvValue(client, { isSensitive });
|
|
1288
1236
|
}
|
|
1289
|
-
|
|
1237
|
+
let { finalValue } = await validateEnvValue({
|
|
1290
1238
|
envName,
|
|
1291
1239
|
initialValue: envValue,
|
|
1292
1240
|
skipConfirm,
|
|
@@ -1407,13 +1355,189 @@ async function add(client, argv) {
|
|
|
1407
1355
|
finalType = "sensitive";
|
|
1408
1356
|
}
|
|
1409
1357
|
}
|
|
1358
|
+
while (finalType === "encrypted" && (looksLikeCredentialName(envName, customSveltePublicPrefix) || looksLikeSecretValue(finalValue))) {
|
|
1359
|
+
printEnvAddWarning(
|
|
1360
|
+
"This name or value looks like a credential. Config values can be revealed after saving."
|
|
1361
|
+
);
|
|
1362
|
+
const publicPrefix = getApiPublicPrefix(envName) ?? getFrameworkPublicPrefix(project.framework, envName) ?? customSveltePublicPrefix;
|
|
1363
|
+
if (publicPrefix !== void 0 && typeSource === "inferred") {
|
|
1364
|
+
const privateName = envName.slice(publicPrefix.length);
|
|
1365
|
+
const privateCommand = buildEnvAddCommandWithPreservedArgs(
|
|
1366
|
+
client.argv,
|
|
1367
|
+
`env add ${privateName} ${envTargets.join(
|
|
1368
|
+
","
|
|
1369
|
+
)} --type secret --value "<value>" --yes`
|
|
1370
|
+
);
|
|
1371
|
+
const publicCommand = buildEnvAddCommandWithPreservedArgs(
|
|
1372
|
+
client.argv,
|
|
1373
|
+
`env add ${envName} ${envTargets.join(
|
|
1374
|
+
","
|
|
1375
|
+
)} --type config --value "<value>" --yes`
|
|
1376
|
+
);
|
|
1377
|
+
const privateHumanCommand = buildHumanEnvAddCommand(
|
|
1378
|
+
client.argv,
|
|
1379
|
+
`env add ${privateName} ${envTargets.join(",")} --type secret`
|
|
1380
|
+
);
|
|
1381
|
+
const publicHumanCommand = buildHumanEnvAddCommand(
|
|
1382
|
+
client.argv,
|
|
1383
|
+
`env add ${envName} ${envTargets.join(",")} --type config`
|
|
1384
|
+
);
|
|
1385
|
+
const message = publicPrefix === "" ? `\`${envName}\` looks like a credential, and this SvelteKit project exposes every Environment Variable to the browser. Change the SvelteKit \`publicPrefix\` to keep it private, or use \`--type config\` only if the value is safe to expose.` : `\`${envName}\` looks like a credential, and \`${publicPrefix}\` exposes its value to anyone visiting your site. Choose explicitly: rename to \`${privateName}\` with \`--type secret\` to keep it private, or keep the name with \`--type config\` to expose it.`;
|
|
1386
|
+
if (client.nonInteractive) {
|
|
1387
|
+
outputActionRequired(client, {
|
|
1388
|
+
status: "action_required",
|
|
1389
|
+
reason: "public_prefix_requires_type",
|
|
1390
|
+
message,
|
|
1391
|
+
next: [
|
|
1392
|
+
...publicPrefix === "" ? [] : [
|
|
1393
|
+
{
|
|
1394
|
+
command: privateCommand,
|
|
1395
|
+
when: "Keep it private; replace <value> before running"
|
|
1396
|
+
}
|
|
1397
|
+
],
|
|
1398
|
+
{
|
|
1399
|
+
command: publicCommand,
|
|
1400
|
+
when: "Expose it publicly; replace <value> before running"
|
|
1401
|
+
}
|
|
1402
|
+
]
|
|
1403
|
+
});
|
|
1404
|
+
}
|
|
1405
|
+
if (opts["--yes"]) {
|
|
1406
|
+
output_manager_default.fatal(message);
|
|
1407
|
+
if (publicPrefix !== "") {
|
|
1408
|
+
output_manager_default.print(` Keep it private:
|
|
1409
|
+
${privateHumanCommand}
|
|
1410
|
+
`);
|
|
1411
|
+
}
|
|
1412
|
+
output_manager_default.print(` Expose it publicly:
|
|
1413
|
+
${publicHumanCommand}
|
|
1414
|
+
`);
|
|
1415
|
+
return 1;
|
|
1416
|
+
}
|
|
1417
|
+
const selectedAction = await client.input.select({
|
|
1418
|
+
message: "How should this variable be stored?",
|
|
1419
|
+
choices: [
|
|
1420
|
+
...publicPrefix === "" ? [] : [
|
|
1421
|
+
{
|
|
1422
|
+
name: `Keep private: rename to ${privateName} and use Secret`,
|
|
1423
|
+
value: "private"
|
|
1424
|
+
}
|
|
1425
|
+
],
|
|
1426
|
+
{
|
|
1427
|
+
name: `Expose to anyone visiting your site: keep ${envName} as Config`,
|
|
1428
|
+
value: "public"
|
|
1429
|
+
},
|
|
1430
|
+
{ name: "Enter a different value", value: "reenter" }
|
|
1431
|
+
]
|
|
1432
|
+
});
|
|
1433
|
+
if (selectedAction === "private") {
|
|
1434
|
+
envName = privateName;
|
|
1435
|
+
finalType = "sensitive";
|
|
1436
|
+
explicitType = "secret";
|
|
1437
|
+
typeSource = "prompt";
|
|
1438
|
+
output_manager_default.log(`Renamed to ${envName}`);
|
|
1439
|
+
break;
|
|
1440
|
+
}
|
|
1441
|
+
if (selectedAction === "reenter") {
|
|
1442
|
+
const reenteredValue = await promptEnvValue(client, {
|
|
1443
|
+
isSensitive: false
|
|
1444
|
+
});
|
|
1445
|
+
const validated = await validateEnvValue({
|
|
1446
|
+
envName,
|
|
1447
|
+
initialValue: reenteredValue,
|
|
1448
|
+
skipConfirm: false,
|
|
1449
|
+
promptForValue: () => promptEnvValue(client, { isSensitive: false }),
|
|
1450
|
+
selectAction: (choices2) => client.input.select({ message: "Value?", choices: choices2 }),
|
|
1451
|
+
showWarning: (msg) => printEnvAddWarning(msg),
|
|
1452
|
+
showLog: (msg) => output_manager_default.log(msg)
|
|
1453
|
+
});
|
|
1454
|
+
finalValue = validated.finalValue;
|
|
1455
|
+
continue;
|
|
1456
|
+
}
|
|
1457
|
+
} else if (typeSource !== "argv" && typeSource !== "prompt" && !opts["--yes"] && !client.nonInteractive) {
|
|
1458
|
+
const selectedType = await client.input.select({
|
|
1459
|
+
message: "Store this value as?",
|
|
1460
|
+
choices: [
|
|
1461
|
+
{
|
|
1462
|
+
name: getSecretStorageChoice(envTargets, "for this value"),
|
|
1463
|
+
value: "secret"
|
|
1464
|
+
},
|
|
1465
|
+
{
|
|
1466
|
+
name: "Config (can be revealed after saving)",
|
|
1467
|
+
value: "config"
|
|
1468
|
+
}
|
|
1469
|
+
]
|
|
1470
|
+
});
|
|
1471
|
+
if (selectedType === "secret") {
|
|
1472
|
+
finalType = "sensitive";
|
|
1473
|
+
explicitType = "secret";
|
|
1474
|
+
typeSource = "prompt";
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
break;
|
|
1478
|
+
}
|
|
1479
|
+
if (finalType === "sensitive" && customSveltePublicPrefix !== void 0 && envName.startsWith(customSveltePublicPrefix)) {
|
|
1480
|
+
printEnvAddWarning(
|
|
1481
|
+
"This SvelteKit project exposes this variable to the browser; the Secret type does not prevent that. Rename the variable without the configured public prefix to keep it private."
|
|
1482
|
+
);
|
|
1483
|
+
}
|
|
1484
|
+
if (isFlagsSecretNeedingSplit({
|
|
1485
|
+
key: envName,
|
|
1486
|
+
type: finalType,
|
|
1487
|
+
targets: envTargets.filter(isValidEnvTarget),
|
|
1488
|
+
customEnvironmentIds: envTargets.filter(
|
|
1489
|
+
(target) => !isValidEnvTarget(target)
|
|
1490
|
+
)
|
|
1491
|
+
})) {
|
|
1492
|
+
printEnvAddWarning(
|
|
1493
|
+
"FLAGS_SECRET should use a separate value for each environment so Development overrides cannot affect Preview or Production."
|
|
1494
|
+
);
|
|
1495
|
+
}
|
|
1496
|
+
const hasProduction = envTargets.includes("production");
|
|
1497
|
+
const hasNonProduction = envTargets.some((target) => target !== "production");
|
|
1498
|
+
if (finalType === "sensitive" && disjunctiveProductionSecretPolicyOn && hasProduction && hasNonProduction) {
|
|
1499
|
+
const message = "Your team requires Production and non-Production Secrets to be stored separately with different values. Run one command for Production and another for the remaining environments.";
|
|
1500
|
+
if (client.nonInteractive) {
|
|
1501
|
+
outputAgentError(
|
|
1502
|
+
client,
|
|
1503
|
+
{
|
|
1504
|
+
status: "error",
|
|
1505
|
+
reason: "production_secret_must_be_separate",
|
|
1506
|
+
message,
|
|
1507
|
+
next: [
|
|
1508
|
+
{
|
|
1509
|
+
command: buildEnvAddCommandWithPreservedArgs(
|
|
1510
|
+
client.argv,
|
|
1511
|
+
`env add ${envName} production --type secret --value "<production-value>" --yes`
|
|
1512
|
+
),
|
|
1513
|
+
when: "Set the Production Secret"
|
|
1514
|
+
},
|
|
1515
|
+
{
|
|
1516
|
+
command: buildEnvAddCommandWithPreservedArgs(
|
|
1517
|
+
client.argv,
|
|
1518
|
+
`env add ${envName} ${envTargets.filter((target) => target !== "production").join(
|
|
1519
|
+
","
|
|
1520
|
+
)} --type secret --value "<non-production-value>" --yes`
|
|
1521
|
+
),
|
|
1522
|
+
when: "Set the non-Production Secret"
|
|
1523
|
+
}
|
|
1524
|
+
]
|
|
1525
|
+
},
|
|
1526
|
+
1
|
|
1527
|
+
);
|
|
1528
|
+
}
|
|
1529
|
+
output_manager_default.fatal(message);
|
|
1530
|
+
return 1;
|
|
1531
|
+
}
|
|
1410
1532
|
const upsert = opts["--force"] ? "true" : "";
|
|
1411
1533
|
const { visibility, error: visibilityError } = resolveEnvVarVisibility({
|
|
1412
|
-
explicitVisibility,
|
|
1534
|
+
explicitVisibility: explicitType,
|
|
1535
|
+
explicitOptionSource: typeOption.source,
|
|
1413
1536
|
type: finalType,
|
|
1414
1537
|
key: envName,
|
|
1415
1538
|
envTargets,
|
|
1416
|
-
teamSensitivePolicyOn
|
|
1539
|
+
teamSensitivePolicyOn,
|
|
1540
|
+
context: "add"
|
|
1417
1541
|
});
|
|
1418
1542
|
if (visibilityError) {
|
|
1419
1543
|
if (client.nonInteractive) {
|
|
@@ -1421,13 +1545,13 @@ async function add(client, argv) {
|
|
|
1421
1545
|
client,
|
|
1422
1546
|
{
|
|
1423
1547
|
status: "error",
|
|
1424
|
-
reason: "
|
|
1548
|
+
reason: "invalid_type",
|
|
1425
1549
|
message: visibilityError
|
|
1426
1550
|
},
|
|
1427
1551
|
1
|
|
1428
1552
|
);
|
|
1429
1553
|
}
|
|
1430
|
-
output_manager_default.
|
|
1554
|
+
output_manager_default.fatal(visibilityError);
|
|
1431
1555
|
return 1;
|
|
1432
1556
|
}
|
|
1433
1557
|
try {
|
|
@@ -1445,13 +1569,18 @@ async function add(client, argv) {
|
|
|
1445
1569
|
);
|
|
1446
1570
|
} catch (err) {
|
|
1447
1571
|
if (client.nonInteractive && isAPIError(err)) {
|
|
1448
|
-
const
|
|
1572
|
+
const productionSecretPolicyError = getProductionSecretPolicyErrorKind(
|
|
1573
|
+
err.serverMessage
|
|
1574
|
+
);
|
|
1575
|
+
const reason = productionSecretPolicyError ? productionSecretPolicyError === "different-values" ? "production_secret_requires_different_value" : "production_secret_must_be_separate" : err.slug || (err.serverMessage?.toLowerCase().includes("branch") ? "branch_not_found" : "api_error");
|
|
1449
1576
|
outputAgentError(
|
|
1450
1577
|
client,
|
|
1451
1578
|
{
|
|
1452
1579
|
status: "error",
|
|
1453
1580
|
reason,
|
|
1454
|
-
message: err.serverMessage
|
|
1581
|
+
message: productionSecretPolicyError ? `${err.serverMessage} ${getProductionSecretPolicyRecovery(
|
|
1582
|
+
productionSecretPolicyError
|
|
1583
|
+
)}` : err.serverMessage
|
|
1455
1584
|
},
|
|
1456
1585
|
1
|
|
1457
1586
|
);
|
|
@@ -1472,13 +1601,30 @@ async function add(client, argv) {
|
|
|
1472
1601
|
Boolean(opts["--force"]),
|
|
1473
1602
|
visibility
|
|
1474
1603
|
);
|
|
1475
|
-
|
|
1476
|
-
|
|
1604
|
+
if (typeSource === "default") {
|
|
1605
|
+
output_manager_default.print(
|
|
1606
|
+
` ${import_chalk.default.dim(getDefaultSecretStorageGuidance(envTargets))}
|
|
1607
|
+
`
|
|
1608
|
+
);
|
|
1609
|
+
}
|
|
1610
|
+
const { isAgent } = await determineAgent();
|
|
1611
|
+
const guidanceMode = isGuidanceEnabled(
|
|
1612
|
+
client,
|
|
1613
|
+
parsedArgs.flags["--guidance"],
|
|
1614
|
+
isAgent
|
|
1615
|
+
);
|
|
1477
1616
|
if (guidanceMode) {
|
|
1478
|
-
const projectFlag = opts["--project"] ? ` --project ${opts["--project"]}` : "";
|
|
1479
1617
|
suggestNextCommands([
|
|
1480
|
-
|
|
1481
|
-
|
|
1618
|
+
{
|
|
1619
|
+
description: "List Environment Variables",
|
|
1620
|
+
command: withGlobalFlags(client, "env ls", { preserveProject: true })
|
|
1621
|
+
},
|
|
1622
|
+
{
|
|
1623
|
+
description: "Pull Development Environment Variables into .env.local",
|
|
1624
|
+
command: withGlobalFlags(client, "env pull", {
|
|
1625
|
+
preserveProject: true
|
|
1626
|
+
})
|
|
1627
|
+
}
|
|
1482
1628
|
]);
|
|
1483
1629
|
}
|
|
1484
1630
|
return 0;
|
|
@@ -1606,7 +1752,7 @@ async function ls(client, argv) {
|
|
|
1606
1752
|
const jsonOutput = {
|
|
1607
1753
|
envs: envs.map((env) => ({
|
|
1608
1754
|
key: env.key,
|
|
1609
|
-
value:
|
|
1755
|
+
value: isSecretEnvVar(env) ? void 0 : env.value,
|
|
1610
1756
|
type: env.type,
|
|
1611
1757
|
visibility: env.visibility,
|
|
1612
1758
|
target: env.target,
|
|
@@ -1631,13 +1777,31 @@ async function ls(client, argv) {
|
|
|
1631
1777
|
}
|
|
1632
1778
|
if (!asJson) {
|
|
1633
1779
|
const { isAgent } = await determineAgent2();
|
|
1634
|
-
const guidanceMode =
|
|
1780
|
+
const guidanceMode = isGuidanceEnabled(
|
|
1781
|
+
client,
|
|
1782
|
+
parsedArgs.flags["--guidance"],
|
|
1783
|
+
isAgent
|
|
1784
|
+
);
|
|
1635
1785
|
if (guidanceMode) {
|
|
1636
|
-
const projectFlag = projectName ? ` --project ${projectName}` : "";
|
|
1637
1786
|
suggestNextCommands([
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1787
|
+
{
|
|
1788
|
+
description: "Add an Environment Variable",
|
|
1789
|
+
command: withGlobalFlags(client, "env add", {
|
|
1790
|
+
preserveProject: true
|
|
1791
|
+
})
|
|
1792
|
+
},
|
|
1793
|
+
{
|
|
1794
|
+
description: "Remove an Environment Variable",
|
|
1795
|
+
command: withGlobalFlags(client, "env rm", {
|
|
1796
|
+
preserveProject: true
|
|
1797
|
+
})
|
|
1798
|
+
},
|
|
1799
|
+
{
|
|
1800
|
+
description: "Pull Development Environment Variables into .env.local",
|
|
1801
|
+
command: withGlobalFlags(client, "env pull", {
|
|
1802
|
+
preserveProject: true
|
|
1803
|
+
})
|
|
1804
|
+
}
|
|
1641
1805
|
]);
|
|
1642
1806
|
}
|
|
1643
1807
|
}
|
|
@@ -1658,7 +1822,7 @@ function getTable(link, records, customEnvironments) {
|
|
|
1658
1822
|
}
|
|
1659
1823
|
function getRow(link, env, customEnvironments) {
|
|
1660
1824
|
let value;
|
|
1661
|
-
if (
|
|
1825
|
+
if (isSecretEnvVar(env)) {
|
|
1662
1826
|
value = import_chalk2.default.gray.italic("Hidden");
|
|
1663
1827
|
} else if (env.type === "system") {
|
|
1664
1828
|
value = import_chalk2.default.gray.italic(env.value);
|
|
@@ -1675,14 +1839,14 @@ function getRow(link, env, customEnvironments) {
|
|
|
1675
1839
|
env.createdAt ? `${(0, import_ms.default)(now - env.createdAt)} ago` : ""
|
|
1676
1840
|
];
|
|
1677
1841
|
}
|
|
1678
|
-
function isSensitiveEnvironmentVariable(env) {
|
|
1679
|
-
return env.type === "sensitive" || env.visibility === "secret";
|
|
1680
|
-
}
|
|
1681
1842
|
function getEnvironmentVariableTypeLabel(env) {
|
|
1682
|
-
if (
|
|
1683
|
-
return "
|
|
1843
|
+
if (isSecretEnvVar(env)) {
|
|
1844
|
+
return "Secret";
|
|
1845
|
+
}
|
|
1846
|
+
if (env.type === "system") {
|
|
1847
|
+
return "System";
|
|
1684
1848
|
}
|
|
1685
|
-
return
|
|
1849
|
+
return "Config";
|
|
1686
1850
|
}
|
|
1687
1851
|
|
|
1688
1852
|
// src/commands/env/rm.ts
|
|
@@ -1733,6 +1897,10 @@ var EnvRmTelemetryClient = class extends TelemetryClient {
|
|
|
1733
1897
|
};
|
|
1734
1898
|
|
|
1735
1899
|
// src/commands/env/rm.ts
|
|
1900
|
+
function printEnvRmWarning(message) {
|
|
1901
|
+
output_manager_default.print(`${import_chalk3.default.yellow("!")} ${message}
|
|
1902
|
+
`);
|
|
1903
|
+
}
|
|
1736
1904
|
async function rm(client, argv) {
|
|
1737
1905
|
const telemetryClient = new EnvRmTelemetryClient({
|
|
1738
1906
|
opts: {
|
|
@@ -1766,9 +1934,9 @@ async function rm(client, argv) {
|
|
|
1766
1934
|
{
|
|
1767
1935
|
status: "error",
|
|
1768
1936
|
reason: "invalid_arguments",
|
|
1769
|
-
message: `Invalid number of arguments. Usage:
|
|
1937
|
+
message: `Invalid number of arguments. Usage: \`${getCommandNamePlain(
|
|
1770
1938
|
`env rm <name> ${getEnvTargetPlaceholder()} <gitbranch>`
|
|
1771
|
-
)}
|
|
1939
|
+
)}\``
|
|
1772
1940
|
},
|
|
1773
1941
|
1
|
|
1774
1942
|
);
|
|
@@ -1809,9 +1977,9 @@ async function rm(client, argv) {
|
|
|
1809
1977
|
{
|
|
1810
1978
|
status: "error",
|
|
1811
1979
|
reason: "not_linked",
|
|
1812
|
-
message: `Your codebase isn't linked to a project on Vercel. Run
|
|
1980
|
+
message: `Your codebase isn't linked to a project on Vercel. Run \`${getCommandNamePlain(
|
|
1813
1981
|
"link"
|
|
1814
|
-
)} to begin. Use
|
|
1982
|
+
)}\` to begin. Use \`--yes\` for non-interactive; use \`--scope\` or \`--project\` to specify team or project.`,
|
|
1815
1983
|
next: [
|
|
1816
1984
|
{ command: buildCommandWithYes(linkArgv) },
|
|
1817
1985
|
{ command: buildCommandWithYes(client.argv) }
|
|
@@ -1837,7 +2005,7 @@ async function rm(client, argv) {
|
|
|
1837
2005
|
{
|
|
1838
2006
|
status: "action_required",
|
|
1839
2007
|
reason: "missing_name",
|
|
1840
|
-
message: "Provide the variable name as an argument. Example: vercel env rm <name> --yes",
|
|
2008
|
+
message: "Provide the variable name as an argument. Example: `vercel env rm <name> --yes`",
|
|
1841
2009
|
next: [
|
|
1842
2010
|
{
|
|
1843
2011
|
command: buildEnvRmCommandWithPreservedArgs(
|
|
@@ -1912,6 +2080,15 @@ async function rm(client, argv) {
|
|
|
1912
2080
|
envs = envs.filter((env2) => env2.id === id);
|
|
1913
2081
|
}
|
|
1914
2082
|
const env = envs[0];
|
|
2083
|
+
const shouldWarnAboutRotation = shouldConfirmRotationBeforeDelete({
|
|
2084
|
+
key: env.key,
|
|
2085
|
+
type: env.type,
|
|
2086
|
+
hasPublicPrefix: getPublicPrefix(env.key) !== null
|
|
2087
|
+
});
|
|
2088
|
+
const rotationWarning = "Removing this variable from Vercel does not revoke the credential. Rotate or disable it at its provider.";
|
|
2089
|
+
if (shouldWarnAboutRotation) {
|
|
2090
|
+
printEnvRmWarning(rotationWarning);
|
|
2091
|
+
}
|
|
1915
2092
|
const skipConfirmation = opts["--yes"];
|
|
1916
2093
|
if (!skipConfirmation) {
|
|
1917
2094
|
if (client.nonInteractive) {
|
|
@@ -1920,18 +2097,18 @@ async function rm(client, argv) {
|
|
|
1920
2097
|
{
|
|
1921
2098
|
status: "action_required",
|
|
1922
2099
|
reason: "confirmation_required",
|
|
1923
|
-
message: `Removing Environment Variable ${env.key}. Use --yes to confirm.`,
|
|
2100
|
+
message: `Removing Environment Variable ${env.key}. ${shouldWarnAboutRotation ? `${rotationWarning} ` : ""}Use --yes to confirm.`,
|
|
1924
2101
|
next: [{ command: buildCommandWithYes(client.argv) }]
|
|
1925
2102
|
},
|
|
1926
2103
|
1
|
|
1927
2104
|
);
|
|
1928
2105
|
}
|
|
1929
2106
|
if (!await client.input.confirm(
|
|
1930
|
-
`
|
|
2107
|
+
`Remove ${param(env.key)} from ${formatEnvironments(
|
|
1931
2108
|
link,
|
|
1932
2109
|
env,
|
|
1933
2110
|
customEnvironments
|
|
1934
|
-
)} in Project ${import_chalk3.default.bold(project.name)}
|
|
2111
|
+
)} in Project ${import_chalk3.default.bold(project.name)}?`,
|
|
1935
2112
|
false
|
|
1936
2113
|
)) {
|
|
1937
2114
|
output_manager_default.log("Canceled");
|
|
@@ -1973,7 +2150,21 @@ async function rm(client, argv) {
|
|
|
1973
2150
|
|
|
1974
2151
|
// src/commands/env/run.ts
|
|
1975
2152
|
var import_env = __toESM(require_dist3(), 1);
|
|
2153
|
+
var import_chalk4 = __toESM(require_source(), 1);
|
|
1976
2154
|
var import_execa = __toESM(require_execa(), 1);
|
|
2155
|
+
function printEnvRunWarning(message) {
|
|
2156
|
+
output_manager_default.print(`${import_chalk4.default.yellow("!")} ${message}
|
|
2157
|
+
`);
|
|
2158
|
+
}
|
|
2159
|
+
function omitUnavailableSecretPlaceholders(localEnv, secretKeys) {
|
|
2160
|
+
const safeLocalEnv = { ...localEnv };
|
|
2161
|
+
for (const key of secretKeys) {
|
|
2162
|
+
if (safeLocalEnv[key] === SENSITIVE_ENV_VALUE_PLACEHOLDER) {
|
|
2163
|
+
delete safeLocalEnv[key];
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
return safeLocalEnv;
|
|
2167
|
+
}
|
|
1977
2168
|
function parseRunArgs(argv) {
|
|
1978
2169
|
const argvIndex = argv.indexOf("--");
|
|
1979
2170
|
const hasDoubleDash = argvIndex !== -1;
|
|
@@ -2002,6 +2193,16 @@ async function run(client, telemetry) {
|
|
|
2002
2193
|
return 1;
|
|
2003
2194
|
}
|
|
2004
2195
|
if (userCommand.length === 0) {
|
|
2196
|
+
outputActionRequired(
|
|
2197
|
+
client,
|
|
2198
|
+
{
|
|
2199
|
+
status: "action_required",
|
|
2200
|
+
reason: "missing_command",
|
|
2201
|
+
message: "No command provided. Use `--` to separate Vercel flags from your command.",
|
|
2202
|
+
next: [{ command: getCommandNamePlain("env run -- <command>") }]
|
|
2203
|
+
},
|
|
2204
|
+
1
|
|
2205
|
+
);
|
|
2005
2206
|
output_manager_default.error(
|
|
2006
2207
|
`No command provided. Use \`--\` to separate vercel flags from your command.`
|
|
2007
2208
|
);
|
|
@@ -2016,6 +2217,16 @@ async function run(client, telemetry) {
|
|
|
2016
2217
|
if (link.status === "error") {
|
|
2017
2218
|
return link.exitCode;
|
|
2018
2219
|
} else if (link.status === "not_linked") {
|
|
2220
|
+
outputActionRequired(
|
|
2221
|
+
client,
|
|
2222
|
+
{
|
|
2223
|
+
status: "action_required",
|
|
2224
|
+
reason: "not_linked",
|
|
2225
|
+
message: "Your codebase isn't linked to a project on Vercel. Run `vercel link`, then retry this command.",
|
|
2226
|
+
next: [{ command: getCommandNamePlain("link") }]
|
|
2227
|
+
},
|
|
2228
|
+
1
|
|
2229
|
+
);
|
|
2019
2230
|
output_manager_default.error(
|
|
2020
2231
|
`Your codebase isn't linked to a project on Vercel. Run ${getCommandName(
|
|
2021
2232
|
"link"
|
|
@@ -2049,6 +2260,45 @@ async function run(client, telemetry) {
|
|
|
2049
2260
|
} catch (err) {
|
|
2050
2261
|
output_manager_default.debug(`Failed to load local env files: ${err}`);
|
|
2051
2262
|
}
|
|
2263
|
+
const localPlaceholderKeys = Object.entries(localEnv).filter(([, value]) => value === SENSITIVE_ENV_VALUE_PLACEHOLDER).map(([key]) => key);
|
|
2264
|
+
const safeLocalEnv = omitUnavailableSecretPlaceholders(
|
|
2265
|
+
localEnv,
|
|
2266
|
+
localPlaceholderKeys
|
|
2267
|
+
);
|
|
2268
|
+
const processPlaceholderKeys = Object.keys(records.env).filter(
|
|
2269
|
+
(key) => process.env[key] === SENSITIVE_ENV_VALUE_PLACEHOLDER
|
|
2270
|
+
);
|
|
2271
|
+
const safeProcessEnv = omitUnavailableSecretPlaceholders(
|
|
2272
|
+
process.env,
|
|
2273
|
+
processPlaceholderKeys
|
|
2274
|
+
);
|
|
2275
|
+
const unavailableCandidateKeys = new Set(
|
|
2276
|
+
Object.entries(records.env).filter(
|
|
2277
|
+
([key, value]) => !value && !safeLocalEnv[key] && !safeProcessEnv[key]
|
|
2278
|
+
).map(([key]) => key)
|
|
2279
|
+
);
|
|
2280
|
+
if (unavailableCandidateKeys.size > 0) {
|
|
2281
|
+
try {
|
|
2282
|
+
const { envs } = await getEnvRecords(
|
|
2283
|
+
client,
|
|
2284
|
+
link.project.id,
|
|
2285
|
+
"vercel-cli:env:run",
|
|
2286
|
+
{ target: environment, gitBranch }
|
|
2287
|
+
);
|
|
2288
|
+
const unavailableSecretKeys = envs.filter(
|
|
2289
|
+
(env) => isSecretEnvVar(env) && unavailableCandidateKeys.has(env.key)
|
|
2290
|
+
);
|
|
2291
|
+
if (unavailableSecretKeys.length > 0) {
|
|
2292
|
+
printEnvRunWarning(
|
|
2293
|
+
`${getUnavailableSecretValuesMessage(
|
|
2294
|
+
environment,
|
|
2295
|
+
unavailableSecretKeys.length
|
|
2296
|
+
)}${getLocalSecretFallbackMessage(unavailableSecretKeys.length)}`
|
|
2297
|
+
);
|
|
2298
|
+
}
|
|
2299
|
+
} catch {
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
2052
2302
|
try {
|
|
2053
2303
|
const result = await (0, import_execa.default)(userCommand[0], userCommand.slice(1), {
|
|
2054
2304
|
cwd: client.cwd,
|
|
@@ -2056,8 +2306,8 @@ async function run(client, telemetry) {
|
|
|
2056
2306
|
reject: false,
|
|
2057
2307
|
env: {
|
|
2058
2308
|
...records.env,
|
|
2059
|
-
...
|
|
2060
|
-
...
|
|
2309
|
+
...safeLocalEnv,
|
|
2310
|
+
...safeProcessEnv
|
|
2061
2311
|
}
|
|
2062
2312
|
});
|
|
2063
2313
|
if (result instanceof Error && typeof result.exitCode !== "number") {
|
|
@@ -2072,10 +2322,10 @@ async function run(client, telemetry) {
|
|
|
2072
2322
|
}
|
|
2073
2323
|
|
|
2074
2324
|
// src/commands/env/update.ts
|
|
2075
|
-
var
|
|
2325
|
+
var import_chalk5 = __toESM(require_source(), 1);
|
|
2076
2326
|
|
|
2077
2327
|
// src/util/env/update-env-record.ts
|
|
2078
|
-
var
|
|
2328
|
+
var import_constants3 = __toESM(require_dist2(), 1);
|
|
2079
2329
|
async function updateEnvRecord(client, projectId, envId, type, key, value, targets, gitBranch, visibility) {
|
|
2080
2330
|
output_manager_default.debug(
|
|
2081
2331
|
`Updating ${type} Environment Variable ${key} in ${targets.length} targets`
|
|
@@ -2083,7 +2333,7 @@ async function updateEnvRecord(client, projectId, envId, type, key, value, targe
|
|
|
2083
2333
|
const target = [];
|
|
2084
2334
|
const customEnvironmentIds = [];
|
|
2085
2335
|
for (const t of targets) {
|
|
2086
|
-
const arr =
|
|
2336
|
+
const arr = import_constants3.PROJECT_ENV_TARGET.includes(t) ? target : customEnvironmentIds;
|
|
2087
2337
|
arr.push(t);
|
|
2088
2338
|
}
|
|
2089
2339
|
const body = {
|
|
@@ -2159,9 +2409,51 @@ var EnvUpdateTelemetryClient = class extends TelemetryClient {
|
|
|
2159
2409
|
});
|
|
2160
2410
|
}
|
|
2161
2411
|
}
|
|
2412
|
+
trackCliOptionType(type) {
|
|
2413
|
+
if (type) {
|
|
2414
|
+
const validTypes = ["config", "secret"];
|
|
2415
|
+
this.trackCliOption({
|
|
2416
|
+
option: "type",
|
|
2417
|
+
value: validTypes.includes(type) ? type : this.redactedValue
|
|
2418
|
+
});
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2162
2421
|
};
|
|
2163
2422
|
|
|
2164
2423
|
// src/commands/env/update.ts
|
|
2424
|
+
function looksLikeCredentialName2(key, publicPrefix = getPublicPrefix(key)) {
|
|
2425
|
+
return looksLikeSecret(publicPrefix ? key.slice(publicPrefix.length) : key);
|
|
2426
|
+
}
|
|
2427
|
+
function printEnvUpdateWarning(message) {
|
|
2428
|
+
output_manager_default.print(`${import_chalk5.default.yellow("!")} ${message}
|
|
2429
|
+
`);
|
|
2430
|
+
}
|
|
2431
|
+
function omitEnvValueArgs(argv) {
|
|
2432
|
+
const out = [];
|
|
2433
|
+
for (let i = 0; i < argv.length; i++) {
|
|
2434
|
+
if (argv[i] === "--value") {
|
|
2435
|
+
i++;
|
|
2436
|
+
continue;
|
|
2437
|
+
}
|
|
2438
|
+
if (argv[i].startsWith("--value="))
|
|
2439
|
+
continue;
|
|
2440
|
+
out.push(argv[i]);
|
|
2441
|
+
}
|
|
2442
|
+
return out;
|
|
2443
|
+
}
|
|
2444
|
+
function formatTargetArg(targets, customEnvironments) {
|
|
2445
|
+
return targets.map(
|
|
2446
|
+
(target) => customEnvironments.find(
|
|
2447
|
+
(environment) => environment.id === target || environment.slug === target
|
|
2448
|
+
)?.slug ?? target
|
|
2449
|
+
).join(",");
|
|
2450
|
+
}
|
|
2451
|
+
function promptEnvUpdateValue(client, envName, isSecret) {
|
|
2452
|
+
return client.input.text({
|
|
2453
|
+
message: `What's the new value of ${envName}?`,
|
|
2454
|
+
...isSecret ? { transformer: (value) => "*".repeat(value.length) } : {}
|
|
2455
|
+
});
|
|
2456
|
+
}
|
|
2165
2457
|
async function update(client, argv) {
|
|
2166
2458
|
let parsedArgs;
|
|
2167
2459
|
const flagsSpecification = getFlagsSpecification(updateSubcommand.options);
|
|
@@ -2186,6 +2478,12 @@ async function update(client, argv) {
|
|
|
2186
2478
|
const valueFromFlag = typeof opts["--value"] === "string" ? opts["--value"] : void 0;
|
|
2187
2479
|
const stdInput = await readStandardInput(client.stdin);
|
|
2188
2480
|
let [envName, envTargetArg, envGitBranch] = args;
|
|
2481
|
+
const typeOption = resolveEnvVarTypeOption({
|
|
2482
|
+
type: typeof opts["--type"] === "string" ? opts["--type"] : void 0,
|
|
2483
|
+
visibility: typeof opts["--visibility"] === "string" ? opts["--visibility"] : void 0
|
|
2484
|
+
});
|
|
2485
|
+
let explicitType = typeOption.explicitVisibility;
|
|
2486
|
+
const typeWasExplicit = explicitType !== void 0 || Boolean(opts["--sensitive"]);
|
|
2189
2487
|
const telemetryClient = new EnvUpdateTelemetryClient({
|
|
2190
2488
|
opts: {
|
|
2191
2489
|
store: client.telemetryEventStore
|
|
@@ -2196,10 +2494,49 @@ async function update(client, argv) {
|
|
|
2196
2494
|
telemetryClient.trackCliArgumentGitBranch(envGitBranch);
|
|
2197
2495
|
telemetryClient.trackCliFlagSensitive(opts["--sensitive"]);
|
|
2198
2496
|
telemetryClient.trackCliFlagYes(opts["--yes"]);
|
|
2199
|
-
telemetryClient.trackCliOptionValue(
|
|
2497
|
+
telemetryClient.trackCliOptionValue(
|
|
2498
|
+
valueFromFlag === void 0 ? void 0 : "<redacted>"
|
|
2499
|
+
);
|
|
2500
|
+
telemetryClient.trackCliOptionType(
|
|
2501
|
+
typeof opts["--type"] === "string" ? opts["--type"] : void 0
|
|
2502
|
+
);
|
|
2200
2503
|
telemetryClient.trackCliOptionVisibility(
|
|
2201
2504
|
typeof opts["--visibility"] === "string" ? opts["--visibility"] : void 0
|
|
2202
2505
|
);
|
|
2506
|
+
if (typeOption.error) {
|
|
2507
|
+
if (client.nonInteractive) {
|
|
2508
|
+
outputAgentError(
|
|
2509
|
+
client,
|
|
2510
|
+
{
|
|
2511
|
+
status: "error",
|
|
2512
|
+
reason: typeOption.errorReason ?? "invalid_type",
|
|
2513
|
+
message: typeOption.error
|
|
2514
|
+
},
|
|
2515
|
+
1
|
|
2516
|
+
);
|
|
2517
|
+
}
|
|
2518
|
+
output_manager_default.fatal(typeOption.error);
|
|
2519
|
+
return 1;
|
|
2520
|
+
}
|
|
2521
|
+
if (typeOption.usedDeprecatedVisibility) {
|
|
2522
|
+
printEnvUpdateWarning(ENV_VISIBILITY_DEPRECATION_MESSAGE);
|
|
2523
|
+
}
|
|
2524
|
+
if (explicitType === "config" && opts["--sensitive"]) {
|
|
2525
|
+
const message = "`--type config` cannot be used with `--sensitive`. Pick one.";
|
|
2526
|
+
if (client.nonInteractive) {
|
|
2527
|
+
outputAgentError(
|
|
2528
|
+
client,
|
|
2529
|
+
{
|
|
2530
|
+
status: "error",
|
|
2531
|
+
reason: "conflicting_type_flags",
|
|
2532
|
+
message
|
|
2533
|
+
},
|
|
2534
|
+
1
|
|
2535
|
+
);
|
|
2536
|
+
}
|
|
2537
|
+
output_manager_default.fatal(message);
|
|
2538
|
+
return 1;
|
|
2539
|
+
}
|
|
2203
2540
|
if (args.length > 3) {
|
|
2204
2541
|
if (client.nonInteractive) {
|
|
2205
2542
|
outputAgentError(
|
|
@@ -2207,9 +2544,9 @@ async function update(client, argv) {
|
|
|
2207
2544
|
{
|
|
2208
2545
|
status: "error",
|
|
2209
2546
|
reason: "invalid_arguments",
|
|
2210
|
-
message: `Invalid number of arguments. Usage:
|
|
2547
|
+
message: `Invalid number of arguments. Usage: \`${getCommandNamePlain(
|
|
2211
2548
|
`env update <name> ${getEnvTargetPlaceholder()} <gitbranch>`
|
|
2212
|
-
)}
|
|
2549
|
+
)}\``
|
|
2213
2550
|
},
|
|
2214
2551
|
1
|
|
2215
2552
|
);
|
|
@@ -2301,9 +2638,9 @@ async function update(client, argv) {
|
|
|
2301
2638
|
return link.exitCode;
|
|
2302
2639
|
} else if (link.status === "not_linked") {
|
|
2303
2640
|
if (client.nonInteractive) {
|
|
2304
|
-
const preserved =
|
|
2305
|
-
(
|
|
2306
|
-
);
|
|
2641
|
+
const preserved = omitEnvValueArgs(
|
|
2642
|
+
getPreservedArgsForEnvUpdate(client.argv)
|
|
2643
|
+
).filter((a) => a !== "--yes" && a !== "-y");
|
|
2307
2644
|
const linkArgv = [
|
|
2308
2645
|
...client.argv.slice(0, 2),
|
|
2309
2646
|
"link",
|
|
@@ -2321,7 +2658,9 @@ async function update(client, argv) {
|
|
|
2321
2658
|
)} to begin. Use --yes for non-interactive; use --scope or --project to specify team or project.`,
|
|
2322
2659
|
next: [
|
|
2323
2660
|
{ command: buildCommandWithYes(linkArgv) },
|
|
2324
|
-
{
|
|
2661
|
+
{
|
|
2662
|
+
command: buildCommandWithYes(redactEnvValueArgs(client.argv))
|
|
2663
|
+
}
|
|
2325
2664
|
]
|
|
2326
2665
|
},
|
|
2327
2666
|
1
|
|
@@ -2404,7 +2743,7 @@ async function update(client, argv) {
|
|
|
2404
2743
|
{
|
|
2405
2744
|
command: buildEnvUpdateCommandWithPreservedArgs(
|
|
2406
2745
|
client.argv,
|
|
2407
|
-
`env update ${envName} ${getEnvTargetPlaceholder()} <gitbranch
|
|
2746
|
+
`env update ${envName} ${getEnvTargetPlaceholder()} <gitbranch> --value "<value>" --yes`
|
|
2408
2747
|
)
|
|
2409
2748
|
}
|
|
2410
2749
|
]
|
|
@@ -2439,7 +2778,7 @@ async function update(client, argv) {
|
|
|
2439
2778
|
{
|
|
2440
2779
|
command: buildEnvUpdateCommandWithPreservedArgs(
|
|
2441
2780
|
client.argv,
|
|
2442
|
-
`env update ${envName} ${getEnvTargetPlaceholder()} <gitbranch
|
|
2781
|
+
`env update ${envName} ${getEnvTargetPlaceholder()} <gitbranch> --value "<value>" --yes`
|
|
2443
2782
|
)
|
|
2444
2783
|
}
|
|
2445
2784
|
]
|
|
@@ -2460,15 +2799,178 @@ async function update(client, argv) {
|
|
|
2460
2799
|
});
|
|
2461
2800
|
selectedEnv = matchingEnvs[selectedIndex];
|
|
2462
2801
|
}
|
|
2802
|
+
let customSveltePublicPrefix;
|
|
2803
|
+
const apiPublicPrefix = getApiPublicPrefix(envName);
|
|
2804
|
+
const frameworkPublicPrefix = getFrameworkPublicPrefix(
|
|
2805
|
+
project.framework,
|
|
2806
|
+
envName
|
|
2807
|
+
);
|
|
2808
|
+
if (project.framework === "sveltekit" || project.framework === "sveltekit-1" || project.framework === "sveltekit-2") {
|
|
2809
|
+
const localPublicPrefixes = await getLocalSvelteKitPublicPrefixes(
|
|
2810
|
+
link.repoRoot ?? client.cwd,
|
|
2811
|
+
project.rootDirectory
|
|
2812
|
+
);
|
|
2813
|
+
const matchingLocalPrefix = localPublicPrefixes?.find(
|
|
2814
|
+
(prefix) => envName.startsWith(prefix)
|
|
2815
|
+
);
|
|
2816
|
+
if (matchingLocalPrefix !== void 0 && apiPublicPrefix === null && frameworkPublicPrefix === null) {
|
|
2817
|
+
customSveltePublicPrefix = matchingLocalPrefix;
|
|
2818
|
+
}
|
|
2819
|
+
}
|
|
2820
|
+
const targets = Array.isArray(selectedEnv.target) ? selectedEnv.target : [selectedEnv.target].filter(
|
|
2821
|
+
(r) => Boolean(r)
|
|
2822
|
+
);
|
|
2823
|
+
const allTargets = [...targets, ...selectedEnv.customEnvironmentIds || []];
|
|
2824
|
+
const selectedEnvIsSecret = isSecretEnvVar(selectedEnv);
|
|
2825
|
+
if (explicitType === "config" && selectedEnvIsSecret) {
|
|
2826
|
+
const removeTargetArg = envTargetArg || targets[0] || allTargets[0] || getEnvTargetPlaceholder();
|
|
2827
|
+
const addTargetArg = formatTargetArg(allTargets, customEnvironments) || removeTargetArg;
|
|
2828
|
+
const removeBranchArg = selectedEnv.gitBranch ? ` ${quoteArg(selectedEnv.gitBranch)}` : "";
|
|
2829
|
+
const addBranchArg = selectedEnv.gitBranch ? ` --git-branch ${quoteArg(selectedEnv.gitBranch)}` : "";
|
|
2830
|
+
const globalFlags = getGlobalFlagsFromArgs(client.argv.slice(2), {
|
|
2831
|
+
preserveProject: true
|
|
2832
|
+
});
|
|
2833
|
+
const humanGlobalFlags = globalFlags.filter(
|
|
2834
|
+
(flag) => !flag.startsWith("--non-interactive")
|
|
2835
|
+
);
|
|
2836
|
+
const globalSuffix = globalFlags.length > 0 ? ` ${globalFlags.map(quoteArg).join(" ")}` : "";
|
|
2837
|
+
const humanGlobalSuffix = humanGlobalFlags.length > 0 ? ` ${humanGlobalFlags.map(quoteArg).join(" ")}` : "";
|
|
2838
|
+
const removeCommand = getCommandNamePlain(
|
|
2839
|
+
`env rm ${envName} ${removeTargetArg}${removeBranchArg} --yes${globalSuffix}`
|
|
2840
|
+
);
|
|
2841
|
+
const addCommand = getCommandNamePlain(
|
|
2842
|
+
`env add ${envName} ${addTargetArg}${addBranchArg} --type config --value "<value>" --yes${globalSuffix}`
|
|
2843
|
+
);
|
|
2844
|
+
const removeHumanCommand = getCommandNamePlain(
|
|
2845
|
+
`env rm ${envName} ${removeTargetArg}${removeBranchArg}${humanGlobalSuffix}`
|
|
2846
|
+
);
|
|
2847
|
+
const addHumanCommand = getCommandNamePlain(
|
|
2848
|
+
`env add ${envName} ${addTargetArg}${addBranchArg} --type config${humanGlobalSuffix}`
|
|
2849
|
+
);
|
|
2850
|
+
const message = "A Secret cannot be changed to Config. To store this value as Config, remove the variable and add it again with `--type config`.";
|
|
2851
|
+
if (client.nonInteractive) {
|
|
2852
|
+
outputAgentError(
|
|
2853
|
+
client,
|
|
2854
|
+
{
|
|
2855
|
+
status: "error",
|
|
2856
|
+
reason: "secret_cannot_become_config",
|
|
2857
|
+
message,
|
|
2858
|
+
next: [
|
|
2859
|
+
{
|
|
2860
|
+
command: removeCommand,
|
|
2861
|
+
when: "Remove the Secret from all of its environments"
|
|
2862
|
+
},
|
|
2863
|
+
{
|
|
2864
|
+
command: addCommand,
|
|
2865
|
+
when: "Add it again as Config; replace <value> before running"
|
|
2866
|
+
}
|
|
2867
|
+
]
|
|
2868
|
+
},
|
|
2869
|
+
1
|
|
2870
|
+
);
|
|
2871
|
+
}
|
|
2872
|
+
output_manager_default.fatal(
|
|
2873
|
+
`A Secret cannot be changed to Config. Remove the variable, then add it again as Config. ${param(envName)} will be unavailable to new builds between these commands.`
|
|
2874
|
+
);
|
|
2875
|
+
output_manager_default.print(` Remove:
|
|
2876
|
+
${removeHumanCommand}
|
|
2877
|
+
`);
|
|
2878
|
+
output_manager_default.print(
|
|
2879
|
+
` Add as Config (prompts for the value):
|
|
2880
|
+
${addHumanCommand}
|
|
2881
|
+
`
|
|
2882
|
+
);
|
|
2883
|
+
return 1;
|
|
2884
|
+
}
|
|
2885
|
+
if (explicitType === "secret" || opts["--sensitive"]) {
|
|
2886
|
+
const knownPublicPrefix = apiPublicPrefix ?? frameworkPublicPrefix;
|
|
2887
|
+
const publicPrefix = knownPublicPrefix ?? customSveltePublicPrefix;
|
|
2888
|
+
const apiPublicPrefixError = apiPublicPrefix ? getPublicPrefixSecretVisibilityError(envName, {
|
|
2889
|
+
visibility: explicitType === "secret" ? "secret" : void 0,
|
|
2890
|
+
type: "sensitive",
|
|
2891
|
+
context: "update"
|
|
2892
|
+
}) : null;
|
|
2893
|
+
const publicPrefixError = apiPublicPrefixError ? apiPublicPrefixError : knownPublicPrefix ? `\`${knownPublicPrefix}\` exposes this value to anyone visiting your site, so \`${envName}\` cannot be kept private as a Secret. Add a new Secret without the public prefix, then remove this Config.` : customSveltePublicPrefix === "" ? "This SvelteKit project uses an empty `publicPrefix`, so every Environment Variable is exposed to the browser and cannot be kept private as a Secret. Change the SvelteKit `publicPrefix`, or keep this variable as Config only if the value is safe to expose." : customSveltePublicPrefix !== void 0 ? `\`${customSveltePublicPrefix}\` exposes this value to anyone visiting your site, so \`${envName}\` cannot be kept private as a Secret. Add a new Secret without the configured public prefix, then remove this Config.` : null;
|
|
2894
|
+
if (publicPrefixError) {
|
|
2895
|
+
const privateName = publicPrefix === void 0 ? envName : envName.slice(publicPrefix.length);
|
|
2896
|
+
const removeTargetArg = envTargetArg || targets[0] || allTargets[0] || getEnvTargetPlaceholder();
|
|
2897
|
+
const addTargetArg = formatTargetArg(allTargets, customEnvironments) || removeTargetArg;
|
|
2898
|
+
const removeBranchArg = selectedEnv.gitBranch ? ` ${quoteArg(selectedEnv.gitBranch)}` : "";
|
|
2899
|
+
const addBranchArg = selectedEnv.gitBranch ? ` --git-branch ${quoteArg(selectedEnv.gitBranch)}` : "";
|
|
2900
|
+
const globalFlags = getGlobalFlagsFromArgs(client.argv.slice(2), {
|
|
2901
|
+
preserveProject: true
|
|
2902
|
+
});
|
|
2903
|
+
const humanGlobalFlags = globalFlags.filter(
|
|
2904
|
+
(flag) => !flag.startsWith("--non-interactive")
|
|
2905
|
+
);
|
|
2906
|
+
const globalSuffix = globalFlags.length > 0 ? ` ${globalFlags.map(quoteArg).join(" ")}` : "";
|
|
2907
|
+
const humanGlobalSuffix = humanGlobalFlags.length > 0 ? ` ${humanGlobalFlags.map(quoteArg).join(" ")}` : "";
|
|
2908
|
+
const addCommand = publicPrefix === "" ? void 0 : getCommandNamePlain(
|
|
2909
|
+
`env add ${privateName} ${addTargetArg}${addBranchArg} --type secret --value "<value>" --yes${globalSuffix}`
|
|
2910
|
+
);
|
|
2911
|
+
const removeCommand = getCommandNamePlain(
|
|
2912
|
+
`env rm ${envName} ${removeTargetArg}${removeBranchArg} --yes${globalSuffix}`
|
|
2913
|
+
);
|
|
2914
|
+
const addHumanCommand = publicPrefix === "" ? void 0 : getCommandNamePlain(
|
|
2915
|
+
`env add ${privateName} ${addTargetArg}${addBranchArg} --type secret${humanGlobalSuffix}`
|
|
2916
|
+
);
|
|
2917
|
+
const removeHumanCommand = getCommandNamePlain(
|
|
2918
|
+
`env rm ${envName} ${removeTargetArg}${removeBranchArg}${humanGlobalSuffix}`
|
|
2919
|
+
);
|
|
2920
|
+
if (client.nonInteractive) {
|
|
2921
|
+
outputAgentError(
|
|
2922
|
+
client,
|
|
2923
|
+
{
|
|
2924
|
+
status: "error",
|
|
2925
|
+
reason: "invalid_type",
|
|
2926
|
+
message: publicPrefixError,
|
|
2927
|
+
next: addCommand ? [
|
|
2928
|
+
{
|
|
2929
|
+
command: addCommand,
|
|
2930
|
+
when: "Add the private Secret; replace <value> before running"
|
|
2931
|
+
},
|
|
2932
|
+
{
|
|
2933
|
+
command: removeCommand,
|
|
2934
|
+
when: "Remove the public Config after the Secret is available"
|
|
2935
|
+
}
|
|
2936
|
+
] : []
|
|
2937
|
+
},
|
|
2938
|
+
1
|
|
2939
|
+
);
|
|
2940
|
+
}
|
|
2941
|
+
output_manager_default.fatal(publicPrefixError);
|
|
2942
|
+
if (addHumanCommand) {
|
|
2943
|
+
output_manager_default.print(
|
|
2944
|
+
` Add the private Secret (prompts for the value):
|
|
2945
|
+
${addHumanCommand}
|
|
2946
|
+
`
|
|
2947
|
+
);
|
|
2948
|
+
output_manager_default.print(
|
|
2949
|
+
` Remove the public Config:
|
|
2950
|
+
${removeHumanCommand}
|
|
2951
|
+
`
|
|
2952
|
+
);
|
|
2953
|
+
}
|
|
2954
|
+
return 1;
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
if (customSveltePublicPrefix !== void 0) {
|
|
2958
|
+
printEnvUpdateWarning(
|
|
2959
|
+
customSveltePublicPrefix === "" ? "This SvelteKit project uses an empty `publicPrefix`, so every Environment Variable is exposed to the browser." : `\`${customSveltePublicPrefix}\` variables are exposed to the browser by this SvelteKit project.`
|
|
2960
|
+
);
|
|
2961
|
+
}
|
|
2463
2962
|
let teamSensitivePolicyOn = false;
|
|
2963
|
+
let disjunctiveProductionSecretPolicyOn = false;
|
|
2464
2964
|
if (link.org.type === "team") {
|
|
2465
2965
|
try {
|
|
2466
2966
|
const team = await getTeamById(client, link.org.id);
|
|
2467
2967
|
teamSensitivePolicyOn = team?.sensitiveEnvironmentVariablePolicy === "on";
|
|
2968
|
+
disjunctiveProductionSecretPolicyOn = team?.disjunctiveProductionSecretPolicy === "on";
|
|
2468
2969
|
} catch {
|
|
2469
2970
|
}
|
|
2470
2971
|
}
|
|
2471
2972
|
let envValue;
|
|
2973
|
+
const shouldMaskValue = Boolean(opts["--sensitive"]) || explicitType === "secret" || explicitType === void 0 && selectedEnvIsSecret;
|
|
2472
2974
|
if (stdInput) {
|
|
2473
2975
|
const normalizedStdinValue = normalizeStdinEnvValue(stdInput);
|
|
2474
2976
|
envValue = normalizedStdinValue.value;
|
|
@@ -2486,7 +2988,7 @@ async function update(client, argv) {
|
|
|
2486
2988
|
{
|
|
2487
2989
|
status: "action_required",
|
|
2488
2990
|
reason: "missing_value",
|
|
2489
|
-
message:
|
|
2991
|
+
message: 'In non-interactive mode, provide the new value with `--value` or stdin. Example: `vercel env update <name> <environment> --value "<value>" --yes`',
|
|
2490
2992
|
next: [
|
|
2491
2993
|
{
|
|
2492
2994
|
command: buildEnvUpdateCommandWithPreservedArgs(
|
|
@@ -2499,85 +3001,205 @@ async function update(client, argv) {
|
|
|
2499
3001
|
1
|
|
2500
3002
|
);
|
|
2501
3003
|
}
|
|
2502
|
-
envValue = await client
|
|
2503
|
-
message: `What's the new value of ${envName}?`
|
|
2504
|
-
});
|
|
3004
|
+
envValue = await promptEnvUpdateValue(client, envName, shouldMaskValue);
|
|
2505
3005
|
}
|
|
2506
3006
|
const skipConfirm = opts["--yes"] || !!stdInput || valueFromFlag !== void 0;
|
|
2507
|
-
const { finalValue
|
|
3007
|
+
const { finalValue } = await validateEnvValue({
|
|
2508
3008
|
envName,
|
|
2509
3009
|
initialValue: envValue,
|
|
2510
3010
|
skipConfirm,
|
|
2511
|
-
promptForValue: () => client
|
|
3011
|
+
promptForValue: () => promptEnvUpdateValue(client, envName, shouldMaskValue),
|
|
2512
3012
|
selectAction: (choices) => client.input.select({ message: "How to proceed?", choices }),
|
|
2513
|
-
showWarning:
|
|
3013
|
+
showWarning: printEnvUpdateWarning,
|
|
2514
3014
|
showLog: (msg) => output_manager_default.log(msg)
|
|
2515
3015
|
});
|
|
2516
|
-
|
|
3016
|
+
let type = opts["--sensitive"] || explicitType === "secret" ? "sensitive" : explicitType === "config" ? "encrypted" : selectedEnv.type;
|
|
3017
|
+
const isFinalSecret = () => type === "sensitive" || explicitType === void 0 && selectedEnvIsSecret;
|
|
3018
|
+
if (!isFinalSecret() && (type === "plain" || type === "encrypted") && (looksLikeCredentialName2(envName, customSveltePublicPrefix) || looksLikeSecretValue(finalValue))) {
|
|
3019
|
+
printEnvUpdateWarning(
|
|
3020
|
+
"This name or value looks like a credential. Config values can be revealed after saving."
|
|
3021
|
+
);
|
|
3022
|
+
const publicPrefix = apiPublicPrefix ?? frameworkPublicPrefix ?? customSveltePublicPrefix;
|
|
3023
|
+
if (publicPrefix !== null && publicPrefix !== void 0) {
|
|
3024
|
+
printEnvUpdateWarning(
|
|
3025
|
+
publicPrefix === "" ? "This SvelteKit project exposes every Environment Variable to the browser. Keep Config only if the value is safe to expose." : `\`${publicPrefix}\` exposes this value to anyone visiting your site. Keep Config only if the value is safe to expose.`
|
|
3026
|
+
);
|
|
3027
|
+
if (!typeWasExplicit && (opts["--yes"] || client.nonInteractive)) {
|
|
3028
|
+
const message = publicPrefix === "" ? "This SvelteKit project exposes every Environment Variable to the browser. To keep this value private, change the configured public prefix before storing it as Secret. If the value is safe to expose, rerun with `--type config`." : `\`${publicPrefix}\` exposes \`${envName}\` to anyone visiting your site. To keep this value private, add \`${envName.slice(
|
|
3029
|
+
publicPrefix.length
|
|
3030
|
+
)}\` as Secret, then remove \`${envName}\`. If the value is safe to expose, rerun with \`--type config\`.`;
|
|
3031
|
+
if (client.nonInteractive) {
|
|
3032
|
+
outputAgentError(
|
|
3033
|
+
client,
|
|
3034
|
+
{
|
|
3035
|
+
status: "error",
|
|
3036
|
+
reason: "unsafe_public_config",
|
|
3037
|
+
message
|
|
3038
|
+
},
|
|
3039
|
+
1
|
|
3040
|
+
);
|
|
3041
|
+
}
|
|
3042
|
+
output_manager_default.fatal(message);
|
|
3043
|
+
return 1;
|
|
3044
|
+
}
|
|
3045
|
+
if (publicPrefix !== "" && !typeWasExplicit && !opts["--yes"] && !client.nonInteractive) {
|
|
3046
|
+
const privateName = envName.slice(publicPrefix.length);
|
|
3047
|
+
const removeTargetArg = envTargetArg || targets[0] || allTargets[0] || getEnvTargetPlaceholder();
|
|
3048
|
+
const addTargetArg = formatTargetArg(allTargets, customEnvironments) || removeTargetArg;
|
|
3049
|
+
const removeBranchArg = selectedEnv.gitBranch ? ` ${quoteArg(selectedEnv.gitBranch)}` : "";
|
|
3050
|
+
const addBranchArg = selectedEnv.gitBranch ? ` --git-branch ${quoteArg(selectedEnv.gitBranch)}` : "";
|
|
3051
|
+
const humanGlobalFlags = getGlobalFlagsFromArgs(client.argv.slice(2), {
|
|
3052
|
+
preserveProject: true
|
|
3053
|
+
}).filter((flag) => !flag.startsWith("--non-interactive"));
|
|
3054
|
+
const humanGlobalSuffix = humanGlobalFlags.length > 0 ? ` ${humanGlobalFlags.map(quoteArg).join(" ")}` : "";
|
|
3055
|
+
const addPrivateCommand = getCommandNamePlain(
|
|
3056
|
+
`env add ${privateName} ${addTargetArg}${addBranchArg} --type secret${humanGlobalSuffix}`
|
|
3057
|
+
);
|
|
3058
|
+
const removePublicCommand = getCommandNamePlain(
|
|
3059
|
+
`env rm ${envName} ${removeTargetArg}${removeBranchArg}${humanGlobalSuffix}`
|
|
3060
|
+
);
|
|
3061
|
+
const selectedAction = await client.input.select({
|
|
3062
|
+
message: "How should this variable be stored?",
|
|
3063
|
+
choices: [
|
|
3064
|
+
{
|
|
3065
|
+
name: `Keep private: add ${privateName} as Secret, then remove ${envName}`,
|
|
3066
|
+
value: "private"
|
|
3067
|
+
},
|
|
3068
|
+
{
|
|
3069
|
+
name: `Expose to anyone visiting your site: keep ${envName} as Config`,
|
|
3070
|
+
value: "config"
|
|
3071
|
+
}
|
|
3072
|
+
]
|
|
3073
|
+
});
|
|
3074
|
+
if (selectedAction === "private") {
|
|
3075
|
+
output_manager_default.print(" Add the private Secret (prompts for the value):\n");
|
|
3076
|
+
output_manager_default.print(` ${addPrivateCommand}
|
|
3077
|
+
`);
|
|
3078
|
+
output_manager_default.print(" Remove the public Config:\n");
|
|
3079
|
+
output_manager_default.print(` ${removePublicCommand}
|
|
3080
|
+
`);
|
|
3081
|
+
return 1;
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
} else if (!typeWasExplicit && !opts["--yes"] && !client.nonInteractive) {
|
|
3085
|
+
const selectedType = await client.input.select({
|
|
3086
|
+
message: "Store this value as?",
|
|
3087
|
+
choices: [
|
|
3088
|
+
{
|
|
3089
|
+
name: getSecretStorageChoice(targets, "for this value"),
|
|
3090
|
+
value: "secret"
|
|
3091
|
+
},
|
|
3092
|
+
{
|
|
3093
|
+
name: "Config (can be revealed after saving)",
|
|
3094
|
+
value: "config"
|
|
3095
|
+
}
|
|
3096
|
+
]
|
|
3097
|
+
});
|
|
3098
|
+
if (selectedType === "secret") {
|
|
3099
|
+
type = "sensitive";
|
|
3100
|
+
explicitType = "secret";
|
|
3101
|
+
}
|
|
3102
|
+
} else if (!typeWasExplicit) {
|
|
3103
|
+
printEnvUpdateWarning("Re-run with `--type secret` to protect it.");
|
|
3104
|
+
}
|
|
3105
|
+
}
|
|
3106
|
+
if (isFinalSecret() && !selectedEnvIsSecret) {
|
|
3107
|
+
printEnvUpdateWarning(
|
|
3108
|
+
"The previous value was readable as Config and may have been exposed. If this variable still holds the same credential, rotate it at its provider and update this variable again."
|
|
3109
|
+
);
|
|
3110
|
+
}
|
|
3111
|
+
const finalPublicPrefix = apiPublicPrefix ?? frameworkPublicPrefix ?? customSveltePublicPrefix;
|
|
3112
|
+
if (isFinalSecret() && finalPublicPrefix !== null && finalPublicPrefix !== void 0) {
|
|
3113
|
+
printEnvUpdateWarning(
|
|
3114
|
+
finalPublicPrefix === "" ? "This SvelteKit project exposes every Environment Variable to the browser; the Secret type does not prevent that. Change the configured public prefix to keep values private." : `\`${finalPublicPrefix}\` exposes this variable to the browser; the Secret type does not prevent that. Rename the variable without the public prefix to keep it private.`
|
|
3115
|
+
);
|
|
3116
|
+
}
|
|
3117
|
+
if (isFinalSecret() && disjunctiveProductionSecretPolicyOn && targets.includes("production") && allTargets.some((target) => target !== "production")) {
|
|
3118
|
+
const message = "Your team requires Production and non-Production Secrets to be stored separately with different values. Create separate variables with different values before converting this one.";
|
|
2517
3119
|
if (client.nonInteractive) {
|
|
2518
|
-
|
|
3120
|
+
outputAgentError(
|
|
2519
3121
|
client,
|
|
2520
3122
|
{
|
|
2521
|
-
status: "
|
|
2522
|
-
reason: "
|
|
2523
|
-
message
|
|
2524
|
-
next: [{ command: buildCommandWithYes(client.argv) }]
|
|
3123
|
+
status: "error",
|
|
3124
|
+
reason: "production_secret_must_be_separate",
|
|
3125
|
+
message
|
|
2525
3126
|
},
|
|
2526
3127
|
1
|
|
2527
3128
|
);
|
|
2528
3129
|
}
|
|
2529
|
-
|
|
2530
|
-
link,
|
|
2531
|
-
selectedEnv,
|
|
2532
|
-
customEnvironments
|
|
2533
|
-
);
|
|
2534
|
-
const confirmed = await client.input.confirm(
|
|
2535
|
-
`Updating Environment Variable ${param(envName)} in ${currentTargets} in Project ${import_chalk4.default.bold(project.name)}. Are you sure?`,
|
|
2536
|
-
false
|
|
2537
|
-
);
|
|
2538
|
-
if (!confirmed) {
|
|
2539
|
-
output_manager_default.log("Canceled");
|
|
2540
|
-
return 0;
|
|
2541
|
-
}
|
|
2542
|
-
}
|
|
2543
|
-
const type = opts["--sensitive"] ? "sensitive" : selectedEnv.type;
|
|
2544
|
-
const explicitVisibility = typeof opts["--visibility"] === "string" ? opts["--visibility"] : void 0;
|
|
2545
|
-
if (explicitVisibility === "config" && opts["--sensitive"]) {
|
|
2546
|
-
output_manager_default.error(
|
|
2547
|
-
"`--visibility config` cannot be used with `--sensitive`. Pick one."
|
|
2548
|
-
);
|
|
3130
|
+
output_manager_default.fatal(message);
|
|
2549
3131
|
return 1;
|
|
2550
3132
|
}
|
|
2551
|
-
const
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
const { visibility, error: visibilityError } = resolveEnvVarVisibility({
|
|
2556
|
-
explicitVisibility,
|
|
3133
|
+
const preserveExistingVisibility = explicitType === void 0 && selectedEnv.visibility === "secret" && type !== "sensitive";
|
|
3134
|
+
const { visibility: resolvedVisibility, error: visibilityError } = resolveEnvVarVisibility({
|
|
3135
|
+
explicitVisibility: typeOption.source ? explicitType : void 0,
|
|
3136
|
+
explicitOptionSource: typeOption.source,
|
|
2557
3137
|
type,
|
|
2558
3138
|
key: envName,
|
|
2559
3139
|
envTargets: allTargets,
|
|
2560
|
-
teamSensitivePolicyOn
|
|
3140
|
+
teamSensitivePolicyOn,
|
|
3141
|
+
context: "update"
|
|
2561
3142
|
});
|
|
3143
|
+
const visibility = preserveExistingVisibility ? void 0 : resolvedVisibility;
|
|
3144
|
+
const displayVisibility = preserveExistingVisibility ? selectedEnv.visibility : visibility;
|
|
2562
3145
|
if (visibilityError) {
|
|
2563
3146
|
if (client.nonInteractive) {
|
|
2564
3147
|
outputAgentError(
|
|
2565
3148
|
client,
|
|
2566
3149
|
{
|
|
2567
3150
|
status: "error",
|
|
2568
|
-
reason: "
|
|
3151
|
+
reason: "invalid_type",
|
|
2569
3152
|
message: visibilityError
|
|
2570
3153
|
},
|
|
2571
3154
|
1
|
|
2572
3155
|
);
|
|
2573
3156
|
}
|
|
2574
|
-
output_manager_default.
|
|
3157
|
+
output_manager_default.fatal(visibilityError);
|
|
2575
3158
|
return 1;
|
|
2576
3159
|
}
|
|
2577
|
-
|
|
3160
|
+
if (!opts["--yes"]) {
|
|
3161
|
+
const visibilityLabel2 = formatVisibilityLabel(displayVisibility, type);
|
|
3162
|
+
if (client.nonInteractive) {
|
|
3163
|
+
outputActionRequired(
|
|
3164
|
+
client,
|
|
3165
|
+
{
|
|
3166
|
+
status: "action_required",
|
|
3167
|
+
reason: "confirmation_required",
|
|
3168
|
+
message: `Update ${envName} as ${visibilityLabel2} in ${formatEnvironments(
|
|
3169
|
+
link,
|
|
3170
|
+
selectedEnv,
|
|
3171
|
+
customEnvironments
|
|
3172
|
+
)}? Use --yes to confirm.`,
|
|
3173
|
+
next: [
|
|
3174
|
+
{
|
|
3175
|
+
command: buildCommandWithYes(redactEnvValueArgs(client.argv))
|
|
3176
|
+
}
|
|
3177
|
+
]
|
|
3178
|
+
},
|
|
3179
|
+
1
|
|
3180
|
+
);
|
|
3181
|
+
}
|
|
3182
|
+
output_manager_default.print("\n");
|
|
3183
|
+
printAlignedLabel("Project", `${link.org.slug}/${project.name}`);
|
|
3184
|
+
printAlignedLabel(
|
|
3185
|
+
"Environments",
|
|
3186
|
+
formatEnvironments(link, selectedEnv, customEnvironments)
|
|
3187
|
+
);
|
|
3188
|
+
if (visibilityLabel2) {
|
|
3189
|
+
printAlignedLabel("Type", visibilityLabel2);
|
|
3190
|
+
}
|
|
3191
|
+
const confirmed = await client.input.confirm(
|
|
3192
|
+
"Update this Environment Variable?",
|
|
3193
|
+
false
|
|
3194
|
+
);
|
|
3195
|
+
if (!confirmed) {
|
|
3196
|
+
output_manager_default.log("Canceled");
|
|
3197
|
+
return 0;
|
|
3198
|
+
}
|
|
3199
|
+
}
|
|
2578
3200
|
try {
|
|
2579
3201
|
output_manager_default.spinner("Updating");
|
|
2580
|
-
const keyToUpdate =
|
|
3202
|
+
const keyToUpdate = isFinalSecret() ? void 0 : envName;
|
|
2581
3203
|
await updateEnvRecord(
|
|
2582
3204
|
client,
|
|
2583
3205
|
project.id,
|
|
@@ -2591,13 +3213,18 @@ async function update(client, argv) {
|
|
|
2591
3213
|
);
|
|
2592
3214
|
} catch (err) {
|
|
2593
3215
|
if (client.nonInteractive && isAPIError(err)) {
|
|
2594
|
-
const
|
|
3216
|
+
const productionSecretPolicyError = getProductionSecretPolicyErrorKind(
|
|
3217
|
+
err.serverMessage
|
|
3218
|
+
);
|
|
3219
|
+
const reason = productionSecretPolicyError ? productionSecretPolicyError === "different-values" ? "production_secret_requires_different_value" : "production_secret_must_be_separate" : err.slug || (err.serverMessage?.toLowerCase().includes("branch") ? "branch_not_found" : "api_error");
|
|
2595
3220
|
outputAgentError(
|
|
2596
3221
|
client,
|
|
2597
3222
|
{
|
|
2598
3223
|
status: "error",
|
|
2599
3224
|
reason,
|
|
2600
|
-
message: err.serverMessage
|
|
3225
|
+
message: productionSecretPolicyError ? `${err.serverMessage} ${getProductionSecretPolicyRecovery(
|
|
3226
|
+
productionSecretPolicyError
|
|
3227
|
+
)}` : err.serverMessage
|
|
2601
3228
|
},
|
|
2602
3229
|
1
|
|
2603
3230
|
);
|
|
@@ -2608,18 +3235,16 @@ async function update(client, argv) {
|
|
|
2608
3235
|
}
|
|
2609
3236
|
throw err;
|
|
2610
3237
|
}
|
|
2611
|
-
output_manager_default.print(
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
)}
|
|
2618
|
-
`
|
|
3238
|
+
output_manager_default.print("\n");
|
|
3239
|
+
printAlignedLabel("Updated", envName, { gutter: "\u2713" });
|
|
3240
|
+
printAlignedLabel("Project", `${link.org.slug}/${project.name}`);
|
|
3241
|
+
printAlignedLabel(
|
|
3242
|
+
"Environments",
|
|
3243
|
+
formatEnvironments(link, selectedEnv, customEnvironments)
|
|
2619
3244
|
);
|
|
2620
|
-
const visibilityLabel = formatVisibilityLabel(
|
|
3245
|
+
const visibilityLabel = formatVisibilityLabel(displayVisibility, type);
|
|
2621
3246
|
if (visibilityLabel) {
|
|
2622
|
-
printAlignedLabel("
|
|
3247
|
+
printAlignedLabel("Type", visibilityLabel);
|
|
2623
3248
|
}
|
|
2624
3249
|
return 0;
|
|
2625
3250
|
}
|