@clef-sh/core 0.1.8 → 0.1.9-beta.57
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/artifact/packer.d.ts +2 -1
- package/dist/artifact/packer.d.ts.map +1 -1
- package/dist/artifact/signer.d.ts.map +1 -1
- package/dist/artifact/types.d.ts +7 -3
- package/dist/artifact/types.d.ts.map +1 -1
- package/dist/drift/detector.d.ts +1 -7
- package/dist/drift/detector.d.ts.map +1 -1
- package/dist/index.d.mts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +188 -203
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +187 -206
- package/dist/index.mjs.map +4 -4
- package/dist/kms/index.d.ts +1 -0
- package/dist/kms/index.d.ts.map +1 -1
- package/dist/kms/types.d.ts +1 -0
- package/dist/kms/types.d.ts.map +1 -1
- package/dist/manifest/parser.d.ts.map +1 -1
- package/dist/matrix/manager.d.ts.map +1 -1
- package/dist/report/generator.d.ts.map +1 -1
- package/dist/scanner/index.d.ts.map +1 -1
- package/dist/sops/client.d.ts.map +1 -1
- package/dist/sops/keys.d.ts +9 -0
- package/dist/sops/keys.d.ts.map +1 -0
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -411,6 +411,12 @@ var ManifestParser = class {
|
|
|
411
411
|
"namespaces"
|
|
412
412
|
);
|
|
413
413
|
}
|
|
414
|
+
if (!ENV_NAME_PATTERN.test(nsObj.name)) {
|
|
415
|
+
throw new ManifestValidationError(
|
|
416
|
+
`Namespace name '${nsObj.name}' is invalid. Names must start with a lowercase letter and contain only lowercase letters, digits, hyphens, and underscores.`,
|
|
417
|
+
"namespaces"
|
|
418
|
+
);
|
|
419
|
+
}
|
|
414
420
|
if (!nsObj.description || typeof nsObj.description !== "string") {
|
|
415
421
|
throw new ManifestValidationError(
|
|
416
422
|
`Namespace '${nsObj.name}' is missing a 'description' string.`,
|
|
@@ -511,9 +517,9 @@ var ManifestParser = class {
|
|
|
511
517
|
);
|
|
512
518
|
}
|
|
513
519
|
const siName = siObj.name;
|
|
514
|
-
if (
|
|
520
|
+
if (siObj.description != null && typeof siObj.description !== "string") {
|
|
515
521
|
throw new ManifestValidationError(
|
|
516
|
-
`Service identity '${siName}'
|
|
522
|
+
`Service identity '${siName}' has a non-string 'description'.`,
|
|
517
523
|
"service_identities"
|
|
518
524
|
);
|
|
519
525
|
}
|
|
@@ -628,7 +634,7 @@ var ManifestParser = class {
|
|
|
628
634
|
}
|
|
629
635
|
return {
|
|
630
636
|
name: siName,
|
|
631
|
-
description: siObj.description,
|
|
637
|
+
description: siObj.description ?? "",
|
|
632
638
|
namespaces: siObj.namespaces,
|
|
633
639
|
environments: parsedEnvs
|
|
634
640
|
};
|
|
@@ -809,7 +815,11 @@ function matchesGlob(filePath, pattern) {
|
|
|
809
815
|
|
|
810
816
|
// src/scanner/index.ts
|
|
811
817
|
var ALWAYS_SKIP_EXTENSIONS = [".enc.yaml", ".enc.json"];
|
|
812
|
-
var ALWAYS_SKIP_NAMES = [
|
|
818
|
+
var ALWAYS_SKIP_NAMES = [
|
|
819
|
+
".clef-meta.yaml",
|
|
820
|
+
".sops.yaml"
|
|
821
|
+
// contains age public keys and KMS ARNs — configuration, not secrets
|
|
822
|
+
];
|
|
813
823
|
var ALWAYS_SKIP_DIRS = ["node_modules", ".git"];
|
|
814
824
|
var MAX_FILE_SIZE = 1024 * 1024;
|
|
815
825
|
var ScanRunner = class {
|
|
@@ -1010,9 +1020,9 @@ var ScanRunner = class {
|
|
|
1010
1020
|
};
|
|
1011
1021
|
|
|
1012
1022
|
// src/matrix/manager.ts
|
|
1013
|
-
import * as
|
|
1023
|
+
import * as fs6 from "fs";
|
|
1014
1024
|
import * as path4 from "path";
|
|
1015
|
-
import * as
|
|
1025
|
+
import * as YAML4 from "yaml";
|
|
1016
1026
|
|
|
1017
1027
|
// src/pending/metadata.ts
|
|
1018
1028
|
import * as fs4 from "fs";
|
|
@@ -1102,6 +1112,20 @@ async function markPendingWithRetry(filePath, keys, setBy, retryDelayMs = 200) {
|
|
|
1102
1112
|
}
|
|
1103
1113
|
}
|
|
1104
1114
|
|
|
1115
|
+
// src/sops/keys.ts
|
|
1116
|
+
import * as fs5 from "fs";
|
|
1117
|
+
import * as YAML3 from "yaml";
|
|
1118
|
+
function readSopsKeyNames(filePath) {
|
|
1119
|
+
try {
|
|
1120
|
+
const raw = fs5.readFileSync(filePath, "utf-8");
|
|
1121
|
+
const parsed = YAML3.parse(raw);
|
|
1122
|
+
if (parsed === null || parsed === void 0 || typeof parsed !== "object") return null;
|
|
1123
|
+
return Object.keys(parsed).filter((k) => k !== "sops");
|
|
1124
|
+
} catch {
|
|
1125
|
+
return null;
|
|
1126
|
+
}
|
|
1127
|
+
}
|
|
1128
|
+
|
|
1105
1129
|
// src/matrix/manager.ts
|
|
1106
1130
|
var MatrixManager = class {
|
|
1107
1131
|
/**
|
|
@@ -1121,7 +1145,7 @@ var MatrixManager = class {
|
|
|
1121
1145
|
namespace: ns.name,
|
|
1122
1146
|
environment: env.name,
|
|
1123
1147
|
filePath,
|
|
1124
|
-
exists:
|
|
1148
|
+
exists: fs6.existsSync(filePath)
|
|
1125
1149
|
});
|
|
1126
1150
|
}
|
|
1127
1151
|
}
|
|
@@ -1145,8 +1169,8 @@ var MatrixManager = class {
|
|
|
1145
1169
|
*/
|
|
1146
1170
|
async scaffoldCell(cell, sopsClient, manifest) {
|
|
1147
1171
|
const dir = path4.dirname(cell.filePath);
|
|
1148
|
-
if (!
|
|
1149
|
-
|
|
1172
|
+
if (!fs6.existsSync(dir)) {
|
|
1173
|
+
fs6.mkdirSync(dir, { recursive: true });
|
|
1150
1174
|
}
|
|
1151
1175
|
await sopsClient.encrypt(cell.filePath, {}, manifest, cell.environment);
|
|
1152
1176
|
}
|
|
@@ -1215,22 +1239,15 @@ var MatrixManager = class {
|
|
|
1215
1239
|
* SOPS stores key names in plaintext — only values are encrypted.
|
|
1216
1240
|
*/
|
|
1217
1241
|
readKeyNames(filePath) {
|
|
1218
|
-
|
|
1219
|
-
const raw = fs5.readFileSync(filePath, "utf-8");
|
|
1220
|
-
const parsed = YAML3.parse(raw);
|
|
1221
|
-
if (!parsed || typeof parsed !== "object") return [];
|
|
1222
|
-
return Object.keys(parsed).filter((k) => k !== "sops");
|
|
1223
|
-
} catch {
|
|
1224
|
-
return [];
|
|
1225
|
-
}
|
|
1242
|
+
return readSopsKeyNames(filePath) ?? [];
|
|
1226
1243
|
}
|
|
1227
1244
|
/**
|
|
1228
1245
|
* Read the lastModified timestamp from SOPS metadata without decryption.
|
|
1229
1246
|
*/
|
|
1230
1247
|
readLastModified(filePath) {
|
|
1231
1248
|
try {
|
|
1232
|
-
const raw =
|
|
1233
|
-
const parsed =
|
|
1249
|
+
const raw = fs6.readFileSync(filePath, "utf-8");
|
|
1250
|
+
const parsed = YAML4.parse(raw);
|
|
1234
1251
|
const sops = parsed?.sops;
|
|
1235
1252
|
if (sops?.lastmodified) return new Date(String(sops.lastmodified));
|
|
1236
1253
|
return null;
|
|
@@ -1251,8 +1268,8 @@ var MatrixManager = class {
|
|
|
1251
1268
|
};
|
|
1252
1269
|
|
|
1253
1270
|
// src/schema/validator.ts
|
|
1254
|
-
import * as
|
|
1255
|
-
import * as
|
|
1271
|
+
import * as fs7 from "fs";
|
|
1272
|
+
import * as YAML5 from "yaml";
|
|
1256
1273
|
var SchemaValidator = class {
|
|
1257
1274
|
/**
|
|
1258
1275
|
* Read and parse a YAML schema file from disk.
|
|
@@ -1264,13 +1281,13 @@ var SchemaValidator = class {
|
|
|
1264
1281
|
loadSchema(filePath) {
|
|
1265
1282
|
let raw;
|
|
1266
1283
|
try {
|
|
1267
|
-
raw =
|
|
1284
|
+
raw = fs7.readFileSync(filePath, "utf-8");
|
|
1268
1285
|
} catch {
|
|
1269
1286
|
throw new SchemaLoadError(`Could not read schema file at '${filePath}'.`, filePath);
|
|
1270
1287
|
}
|
|
1271
1288
|
let parsed;
|
|
1272
1289
|
try {
|
|
1273
|
-
parsed =
|
|
1290
|
+
parsed = YAML5.parse(raw);
|
|
1274
1291
|
} catch {
|
|
1275
1292
|
throw new SchemaLoadError(`Schema file '${filePath}' contains invalid YAML.`, filePath);
|
|
1276
1293
|
}
|
|
@@ -1571,7 +1588,7 @@ ${details}`
|
|
|
1571
1588
|
};
|
|
1572
1589
|
|
|
1573
1590
|
// src/git/integration.ts
|
|
1574
|
-
import * as
|
|
1591
|
+
import * as fs8 from "fs";
|
|
1575
1592
|
import * as path7 from "path";
|
|
1576
1593
|
var PRE_COMMIT_HOOK = `#!/bin/sh
|
|
1577
1594
|
# Clef pre-commit hook \u2014 blocks commits of files missing SOPS encryption metadata
|
|
@@ -1780,14 +1797,14 @@ var GitIntegration = class {
|
|
|
1780
1797
|
});
|
|
1781
1798
|
const gitConfig = configResult.exitCode === 0 && configResult.stdout.trim().length > 0;
|
|
1782
1799
|
const attrFilePath = path7.join(repoRoot, ".gitattributes");
|
|
1783
|
-
const attrContent =
|
|
1800
|
+
const attrContent = fs8.existsSync(attrFilePath) ? fs8.readFileSync(attrFilePath, "utf-8") : "";
|
|
1784
1801
|
const gitattributes = attrContent.includes("merge=sops");
|
|
1785
1802
|
return { gitConfig, gitattributes };
|
|
1786
1803
|
}
|
|
1787
1804
|
async ensureGitattributes(repoRoot) {
|
|
1788
1805
|
const attrPath = path7.join(repoRoot, ".gitattributes");
|
|
1789
1806
|
const mergeRule = "*.enc.yaml merge=sops\n*.enc.json merge=sops";
|
|
1790
|
-
const existing =
|
|
1807
|
+
const existing = fs8.existsSync(attrPath) ? fs8.readFileSync(attrPath, "utf-8") : "";
|
|
1791
1808
|
if (existing.includes("merge=sops")) {
|
|
1792
1809
|
return;
|
|
1793
1810
|
}
|
|
@@ -1835,17 +1852,17 @@ ${mergeRule}
|
|
|
1835
1852
|
};
|
|
1836
1853
|
|
|
1837
1854
|
// src/sops/client.ts
|
|
1838
|
-
import * as
|
|
1855
|
+
import * as fs11 from "fs";
|
|
1839
1856
|
import * as net from "net";
|
|
1840
1857
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
1841
|
-
import * as
|
|
1858
|
+
import * as YAML6 from "yaml";
|
|
1842
1859
|
|
|
1843
1860
|
// src/sops/resolver.ts
|
|
1844
|
-
import * as
|
|
1861
|
+
import * as fs10 from "fs";
|
|
1845
1862
|
import * as path9 from "path";
|
|
1846
1863
|
|
|
1847
1864
|
// src/sops/bundled.ts
|
|
1848
|
-
import * as
|
|
1865
|
+
import * as fs9 from "fs";
|
|
1849
1866
|
import * as path8 from "path";
|
|
1850
1867
|
function tryBundled() {
|
|
1851
1868
|
const platform = process.platform;
|
|
@@ -1860,7 +1877,7 @@ function tryBundled() {
|
|
|
1860
1877
|
const packageMain = __require.resolve(`${packageName}/package.json`);
|
|
1861
1878
|
const packageDir = path8.dirname(packageMain);
|
|
1862
1879
|
const binPath = path8.join(packageDir, "bin", binName);
|
|
1863
|
-
return
|
|
1880
|
+
return fs9.existsSync(binPath) ? binPath : null;
|
|
1864
1881
|
} catch {
|
|
1865
1882
|
return null;
|
|
1866
1883
|
}
|
|
@@ -1884,7 +1901,7 @@ function resolveSopsPath() {
|
|
|
1884
1901
|
const envPath = process.env.CLEF_SOPS_PATH?.trim();
|
|
1885
1902
|
if (envPath) {
|
|
1886
1903
|
validateSopsPath(envPath);
|
|
1887
|
-
if (!
|
|
1904
|
+
if (!fs10.existsSync(envPath)) {
|
|
1888
1905
|
throw new Error(`CLEF_SOPS_PATH points to '${envPath}' but the file does not exist.`);
|
|
1889
1906
|
}
|
|
1890
1907
|
cached = { path: envPath, source: "env" };
|
|
@@ -2092,7 +2109,7 @@ var SopsClient = class {
|
|
|
2092
2109
|
}
|
|
2093
2110
|
let parsed;
|
|
2094
2111
|
try {
|
|
2095
|
-
parsed =
|
|
2112
|
+
parsed = YAML6.parse(result.stdout) ?? {};
|
|
2096
2113
|
} catch {
|
|
2097
2114
|
throw new SopsDecryptionError(
|
|
2098
2115
|
`Decrypted content of '${filePath}' is not valid YAML.`,
|
|
@@ -2119,7 +2136,7 @@ var SopsClient = class {
|
|
|
2119
2136
|
async encrypt(filePath, values, manifest, environment) {
|
|
2120
2137
|
await assertSops(this.runner, this.sopsCommand);
|
|
2121
2138
|
const fmt = formatFromPath(filePath);
|
|
2122
|
-
const content = fmt === "json" ? JSON.stringify(values, null, 2) :
|
|
2139
|
+
const content = fmt === "json" ? JSON.stringify(values, null, 2) : YAML6.stringify(values);
|
|
2123
2140
|
const args = this.buildEncryptArgs(filePath, manifest, environment);
|
|
2124
2141
|
const env = this.buildSopsEnv();
|
|
2125
2142
|
let inputArg;
|
|
@@ -2163,7 +2180,7 @@ var SopsClient = class {
|
|
|
2163
2180
|
);
|
|
2164
2181
|
}
|
|
2165
2182
|
try {
|
|
2166
|
-
|
|
2183
|
+
fs11.writeFileSync(filePath, result.stdout);
|
|
2167
2184
|
} catch {
|
|
2168
2185
|
throw new SopsEncryptionError(`Failed to write encrypted data to '${filePath}'.`, filePath);
|
|
2169
2186
|
}
|
|
@@ -2176,21 +2193,7 @@ var SopsClient = class {
|
|
|
2176
2193
|
* @throws {@link SopsEncryptionError} On failure.
|
|
2177
2194
|
*/
|
|
2178
2195
|
async reEncrypt(filePath, newKey) {
|
|
2179
|
-
await
|
|
2180
|
-
const env = this.buildSopsEnv();
|
|
2181
|
-
const result = await this.runner.run(
|
|
2182
|
-
this.sopsCommand,
|
|
2183
|
-
["rotate", "-i", "--add-age", newKey, filePath],
|
|
2184
|
-
{
|
|
2185
|
-
...env ? { env } : {}
|
|
2186
|
-
}
|
|
2187
|
-
);
|
|
2188
|
-
if (result.exitCode !== 0) {
|
|
2189
|
-
throw new SopsEncryptionError(
|
|
2190
|
-
`Failed to re-encrypt '${filePath}': ${result.stderr.trim()}`,
|
|
2191
|
-
filePath
|
|
2192
|
-
);
|
|
2193
|
-
}
|
|
2196
|
+
await this.addRecipient(filePath, newKey);
|
|
2194
2197
|
}
|
|
2195
2198
|
/**
|
|
2196
2199
|
* Add an age recipient to an existing SOPS file.
|
|
@@ -2293,7 +2296,7 @@ var SopsClient = class {
|
|
|
2293
2296
|
if (!this.ageKey && !this.ageKeyFile) return "key-not-found";
|
|
2294
2297
|
let keyContent;
|
|
2295
2298
|
try {
|
|
2296
|
-
keyContent = this.ageKey ??
|
|
2299
|
+
keyContent = this.ageKey ?? fs11.readFileSync(this.ageKeyFile, "utf-8");
|
|
2297
2300
|
} catch {
|
|
2298
2301
|
return "key-not-found";
|
|
2299
2302
|
}
|
|
@@ -2310,7 +2313,7 @@ var SopsClient = class {
|
|
|
2310
2313
|
parseMetadataFromFile(filePath) {
|
|
2311
2314
|
let content;
|
|
2312
2315
|
try {
|
|
2313
|
-
content =
|
|
2316
|
+
content = fs11.readFileSync(filePath, "utf-8");
|
|
2314
2317
|
} catch {
|
|
2315
2318
|
throw new SopsDecryptionError(
|
|
2316
2319
|
`Could not read file '${filePath}' to extract SOPS metadata.`,
|
|
@@ -2319,7 +2322,7 @@ var SopsClient = class {
|
|
|
2319
2322
|
}
|
|
2320
2323
|
let parsed;
|
|
2321
2324
|
try {
|
|
2322
|
-
parsed =
|
|
2325
|
+
parsed = YAML6.parse(content);
|
|
2323
2326
|
} catch {
|
|
2324
2327
|
throw new SopsDecryptionError(
|
|
2325
2328
|
`File '${filePath}' is not valid YAML. Cannot extract SOPS metadata.`,
|
|
@@ -2751,7 +2754,7 @@ import * as path12 from "path";
|
|
|
2751
2754
|
|
|
2752
2755
|
// src/import/parsers.ts
|
|
2753
2756
|
import * as path11 from "path";
|
|
2754
|
-
import * as
|
|
2757
|
+
import * as YAML7 from "yaml";
|
|
2755
2758
|
function detectFormat(filePath, content) {
|
|
2756
2759
|
const base = path11.basename(filePath);
|
|
2757
2760
|
const ext = path11.extname(filePath).toLowerCase();
|
|
@@ -2775,7 +2778,7 @@ function detectFormat(filePath, content) {
|
|
|
2775
2778
|
} catch {
|
|
2776
2779
|
}
|
|
2777
2780
|
try {
|
|
2778
|
-
const parsed =
|
|
2781
|
+
const parsed = YAML7.parse(content);
|
|
2779
2782
|
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
2780
2783
|
return "yaml";
|
|
2781
2784
|
}
|
|
@@ -2856,7 +2859,7 @@ function parseJson(content) {
|
|
|
2856
2859
|
function parseYaml(content) {
|
|
2857
2860
|
let parsed;
|
|
2858
2861
|
try {
|
|
2859
|
-
parsed =
|
|
2862
|
+
parsed = YAML7.parse(content);
|
|
2860
2863
|
} catch (err) {
|
|
2861
2864
|
throw new Error(`Invalid YAML: ${err.message}`);
|
|
2862
2865
|
}
|
|
@@ -2890,7 +2893,7 @@ function parseYaml(content) {
|
|
|
2890
2893
|
}
|
|
2891
2894
|
return { pairs, format: "yaml", skipped, warnings };
|
|
2892
2895
|
}
|
|
2893
|
-
function
|
|
2896
|
+
function parse8(content, format, filePath) {
|
|
2894
2897
|
const resolved = format === "auto" ? detectFormat(filePath ?? "", content) : format;
|
|
2895
2898
|
switch (resolved) {
|
|
2896
2899
|
case "dotenv":
|
|
@@ -2923,7 +2926,7 @@ var ImportRunner = class {
|
|
|
2923
2926
|
repoRoot,
|
|
2924
2927
|
manifest.file_pattern.replace("{namespace}", ns).replace("{environment}", env)
|
|
2925
2928
|
);
|
|
2926
|
-
const parsed =
|
|
2929
|
+
const parsed = parse8(content, options.format ?? "auto", sourcePath ?? "");
|
|
2927
2930
|
let candidates = Object.entries(parsed.pairs);
|
|
2928
2931
|
if (options.prefix) {
|
|
2929
2932
|
const prefix = options.prefix;
|
|
@@ -2977,9 +2980,9 @@ var ImportRunner = class {
|
|
|
2977
2980
|
};
|
|
2978
2981
|
|
|
2979
2982
|
// src/recipients/index.ts
|
|
2980
|
-
import * as
|
|
2983
|
+
import * as fs12 from "fs";
|
|
2981
2984
|
import * as path13 from "path";
|
|
2982
|
-
import * as
|
|
2985
|
+
import * as YAML8 from "yaml";
|
|
2983
2986
|
function parseRecipientEntry(entry) {
|
|
2984
2987
|
if (typeof entry === "string") {
|
|
2985
2988
|
return { key: entry };
|
|
@@ -3002,12 +3005,12 @@ function toRecipient(entry) {
|
|
|
3002
3005
|
}
|
|
3003
3006
|
function readManifestYaml(repoRoot) {
|
|
3004
3007
|
const manifestPath = path13.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
3005
|
-
const raw =
|
|
3006
|
-
return
|
|
3008
|
+
const raw = fs12.readFileSync(manifestPath, "utf-8");
|
|
3009
|
+
return YAML8.parse(raw);
|
|
3007
3010
|
}
|
|
3008
3011
|
function writeManifestYaml(repoRoot, doc) {
|
|
3009
3012
|
const manifestPath = path13.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
3010
|
-
|
|
3013
|
+
fs12.writeFileSync(manifestPath, YAML8.stringify(doc), "utf-8");
|
|
3011
3014
|
}
|
|
3012
3015
|
function getRecipientsArray(doc) {
|
|
3013
3016
|
const sops = doc.sops;
|
|
@@ -3108,7 +3111,7 @@ var RecipientManager = class {
|
|
|
3108
3111
|
throw new Error(`Recipient '${keyPreview(normalizedKey)}' is already present.`);
|
|
3109
3112
|
}
|
|
3110
3113
|
const manifestPath = path13.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
3111
|
-
const manifestBackup =
|
|
3114
|
+
const manifestBackup = fs12.readFileSync(manifestPath, "utf-8");
|
|
3112
3115
|
const recipients = environment ? ensureEnvironmentRecipientsArray(doc, environment) : ensureRecipientsArray(doc);
|
|
3113
3116
|
if (label) {
|
|
3114
3117
|
recipients.push({ key: normalizedKey, label });
|
|
@@ -3123,16 +3126,16 @@ var RecipientManager = class {
|
|
|
3123
3126
|
const fileBackups = /* @__PURE__ */ new Map();
|
|
3124
3127
|
for (const cell of cells) {
|
|
3125
3128
|
try {
|
|
3126
|
-
fileBackups.set(cell.filePath,
|
|
3129
|
+
fileBackups.set(cell.filePath, fs12.readFileSync(cell.filePath, "utf-8"));
|
|
3127
3130
|
await this.encryption.addRecipient(cell.filePath, normalizedKey);
|
|
3128
3131
|
reEncryptedFiles.push(cell.filePath);
|
|
3129
3132
|
} catch {
|
|
3130
3133
|
failedFiles.push(cell.filePath);
|
|
3131
|
-
|
|
3134
|
+
fs12.writeFileSync(manifestPath, manifestBackup, "utf-8");
|
|
3132
3135
|
for (const reEncryptedFile of reEncryptedFiles) {
|
|
3133
3136
|
const backup = fileBackups.get(reEncryptedFile);
|
|
3134
3137
|
if (backup) {
|
|
3135
|
-
|
|
3138
|
+
fs12.writeFileSync(reEncryptedFile, backup, "utf-8");
|
|
3136
3139
|
}
|
|
3137
3140
|
}
|
|
3138
3141
|
const restoredDoc = readManifestYaml(repoRoot);
|
|
@@ -3186,7 +3189,7 @@ var RecipientManager = class {
|
|
|
3186
3189
|
}
|
|
3187
3190
|
const removedEntry = parsed[matchIndex];
|
|
3188
3191
|
const manifestPath = path13.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
3189
|
-
const manifestBackup =
|
|
3192
|
+
const manifestBackup = fs12.readFileSync(manifestPath, "utf-8");
|
|
3190
3193
|
const recipients = environment ? ensureEnvironmentRecipientsArray(doc, environment) : ensureRecipientsArray(doc);
|
|
3191
3194
|
recipients.splice(matchIndex, 1);
|
|
3192
3195
|
writeManifestYaml(repoRoot, doc);
|
|
@@ -3197,16 +3200,16 @@ var RecipientManager = class {
|
|
|
3197
3200
|
const fileBackups = /* @__PURE__ */ new Map();
|
|
3198
3201
|
for (const cell of cells) {
|
|
3199
3202
|
try {
|
|
3200
|
-
fileBackups.set(cell.filePath,
|
|
3203
|
+
fileBackups.set(cell.filePath, fs12.readFileSync(cell.filePath, "utf-8"));
|
|
3201
3204
|
await this.encryption.removeRecipient(cell.filePath, trimmedKey);
|
|
3202
3205
|
reEncryptedFiles.push(cell.filePath);
|
|
3203
3206
|
} catch {
|
|
3204
3207
|
failedFiles.push(cell.filePath);
|
|
3205
|
-
|
|
3208
|
+
fs12.writeFileSync(manifestPath, manifestBackup, "utf-8");
|
|
3206
3209
|
for (const reEncryptedFile of reEncryptedFiles) {
|
|
3207
3210
|
const backup = fileBackups.get(reEncryptedFile);
|
|
3208
3211
|
if (backup) {
|
|
3209
|
-
|
|
3212
|
+
fs12.writeFileSync(reEncryptedFile, backup, "utf-8");
|
|
3210
3213
|
}
|
|
3211
3214
|
}
|
|
3212
3215
|
const restoredDoc = readManifestYaml(repoRoot);
|
|
@@ -3240,9 +3243,9 @@ var RecipientManager = class {
|
|
|
3240
3243
|
};
|
|
3241
3244
|
|
|
3242
3245
|
// src/recipients/requests.ts
|
|
3243
|
-
import * as
|
|
3246
|
+
import * as fs13 from "fs";
|
|
3244
3247
|
import * as path14 from "path";
|
|
3245
|
-
import * as
|
|
3248
|
+
import * as YAML9 from "yaml";
|
|
3246
3249
|
var REQUESTS_FILENAME = ".clef-requests.yaml";
|
|
3247
3250
|
var HEADER_COMMENT2 = "# Pending recipient access requests. Approve with: clef recipients approve <label>\n";
|
|
3248
3251
|
function requestsFilePath(repoRoot) {
|
|
@@ -3251,9 +3254,9 @@ function requestsFilePath(repoRoot) {
|
|
|
3251
3254
|
function loadRequests(repoRoot) {
|
|
3252
3255
|
const filePath = requestsFilePath(repoRoot);
|
|
3253
3256
|
try {
|
|
3254
|
-
if (!
|
|
3255
|
-
const content =
|
|
3256
|
-
const parsed =
|
|
3257
|
+
if (!fs13.existsSync(filePath)) return [];
|
|
3258
|
+
const content = fs13.readFileSync(filePath, "utf-8");
|
|
3259
|
+
const parsed = YAML9.parse(content);
|
|
3257
3260
|
if (!parsed || !Array.isArray(parsed.requests)) return [];
|
|
3258
3261
|
return parsed.requests.map((r) => ({
|
|
3259
3262
|
key: r.key,
|
|
@@ -3269,7 +3272,7 @@ function saveRequests(repoRoot, requests) {
|
|
|
3269
3272
|
const filePath = requestsFilePath(repoRoot);
|
|
3270
3273
|
if (requests.length === 0) {
|
|
3271
3274
|
try {
|
|
3272
|
-
|
|
3275
|
+
fs13.unlinkSync(filePath);
|
|
3273
3276
|
} catch {
|
|
3274
3277
|
}
|
|
3275
3278
|
return;
|
|
@@ -3285,7 +3288,7 @@ function saveRequests(repoRoot, requests) {
|
|
|
3285
3288
|
return raw;
|
|
3286
3289
|
})
|
|
3287
3290
|
};
|
|
3288
|
-
|
|
3291
|
+
fs13.writeFileSync(filePath, HEADER_COMMENT2 + YAML9.stringify(data), "utf-8");
|
|
3289
3292
|
}
|
|
3290
3293
|
function upsertRequest(repoRoot, key, label, environment) {
|
|
3291
3294
|
const requests = loadRequests(repoRoot);
|
|
@@ -3321,9 +3324,7 @@ function findInList(requests, identifier) {
|
|
|
3321
3324
|
}
|
|
3322
3325
|
|
|
3323
3326
|
// src/drift/detector.ts
|
|
3324
|
-
import * as fs13 from "fs";
|
|
3325
3327
|
import * as path15 from "path";
|
|
3326
|
-
import * as YAML9 from "yaml";
|
|
3327
3328
|
var DriftDetector = class {
|
|
3328
3329
|
parser = new ManifestParser();
|
|
3329
3330
|
matrix = new MatrixManager();
|
|
@@ -3351,45 +3352,30 @@ var DriftDetector = class {
|
|
|
3351
3352
|
}
|
|
3352
3353
|
const issues = [];
|
|
3353
3354
|
let namespacesClean = 0;
|
|
3355
|
+
const remoteEnvSet = new Set(remoteEnvNames);
|
|
3356
|
+
const sharedEnvSet = new Set(localEnvNames.filter((e) => remoteEnvSet.has(e)));
|
|
3354
3357
|
for (const ns of sharedNamespaces) {
|
|
3355
|
-
const
|
|
3356
|
-
const
|
|
3357
|
-
const localNsCells = localCells.filter((c) => c.namespace === ns);
|
|
3358
|
-
for (const cell of localNsCells) {
|
|
3359
|
-
const keys = this.readKeysFromFile(cell.filePath);
|
|
3360
|
-
if (keys === null) continue;
|
|
3361
|
-
allEnvs.add(cell.environment);
|
|
3362
|
-
for (const key of keys) {
|
|
3363
|
-
if (!keyEnvs.has(key)) keyEnvs.set(key, /* @__PURE__ */ new Set());
|
|
3364
|
-
keyEnvs.get(key).add(cell.environment);
|
|
3365
|
-
}
|
|
3366
|
-
}
|
|
3367
|
-
const remoteNsCells = remoteCells.filter((c) => c.namespace === ns);
|
|
3368
|
-
for (const cell of remoteNsCells) {
|
|
3369
|
-
const keys = this.readKeysFromFile(cell.filePath);
|
|
3370
|
-
if (keys === null) continue;
|
|
3371
|
-
allEnvs.add(cell.environment);
|
|
3372
|
-
for (const key of keys) {
|
|
3373
|
-
if (!keyEnvs.has(key)) keyEnvs.set(key, /* @__PURE__ */ new Set());
|
|
3374
|
-
keyEnvs.get(key).add(cell.environment);
|
|
3375
|
-
}
|
|
3376
|
-
}
|
|
3377
|
-
const envList = [...allEnvs];
|
|
3358
|
+
const localKeyEnvs = this.collectKeyEnvs(localCells, ns, sharedEnvSet);
|
|
3359
|
+
const remoteKeyEnvs = this.collectKeyEnvs(remoteCells, ns, sharedEnvSet);
|
|
3378
3360
|
let nsClean = true;
|
|
3379
|
-
|
|
3380
|
-
const
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3361
|
+
const reportDrift = (sourceMap, targetMap, direction) => {
|
|
3362
|
+
for (const [key, sourceEnvs] of sourceMap) {
|
|
3363
|
+
const targetEnvs = targetMap.get(key);
|
|
3364
|
+
const missingFrom = [...sourceEnvs].filter((e) => !targetEnvs?.has(e)).sort();
|
|
3365
|
+
if (missingFrom.length > 0) {
|
|
3366
|
+
nsClean = false;
|
|
3367
|
+
issues.push({
|
|
3368
|
+
namespace: ns,
|
|
3369
|
+
key,
|
|
3370
|
+
presentIn: [...sourceEnvs].sort(),
|
|
3371
|
+
missingFrom,
|
|
3372
|
+
message: `Key '${key}' in namespace '${ns}' exists in ${direction} [${[...sourceEnvs].sort().join(", ")}] but is missing from [${missingFrom.join(", ")}]`
|
|
3373
|
+
});
|
|
3374
|
+
}
|
|
3391
3375
|
}
|
|
3392
|
-
}
|
|
3376
|
+
};
|
|
3377
|
+
reportDrift(remoteKeyEnvs, localKeyEnvs, "remote");
|
|
3378
|
+
reportDrift(localKeyEnvs, remoteKeyEnvs, "local");
|
|
3393
3379
|
if (nsClean) namespacesClean++;
|
|
3394
3380
|
}
|
|
3395
3381
|
return {
|
|
@@ -3400,29 +3386,23 @@ var DriftDetector = class {
|
|
|
3400
3386
|
remoteEnvironments: remoteEnvNames
|
|
3401
3387
|
};
|
|
3402
3388
|
}
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
|
|
3406
|
-
|
|
3407
|
-
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
const parsed = YAML9.parse(raw);
|
|
3414
|
-
if (parsed === null || parsed === void 0 || typeof parsed !== "object") return null;
|
|
3415
|
-
return Object.keys(parsed).filter((k) => k !== "sops");
|
|
3416
|
-
} catch {
|
|
3417
|
-
return null;
|
|
3389
|
+
collectKeyEnvs(cells, ns, sharedEnvSet) {
|
|
3390
|
+
const keyEnvs = /* @__PURE__ */ new Map();
|
|
3391
|
+
for (const cell of cells) {
|
|
3392
|
+
if (cell.namespace !== ns || !sharedEnvSet.has(cell.environment)) continue;
|
|
3393
|
+
const keys = readSopsKeyNames(cell.filePath);
|
|
3394
|
+
if (keys === null) continue;
|
|
3395
|
+
for (const key of keys) {
|
|
3396
|
+
if (!keyEnvs.has(key)) keyEnvs.set(key, /* @__PURE__ */ new Set());
|
|
3397
|
+
keyEnvs.get(key).add(cell.environment);
|
|
3398
|
+
}
|
|
3418
3399
|
}
|
|
3400
|
+
return keyEnvs;
|
|
3419
3401
|
}
|
|
3420
3402
|
};
|
|
3421
3403
|
|
|
3422
3404
|
// src/report/generator.ts
|
|
3423
|
-
import * as fs14 from "fs";
|
|
3424
3405
|
import * as path16 from "path";
|
|
3425
|
-
import * as YAML10 from "yaml";
|
|
3426
3406
|
|
|
3427
3407
|
// src/report/sanitizer.ts
|
|
3428
3408
|
var ReportSanitizer = class {
|
|
@@ -3727,15 +3707,7 @@ var ReportGenerator = class {
|
|
|
3727
3707
|
};
|
|
3728
3708
|
}
|
|
3729
3709
|
readKeyCount(filePath) {
|
|
3730
|
-
|
|
3731
|
-
if (!fs14.existsSync(filePath)) return 0;
|
|
3732
|
-
const raw = fs14.readFileSync(filePath, "utf-8");
|
|
3733
|
-
const parsed = YAML10.parse(raw);
|
|
3734
|
-
if (parsed === null || parsed === void 0 || typeof parsed !== "object") return 0;
|
|
3735
|
-
return Object.keys(parsed).filter((k) => k !== "sops").length;
|
|
3736
|
-
} catch {
|
|
3737
|
-
return 0;
|
|
3738
|
-
}
|
|
3710
|
+
return readSopsKeyNames(filePath)?.length ?? 0;
|
|
3739
3711
|
}
|
|
3740
3712
|
async buildPolicy(manifest, repoRoot) {
|
|
3741
3713
|
try {
|
|
@@ -4064,10 +4036,10 @@ var SopsMergeDriver = class {
|
|
|
4064
4036
|
};
|
|
4065
4037
|
|
|
4066
4038
|
// src/service-identity/manager.ts
|
|
4067
|
-
import * as
|
|
4039
|
+
import * as fs14 from "fs";
|
|
4068
4040
|
import * as os from "os";
|
|
4069
4041
|
import * as path17 from "path";
|
|
4070
|
-
import * as
|
|
4042
|
+
import * as YAML10 from "yaml";
|
|
4071
4043
|
var PartialRotationError = class extends Error {
|
|
4072
4044
|
constructor(message, rotatedKeys) {
|
|
4073
4045
|
super(message);
|
|
@@ -4119,8 +4091,8 @@ var ServiceIdentityManager = class {
|
|
|
4119
4091
|
};
|
|
4120
4092
|
await this.registerRecipients(definition, manifest, repoRoot);
|
|
4121
4093
|
const manifestPath = path17.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
4122
|
-
const raw =
|
|
4123
|
-
const doc =
|
|
4094
|
+
const raw = fs14.readFileSync(manifestPath, "utf-8");
|
|
4095
|
+
const doc = YAML10.parse(raw);
|
|
4124
4096
|
if (!Array.isArray(doc.service_identities)) {
|
|
4125
4097
|
doc.service_identities = [];
|
|
4126
4098
|
}
|
|
@@ -4132,11 +4104,11 @@ var ServiceIdentityManager = class {
|
|
|
4132
4104
|
});
|
|
4133
4105
|
const tmpCreate = path17.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
|
|
4134
4106
|
try {
|
|
4135
|
-
|
|
4136
|
-
|
|
4107
|
+
fs14.writeFileSync(tmpCreate, YAML10.stringify(doc), "utf-8");
|
|
4108
|
+
fs14.renameSync(tmpCreate, manifestPath);
|
|
4137
4109
|
} finally {
|
|
4138
4110
|
try {
|
|
4139
|
-
|
|
4111
|
+
fs14.unlinkSync(tmpCreate);
|
|
4140
4112
|
} catch {
|
|
4141
4113
|
}
|
|
4142
4114
|
}
|
|
@@ -4175,8 +4147,8 @@ var ServiceIdentityManager = class {
|
|
|
4175
4147
|
}
|
|
4176
4148
|
}
|
|
4177
4149
|
const manifestPath = path17.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
4178
|
-
const raw =
|
|
4179
|
-
const doc =
|
|
4150
|
+
const raw = fs14.readFileSync(manifestPath, "utf-8");
|
|
4151
|
+
const doc = YAML10.parse(raw);
|
|
4180
4152
|
const identities = doc.service_identities;
|
|
4181
4153
|
if (Array.isArray(identities)) {
|
|
4182
4154
|
doc.service_identities = identities.filter(
|
|
@@ -4185,11 +4157,11 @@ var ServiceIdentityManager = class {
|
|
|
4185
4157
|
}
|
|
4186
4158
|
const tmp = path17.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
|
|
4187
4159
|
try {
|
|
4188
|
-
|
|
4189
|
-
|
|
4160
|
+
fs14.writeFileSync(tmp, YAML10.stringify(doc), "utf-8");
|
|
4161
|
+
fs14.renameSync(tmp, manifestPath);
|
|
4190
4162
|
} finally {
|
|
4191
4163
|
try {
|
|
4192
|
-
|
|
4164
|
+
fs14.unlinkSync(tmp);
|
|
4193
4165
|
} catch {
|
|
4194
4166
|
}
|
|
4195
4167
|
}
|
|
@@ -4205,8 +4177,8 @@ var ServiceIdentityManager = class {
|
|
|
4205
4177
|
throw new Error(`Service identity '${name}' not found.`);
|
|
4206
4178
|
}
|
|
4207
4179
|
const manifestPath = path17.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
4208
|
-
const raw =
|
|
4209
|
-
const doc =
|
|
4180
|
+
const raw = fs14.readFileSync(manifestPath, "utf-8");
|
|
4181
|
+
const doc = YAML10.parse(raw);
|
|
4210
4182
|
const identities = doc.service_identities;
|
|
4211
4183
|
const siDoc = identities.find((si) => si.name === name);
|
|
4212
4184
|
const envs = siDoc.environments;
|
|
@@ -4233,11 +4205,11 @@ var ServiceIdentityManager = class {
|
|
|
4233
4205
|
}
|
|
4234
4206
|
const tmp = path17.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
|
|
4235
4207
|
try {
|
|
4236
|
-
|
|
4237
|
-
|
|
4208
|
+
fs14.writeFileSync(tmp, YAML10.stringify(doc), "utf-8");
|
|
4209
|
+
fs14.renameSync(tmp, manifestPath);
|
|
4238
4210
|
} finally {
|
|
4239
4211
|
try {
|
|
4240
|
-
|
|
4212
|
+
fs14.unlinkSync(tmp);
|
|
4241
4213
|
} catch {
|
|
4242
4214
|
}
|
|
4243
4215
|
}
|
|
@@ -4274,8 +4246,8 @@ var ServiceIdentityManager = class {
|
|
|
4274
4246
|
throw new Error(`Service identity '${name}' not found.`);
|
|
4275
4247
|
}
|
|
4276
4248
|
const manifestPath = path17.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
4277
|
-
const raw =
|
|
4278
|
-
const doc =
|
|
4249
|
+
const raw = fs14.readFileSync(manifestPath, "utf-8");
|
|
4250
|
+
const doc = YAML10.parse(raw);
|
|
4279
4251
|
const identities = doc.service_identities;
|
|
4280
4252
|
const siDoc = identities.find((si) => si.name === name);
|
|
4281
4253
|
const envs = siDoc.environments;
|
|
@@ -4330,11 +4302,11 @@ var ServiceIdentityManager = class {
|
|
|
4330
4302
|
}
|
|
4331
4303
|
const tmpRotate = path17.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
|
|
4332
4304
|
try {
|
|
4333
|
-
|
|
4334
|
-
|
|
4305
|
+
fs14.writeFileSync(tmpRotate, YAML10.stringify(doc), "utf-8");
|
|
4306
|
+
fs14.renameSync(tmpRotate, manifestPath);
|
|
4335
4307
|
} finally {
|
|
4336
4308
|
try {
|
|
4337
|
-
|
|
4309
|
+
fs14.unlinkSync(tmpRotate);
|
|
4338
4310
|
} catch {
|
|
4339
4311
|
}
|
|
4340
4312
|
}
|
|
@@ -4455,7 +4427,7 @@ async function resolveIdentitySecrets(identityName, environment, manifest, repoR
|
|
|
4455
4427
|
}
|
|
4456
4428
|
|
|
4457
4429
|
// src/artifact/packer.ts
|
|
4458
|
-
import * as
|
|
4430
|
+
import * as fs15 from "fs";
|
|
4459
4431
|
import * as path18 from "path";
|
|
4460
4432
|
import * as crypto3 from "crypto";
|
|
4461
4433
|
|
|
@@ -4463,7 +4435,7 @@ import * as crypto3 from "crypto";
|
|
|
4463
4435
|
import * as crypto2 from "crypto";
|
|
4464
4436
|
function buildSigningPayload(artifact) {
|
|
4465
4437
|
const fields = [
|
|
4466
|
-
"clef-sig-
|
|
4438
|
+
"clef-sig-v2",
|
|
4467
4439
|
String(artifact.version),
|
|
4468
4440
|
artifact.identity,
|
|
4469
4441
|
artifact.environment,
|
|
@@ -4475,7 +4447,9 @@ function buildSigningPayload(artifact) {
|
|
|
4475
4447
|
artifact.envelope?.provider ?? "",
|
|
4476
4448
|
artifact.envelope?.keyId ?? "",
|
|
4477
4449
|
artifact.envelope?.wrappedKey ?? "",
|
|
4478
|
-
artifact.envelope?.algorithm ?? ""
|
|
4450
|
+
artifact.envelope?.algorithm ?? "",
|
|
4451
|
+
artifact.envelope?.iv ?? "",
|
|
4452
|
+
artifact.envelope?.authTag ?? ""
|
|
4479
4453
|
];
|
|
4480
4454
|
return Buffer.from(fields.join("\n"), "utf-8");
|
|
4481
4455
|
}
|
|
@@ -4569,40 +4543,41 @@ var ArtifactPacker = class {
|
|
|
4569
4543
|
if (!this.kms) {
|
|
4570
4544
|
throw new Error("KMS provider required for envelope encryption but none was provided.");
|
|
4571
4545
|
}
|
|
4572
|
-
const
|
|
4573
|
-
|
|
4574
|
-
"age-encryption"
|
|
4575
|
-
);
|
|
4576
|
-
const ephemeralPrivateKey = await generateIdentity();
|
|
4577
|
-
const ephemeralPublicKey = await identityToRecipient(ephemeralPrivateKey);
|
|
4546
|
+
const dek = crypto3.randomBytes(32);
|
|
4547
|
+
const iv = crypto3.randomBytes(12);
|
|
4578
4548
|
try {
|
|
4579
|
-
const
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4549
|
+
const cipher = crypto3.createCipheriv("aes-256-gcm", dek, iv);
|
|
4550
|
+
const ciphertextBuf = Buffer.concat([
|
|
4551
|
+
cipher.update(Buffer.from(plaintext, "utf-8")),
|
|
4552
|
+
cipher.final()
|
|
4553
|
+
]);
|
|
4554
|
+
const authTag = cipher.getAuthTag();
|
|
4555
|
+
ciphertext = ciphertextBuf.toString("base64");
|
|
4556
|
+
const kmsConfig = resolved.envConfig.kms;
|
|
4557
|
+
const wrapped = await this.kms.wrap(kmsConfig.keyId, dek);
|
|
4558
|
+
const revision = `${Date.now()}-${crypto3.randomBytes(4).toString("hex")}`;
|
|
4559
|
+
const ciphertextHash = crypto3.createHash("sha256").update(ciphertext).digest("hex");
|
|
4560
|
+
artifact = {
|
|
4561
|
+
version: 1,
|
|
4562
|
+
identity: config.identity,
|
|
4563
|
+
environment: config.environment,
|
|
4564
|
+
packedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4565
|
+
revision,
|
|
4566
|
+
ciphertextHash,
|
|
4567
|
+
ciphertext,
|
|
4568
|
+
keys: Object.keys(resolved.values),
|
|
4569
|
+
envelope: {
|
|
4570
|
+
provider: kmsConfig.provider,
|
|
4571
|
+
keyId: kmsConfig.keyId,
|
|
4572
|
+
wrappedKey: wrapped.wrappedKey.toString("base64"),
|
|
4573
|
+
algorithm: wrapped.algorithm,
|
|
4574
|
+
iv: iv.toString("base64"),
|
|
4575
|
+
authTag: authTag.toString("base64")
|
|
4576
|
+
}
|
|
4577
|
+
};
|
|
4578
|
+
} finally {
|
|
4579
|
+
dek.fill(0);
|
|
4585
4580
|
}
|
|
4586
|
-
const kmsConfig = resolved.envConfig.kms;
|
|
4587
|
-
const wrapped = await this.kms.wrap(kmsConfig.keyId, Buffer.from(ephemeralPrivateKey));
|
|
4588
|
-
const revision = `${Date.now()}-${crypto3.randomBytes(4).toString("hex")}`;
|
|
4589
|
-
const ciphertextHash = crypto3.createHash("sha256").update(ciphertext).digest("hex");
|
|
4590
|
-
artifact = {
|
|
4591
|
-
version: 1,
|
|
4592
|
-
identity: config.identity,
|
|
4593
|
-
environment: config.environment,
|
|
4594
|
-
packedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4595
|
-
revision,
|
|
4596
|
-
ciphertextHash,
|
|
4597
|
-
ciphertext,
|
|
4598
|
-
keys: Object.keys(resolved.values),
|
|
4599
|
-
envelope: {
|
|
4600
|
-
provider: kmsConfig.provider,
|
|
4601
|
-
keyId: kmsConfig.keyId,
|
|
4602
|
-
wrappedKey: wrapped.wrappedKey.toString("base64"),
|
|
4603
|
-
algorithm: wrapped.algorithm
|
|
4604
|
-
}
|
|
4605
|
-
};
|
|
4606
4581
|
} else {
|
|
4607
4582
|
try {
|
|
4608
4583
|
const { Encrypter } = await import("age-encryption");
|
|
@@ -4610,8 +4585,10 @@ var ArtifactPacker = class {
|
|
|
4610
4585
|
e.addRecipient(resolved.recipient);
|
|
4611
4586
|
const encrypted = await e.encrypt(plaintext);
|
|
4612
4587
|
ciphertext = Buffer.from(encrypted).toString("base64");
|
|
4613
|
-
} catch {
|
|
4614
|
-
throw new Error(
|
|
4588
|
+
} catch (err) {
|
|
4589
|
+
throw new Error(
|
|
4590
|
+
`Failed to age-encrypt artifact: ${err instanceof Error ? err.message : String(err)}`
|
|
4591
|
+
);
|
|
4615
4592
|
}
|
|
4616
4593
|
const revision = `${Date.now()}-${crypto3.randomBytes(4).toString("hex")}`;
|
|
4617
4594
|
const ciphertextHash = crypto3.createHash("sha256").update(ciphertext).digest("hex");
|
|
@@ -4627,8 +4604,8 @@ var ArtifactPacker = class {
|
|
|
4627
4604
|
};
|
|
4628
4605
|
}
|
|
4629
4606
|
const outputDir = path18.dirname(config.outputPath);
|
|
4630
|
-
if (!
|
|
4631
|
-
|
|
4607
|
+
if (!fs15.existsSync(outputDir)) {
|
|
4608
|
+
fs15.mkdirSync(outputDir, { recursive: true });
|
|
4632
4609
|
}
|
|
4633
4610
|
if (config.ttl && config.ttl > 0) {
|
|
4634
4611
|
artifact.expiresAt = new Date(Date.now() + config.ttl * 1e3).toISOString();
|
|
@@ -4647,8 +4624,8 @@ var ArtifactPacker = class {
|
|
|
4647
4624
|
}
|
|
4648
4625
|
const json = JSON.stringify(artifact, null, 2);
|
|
4649
4626
|
const tmpOutput = `${config.outputPath}.tmp.${process.pid}`;
|
|
4650
|
-
|
|
4651
|
-
|
|
4627
|
+
fs15.writeFileSync(tmpOutput, json, "utf-8");
|
|
4628
|
+
fs15.renameSync(tmpOutput, config.outputPath);
|
|
4652
4629
|
return {
|
|
4653
4630
|
outputPath: config.outputPath,
|
|
4654
4631
|
namespaceCount: resolved.identity.namespaces.length,
|
|
@@ -4658,6 +4635,9 @@ var ArtifactPacker = class {
|
|
|
4658
4635
|
};
|
|
4659
4636
|
}
|
|
4660
4637
|
};
|
|
4638
|
+
|
|
4639
|
+
// src/kms/types.ts
|
|
4640
|
+
var VALID_KMS_PROVIDERS = ["aws", "gcp", "azure"];
|
|
4661
4641
|
export {
|
|
4662
4642
|
ArtifactPacker,
|
|
4663
4643
|
BulkOps,
|
|
@@ -4695,6 +4675,7 @@ export {
|
|
|
4695
4675
|
SopsMergeDriver,
|
|
4696
4676
|
SopsMissingError,
|
|
4697
4677
|
SopsVersionError,
|
|
4678
|
+
VALID_KMS_PROVIDERS,
|
|
4698
4679
|
assertSops,
|
|
4699
4680
|
buildSigningPayload,
|
|
4700
4681
|
checkAll,
|
|
@@ -4721,7 +4702,7 @@ export {
|
|
|
4721
4702
|
markResolved,
|
|
4722
4703
|
matchPatterns,
|
|
4723
4704
|
metadataPath,
|
|
4724
|
-
|
|
4705
|
+
parse8 as parse,
|
|
4725
4706
|
parseDotenv,
|
|
4726
4707
|
parseIgnoreContent,
|
|
4727
4708
|
parseJson,
|