@jondotsoy/envs 0.1.9-alpha.0 → 0.1.9-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/envs.js +20 -11
- package/package.json +1 -1
package/envs.js
CHANGED
|
@@ -17,11 +17,17 @@ function dotenvProblem(key, text) {
|
|
|
17
17
|
if (!/^[\w.-]+$/.test(key)) {
|
|
18
18
|
return "the name is not a valid variable name (only letters, digits, `_`, `.` and `-`)";
|
|
19
19
|
}
|
|
20
|
+
if (text.includes("'") && text.includes('"') && text.includes("`")) {
|
|
21
|
+
return "the value has single, double and backtick quotes at once, so no .env quoting can hold it as is";
|
|
22
|
+
}
|
|
20
23
|
if (/[\r\n]/.test(text)) {
|
|
21
24
|
return "the value has a line break, which a .env file cannot hold safely (write it on one line, with `\\n` escapes if the application expects them)";
|
|
22
25
|
}
|
|
23
26
|
return;
|
|
24
27
|
}
|
|
28
|
+
function hasSecretPattern(text) {
|
|
29
|
+
return SECRET_PATTERNS.some(([pattern]) => pattern.test(text));
|
|
30
|
+
}
|
|
25
31
|
function isSensitiveKey(key) {
|
|
26
32
|
return SENSITIVE_KEY.test(key);
|
|
27
33
|
}
|
|
@@ -130,13 +136,10 @@ var init_lint_rules = __esm(() => {
|
|
|
130
136
|
},
|
|
131
137
|
{
|
|
132
138
|
id: "open-permissions",
|
|
133
|
-
description: "values.yml
|
|
134
|
-
check: (ctx) =>
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
].filter(({ mode }) => mode !== undefined && (mode & 63) !== 0).map(({ file, mode }) => ({
|
|
138
|
-
location: file,
|
|
139
|
-
message: `${file.slice(".envs/".length)} is readable by other users (mode ${(mode & 511).toString(8)}). Run \`chmod 600 ${file}\`.`
|
|
139
|
+
description: "values.yml, the history or a worktree's .env is readable by other users.",
|
|
140
|
+
check: (ctx) => envFiles(ctx).filter(({ mode }) => mode !== undefined && (mode & 63) !== 0).map(({ location, mode }) => ({
|
|
141
|
+
location,
|
|
142
|
+
message: `${location.replace(/^\.envs\//, "")} is readable by other users (mode ${(mode & 511).toString(8)}). Run \`chmod 600 ${location}\`.`
|
|
140
143
|
}))
|
|
141
144
|
},
|
|
142
145
|
{
|
|
@@ -890,9 +893,13 @@ function parseValue(value) {
|
|
|
890
893
|
return value;
|
|
891
894
|
}
|
|
892
895
|
function formatDotenvValue(value) {
|
|
893
|
-
if (value !== "" && !/[\s#"'
|
|
896
|
+
if (value !== "" && !/[\s#"'`\\$]/.test(value))
|
|
894
897
|
return value;
|
|
895
|
-
|
|
898
|
+
if (!value.includes('"') && !/\\[nr]/.test(value))
|
|
899
|
+
return `"${value}"`;
|
|
900
|
+
if (!value.includes("'"))
|
|
901
|
+
return `'${value}'`;
|
|
902
|
+
return `\`${value}\``;
|
|
896
903
|
}
|
|
897
904
|
function updateDotenv(text, entries, remove = new Set) {
|
|
898
905
|
const pending = new Map(Object.entries(entries));
|
|
@@ -1142,7 +1149,9 @@ async function pushLocked(ctx, only) {
|
|
|
1142
1149
|
}
|
|
1143
1150
|
for (const key of orphans)
|
|
1144
1151
|
removals.set(key, [...removals.get(key) ?? [], label]);
|
|
1145
|
-
|
|
1152
|
+
const dotenvPath = join2(path, ".env");
|
|
1153
|
+
await writeFile(dotenvPath, updateDotenv(current, entries, orphans), { mode: 384 });
|
|
1154
|
+
await chmod(dotenvPath, 384).catch(() => {});
|
|
1146
1155
|
}
|
|
1147
1156
|
for (const [line, names] of changes) {
|
|
1148
1157
|
ctx.log(yellow(`\u21BB ${line} \u2192 ${names.join(", ")}`));
|
|
@@ -1544,7 +1553,7 @@ Commands:
|
|
|
1544
1553
|
history Manage the history (history redact: remove secrets in clear from an existing history)
|
|
1545
1554
|
config Read or change .envs/config.yml (config set <key> <value>, config get [key], config delete <key>)
|
|
1546
1555
|
help Show this help message
|
|
1547
|
-
`, colorsDisabled = () => Boolean(process.env.NO_COLOR), MASK = "********", isMaskedKey = (key) => isSensitiveKey(key) || /(^|_)KEY(_|$)/i.test(key), URL_SECRET, hasUrlSecret = (value) => URL_SECRET.test(value) || /^[a-z][a-z0-9+.-]*:\/\//i.test(value) && sensitiveQuery(value), sensitiveQuery = (value) => [...value.matchAll(/[?&]([^=&\s#]+)=([^&\s#]*)/g)].some(([, name]) => isMaskedKey(name.toUpperCase().replace(/[^A-Z0-9]+/g, "_"))), maskUrlSecrets = (value) => value.replace(URL_SECRET, `$1${MASK}$3`).replace(/([?&])([^=&\s#]+)=([^&\s#]*)/g, (all, sep, name) => isMaskedKey(name.toUpperCase().replace(/[^A-Z0-9]+/g, "_")) ? `${sep}${name}=${MASK}` : all), isSecretEntry = (name, value) => isMaskedKey(name) || hasUrlSecret(value), displayValue = (name, value) => isMaskedKey(name) ? MASK : formatDotenvValue(maskUrlSecrets(value)), paint = (code, text) => colorsDisabled() ? text : `\x1B[${code}m${text}\x1B[0m`, green = (text) => paint(32, text), yellow = (text) => paint(33, text), red = (text) => paint(31, text), defaultContext = () => ({
|
|
1556
|
+
`, colorsDisabled = () => Boolean(process.env.NO_COLOR), MASK = "********", isMaskedKey = (key) => isSensitiveKey(key) || /(^|_)KEY(_|$)/i.test(key), URL_SECRET, hasUrlSecret = (value) => URL_SECRET.test(value) || /^[a-z][a-z0-9+.-]*:\/\//i.test(value) && sensitiveQuery(value), sensitiveQuery = (value) => [...value.matchAll(/[?&]([^=&\s#]+)=([^&\s#]*)/g)].some(([, name]) => isMaskedKey(name.toUpperCase().replace(/[^A-Z0-9]+/g, "_"))), maskUrlSecrets = (value) => value.replace(URL_SECRET, `$1${MASK}$3`).replace(/([?&])([^=&\s#]+)=([^&\s#]*)/g, (all, sep, name) => isMaskedKey(name.toUpperCase().replace(/[^A-Z0-9]+/g, "_")) ? `${sep}${name}=${MASK}` : all), isSecretEntry = (name, value) => isMaskedKey(name) || hasUrlSecret(value) || hasSecretPattern(value), displayValue = (name, value) => isMaskedKey(name) || hasSecretPattern(value) ? MASK : formatDotenvValue(maskUrlSecrets(value)), paint = (code, text) => colorsDisabled() ? text : `\x1B[${code}m${text}\x1B[0m`, green = (text) => paint(32, text), yellow = (text) => paint(33, text), red = (text) => paint(31, text), defaultContext = () => ({
|
|
1548
1557
|
cwd: process.cwd(),
|
|
1549
1558
|
log: (message) => console.log(message),
|
|
1550
1559
|
error: (message) => console.error(message),
|