ultraenv 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +67 -1857
- package/dist/{chunk-GC7RXHLA.js → chunk-2MBSLURI.js} +16 -17
- package/dist/{chunk-IGFVP24Q.js → chunk-3AF476D7.js} +1 -1
- package/dist/{chunk-N5PAV4NM.js → chunk-5WUBB633.js} +17 -26
- package/dist/{chunk-2USZPWLZ.js → chunk-6NFA23AY.js} +28 -39
- package/dist/{chunk-AWN6ADV7.js → chunk-6X3BUE5S.js} +45 -54
- package/dist/{chunk-NBOABPHM.js → chunk-72UKVOO5.js} +24 -40
- package/dist/{chunk-JB7RKV3C.js → chunk-7AHG2IP4.js} +1 -7
- package/dist/{chunk-6KS56D6E.js → chunk-7VJ7LK2M.js} +1 -1
- package/dist/{chunk-CIFMBJ4H.js → chunk-BNUHE2ZI.js} +57 -21
- package/dist/{chunk-HFXQGJY3.js → chunk-CVJPO3QY.js} +13 -27
- package/dist/{chunk-IKPTKALB.js → chunk-F7YSINGU.js} +1 -3
- package/dist/{chunk-3VYXPTYV.js → chunk-FSKVYBEP.js} +1 -1
- package/dist/{chunk-4XUYMRK5.js → chunk-GJC64ZG7.js} +4 -3
- package/dist/{chunk-YMMP4VQL.js → chunk-H3QEGEZ6.js} +1 -1
- package/dist/{chunk-CHVO6NWI.js → chunk-LFIKYFPS.js} +2 -2
- package/dist/{chunk-3UV2QNJL.js → chunk-LJSCUOD4.js} +19 -21
- package/dist/{chunk-YVWLXFUT.js → chunk-LQZK6BBQ.js} +2 -2
- package/dist/{chunk-5G2DU52U.js → chunk-N7GOHQBF.js} +7 -1
- package/dist/{chunk-MSXMESFP.js → chunk-OBLMAUCF.js} +8 -14
- package/dist/{chunk-UEWYFN6A.js → chunk-RJTUAMK3.js} +16 -29
- package/dist/{chunk-MNVFG7H4.js → chunk-XPZC32UY.js} +16 -25
- package/dist/{chunk-WMHN5RW2.js → chunk-YLGJQOMM.js} +3 -9
- package/dist/{ci-check-sync-VBMSVWIV.js → ci-check-sync-UO5PARKO.js} +4 -4
- package/dist/{ci-scan-24MT5XGS.js → ci-scan-5D7QBN5X.js} +2 -5
- package/dist/{ci-setup-C2NKEFRD.js → ci-setup-J34DS6KD.js} +2 -2
- package/dist/{ci-validate-7AW24LSQ.js → ci-validate-LWP5NBDN.js} +4 -4
- package/dist/cli/index.cjs +470 -390
- package/dist/cli/index.js +130 -55
- package/dist/comparator-AIRTWBOL.js +13 -0
- package/dist/{config-O5YRQP5Z.js → config-67GDO3CW.js} +3 -3
- package/dist/{debug-PTPXAF3K.js → debug-6VCX3QSP.js} +6 -6
- package/dist/{declaration-LEME4AFZ.js → declaration-YGOVZOXG.js} +3 -3
- package/dist/{doctor-FZAUPKHS.js → doctor-FF7QOTP2.js} +7 -5
- package/dist/{envs-compare-5K3HESX5.js → envs-compare-P7GPKGQX.js} +4 -4
- package/dist/{envs-create-2XXHXMGA.js → envs-create-ISG4SECU.js} +4 -4
- package/dist/{envs-list-NQM5252B.js → envs-list-PUW67HOC.js} +5 -5
- package/dist/{envs-switch-6L2AQYID.js → envs-switch-P4YDJ6LG.js} +4 -4
- package/dist/{envs-validate-FL73Q76T.js → envs-validate-VNKBKYO3.js} +6 -9
- package/dist/{fs-VH7ATUS3.js → fs-7HKOZY5K.js} +2 -2
- package/dist/{generator-LFZBMZZS.js → generator-O23ATCIY.js} +4 -4
- package/dist/{help-3XJBXEHE.js → help-THFLI6YT.js} +108 -26
- package/dist/index.cjs +295 -381
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +81 -100
- package/dist/{init-Y7JQ2KYJ.js → init-KBLVTHQW.js} +15 -11
- package/dist/{install-hook-SKXIV6NV.js → install-hook-42F22BLY.js} +2 -2
- package/dist/{json-schema-I26YNQBH.js → json-schema-YULPWDKA.js} +3 -3
- package/dist/{key-manager-O3G55WPU.js → key-manager-WDWPX3IQ.js} +3 -3
- package/dist/middleware/express.cjs +1 -3
- package/dist/middleware/express.js +1 -1
- package/dist/middleware/fastify.cjs +1 -7
- package/dist/middleware/fastify.js +1 -1
- package/dist/{module-IDIZPP4M.js → module-FGH2V6N2.js} +3 -3
- package/dist/{protect-NCWPM6VC.js → protect-A4G7LQFJ.js} +26 -24
- package/dist/{scan-TRLY36TT.js → scan-4BXGHR33.js} +1 -1
- package/dist/schema/index.cjs +57 -21
- package/dist/schema/index.js +1 -1
- package/dist/{sync-TMHMTLH2.js → sync-MYLMDDY6.js} +23 -14
- package/dist/{typegen-SQOSXBWM.js → typegen-GLBRHWSK.js} +17 -23
- package/dist/{validate-IOAM5HWS.js → validate-J73ETKXD.js} +5 -5
- package/dist/{vault-decrypt-U6HJZNBV.js → vault-decrypt-V3GY5HES.js} +7 -7
- package/dist/{vault-diff-B3ZOQTWI.js → vault-diff-QVE6S6KP.js} +5 -5
- package/dist/{vault-encrypt-GUSLCSKS.js → vault-encrypt-WUBY3OVF.js} +7 -7
- package/dist/{vault-init-GUBOTOUL.js → vault-init-EWSAED44.js} +5 -5
- package/dist/{vault-rekey-DAHT7JCN.js → vault-rekey-VODMGCNA.js} +7 -7
- package/dist/{vault-status-GDLRU2OK.js → vault-status-YXDK6O7X.js} +4 -4
- package/dist/{vault-verify-CD76FJSF.js → vault-verify-SSXGTVBK.js} +7 -7
- package/package.json +1 -1
- package/dist/comparator-RDKX3OI7.js +0 -13
package/dist/cli/index.cjs
CHANGED
|
@@ -306,7 +306,13 @@ var init_errors = __esm({
|
|
|
306
306
|
code;
|
|
307
307
|
constructor(message, options = {}) {
|
|
308
308
|
const fsCode = options.code ?? options.cause?.code ?? "UNKNOWN";
|
|
309
|
-
const opHint = options.path !== void 0 ?
|
|
309
|
+
const opHint = options.path !== void 0 ? (
|
|
310
|
+
/* v8 ignore start */
|
|
311
|
+
`Could not ${options.operation ?? "access"} "${options.path}".`
|
|
312
|
+
) : (
|
|
313
|
+
/* v8 ignore stop */
|
|
314
|
+
""
|
|
315
|
+
);
|
|
310
316
|
super(message, {
|
|
311
317
|
code: `FS_${fsCode}`,
|
|
312
318
|
hint: options.hint ?? `${opHint} Ensure the file exists and you have the necessary permissions.`,
|
|
@@ -773,7 +779,8 @@ function parseYamlScalar(value) {
|
|
|
773
779
|
if (cleanValue === "") return "";
|
|
774
780
|
if (cleanValue === "true" || cleanValue === "True" || cleanValue === "TRUE") return true;
|
|
775
781
|
if (cleanValue === "false" || cleanValue === "False" || cleanValue === "FALSE") return false;
|
|
776
|
-
if (cleanValue === "null" || cleanValue === "Null" || cleanValue === "NULL" || cleanValue === "~")
|
|
782
|
+
if (cleanValue === "null" || cleanValue === "Null" || cleanValue === "NULL" || cleanValue === "~")
|
|
783
|
+
return null;
|
|
777
784
|
if (/^-?\d+$/.test(cleanValue)) return parseInt(cleanValue, 10);
|
|
778
785
|
if (/^-?\d+\.\d+$/.test(cleanValue)) return parseFloat(cleanValue);
|
|
779
786
|
if (cleanValue.startsWith('"') && cleanValue.endsWith('"') || cleanValue.startsWith("'") && cleanValue.endsWith("'")) {
|
|
@@ -958,14 +965,18 @@ async function run(args, ctx) {
|
|
|
958
965
|
const envDir = await prompt(" Environment directory", { default: "." });
|
|
959
966
|
writeLine("");
|
|
960
967
|
writeLine(cyan(" Creating configuration..."));
|
|
961
|
-
const configContent = JSON.stringify(
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
968
|
+
const configContent = JSON.stringify(
|
|
969
|
+
{
|
|
970
|
+
envDir,
|
|
971
|
+
expandVariables: true,
|
|
972
|
+
overrideProcessEnv: false,
|
|
973
|
+
mergeStrategy: "last-wins",
|
|
974
|
+
outputFormat: "terminal",
|
|
975
|
+
debug: false
|
|
976
|
+
},
|
|
977
|
+
null,
|
|
978
|
+
2
|
|
979
|
+
) + "\n";
|
|
969
980
|
await writeFile(configPath, configContent);
|
|
970
981
|
writeLine(green(` \u2713 Created ${configPath}`));
|
|
971
982
|
if (!await exists(envPath)) {
|
|
@@ -1104,14 +1115,11 @@ function resolveEscapeSequence(chars, startIndex, filePath, lineNumber) {
|
|
|
1104
1115
|
}
|
|
1105
1116
|
return { resolved: String.fromCodePoint(codePoint), charsConsumed: 4 };
|
|
1106
1117
|
}
|
|
1107
|
-
throw new ParseError(
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
hint: "Hex escapes must be exactly 2 hex digits, e.g. \\x0A for newline."
|
|
1113
|
-
}
|
|
1114
|
-
);
|
|
1118
|
+
throw new ParseError(`Invalid hex escape sequence: ${"\\"}x${hex}`, {
|
|
1119
|
+
line: lineNumber,
|
|
1120
|
+
filePath,
|
|
1121
|
+
hint: "Hex escapes must be exactly 2 hex digits, e.g. \\x0A for newline."
|
|
1122
|
+
});
|
|
1115
1123
|
}
|
|
1116
1124
|
case "u":
|
|
1117
1125
|
case "U": {
|
|
@@ -1126,14 +1134,11 @@ function resolveEscapeSequence(chars, startIndex, filePath, lineNumber) {
|
|
|
1126
1134
|
}
|
|
1127
1135
|
return { resolved: String.fromCodePoint(codePoint), charsConsumed: 6 };
|
|
1128
1136
|
}
|
|
1129
|
-
throw new ParseError(
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
hint: 'Unicode escapes must be exactly 4 hex digits, e.g. \\u0041 for "A".'
|
|
1135
|
-
}
|
|
1136
|
-
);
|
|
1137
|
+
throw new ParseError(`Invalid unicode escape sequence: ${"\\"}u${hexDigits}`, {
|
|
1138
|
+
line: lineNumber,
|
|
1139
|
+
filePath,
|
|
1140
|
+
hint: 'Unicode escapes must be exactly 4 hex digits, e.g. \\u0041 for "A".'
|
|
1141
|
+
});
|
|
1137
1142
|
}
|
|
1138
1143
|
/* v8 ignore start */
|
|
1139
1144
|
default: {
|
|
@@ -1415,11 +1420,7 @@ function parseEnvFile(content, filePath) {
|
|
|
1415
1420
|
comment = trimmedAfter.slice(1).trim();
|
|
1416
1421
|
}
|
|
1417
1422
|
} else if (firstChar === "'") {
|
|
1418
|
-
const result = parseSingleQuotedValue(
|
|
1419
|
-
lines,
|
|
1420
|
-
lineIndex,
|
|
1421
|
-
valueStartIndex + 1
|
|
1422
|
-
);
|
|
1423
|
+
const result = parseSingleQuotedValue(lines, lineIndex, valueStartIndex + 1);
|
|
1423
1424
|
if (!result.closed) {
|
|
1424
1425
|
throw new ParseError("Unterminated single-quoted string", {
|
|
1425
1426
|
line: oneBasedLine,
|
|
@@ -1440,11 +1441,7 @@ function parseEnvFile(content, filePath) {
|
|
|
1440
1441
|
comment = trimmedAfter.slice(1).trim();
|
|
1441
1442
|
}
|
|
1442
1443
|
} else if (firstChar === "`") {
|
|
1443
|
-
const result = parseBacktickQuotedValue(
|
|
1444
|
-
lines,
|
|
1445
|
-
lineIndex,
|
|
1446
|
-
valueStartIndex + 1
|
|
1447
|
-
);
|
|
1444
|
+
const result = parseBacktickQuotedValue(lines, lineIndex, valueStartIndex + 1);
|
|
1448
1445
|
if (!result.closed) {
|
|
1449
1446
|
throw new ParseError("Unterminated backtick-quoted string", {
|
|
1450
1447
|
line: oneBasedLine,
|
|
@@ -1676,12 +1673,9 @@ function expandVariables(vars, env, options) {
|
|
|
1676
1673
|
const resolving = /* @__PURE__ */ new Set();
|
|
1677
1674
|
function expandValue(raw, depth) {
|
|
1678
1675
|
if (depth > maxDepth) {
|
|
1679
|
-
throw new InterpolationError(
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
hint: "Check for deeply nested variable references. Consider simplifying your variable definitions."
|
|
1683
|
-
}
|
|
1684
|
-
);
|
|
1676
|
+
throw new InterpolationError(`Maximum interpolation depth (${maxDepth}) exceeded`, {
|
|
1677
|
+
hint: "Check for deeply nested variable references. Consider simplifying your variable definitions."
|
|
1678
|
+
});
|
|
1685
1679
|
}
|
|
1686
1680
|
const result2 = [];
|
|
1687
1681
|
let i = 0;
|
|
@@ -1717,14 +1711,11 @@ function expandVariables(vars, env, options) {
|
|
|
1717
1711
|
const parsed = parseExpression(inner);
|
|
1718
1712
|
if (resolving.has(parsed.varName)) {
|
|
1719
1713
|
const chain = Array.from(resolving).concat(parsed.varName).join(" \u2192 ");
|
|
1720
|
-
throw new InterpolationError(
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
hint: "Break the cycle by removing one of the circular references."
|
|
1726
|
-
}
|
|
1727
|
-
);
|
|
1714
|
+
throw new InterpolationError(`Circular variable reference detected: ${chain}`, {
|
|
1715
|
+
variable: parsed.varName,
|
|
1716
|
+
circular: true,
|
|
1717
|
+
hint: "Break the cycle by removing one of the circular references."
|
|
1718
|
+
});
|
|
1728
1719
|
}
|
|
1729
1720
|
resolving.add(parsed.varName);
|
|
1730
1721
|
if (parsed.varName in vars && !(parsed.varName in resolvedMap)) {
|
|
@@ -1755,14 +1746,11 @@ function expandVariables(vars, env, options) {
|
|
|
1755
1746
|
const varName = raw.slice(i, nameEnd);
|
|
1756
1747
|
if (resolving.has(varName)) {
|
|
1757
1748
|
const chain = Array.from(resolving).concat(varName).join(" \u2192 ");
|
|
1758
|
-
throw new InterpolationError(
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
hint: "Break the cycle by removing one of the circular references."
|
|
1764
|
-
}
|
|
1765
|
-
);
|
|
1749
|
+
throw new InterpolationError(`Circular variable reference detected: ${chain}`, {
|
|
1750
|
+
variable: varName,
|
|
1751
|
+
circular: true,
|
|
1752
|
+
hint: "Break the cycle by removing one of the circular references."
|
|
1753
|
+
});
|
|
1766
1754
|
}
|
|
1767
1755
|
resolving.add(varName);
|
|
1768
1756
|
if (varName in vars && !(varName in resolvedMap)) {
|
|
@@ -2181,18 +2169,12 @@ function drawTable(headers, rows, options) {
|
|
|
2181
2169
|
colWidths = naturalWidths.map((w) => Math.min(w, Math.max(avgWidth, 4)));
|
|
2182
2170
|
}
|
|
2183
2171
|
}
|
|
2184
|
-
const wrappedHeaders = headers.map(
|
|
2185
|
-
(h, i) => wrapText(h, colWidths[i] ?? 8)
|
|
2186
|
-
);
|
|
2172
|
+
const wrappedHeaders = headers.map((h, i) => wrapText(h, colWidths[i] ?? 8));
|
|
2187
2173
|
const wrappedRows = rows.map(
|
|
2188
|
-
(row) => row.map(
|
|
2189
|
-
(cell, i) => wrapText(cell, colWidths[i] ?? 8)
|
|
2190
|
-
)
|
|
2174
|
+
(row) => row.map((cell, i) => wrapText(cell, colWidths[i] ?? 8))
|
|
2191
2175
|
);
|
|
2192
2176
|
const maxHeaderLines = Math.max(...wrappedHeaders.map((lines2) => lines2.length));
|
|
2193
|
-
const maxRowLines = rows.length > 0 ? Math.max(...wrappedRows.map(
|
|
2194
|
-
(row) => Math.max(...row.map((cell) => cell.length))
|
|
2195
|
-
)) : 1;
|
|
2177
|
+
const maxRowLines = rows.length > 0 ? Math.max(...wrappedRows.map((row) => Math.max(...row.map((cell) => cell.length)))) : 1;
|
|
2196
2178
|
const maxLines = Math.max(maxHeaderLines, maxRowLines);
|
|
2197
2179
|
const lines = [];
|
|
2198
2180
|
const separatorParts = colWidths.map((w) => "\u2500".repeat(w + opts.padding * 2));
|
|
@@ -2734,8 +2716,8 @@ async function run3(args, ctx) {
|
|
|
2734
2716
|
const format = args.flags["--format"] ?? "declaration";
|
|
2735
2717
|
const outFlag = args.flags["--out"];
|
|
2736
2718
|
const defaultOutPaths = {
|
|
2737
|
-
|
|
2738
|
-
|
|
2719
|
+
declaration: "src/env.d.ts",
|
|
2720
|
+
module: "src/env.ts",
|
|
2739
2721
|
"json-schema": "env.schema.json"
|
|
2740
2722
|
};
|
|
2741
2723
|
const outputPath = outFlag ? (0, import_node_path6.resolve)(cwd, outFlag) : (0, import_node_path6.resolve)(cwd, defaultOutPaths[format] ?? "src/env.d.ts");
|
|
@@ -2747,27 +2729,21 @@ async function run3(args, ctx) {
|
|
|
2747
2729
|
let content = "";
|
|
2748
2730
|
if (format === "declaration") {
|
|
2749
2731
|
const { generateDeclarationContent: generateDeclarationContent2 } = await Promise.resolve().then(() => (init_declaration(), declaration_exports));
|
|
2750
|
-
content = generateDeclarationContent2(
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
);
|
|
2732
|
+
content = generateDeclarationContent2(result.env, schema, {
|
|
2733
|
+
interfaceName,
|
|
2734
|
+
jsdoc: true,
|
|
2735
|
+
indent: 4
|
|
2736
|
+
});
|
|
2755
2737
|
} else if (format === "module") {
|
|
2756
2738
|
const { generateModuleContent: generateModuleContent2 } = await Promise.resolve().then(() => (init_module(), module_exports));
|
|
2757
2739
|
if (!schema) {
|
|
2758
2740
|
writeError(yellow(" Warning: No schema defined. Generating empty module."));
|
|
2759
2741
|
writeError(yellow(" Add a schema to your .ultraenvrc.json for typed output."));
|
|
2760
2742
|
}
|
|
2761
|
-
content = generateModuleContent2(
|
|
2762
|
-
schema ?? {},
|
|
2763
|
-
{ interfaceName, jsdoc: true, indent: 2 }
|
|
2764
|
-
);
|
|
2743
|
+
content = generateModuleContent2(schema ?? {}, { interfaceName, jsdoc: true, indent: 2 });
|
|
2765
2744
|
} else if (format === "json-schema") {
|
|
2766
2745
|
const { generateJsonSchemaContent: generateJsonSchemaContent2 } = await Promise.resolve().then(() => (init_json_schema(), json_schema_exports));
|
|
2767
|
-
content = generateJsonSchemaContent2(
|
|
2768
|
-
schema ?? {},
|
|
2769
|
-
{ includeDescriptions: true, indent: 2 }
|
|
2770
|
-
);
|
|
2746
|
+
content = generateJsonSchemaContent2(schema ?? {}, { includeDescriptions: true, indent: 2 });
|
|
2771
2747
|
}
|
|
2772
2748
|
const { writeFile: writeFile2, ensureDir: ensureDir2 } = await Promise.resolve().then(() => (init_fs(), fs_exports));
|
|
2773
2749
|
await ensureDir2((0, import_node_path6.resolve)(outputPath, ".."));
|
|
@@ -3319,7 +3295,11 @@ async function checkSync(envPath, examplePath, ctx) {
|
|
|
3319
3295
|
if (ctx.outputFormat === "json") {
|
|
3320
3296
|
writeJson({ inSync: false, error: ".env file not found" });
|
|
3321
3297
|
} else {
|
|
3322
|
-
writeError(
|
|
3298
|
+
writeError(
|
|
3299
|
+
yellow(
|
|
3300
|
+
' \u26A0 .env file not found. Run "ultraenv sync --mode generate" to create .env.example.'
|
|
3301
|
+
)
|
|
3302
|
+
);
|
|
3323
3303
|
}
|
|
3324
3304
|
return 1;
|
|
3325
3305
|
}
|
|
@@ -3327,7 +3307,9 @@ async function checkSync(envPath, examplePath, ctx) {
|
|
|
3327
3307
|
if (ctx.outputFormat === "json") {
|
|
3328
3308
|
writeJson({ inSync: false, error: ".env.example not found" });
|
|
3329
3309
|
} else {
|
|
3330
|
-
writeError(
|
|
3310
|
+
writeError(
|
|
3311
|
+
yellow(' \u26A0 .env.example not found. Run "ultraenv sync --mode generate" to create it.')
|
|
3312
|
+
);
|
|
3331
3313
|
}
|
|
3332
3314
|
return 1;
|
|
3333
3315
|
}
|
|
@@ -3348,11 +3330,14 @@ async function checkSync(envPath, examplePath, ctx) {
|
|
|
3348
3330
|
writeLine(formatSyncDiff2(diff));
|
|
3349
3331
|
writeLine("");
|
|
3350
3332
|
if (!diff.inSync) {
|
|
3351
|
-
const box = drawBox(
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3333
|
+
const box = drawBox(
|
|
3334
|
+
[
|
|
3335
|
+
"Your .env is out of sync with .env.example.",
|
|
3336
|
+
'Run "ultraenv sync --mode generate" to update .env.example',
|
|
3337
|
+
'or "ultraenv sync --mode interactive" to review changes.'
|
|
3338
|
+
],
|
|
3339
|
+
{ title: "ACTION NEEDED", border: "rounded" }
|
|
3340
|
+
);
|
|
3356
3341
|
writeLine(box);
|
|
3357
3342
|
writeLine("");
|
|
3358
3343
|
return 1;
|
|
@@ -3671,7 +3656,7 @@ var init_secret_patterns = __esm({
|
|
|
3671
3656
|
{
|
|
3672
3657
|
id: "google-oauth-client-secret",
|
|
3673
3658
|
name: "Google OAuth Client Secret",
|
|
3674
|
-
pattern: /(?:^|["'\s:=,`]GOCSPX-[A-Za-z0-9_-]{28,})(?:["'\s,`;]|$)/gm,
|
|
3659
|
+
pattern: /(?:^|["'\s:=,`])(GOCSPX-[A-Za-z0-9_-]{28,})(?:["'\s,`;]|$)/gm,
|
|
3675
3660
|
confidence: 0.9,
|
|
3676
3661
|
severity: "critical",
|
|
3677
3662
|
description: "Google OAuth Client Secret (new format). Used for OAuth authentication flows.",
|
|
@@ -4435,9 +4420,7 @@ function extractCandidates(line) {
|
|
|
4435
4420
|
const captured = tokenMatch[1];
|
|
4436
4421
|
if (captured === void 0) continue;
|
|
4437
4422
|
const tokenIndex = tokenMatch.index + 1;
|
|
4438
|
-
const existing = candidates.some(
|
|
4439
|
-
(c) => c.value === captured && c.column === tokenIndex
|
|
4440
|
-
);
|
|
4423
|
+
const existing = candidates.some((c) => c.value === captured && c.column === tokenIndex);
|
|
4441
4424
|
if (!existing) {
|
|
4442
4425
|
candidates.push({ value: captured, column: tokenMatch.index + 1 });
|
|
4443
4426
|
}
|
|
@@ -5143,15 +5126,9 @@ function getSeverity(pattern) {
|
|
|
5143
5126
|
function formatTerminal(result) {
|
|
5144
5127
|
const lines = [];
|
|
5145
5128
|
const totalCount = result.secrets.length;
|
|
5146
|
-
const criticalCount = result.secrets.filter(
|
|
5147
|
-
|
|
5148
|
-
).length;
|
|
5149
|
-
const highCount = result.secrets.filter(
|
|
5150
|
-
(s) => getSeverity(s.pattern) === "high"
|
|
5151
|
-
).length;
|
|
5152
|
-
const mediumCount = result.secrets.filter(
|
|
5153
|
-
(s) => getSeverity(s.pattern) === "medium"
|
|
5154
|
-
).length;
|
|
5129
|
+
const criticalCount = result.secrets.filter((s) => getSeverity(s.pattern) === "critical").length;
|
|
5130
|
+
const highCount = result.secrets.filter((s) => getSeverity(s.pattern) === "high").length;
|
|
5131
|
+
const mediumCount = result.secrets.filter((s) => getSeverity(s.pattern) === "medium").length;
|
|
5155
5132
|
lines.push("");
|
|
5156
5133
|
lines.push(`${BOLD}=== ultraenv Secret Scan Report ===${RESET}`);
|
|
5157
5134
|
lines.push("");
|
|
@@ -5167,7 +5144,9 @@ function formatTerminal(result) {
|
|
|
5167
5144
|
}
|
|
5168
5145
|
const summaryParts = [];
|
|
5169
5146
|
if (criticalCount > 0) {
|
|
5170
|
-
summaryParts.push(
|
|
5147
|
+
summaryParts.push(
|
|
5148
|
+
`${SEVERITY_CONFIG.critical.terminalColor}${BOLD}${criticalCount} critical${RESET}`
|
|
5149
|
+
);
|
|
5171
5150
|
}
|
|
5172
5151
|
if (highCount > 0) {
|
|
5173
5152
|
summaryParts.push(`${SEVERITY_CONFIG.high.terminalColor}${BOLD}${highCount} high${RESET}`);
|
|
@@ -5693,13 +5672,16 @@ async function run7(args, ctx) {
|
|
|
5693
5672
|
if (!gitignoreExists) {
|
|
5694
5673
|
writeError(red(" \u2717 No .gitignore file found!"));
|
|
5695
5674
|
writeLine("");
|
|
5696
|
-
const box = drawBox(
|
|
5697
|
-
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
5702
|
-
|
|
5675
|
+
const box = drawBox(
|
|
5676
|
+
[
|
|
5677
|
+
"Your project has no .gitignore file.",
|
|
5678
|
+
"Secrets in .env files could be committed to version control.",
|
|
5679
|
+
"Create a .gitignore with ultraenv entries:",
|
|
5680
|
+
"",
|
|
5681
|
+
" ultraenv init"
|
|
5682
|
+
],
|
|
5683
|
+
{ title: "DANGER", border: "double" }
|
|
5684
|
+
);
|
|
5703
5685
|
writeLine(box);
|
|
5704
5686
|
writeLine("");
|
|
5705
5687
|
return 1;
|
|
@@ -5715,7 +5697,9 @@ async function run7(args, ctx) {
|
|
|
5715
5697
|
issues.push(pattern);
|
|
5716
5698
|
}
|
|
5717
5699
|
}
|
|
5718
|
-
writeLine(
|
|
5700
|
+
writeLine(
|
|
5701
|
+
green(` \u2713 ${protectedEntries.length}/${PROTECTED_PATTERNS.length} patterns protected`)
|
|
5702
|
+
);
|
|
5719
5703
|
const envFiles = [".env", ".env.local", ".env.production", ".env.development"];
|
|
5720
5704
|
const notIgnored = [];
|
|
5721
5705
|
for (const envFile of envFiles) {
|
|
@@ -5746,13 +5730,16 @@ async function run7(args, ctx) {
|
|
|
5746
5730
|
writeError(red(` - ${f}`));
|
|
5747
5731
|
}
|
|
5748
5732
|
writeLine("");
|
|
5749
|
-
const warnBox = drawBox(
|
|
5750
|
-
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5733
|
+
const warnBox = drawBox(
|
|
5734
|
+
[
|
|
5735
|
+
"Tracked .env files may contain secrets.",
|
|
5736
|
+
"Remove them from version control immediately:",
|
|
5737
|
+
"",
|
|
5738
|
+
" git rm --cached .env*",
|
|
5739
|
+
' git commit -m "Remove tracked .env files"'
|
|
5740
|
+
],
|
|
5741
|
+
{ title: "WARNING", border: "double" }
|
|
5742
|
+
);
|
|
5756
5743
|
writeLine(warnBox);
|
|
5757
5744
|
writeLine("");
|
|
5758
5745
|
return 1;
|
|
@@ -5808,13 +5795,7 @@ var init_protect = __esm({
|
|
|
5808
5795
|
import_node_path11 = require("path");
|
|
5809
5796
|
init_fs();
|
|
5810
5797
|
init_git();
|
|
5811
|
-
PROTECTED_PATTERNS = [
|
|
5812
|
-
".env",
|
|
5813
|
-
".env.local",
|
|
5814
|
-
".env.*.local",
|
|
5815
|
-
".env.vault",
|
|
5816
|
-
".env.keys"
|
|
5817
|
-
];
|
|
5798
|
+
PROTECTED_PATTERNS = [".env", ".env.local", ".env.*.local", ".env.vault", ".env.keys"];
|
|
5818
5799
|
}
|
|
5819
5800
|
});
|
|
5820
5801
|
|
|
@@ -5841,11 +5822,7 @@ function manualHkdf(ikm, salt, info, length) {
|
|
|
5841
5822
|
const okm = Buffer.alloc(length);
|
|
5842
5823
|
let previous = Buffer.alloc(0);
|
|
5843
5824
|
for (let i = 1; i <= n; i++) {
|
|
5844
|
-
const hmacData = Buffer.concat([
|
|
5845
|
-
previous,
|
|
5846
|
-
infoBuffer,
|
|
5847
|
-
Buffer.from([i])
|
|
5848
|
-
]);
|
|
5825
|
+
const hmacData = Buffer.concat([previous, infoBuffer, Buffer.from([i])]);
|
|
5849
5826
|
previous = (0, import_node_crypto.createHmac)("sha256", prk).update(hmacData).digest();
|
|
5850
5827
|
const offset = (i - 1) * hashLen;
|
|
5851
5828
|
const copyLen = Math.min(hashLen, length - offset);
|
|
@@ -5862,10 +5839,7 @@ function encrypt(key, plaintext) {
|
|
|
5862
5839
|
const iv = (0, import_node_crypto.randomBytes)(12);
|
|
5863
5840
|
const algo = `aes-${key.length * 8}-gcm`;
|
|
5864
5841
|
const cipher = (0, import_node_crypto.createCipheriv)(algo, key, iv);
|
|
5865
|
-
const ciphertext = Buffer.concat([
|
|
5866
|
-
cipher.update(plaintext),
|
|
5867
|
-
cipher.final()
|
|
5868
|
-
]);
|
|
5842
|
+
const ciphertext = Buffer.concat([cipher.update(plaintext), cipher.final()]);
|
|
5869
5843
|
const authTag = cipher.getAuthTag();
|
|
5870
5844
|
return { iv, authTag, ciphertext };
|
|
5871
5845
|
}
|
|
@@ -5879,10 +5853,7 @@ function decrypt(key, iv, authTag, ciphertext) {
|
|
|
5879
5853
|
const decipher = (0, import_node_crypto.createDecipheriv)(algo, key, iv);
|
|
5880
5854
|
decipher.setAuthTag(authTag);
|
|
5881
5855
|
try {
|
|
5882
|
-
return Buffer.concat([
|
|
5883
|
-
decipher.update(ciphertext),
|
|
5884
|
-
decipher.final()
|
|
5885
|
-
]);
|
|
5856
|
+
return Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
5886
5857
|
} catch (error) {
|
|
5887
5858
|
const message = error instanceof Error ? error.message : String(error);
|
|
5888
5859
|
throw new Error(
|
|
@@ -5934,12 +5905,9 @@ function decryptValue(encrypted, key) {
|
|
|
5934
5905
|
);
|
|
5935
5906
|
}
|
|
5936
5907
|
if (!encrypted.startsWith(ENCRYPTED_PREFIX)) {
|
|
5937
|
-
throw new EncryptionError(
|
|
5938
|
-
"
|
|
5939
|
-
|
|
5940
|
-
hint: `Expected the value to start with "${ENCRYPTED_PREFIX}". This value may not have been encrypted by ultraenv.`
|
|
5941
|
-
}
|
|
5942
|
-
);
|
|
5908
|
+
throw new EncryptionError("Invalid encrypted value format: missing required prefix", {
|
|
5909
|
+
hint: `Expected the value to start with "${ENCRYPTED_PREFIX}". This value may not have been encrypted by ultraenv.`
|
|
5910
|
+
});
|
|
5943
5911
|
}
|
|
5944
5912
|
const payload = encrypted.slice(ENCRYPTED_PREFIX.length);
|
|
5945
5913
|
const parts = payload.split(":");
|
|
@@ -5955,16 +5923,14 @@ function decryptValue(encrypted, key) {
|
|
|
5955
5923
|
const authTagB64 = parts[1];
|
|
5956
5924
|
const ciphertextB64 = parts[2];
|
|
5957
5925
|
if (ivB64 === void 0 || authTagB64 === void 0 || ciphertextB64 === void 0) {
|
|
5958
|
-
throw new EncryptionError(
|
|
5959
|
-
"
|
|
5960
|
-
|
|
5961
|
-
);
|
|
5926
|
+
throw new EncryptionError("Invalid encrypted value: unexpected component structure", {
|
|
5927
|
+
hint: "The encrypted data may be corrupted. Try re-encrypting the value."
|
|
5928
|
+
});
|
|
5962
5929
|
}
|
|
5963
5930
|
if (ivB64.length === 0 || authTagB64.length === 0 || ciphertextB64.length === 0) {
|
|
5964
|
-
throw new EncryptionError(
|
|
5965
|
-
"
|
|
5966
|
-
|
|
5967
|
-
);
|
|
5931
|
+
throw new EncryptionError("Invalid encrypted value: one or more base64 components are empty", {
|
|
5932
|
+
hint: "The encrypted data may be corrupted. Try re-encrypting the value."
|
|
5933
|
+
});
|
|
5968
5934
|
}
|
|
5969
5935
|
try {
|
|
5970
5936
|
const iv = base64ToBuffer(ivB64);
|
|
@@ -5973,7 +5939,9 @@ function decryptValue(encrypted, key) {
|
|
|
5973
5939
|
if (iv.length !== IV_LENGTH) {
|
|
5974
5940
|
throw new EncryptionError(
|
|
5975
5941
|
`Invalid IV length: expected ${IV_LENGTH} bytes, got ${iv.length}`,
|
|
5976
|
-
{
|
|
5942
|
+
{
|
|
5943
|
+
hint: "The encrypted data may be corrupted or was produced by a different version of ultraenv."
|
|
5944
|
+
}
|
|
5977
5945
|
);
|
|
5978
5946
|
}
|
|
5979
5947
|
if (authTag.length !== AUTH_TAG_LENGTH) {
|
|
@@ -5988,10 +5956,9 @@ function decryptValue(encrypted, key) {
|
|
|
5988
5956
|
if (error instanceof EncryptionError) throw error;
|
|
5989
5957
|
const message = error instanceof Error ? error.message : String(error);
|
|
5990
5958
|
if (message.includes("Invalid") || message.includes("base64")) {
|
|
5991
|
-
throw new EncryptionError(
|
|
5992
|
-
"
|
|
5993
|
-
|
|
5994
|
-
);
|
|
5959
|
+
throw new EncryptionError("Invalid base64 encoding in encrypted value", {
|
|
5960
|
+
hint: "The encrypted data may be corrupted. Ensure the value was not modified."
|
|
5961
|
+
});
|
|
5995
5962
|
}
|
|
5996
5963
|
throw new EncryptionError(
|
|
5997
5964
|
"Failed to decrypt value. The key may be incorrect or the ciphertext was tampered with.",
|
|
@@ -6041,10 +6008,9 @@ function deriveEnvironmentKey(masterKey, environment) {
|
|
|
6041
6008
|
);
|
|
6042
6009
|
}
|
|
6043
6010
|
if (environment.length === 0) {
|
|
6044
|
-
throw new EncryptionError(
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
);
|
|
6011
|
+
throw new EncryptionError("Environment name cannot be empty", {
|
|
6012
|
+
hint: 'Provide a valid environment name (e.g., "development", "production").'
|
|
6013
|
+
});
|
|
6048
6014
|
}
|
|
6049
6015
|
if (HKDF_SALT.length < DEFAULT_SALT_LENGTH) {
|
|
6050
6016
|
const paddedSalt = Buffer.alloc(DEFAULT_SALT_LENGTH);
|
|
@@ -6056,12 +6022,7 @@ function deriveEnvironmentKey(masterKey, environment) {
|
|
|
6056
6022
|
DEFAULT_KEY_LENGTH
|
|
6057
6023
|
);
|
|
6058
6024
|
}
|
|
6059
|
-
return deriveKey(
|
|
6060
|
-
masterKey,
|
|
6061
|
-
HKDF_SALT,
|
|
6062
|
-
`${HKDF_INFO_PREFIX}${environment}`,
|
|
6063
|
-
DEFAULT_KEY_LENGTH
|
|
6064
|
-
);
|
|
6025
|
+
return deriveKey(masterKey, HKDF_SALT, `${HKDF_INFO_PREFIX}${environment}`, DEFAULT_KEY_LENGTH);
|
|
6065
6026
|
}
|
|
6066
6027
|
function formatKey(key) {
|
|
6067
6028
|
if (key.length === 0) {
|
|
@@ -6081,21 +6042,17 @@ function parseKey2(formatted) {
|
|
|
6081
6042
|
}
|
|
6082
6043
|
const base64Part = formatted.slice(KEY_PREFIX.length);
|
|
6083
6044
|
if (base64Part.length === 0) {
|
|
6084
|
-
throw new EncryptionError(
|
|
6085
|
-
"
|
|
6086
|
-
|
|
6087
|
-
);
|
|
6045
|
+
throw new EncryptionError("Invalid key format: base64 payload is empty after prefix", {
|
|
6046
|
+
hint: "The key appears to be truncated. Generate a new key."
|
|
6047
|
+
});
|
|
6088
6048
|
}
|
|
6089
6049
|
try {
|
|
6090
6050
|
return base64ToBuffer(base64Part);
|
|
6091
6051
|
} catch (error) {
|
|
6092
|
-
throw new EncryptionError(
|
|
6093
|
-
|
|
6094
|
-
|
|
6095
|
-
|
|
6096
|
-
hint: 'The key may be corrupted. Generate a new key with "ultraenv key generate".'
|
|
6097
|
-
}
|
|
6098
|
-
);
|
|
6052
|
+
throw new EncryptionError("Failed to decode key: invalid base64 encoding", {
|
|
6053
|
+
cause: error instanceof Error ? error : void 0,
|
|
6054
|
+
hint: 'The key may be corrupted. Generate a new key with "ultraenv key generate".'
|
|
6055
|
+
});
|
|
6099
6056
|
}
|
|
6100
6057
|
}
|
|
6101
6058
|
function isValidKeyFormat(formatted) {
|
|
@@ -6157,12 +6114,9 @@ function parseKeysFile(content) {
|
|
|
6157
6114
|
if (!eqMatch) {
|
|
6158
6115
|
const plainMatch = line.match(/^ULTRAENV_KEY_([A-Za-z0-9_]+)=(.*)$/);
|
|
6159
6116
|
if (!plainMatch) {
|
|
6160
|
-
throw new EncryptionError(
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
hint: 'Each key entry should be in the format: ULTRAENV_KEY_{ENVIRONMENT}="ultraenv_key_v1_..."'
|
|
6164
|
-
}
|
|
6165
|
-
);
|
|
6117
|
+
throw new EncryptionError(`Invalid keys file format at line ${i + 1}: "${line}"`, {
|
|
6118
|
+
hint: 'Each key entry should be in the format: ULTRAENV_KEY_{ENVIRONMENT}="ultraenv_key_v1_..."'
|
|
6119
|
+
});
|
|
6166
6120
|
}
|
|
6167
6121
|
const envName2 = plainMatch[1].toLowerCase();
|
|
6168
6122
|
const keyValue2 = plainMatch[2];
|
|
@@ -6308,21 +6262,14 @@ function parseVaultFile(content) {
|
|
|
6308
6262
|
if (rawLine === void 0) continue;
|
|
6309
6263
|
const line = rawLine.trim();
|
|
6310
6264
|
if (line.length === 0 || line.startsWith("#")) continue;
|
|
6311
|
-
const match = line.match(
|
|
6312
|
-
new RegExp(`^${VAULT_VAR_PREFIX}([A-Za-z0-9_]+)="(.*)"$`)
|
|
6313
|
-
);
|
|
6265
|
+
const match = line.match(new RegExp(`^${VAULT_VAR_PREFIX}([A-Za-z0-9_]+)="(.*)"$`));
|
|
6314
6266
|
if (!match) {
|
|
6315
|
-
const plainMatch = line.match(
|
|
6316
|
-
new RegExp(`^${VAULT_VAR_PREFIX}([A-Za-z0-9_]+)=(.*)$`)
|
|
6317
|
-
);
|
|
6267
|
+
const plainMatch = line.match(new RegExp(`^${VAULT_VAR_PREFIX}([A-Za-z0-9_]+)=(.*)$`));
|
|
6318
6268
|
if (!plainMatch) {
|
|
6319
|
-
throw new VaultError(
|
|
6320
|
-
|
|
6321
|
-
{
|
|
6322
|
-
|
|
6323
|
-
hint: `Each environment entry should be in the format: ${VAULT_VAR_PREFIX}{ENVIRONMENT}="encrypted:..."`
|
|
6324
|
-
}
|
|
6325
|
-
);
|
|
6269
|
+
throw new VaultError(`Invalid vault file format at line ${lineNumber}: "${line}"`, {
|
|
6270
|
+
operation: "parse",
|
|
6271
|
+
hint: `Each environment entry should be in the format: ${VAULT_VAR_PREFIX}{ENVIRONMENT}="encrypted:..."`
|
|
6272
|
+
});
|
|
6326
6273
|
}
|
|
6327
6274
|
const envName2 = plainMatch[1].toLowerCase();
|
|
6328
6275
|
const encryptedValue2 = plainMatch[2];
|
|
@@ -6375,41 +6322,32 @@ async function readVaultFile(path) {
|
|
|
6375
6322
|
return parseVaultFile(content);
|
|
6376
6323
|
} catch (error) {
|
|
6377
6324
|
if (error instanceof VaultError) throw error;
|
|
6378
|
-
throw new VaultError(
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
6382
|
-
|
|
6383
|
-
|
|
6384
|
-
/* v8 ignore stop */
|
|
6385
|
-
}
|
|
6386
|
-
);
|
|
6325
|
+
throw new VaultError(`Failed to read vault file "${path}"`, {
|
|
6326
|
+
operation: "read",
|
|
6327
|
+
/* v8 ignore start */
|
|
6328
|
+
cause: error instanceof Error ? error : void 0
|
|
6329
|
+
/* v8 ignore stop */
|
|
6330
|
+
});
|
|
6387
6331
|
}
|
|
6388
6332
|
}
|
|
6389
6333
|
async function writeVaultFile(path, environments) {
|
|
6390
6334
|
if (environments.size === 0) {
|
|
6391
|
-
throw new VaultError(
|
|
6392
|
-
"
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
hint: "Add at least one environment to the vault before writing."
|
|
6396
|
-
}
|
|
6397
|
-
);
|
|
6335
|
+
throw new VaultError("Cannot write an empty vault file", {
|
|
6336
|
+
operation: "write",
|
|
6337
|
+
hint: "Add at least one environment to the vault before writing."
|
|
6338
|
+
});
|
|
6398
6339
|
}
|
|
6399
6340
|
try {
|
|
6400
6341
|
const content = serializeVaultFile(environments);
|
|
6401
6342
|
await writeFile(path, content, "utf-8");
|
|
6402
6343
|
} catch (error) {
|
|
6403
6344
|
if (error instanceof VaultError) throw error;
|
|
6404
|
-
throw new VaultError(
|
|
6405
|
-
|
|
6406
|
-
|
|
6407
|
-
|
|
6408
|
-
|
|
6409
|
-
|
|
6410
|
-
/* v8 ignore stop */
|
|
6411
|
-
}
|
|
6412
|
-
);
|
|
6345
|
+
throw new VaultError(`Failed to write vault file "${path}"`, {
|
|
6346
|
+
operation: "write",
|
|
6347
|
+
/* v8 ignore start */
|
|
6348
|
+
cause: error instanceof Error ? error : void 0
|
|
6349
|
+
/* v8 ignore stop */
|
|
6350
|
+
});
|
|
6413
6351
|
}
|
|
6414
6352
|
}
|
|
6415
6353
|
function countEncryptedVars(encrypted) {
|
|
@@ -6942,16 +6880,14 @@ var init_vault_diff = __esm({
|
|
|
6942
6880
|
// src/vault/integrity.ts
|
|
6943
6881
|
function computeIntegrity(data, key) {
|
|
6944
6882
|
if (key.length === 0) {
|
|
6945
|
-
throw new EncryptionError(
|
|
6946
|
-
"
|
|
6947
|
-
|
|
6948
|
-
);
|
|
6883
|
+
throw new EncryptionError("Cannot compute integrity with an empty key", {
|
|
6884
|
+
hint: "Provide a valid encryption key for integrity computation."
|
|
6885
|
+
});
|
|
6949
6886
|
}
|
|
6950
6887
|
if (data.length === 0) {
|
|
6951
|
-
throw new EncryptionError(
|
|
6952
|
-
"
|
|
6953
|
-
|
|
6954
|
-
);
|
|
6888
|
+
throw new EncryptionError("Cannot compute integrity for empty data", {
|
|
6889
|
+
hint: "Provide non-empty data for integrity computation."
|
|
6890
|
+
});
|
|
6955
6891
|
}
|
|
6956
6892
|
const hmac = (0, import_node_crypto3.createHmac)(HMAC_ALGORITHM, key);
|
|
6957
6893
|
hmac.update(data, "utf-8");
|
|
@@ -7183,12 +7119,14 @@ async function validateAllEnvironments(schema, cwd) {
|
|
|
7183
7119
|
const message = error instanceof Error ? error.message : String(error);
|
|
7184
7120
|
results.set(envName ?? pattern, {
|
|
7185
7121
|
valid: false,
|
|
7186
|
-
errors: [
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7190
|
-
|
|
7191
|
-
|
|
7122
|
+
errors: [
|
|
7123
|
+
{
|
|
7124
|
+
field: "",
|
|
7125
|
+
value: "",
|
|
7126
|
+
message: `Failed to read/parse file: ${message}`,
|
|
7127
|
+
hint: "Check that the file is a valid .env file."
|
|
7128
|
+
}
|
|
7129
|
+
],
|
|
7192
7130
|
warnings: []
|
|
7193
7131
|
});
|
|
7194
7132
|
}
|
|
@@ -7199,14 +7137,11 @@ async function switchEnvironment(envName, cwd) {
|
|
|
7199
7137
|
const baseDir = (0, import_node_path19.resolve)(cwd ?? process.cwd());
|
|
7200
7138
|
const envFile = (0, import_node_path19.join)(baseDir, `.env.${envName}`);
|
|
7201
7139
|
if (!await exists(envFile)) {
|
|
7202
|
-
throw new FileSystemError(
|
|
7203
|
-
|
|
7204
|
-
|
|
7205
|
-
|
|
7206
|
-
|
|
7207
|
-
hint: `Create a ".env.${envName}" file first, or use "ultraenv env create ${envName}".`
|
|
7208
|
-
}
|
|
7209
|
-
);
|
|
7140
|
+
throw new FileSystemError(`Environment file ".env.${envName}" not found`, {
|
|
7141
|
+
path: envFile,
|
|
7142
|
+
operation: "read",
|
|
7143
|
+
hint: `Create a ".env.${envName}" file first, or use "ultraenv env create ${envName}".`
|
|
7144
|
+
});
|
|
7210
7145
|
}
|
|
7211
7146
|
const content = await readFile(envFile);
|
|
7212
7147
|
const header = [
|
|
@@ -7392,24 +7327,18 @@ async function compareEnvironments(env1, env2, cwd, _schema) {
|
|
|
7392
7327
|
const resolvedEnv1Path = env1.includes("/") || env1.includes("\\") ? (0, import_node_path20.resolve)(env1) : env1Path;
|
|
7393
7328
|
const resolvedEnv2Path = env2.includes("/") || env2.includes("\\") ? (0, import_node_path20.resolve)(env2) : env2Path;
|
|
7394
7329
|
if (!await exists(resolvedEnv1Path)) {
|
|
7395
|
-
throw new FileSystemError(
|
|
7396
|
-
|
|
7397
|
-
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
hint: `Ensure ".env.${env1}" exists in the project directory.`
|
|
7401
|
-
}
|
|
7402
|
-
);
|
|
7330
|
+
throw new FileSystemError(`Environment file not found: "${resolvedEnv1Path}"`, {
|
|
7331
|
+
path: resolvedEnv1Path,
|
|
7332
|
+
operation: "read",
|
|
7333
|
+
hint: `Ensure ".env.${env1}" exists in the project directory.`
|
|
7334
|
+
});
|
|
7403
7335
|
}
|
|
7404
7336
|
if (!await exists(resolvedEnv2Path)) {
|
|
7405
|
-
throw new FileSystemError(
|
|
7406
|
-
|
|
7407
|
-
|
|
7408
|
-
|
|
7409
|
-
|
|
7410
|
-
hint: `Ensure ".env.${env2}" exists in the project directory.`
|
|
7411
|
-
}
|
|
7412
|
-
);
|
|
7337
|
+
throw new FileSystemError(`Environment file not found: "${resolvedEnv2Path}"`, {
|
|
7338
|
+
path: resolvedEnv2Path,
|
|
7339
|
+
operation: "read",
|
|
7340
|
+
hint: `Ensure ".env.${env2}" exists in the project directory.`
|
|
7341
|
+
});
|
|
7413
7342
|
}
|
|
7414
7343
|
const env1Content = await readFile(resolvedEnv1Path);
|
|
7415
7344
|
const env2Content = await readFile(resolvedEnv2Path);
|
|
@@ -7502,14 +7431,18 @@ function formatComparison(comparison) {
|
|
|
7502
7431
|
lines.push("");
|
|
7503
7432
|
lines.push(`Only in ${comparison.env1Name} (${comparison.onlyInEnv1.length}):`);
|
|
7504
7433
|
for (const diff of comparison.onlyInEnv1) {
|
|
7505
|
-
lines.push(
|
|
7434
|
+
lines.push(
|
|
7435
|
+
` - ${diff.key}${diff.isSecret ? " [SECRET]" : ""} = ${diff.value1 || "(empty)"}`
|
|
7436
|
+
);
|
|
7506
7437
|
}
|
|
7507
7438
|
}
|
|
7508
7439
|
if (comparison.onlyInEnv2.length > 0) {
|
|
7509
7440
|
lines.push("");
|
|
7510
7441
|
lines.push(`Only in ${comparison.env2Name} (${comparison.onlyInEnv2.length}):`);
|
|
7511
7442
|
for (const diff of comparison.onlyInEnv2) {
|
|
7512
|
-
lines.push(
|
|
7443
|
+
lines.push(
|
|
7444
|
+
` + ${diff.key}${diff.isSecret ? " [SECRET]" : ""} = ${diff.value2 || "(empty)"}`
|
|
7445
|
+
);
|
|
7513
7446
|
}
|
|
7514
7447
|
}
|
|
7515
7448
|
if (comparison.different.length > 0) {
|
|
@@ -7643,10 +7576,7 @@ async function run17(args, ctx) {
|
|
|
7643
7576
|
writeLine(yellow(" No schema defined in configuration. Basic validation only."));
|
|
7644
7577
|
writeLine("");
|
|
7645
7578
|
}
|
|
7646
|
-
const results = await validateAllEnvironments(
|
|
7647
|
-
ctx.config.schema?.definitions ?? {},
|
|
7648
|
-
cwd
|
|
7649
|
-
);
|
|
7579
|
+
const results = await validateAllEnvironments(ctx.config.schema?.definitions ?? {}, cwd);
|
|
7650
7580
|
if (ctx.outputFormat === "json") {
|
|
7651
7581
|
const jsonResults = {};
|
|
7652
7582
|
for (const [name, result] of results) {
|
|
@@ -7799,14 +7729,11 @@ function validateEnvironmentName(name) {
|
|
|
7799
7729
|
});
|
|
7800
7730
|
}
|
|
7801
7731
|
if (name.length > 64) {
|
|
7802
|
-
throw new FileSystemError(
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
hint: "Use a shorter environment name."
|
|
7808
|
-
}
|
|
7809
|
-
);
|
|
7732
|
+
throw new FileSystemError(`Environment name too long: ${name.length} characters (max 64)`, {
|
|
7733
|
+
path: "",
|
|
7734
|
+
operation: "validate",
|
|
7735
|
+
hint: "Use a shorter environment name."
|
|
7736
|
+
});
|
|
7810
7737
|
}
|
|
7811
7738
|
if (!/^[a-zA-Z0-9_-]+$/.test(name)) {
|
|
7812
7739
|
throw new FileSystemError(
|
|
@@ -7820,14 +7747,11 @@ function validateEnvironmentName(name) {
|
|
|
7820
7747
|
}
|
|
7821
7748
|
const reserved = ["local", "example", "template", "bak", "backup", "old", "tmp", "temp"];
|
|
7822
7749
|
if (reserved.includes(name.toLowerCase())) {
|
|
7823
|
-
throw new FileSystemError(
|
|
7824
|
-
|
|
7825
|
-
|
|
7826
|
-
|
|
7827
|
-
|
|
7828
|
-
hint: `The name "${name}" is reserved. Choose a different name.`
|
|
7829
|
-
}
|
|
7830
|
-
);
|
|
7750
|
+
throw new FileSystemError(`Reserved environment name: "${name}"`, {
|
|
7751
|
+
path: "",
|
|
7752
|
+
operation: "validate",
|
|
7753
|
+
hint: `The name "${name}" is reserved. Choose a different name.`
|
|
7754
|
+
});
|
|
7831
7755
|
}
|
|
7832
7756
|
}
|
|
7833
7757
|
async function createEnvironment(name, options) {
|
|
@@ -7835,28 +7759,22 @@ async function createEnvironment(name, options) {
|
|
|
7835
7759
|
const baseDir = (0, import_node_path21.resolve)(options?.cwd ?? process.cwd());
|
|
7836
7760
|
const outputPath = (0, import_node_path21.join)(baseDir, `.env.${name}`);
|
|
7837
7761
|
if (await exists(outputPath)) {
|
|
7838
|
-
throw new FileSystemError(
|
|
7839
|
-
|
|
7840
|
-
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
hint: "Delete the existing file first, or use a different environment name."
|
|
7844
|
-
}
|
|
7845
|
-
);
|
|
7762
|
+
throw new FileSystemError(`Environment file already exists: ".env.${name}"`, {
|
|
7763
|
+
path: outputPath,
|
|
7764
|
+
operation: "create",
|
|
7765
|
+
hint: "Delete the existing file first, or use a different environment name."
|
|
7766
|
+
});
|
|
7846
7767
|
}
|
|
7847
7768
|
let content;
|
|
7848
7769
|
let variables = [];
|
|
7849
7770
|
if (options?.copyFrom !== void 0) {
|
|
7850
7771
|
const sourcePath = (0, import_node_path21.join)(baseDir, `.env.${options.copyFrom}`);
|
|
7851
7772
|
if (!await exists(sourcePath)) {
|
|
7852
|
-
throw new FileSystemError(
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
hint: `Ensure ".env.${options.copyFrom}" exists before copying.`
|
|
7858
|
-
}
|
|
7859
|
-
);
|
|
7773
|
+
throw new FileSystemError(`Source environment not found: ".env.${options.copyFrom}"`, {
|
|
7774
|
+
path: sourcePath,
|
|
7775
|
+
operation: "read",
|
|
7776
|
+
hint: `Ensure ".env.${options.copyFrom}" exists before copying.`
|
|
7777
|
+
});
|
|
7860
7778
|
}
|
|
7861
7779
|
content = await readFile(sourcePath);
|
|
7862
7780
|
variables = extractVariables(content, options?.schema);
|
|
@@ -7877,14 +7795,11 @@ async function createEnvironment(name, options) {
|
|
|
7877
7795
|
} else if (await exists(templatePath)) {
|
|
7878
7796
|
content = await readFile(templatePath);
|
|
7879
7797
|
} else {
|
|
7880
|
-
throw new FileSystemError(
|
|
7881
|
-
|
|
7882
|
-
|
|
7883
|
-
|
|
7884
|
-
|
|
7885
|
-
hint: "Use a built-in template name (nodejs, nextjs, docker) or a valid file path."
|
|
7886
|
-
}
|
|
7887
|
-
);
|
|
7798
|
+
throw new FileSystemError(`Template not found: "${options.fromTemplate}"`, {
|
|
7799
|
+
path: templatePath,
|
|
7800
|
+
operation: "read",
|
|
7801
|
+
hint: "Use a built-in template name (nodejs, nextjs, docker) or a valid file path."
|
|
7802
|
+
});
|
|
7888
7803
|
}
|
|
7889
7804
|
variables = extractVariables(content, options?.schema);
|
|
7890
7805
|
const values = collectValues(variables, options?.values);
|
|
@@ -7919,9 +7834,18 @@ async function createEnvironment(name, options) {
|
|
|
7919
7834
|
}
|
|
7920
7835
|
function listTemplates() {
|
|
7921
7836
|
return [
|
|
7922
|
-
{
|
|
7923
|
-
|
|
7924
|
-
|
|
7837
|
+
{
|
|
7838
|
+
name: "nodejs",
|
|
7839
|
+
description: "Node.js backend environment (PORT, DATABASE_URL, JWT, CORS, etc.)"
|
|
7840
|
+
},
|
|
7841
|
+
{
|
|
7842
|
+
name: "nextjs",
|
|
7843
|
+
description: "Next.js frontend environment (NEXT_PUBLIC_* variables, analytics, etc.)"
|
|
7844
|
+
},
|
|
7845
|
+
{
|
|
7846
|
+
name: "docker",
|
|
7847
|
+
description: "Docker deployment environment (container ports, Postgres, Redis, etc.)"
|
|
7848
|
+
}
|
|
7925
7849
|
];
|
|
7926
7850
|
}
|
|
7927
7851
|
var import_node_path21, NODEJS_TEMPLATE, NEXTJS_TEMPLATE, DOCKER_TEMPLATE, BUILTIN_TEMPLATES;
|
|
@@ -8213,10 +8137,7 @@ async function run22(args, ctx) {
|
|
|
8213
8137
|
failFast: args.flags["--fail-fast"] ?? true,
|
|
8214
8138
|
outputFormat
|
|
8215
8139
|
});
|
|
8216
|
-
const formatted = formatScanResult(
|
|
8217
|
-
result,
|
|
8218
|
-
outputFormat
|
|
8219
|
-
);
|
|
8140
|
+
const formatted = formatScanResult(result, outputFormat);
|
|
8220
8141
|
process.stdout.write(formatted + "\n");
|
|
8221
8142
|
return result.found ? 1 : 0;
|
|
8222
8143
|
} catch (error) {
|
|
@@ -8560,7 +8481,9 @@ async function run25(args, ctx) {
|
|
|
8560
8481
|
writeJson({ checks, summary: { passed, warnings, failed, total: checks.length } });
|
|
8561
8482
|
return failed > 0 ? 1 : 0;
|
|
8562
8483
|
}
|
|
8563
|
-
writeLine(
|
|
8484
|
+
writeLine(
|
|
8485
|
+
cyan(` ${passed}/${checks.length} passed, ${warnings} warning(s), ${failed} failure(s)`)
|
|
8486
|
+
);
|
|
8564
8487
|
writeLine("");
|
|
8565
8488
|
if (failed > 0) {
|
|
8566
8489
|
writeLine(red(bold(" Some checks failed. Fix the issues above.")));
|
|
@@ -8776,11 +8699,11 @@ async function run27(args, _ctx) {
|
|
|
8776
8699
|
writeLine(` Usage: ${cmd.usage}`);
|
|
8777
8700
|
writeLine("");
|
|
8778
8701
|
const optionsMap = {
|
|
8779
|
-
|
|
8780
|
-
|
|
8781
|
-
|
|
8782
|
-
|
|
8783
|
-
|
|
8702
|
+
init: ["--force", "--cwd <path>"],
|
|
8703
|
+
validate: ["--env-dir <path>", "--quiet"],
|
|
8704
|
+
typegen: ["--format <type>", "--out <path>", "--interface <name>"],
|
|
8705
|
+
sync: ["--mode <mode>", "--file <path>", "--out <path>", "--watch"],
|
|
8706
|
+
scan: ["--scope <scope>", "--format <type>", "--include <glob>", "--exclude <glob>"],
|
|
8784
8707
|
"vault init": ["--env <name>", "--force", "--key <key>"],
|
|
8785
8708
|
"vault encrypt": ["--env <name>", "--key <key>"],
|
|
8786
8709
|
"vault decrypt": ["--env <name>", "--key <key>"],
|
|
@@ -8809,7 +8732,9 @@ async function run27(args, _ctx) {
|
|
|
8809
8732
|
writeLine("");
|
|
8810
8733
|
writeLine(" COMMANDS:");
|
|
8811
8734
|
writeLine("");
|
|
8812
|
-
const core = COMMANDS.filter(
|
|
8735
|
+
const core = COMMANDS.filter(
|
|
8736
|
+
(c) => !c.name.startsWith("vault") && !c.name.startsWith("envs") && !c.name.startsWith("ci")
|
|
8737
|
+
);
|
|
8813
8738
|
const vault = COMMANDS.filter((c) => c.name.startsWith("vault"));
|
|
8814
8739
|
const envs = COMMANDS.filter((c) => c.name.startsWith("envs"));
|
|
8815
8740
|
const ci = COMMANDS.filter((c) => c.name.startsWith("ci"));
|
|
@@ -8848,32 +8773,112 @@ var init_help = __esm({
|
|
|
8848
8773
|
init_colors();
|
|
8849
8774
|
init_constants();
|
|
8850
8775
|
COMMANDS = [
|
|
8851
|
-
{
|
|
8852
|
-
|
|
8853
|
-
|
|
8776
|
+
{
|
|
8777
|
+
name: "init",
|
|
8778
|
+
description: "Initialize ultraenv in a project",
|
|
8779
|
+
usage: "ultraenv init [options]"
|
|
8780
|
+
},
|
|
8781
|
+
{
|
|
8782
|
+
name: "validate",
|
|
8783
|
+
description: "Validate environment against schema",
|
|
8784
|
+
usage: "ultraenv validate [options]"
|
|
8785
|
+
},
|
|
8786
|
+
{
|
|
8787
|
+
name: "typegen",
|
|
8788
|
+
description: "Generate TypeScript types",
|
|
8789
|
+
usage: "ultraenv typegen [options]"
|
|
8790
|
+
},
|
|
8854
8791
|
{ name: "sync", description: "Sync .env.example", usage: "ultraenv sync [options]" },
|
|
8855
8792
|
{ name: "scan", description: "Scan for leaked secrets", usage: "ultraenv scan [options]" },
|
|
8856
8793
|
{ name: "debug", description: "Show environment diagnostics", usage: "ultraenv debug [options]" },
|
|
8857
|
-
{
|
|
8858
|
-
|
|
8859
|
-
|
|
8860
|
-
|
|
8861
|
-
|
|
8862
|
-
{
|
|
8863
|
-
|
|
8864
|
-
|
|
8865
|
-
|
|
8866
|
-
|
|
8867
|
-
{
|
|
8868
|
-
|
|
8869
|
-
|
|
8870
|
-
|
|
8871
|
-
|
|
8794
|
+
{
|
|
8795
|
+
name: "protect",
|
|
8796
|
+
description: "Verify .gitignore protection",
|
|
8797
|
+
usage: "ultraenv protect [options]"
|
|
8798
|
+
},
|
|
8799
|
+
{
|
|
8800
|
+
name: "vault init",
|
|
8801
|
+
description: "Initialize encrypted vault",
|
|
8802
|
+
usage: "ultraenv vault init [options]"
|
|
8803
|
+
},
|
|
8804
|
+
{
|
|
8805
|
+
name: "vault encrypt",
|
|
8806
|
+
description: "Encrypt .env \u2192 vault",
|
|
8807
|
+
usage: "ultraenv vault encrypt [options]"
|
|
8808
|
+
},
|
|
8809
|
+
{
|
|
8810
|
+
name: "vault decrypt",
|
|
8811
|
+
description: "Decrypt vault \u2192 .env",
|
|
8812
|
+
usage: "ultraenv vault decrypt [options]"
|
|
8813
|
+
},
|
|
8814
|
+
{
|
|
8815
|
+
name: "vault rekey",
|
|
8816
|
+
description: "Rotate encryption keys",
|
|
8817
|
+
usage: "ultraenv vault rekey [options]"
|
|
8818
|
+
},
|
|
8819
|
+
{
|
|
8820
|
+
name: "vault status",
|
|
8821
|
+
description: "Show vault status",
|
|
8822
|
+
usage: "ultraenv vault status [options]"
|
|
8823
|
+
},
|
|
8824
|
+
{
|
|
8825
|
+
name: "vault diff",
|
|
8826
|
+
description: "Compare .env vs vault",
|
|
8827
|
+
usage: "ultraenv vault diff [options]"
|
|
8828
|
+
},
|
|
8829
|
+
{
|
|
8830
|
+
name: "vault verify",
|
|
8831
|
+
description: "Verify vault integrity",
|
|
8832
|
+
usage: "ultraenv vault verify [options]"
|
|
8833
|
+
},
|
|
8834
|
+
{
|
|
8835
|
+
name: "envs list",
|
|
8836
|
+
description: "List all environments",
|
|
8837
|
+
usage: "ultraenv envs list [options]"
|
|
8838
|
+
},
|
|
8839
|
+
{
|
|
8840
|
+
name: "envs compare",
|
|
8841
|
+
description: "Compare two environments",
|
|
8842
|
+
usage: "ultraenv envs compare <env1> <env2>"
|
|
8843
|
+
},
|
|
8844
|
+
{
|
|
8845
|
+
name: "envs validate",
|
|
8846
|
+
description: "Validate all environments",
|
|
8847
|
+
usage: "ultraenv envs validate [options]"
|
|
8848
|
+
},
|
|
8849
|
+
{
|
|
8850
|
+
name: "envs create",
|
|
8851
|
+
description: "Create new environment",
|
|
8852
|
+
usage: "ultraenv envs create <name> [options]"
|
|
8853
|
+
},
|
|
8854
|
+
{
|
|
8855
|
+
name: "envs switch",
|
|
8856
|
+
description: "Switch current environment",
|
|
8857
|
+
usage: "ultraenv envs switch <name>"
|
|
8858
|
+
},
|
|
8859
|
+
{
|
|
8860
|
+
name: "ci validate",
|
|
8861
|
+
description: "CI validation mode",
|
|
8862
|
+
usage: "ultraenv ci validate [options]"
|
|
8863
|
+
},
|
|
8864
|
+
{
|
|
8865
|
+
name: "ci check-sync",
|
|
8866
|
+
description: "CI sync check",
|
|
8867
|
+
usage: "ultraenv ci check-sync [options]"
|
|
8868
|
+
},
|
|
8872
8869
|
{ name: "ci scan", description: "CI secret scan", usage: "ultraenv ci scan [options]" },
|
|
8873
8870
|
{ name: "ci setup", description: "Generate CI config", usage: "ultraenv ci setup [options]" },
|
|
8874
|
-
{
|
|
8871
|
+
{
|
|
8872
|
+
name: "install-hook",
|
|
8873
|
+
description: "Install git pre-commit hook",
|
|
8874
|
+
usage: "ultraenv install-hook [options]"
|
|
8875
|
+
},
|
|
8875
8876
|
{ name: "doctor", description: "Self-check installation", usage: "ultraenv doctor [options]" },
|
|
8876
|
-
{
|
|
8877
|
+
{
|
|
8878
|
+
name: "completion",
|
|
8879
|
+
description: "Generate shell completions",
|
|
8880
|
+
usage: "ultraenv completion <shell>"
|
|
8881
|
+
},
|
|
8877
8882
|
{ name: "version", description: "Show version", usage: "ultraenv version" }
|
|
8878
8883
|
];
|
|
8879
8884
|
}
|
|
@@ -8913,19 +8918,8 @@ var VAULT_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
|
8913
8918
|
"diff",
|
|
8914
8919
|
"verify"
|
|
8915
8920
|
]);
|
|
8916
|
-
var ENVS_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
8917
|
-
|
|
8918
|
-
"compare",
|
|
8919
|
-
"validate",
|
|
8920
|
-
"create",
|
|
8921
|
-
"switch"
|
|
8922
|
-
]);
|
|
8923
|
-
var CI_SUBCOMMANDS = /* @__PURE__ */ new Set([
|
|
8924
|
-
"validate",
|
|
8925
|
-
"check-sync",
|
|
8926
|
-
"scan",
|
|
8927
|
-
"setup"
|
|
8928
|
-
]);
|
|
8921
|
+
var ENVS_SUBCOMMANDS = /* @__PURE__ */ new Set(["list", "compare", "validate", "create", "switch"]);
|
|
8922
|
+
var CI_SUBCOMMANDS = /* @__PURE__ */ new Set(["validate", "check-sync", "scan", "setup"]);
|
|
8929
8923
|
var OPTIONS_WITH_VALUES = /* @__PURE__ */ new Set([
|
|
8930
8924
|
"--config",
|
|
8931
8925
|
"--format",
|
|
@@ -9068,37 +9062,97 @@ init_errors();
|
|
|
9068
9062
|
var import_node_path27 = require("path");
|
|
9069
9063
|
var COMMAND_REGISTRY = {
|
|
9070
9064
|
// Core commands
|
|
9071
|
-
|
|
9072
|
-
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
|
|
9065
|
+
init: () => Promise.resolve().then(() => (init_init(), init_exports)).then((m) => ({
|
|
9066
|
+
runner: m.run,
|
|
9067
|
+
description: "Initialize project"
|
|
9068
|
+
})),
|
|
9069
|
+
validate: () => Promise.resolve().then(() => (init_validate(), validate_exports)).then((m) => ({
|
|
9070
|
+
runner: m.run,
|
|
9071
|
+
description: "Validate environment"
|
|
9072
|
+
})),
|
|
9073
|
+
typegen: () => Promise.resolve().then(() => (init_typegen(), typegen_exports)).then((m) => ({
|
|
9074
|
+
runner: m.run,
|
|
9075
|
+
description: "Generate TypeScript types"
|
|
9076
|
+
})),
|
|
9077
|
+
sync: () => Promise.resolve().then(() => (init_sync(), sync_exports)).then((m) => ({ runner: m.run, description: "Sync .env.example" })),
|
|
9078
|
+
scan: () => Promise.resolve().then(() => (init_scan(), scan_exports)).then((m) => ({ runner: m.run, description: "Scan for secrets" })),
|
|
9079
|
+
debug: () => Promise.resolve().then(() => (init_debug(), debug_exports)).then((m) => ({ runner: m.run, description: "Show diagnostics" })),
|
|
9080
|
+
protect: () => Promise.resolve().then(() => (init_protect(), protect_exports)).then((m) => ({
|
|
9081
|
+
runner: m.run,
|
|
9082
|
+
description: "Check .gitignore"
|
|
9083
|
+
})),
|
|
9078
9084
|
// Vault subcommands
|
|
9079
|
-
"vault.init": () => Promise.resolve().then(() => (init_vault_init(), vault_init_exports)).then((m) => ({
|
|
9080
|
-
|
|
9081
|
-
|
|
9082
|
-
|
|
9083
|
-
"vault.
|
|
9084
|
-
|
|
9085
|
-
|
|
9085
|
+
"vault.init": () => Promise.resolve().then(() => (init_vault_init(), vault_init_exports)).then((m) => ({
|
|
9086
|
+
runner: m.run,
|
|
9087
|
+
description: "Initialize vault"
|
|
9088
|
+
})),
|
|
9089
|
+
"vault.encrypt": () => Promise.resolve().then(() => (init_vault_encrypt(), vault_encrypt_exports)).then((m) => ({
|
|
9090
|
+
runner: m.run,
|
|
9091
|
+
description: "Encrypt to vault"
|
|
9092
|
+
})),
|
|
9093
|
+
"vault.decrypt": () => Promise.resolve().then(() => (init_vault_decrypt(), vault_decrypt_exports)).then((m) => ({
|
|
9094
|
+
runner: m.run,
|
|
9095
|
+
description: "Decrypt from vault"
|
|
9096
|
+
})),
|
|
9097
|
+
"vault.rekey": () => Promise.resolve().then(() => (init_vault_rekey(), vault_rekey_exports)).then((m) => ({
|
|
9098
|
+
runner: m.run,
|
|
9099
|
+
description: "Rotate keys"
|
|
9100
|
+
})),
|
|
9101
|
+
"vault.status": () => Promise.resolve().then(() => (init_vault_status(), vault_status_exports)).then((m) => ({
|
|
9102
|
+
runner: m.run,
|
|
9103
|
+
description: "Vault status"
|
|
9104
|
+
})),
|
|
9105
|
+
"vault.diff": () => Promise.resolve().then(() => (init_vault_diff(), vault_diff_exports)).then((m) => ({
|
|
9106
|
+
runner: m.run,
|
|
9107
|
+
description: "Compare vs vault"
|
|
9108
|
+
})),
|
|
9109
|
+
"vault.verify": () => Promise.resolve().then(() => (init_vault_verify(), vault_verify_exports)).then((m) => ({
|
|
9110
|
+
runner: m.run,
|
|
9111
|
+
description: "Verify integrity"
|
|
9112
|
+
})),
|
|
9086
9113
|
// Environment subcommands
|
|
9087
|
-
"envs.list": () => Promise.resolve().then(() => (init_envs_list(), envs_list_exports)).then((m) => ({
|
|
9088
|
-
|
|
9089
|
-
|
|
9090
|
-
|
|
9091
|
-
"envs.
|
|
9114
|
+
"envs.list": () => Promise.resolve().then(() => (init_envs_list(), envs_list_exports)).then((m) => ({
|
|
9115
|
+
runner: m.run,
|
|
9116
|
+
description: "List environments"
|
|
9117
|
+
})),
|
|
9118
|
+
"envs.compare": () => Promise.resolve().then(() => (init_envs_compare(), envs_compare_exports)).then((m) => ({
|
|
9119
|
+
runner: m.run,
|
|
9120
|
+
description: "Compare envs"
|
|
9121
|
+
})),
|
|
9122
|
+
"envs.validate": () => Promise.resolve().then(() => (init_envs_validate(), envs_validate_exports)).then((m) => ({
|
|
9123
|
+
runner: m.run,
|
|
9124
|
+
description: "Validate envs"
|
|
9125
|
+
})),
|
|
9126
|
+
"envs.create": () => Promise.resolve().then(() => (init_envs_create(), envs_create_exports)).then((m) => ({
|
|
9127
|
+
runner: m.run,
|
|
9128
|
+
description: "Create environment"
|
|
9129
|
+
})),
|
|
9130
|
+
"envs.switch": () => Promise.resolve().then(() => (init_envs_switch(), envs_switch_exports)).then((m) => ({
|
|
9131
|
+
runner: m.run,
|
|
9132
|
+
description: "Switch environment"
|
|
9133
|
+
})),
|
|
9092
9134
|
// CI subcommands
|
|
9093
|
-
"ci.validate": () => Promise.resolve().then(() => (init_ci_validate(), ci_validate_exports)).then((m) => ({
|
|
9094
|
-
|
|
9135
|
+
"ci.validate": () => Promise.resolve().then(() => (init_ci_validate(), ci_validate_exports)).then((m) => ({
|
|
9136
|
+
runner: m.run,
|
|
9137
|
+
description: "CI validate"
|
|
9138
|
+
})),
|
|
9139
|
+
"ci.check-sync": () => Promise.resolve().then(() => (init_ci_check_sync(), ci_check_sync_exports)).then((m) => ({
|
|
9140
|
+
runner: m.run,
|
|
9141
|
+
description: "CI sync check"
|
|
9142
|
+
})),
|
|
9095
9143
|
"ci.scan": () => Promise.resolve().then(() => (init_ci_scan(), ci_scan_exports)).then((m) => ({ runner: m.run, description: "CI scan" })),
|
|
9096
9144
|
"ci.setup": () => Promise.resolve().then(() => (init_ci_setup(), ci_setup_exports)).then((m) => ({ runner: m.run, description: "CI setup" })),
|
|
9097
9145
|
// Utility commands
|
|
9098
|
-
"install-hook": () => Promise.resolve().then(() => (init_install_hook(), install_hook_exports)).then((m) => ({
|
|
9099
|
-
|
|
9100
|
-
|
|
9101
|
-
|
|
9146
|
+
"install-hook": () => Promise.resolve().then(() => (init_install_hook(), install_hook_exports)).then((m) => ({
|
|
9147
|
+
runner: m.run,
|
|
9148
|
+
description: "Install git hook"
|
|
9149
|
+
})),
|
|
9150
|
+
doctor: () => Promise.resolve().then(() => (init_doctor(), doctor_exports)).then((m) => ({ runner: m.run, description: "Self-check" })),
|
|
9151
|
+
completion: () => Promise.resolve().then(() => (init_completion(), completion_exports)).then((m) => ({
|
|
9152
|
+
runner: m.run,
|
|
9153
|
+
description: "Shell completions"
|
|
9154
|
+
})),
|
|
9155
|
+
help: () => Promise.resolve().then(() => (init_help(), help_exports)).then((m) => ({ runner: m.run, description: "Show help" }))
|
|
9102
9156
|
};
|
|
9103
9157
|
function handleVersion() {
|
|
9104
9158
|
writeLine(`ultraenv v${VERSION}`);
|
|
@@ -9129,14 +9183,28 @@ async function run28(argv) {
|
|
|
9129
9183
|
const helpCmd2 = COMMAND_REGISTRY["help"];
|
|
9130
9184
|
if (helpCmd2) {
|
|
9131
9185
|
const entry = await helpCmd2();
|
|
9132
|
-
return entry.runner(args, {
|
|
9186
|
+
return entry.runner(args, {
|
|
9187
|
+
config: config2.config,
|
|
9188
|
+
cwd: config2.cwd,
|
|
9189
|
+
colorEnabled: true,
|
|
9190
|
+
debug: config2.debug,
|
|
9191
|
+
quiet: config2.quiet,
|
|
9192
|
+
outputFormat: config2.outputFormat
|
|
9193
|
+
});
|
|
9133
9194
|
}
|
|
9134
9195
|
return 1;
|
|
9135
9196
|
}
|
|
9136
9197
|
const helpCmd = COMMAND_REGISTRY["help"];
|
|
9137
9198
|
if (helpCmd) {
|
|
9138
9199
|
const entry = await helpCmd();
|
|
9139
|
-
return entry.runner(args, {
|
|
9200
|
+
return entry.runner(args, {
|
|
9201
|
+
config: config2.config,
|
|
9202
|
+
cwd: config2.cwd,
|
|
9203
|
+
colorEnabled: true,
|
|
9204
|
+
debug: config2.debug,
|
|
9205
|
+
quiet: config2.quiet,
|
|
9206
|
+
outputFormat: config2.outputFormat
|
|
9207
|
+
});
|
|
9140
9208
|
}
|
|
9141
9209
|
return 1;
|
|
9142
9210
|
}
|
|
@@ -9176,12 +9244,18 @@ async function run28(argv) {
|
|
|
9176
9244
|
} catch (error) {
|
|
9177
9245
|
if (error instanceof UltraenvError) {
|
|
9178
9246
|
if (outputFormat === "json") {
|
|
9179
|
-
writeError(
|
|
9180
|
-
|
|
9181
|
-
|
|
9182
|
-
|
|
9183
|
-
|
|
9184
|
-
|
|
9247
|
+
writeError(
|
|
9248
|
+
JSON.stringify(
|
|
9249
|
+
{
|
|
9250
|
+
error: true,
|
|
9251
|
+
code: error.code,
|
|
9252
|
+
message: error.message,
|
|
9253
|
+
hint: error.hint
|
|
9254
|
+
},
|
|
9255
|
+
null,
|
|
9256
|
+
2
|
|
9257
|
+
)
|
|
9258
|
+
);
|
|
9185
9259
|
} else {
|
|
9186
9260
|
writeError("");
|
|
9187
9261
|
writeError(red(bold(` [${error.code}] ${error.message}`)));
|
|
@@ -9194,10 +9268,16 @@ async function run28(argv) {
|
|
|
9194
9268
|
return 1;
|
|
9195
9269
|
}
|
|
9196
9270
|
if (outputFormat === "json") {
|
|
9197
|
-
writeError(
|
|
9198
|
-
|
|
9199
|
-
|
|
9200
|
-
|
|
9271
|
+
writeError(
|
|
9272
|
+
JSON.stringify(
|
|
9273
|
+
{
|
|
9274
|
+
error: true,
|
|
9275
|
+
message: error instanceof Error ? error.message : String(error)
|
|
9276
|
+
},
|
|
9277
|
+
null,
|
|
9278
|
+
2
|
|
9279
|
+
)
|
|
9280
|
+
);
|
|
9201
9281
|
} else {
|
|
9202
9282
|
writeError("");
|
|
9203
9283
|
writeError(red(bold(" Unexpected error:")));
|