@clef-sh/core 0.1.6-beta.32 → 0.1.7-beta.45
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.map +1 -1
- package/dist/index.js +174 -68
- package/dist/index.js.map +3 -3
- package/dist/index.mjs +174 -68
- package/dist/index.mjs.map +3 -3
- package/dist/matrix/manager.d.ts +10 -1
- package/dist/matrix/manager.d.ts.map +1 -1
- package/dist/service-identity/manager.d.ts +13 -0
- package/dist/service-identity/manager.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"packer.d.ts","sourceRoot":"","sources":["../../src/artifact/packer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAiB,MAAM,UAAU,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAkB,MAAM,SAAS,CAAC;AAGjE;;;;;GAKG;AACH,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAFJ,UAAU,EAAE,iBAAiB,EAC7B,aAAa,EAAE,aAAa,EAC5B,GAAG,CAAC,EAAE,WAAW,YAAA;IAGpC;;;OAGG;IACG,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"packer.d.ts","sourceRoot":"","sources":["../../src/artifact/packer.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAiB,MAAM,UAAU,CAAC;AAC1E,OAAO,EAAE,WAAW,EAAE,MAAM,QAAQ,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAkB,MAAM,SAAS,CAAC;AAGjE;;;;;GAKG;AACH,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;gBAFJ,UAAU,EAAE,iBAAiB,EAC7B,aAAa,EAAE,aAAa,EAC5B,GAAG,CAAC,EAAE,WAAW,YAAA;IAGpC;;;OAGG;IACG,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;CA+G9F"}
|
package/dist/index.js
CHANGED
|
@@ -6972,7 +6972,7 @@ __export(src_exports, {
|
|
|
6972
6972
|
markResolved: () => markResolved,
|
|
6973
6973
|
matchPatterns: () => matchPatterns,
|
|
6974
6974
|
metadataPath: () => metadataPath,
|
|
6975
|
-
parse: () =>
|
|
6975
|
+
parse: () => parse7,
|
|
6976
6976
|
parseDotenv: () => parseDotenv,
|
|
6977
6977
|
parseIgnoreContent: () => parseIgnoreContent,
|
|
6978
6978
|
parseJson: () => parseJson,
|
|
@@ -8002,6 +8002,7 @@ var ScanRunner = class {
|
|
|
8002
8002
|
// src/matrix/manager.ts
|
|
8003
8003
|
var fs5 = __toESM(require("fs"));
|
|
8004
8004
|
var path4 = __toESM(require("path"));
|
|
8005
|
+
var YAML3 = __toESM(require("yaml"));
|
|
8005
8006
|
|
|
8006
8007
|
// src/pending/metadata.ts
|
|
8007
8008
|
var fs4 = __toESM(require("fs"));
|
|
@@ -8146,9 +8147,15 @@ var MatrixManager = class {
|
|
|
8146
8147
|
* @param repoRoot - Absolute path to the repository root.
|
|
8147
8148
|
* @param sopsClient - SOPS client used to decrypt each cell.
|
|
8148
8149
|
*/
|
|
8149
|
-
async getMatrixStatus(manifest, repoRoot,
|
|
8150
|
+
async getMatrixStatus(manifest, repoRoot, _sopsClient) {
|
|
8150
8151
|
const cells = this.resolveMatrix(manifest, repoRoot);
|
|
8151
8152
|
const statuses = [];
|
|
8153
|
+
const cellKeys = /* @__PURE__ */ new Map();
|
|
8154
|
+
for (const cell of cells) {
|
|
8155
|
+
if (cell.exists) {
|
|
8156
|
+
cellKeys.set(cell.filePath, this.readKeyNames(cell.filePath));
|
|
8157
|
+
}
|
|
8158
|
+
}
|
|
8152
8159
|
for (const cell of cells) {
|
|
8153
8160
|
if (!cell.exists) {
|
|
8154
8161
|
statuses.push({
|
|
@@ -8171,48 +8178,56 @@ var MatrixManager = class {
|
|
|
8171
8178
|
pendingCount = pending.length;
|
|
8172
8179
|
} catch {
|
|
8173
8180
|
}
|
|
8174
|
-
|
|
8175
|
-
|
|
8176
|
-
|
|
8177
|
-
|
|
8178
|
-
|
|
8179
|
-
|
|
8180
|
-
|
|
8181
|
-
|
|
8182
|
-
|
|
8183
|
-
|
|
8184
|
-
|
|
8185
|
-
|
|
8186
|
-
|
|
8187
|
-
|
|
8188
|
-
|
|
8189
|
-
|
|
8190
|
-
type: "missing_keys",
|
|
8191
|
-
message: `Key '${mk}' exists in ${sibling.environment} but is missing here.`,
|
|
8192
|
-
key: mk
|
|
8193
|
-
});
|
|
8194
|
-
}
|
|
8195
|
-
} catch {
|
|
8196
|
-
}
|
|
8181
|
+
const keys = cellKeys.get(cell.filePath) ?? [];
|
|
8182
|
+
const keyCount = keys.length;
|
|
8183
|
+
const lastModified = this.readLastModified(cell.filePath);
|
|
8184
|
+
const issues = [];
|
|
8185
|
+
const siblingCells = cells.filter(
|
|
8186
|
+
(c) => c.namespace === cell.namespace && c.environment !== cell.environment && c.exists
|
|
8187
|
+
);
|
|
8188
|
+
for (const sibling of siblingCells) {
|
|
8189
|
+
const siblingKeys = cellKeys.get(sibling.filePath) ?? [];
|
|
8190
|
+
const missingKeys = siblingKeys.filter((k) => !keys.includes(k));
|
|
8191
|
+
for (const mk of missingKeys) {
|
|
8192
|
+
issues.push({
|
|
8193
|
+
type: "missing_keys",
|
|
8194
|
+
message: `Key '${mk}' exists in ${sibling.environment} but is missing here.`,
|
|
8195
|
+
key: mk
|
|
8196
|
+
});
|
|
8197
8197
|
}
|
|
8198
|
-
statuses.push({ cell, keyCount, pendingCount, lastModified, issues });
|
|
8199
|
-
} catch {
|
|
8200
|
-
statuses.push({
|
|
8201
|
-
cell,
|
|
8202
|
-
keyCount: 0,
|
|
8203
|
-
pendingCount: 0,
|
|
8204
|
-
lastModified: null,
|
|
8205
|
-
issues: [
|
|
8206
|
-
{
|
|
8207
|
-
type: "sops_error",
|
|
8208
|
-
message: `Could not decrypt '${cell.filePath}'. Check your key configuration.`
|
|
8209
|
-
}
|
|
8210
|
-
]
|
|
8211
|
-
});
|
|
8212
8198
|
}
|
|
8199
|
+
statuses.push({ cell, keyCount, pendingCount, lastModified, issues });
|
|
8213
8200
|
}
|
|
8214
8201
|
return statuses;
|
|
8215
8202
|
}
|
|
8203
|
+
/**
|
|
8204
|
+
* Read top-level key names from a SOPS file without decryption.
|
|
8205
|
+
* SOPS stores key names in plaintext — only values are encrypted.
|
|
8206
|
+
*/
|
|
8207
|
+
readKeyNames(filePath) {
|
|
8208
|
+
try {
|
|
8209
|
+
const raw = fs5.readFileSync(filePath, "utf-8");
|
|
8210
|
+
const parsed = YAML3.parse(raw);
|
|
8211
|
+
if (!parsed || typeof parsed !== "object") return [];
|
|
8212
|
+
return Object.keys(parsed).filter((k) => k !== "sops");
|
|
8213
|
+
} catch {
|
|
8214
|
+
return [];
|
|
8215
|
+
}
|
|
8216
|
+
}
|
|
8217
|
+
/**
|
|
8218
|
+
* Read the lastModified timestamp from SOPS metadata without decryption.
|
|
8219
|
+
*/
|
|
8220
|
+
readLastModified(filePath) {
|
|
8221
|
+
try {
|
|
8222
|
+
const raw = fs5.readFileSync(filePath, "utf-8");
|
|
8223
|
+
const parsed = YAML3.parse(raw);
|
|
8224
|
+
const sops = parsed?.sops;
|
|
8225
|
+
if (sops?.lastmodified) return new Date(String(sops.lastmodified));
|
|
8226
|
+
return null;
|
|
8227
|
+
} catch {
|
|
8228
|
+
return null;
|
|
8229
|
+
}
|
|
8230
|
+
}
|
|
8216
8231
|
/**
|
|
8217
8232
|
* Check whether an environment has the `protected` flag set in the manifest.
|
|
8218
8233
|
*
|
|
@@ -8227,7 +8242,7 @@ var MatrixManager = class {
|
|
|
8227
8242
|
|
|
8228
8243
|
// src/schema/validator.ts
|
|
8229
8244
|
var fs6 = __toESM(require("fs"));
|
|
8230
|
-
var
|
|
8245
|
+
var YAML4 = __toESM(require("yaml"));
|
|
8231
8246
|
var SchemaValidator = class {
|
|
8232
8247
|
/**
|
|
8233
8248
|
* Read and parse a YAML schema file from disk.
|
|
@@ -8245,7 +8260,7 @@ var SchemaValidator = class {
|
|
|
8245
8260
|
}
|
|
8246
8261
|
let parsed;
|
|
8247
8262
|
try {
|
|
8248
|
-
parsed =
|
|
8263
|
+
parsed = YAML4.parse(raw);
|
|
8249
8264
|
} catch {
|
|
8250
8265
|
throw new SchemaLoadError(`Schema file '${filePath}' contains invalid YAML.`, filePath);
|
|
8251
8266
|
}
|
|
@@ -8813,7 +8828,7 @@ ${mergeRule}
|
|
|
8813
8828
|
var fs10 = __toESM(require("fs"));
|
|
8814
8829
|
var net = __toESM(require("net"));
|
|
8815
8830
|
var import_crypto = require("crypto");
|
|
8816
|
-
var
|
|
8831
|
+
var YAML5 = __toESM(require("yaml"));
|
|
8817
8832
|
|
|
8818
8833
|
// src/sops/resolver.ts
|
|
8819
8834
|
var fs9 = __toESM(require("fs"));
|
|
@@ -9067,7 +9082,7 @@ var SopsClient = class {
|
|
|
9067
9082
|
}
|
|
9068
9083
|
let parsed;
|
|
9069
9084
|
try {
|
|
9070
|
-
parsed =
|
|
9085
|
+
parsed = YAML5.parse(result.stdout) ?? {};
|
|
9071
9086
|
} catch {
|
|
9072
9087
|
throw new SopsDecryptionError(
|
|
9073
9088
|
`Decrypted content of '${filePath}' is not valid YAML.`,
|
|
@@ -9094,7 +9109,7 @@ var SopsClient = class {
|
|
|
9094
9109
|
async encrypt(filePath, values, manifest, environment) {
|
|
9095
9110
|
await assertSops(this.runner, this.sopsCommand);
|
|
9096
9111
|
const fmt = formatFromPath(filePath);
|
|
9097
|
-
const content = fmt === "json" ? JSON.stringify(values, null, 2) :
|
|
9112
|
+
const content = fmt === "json" ? JSON.stringify(values, null, 2) : YAML5.stringify(values);
|
|
9098
9113
|
const args = this.buildEncryptArgs(filePath, manifest, environment);
|
|
9099
9114
|
const env = this.buildSopsEnv();
|
|
9100
9115
|
let inputArg;
|
|
@@ -9294,7 +9309,7 @@ var SopsClient = class {
|
|
|
9294
9309
|
}
|
|
9295
9310
|
let parsed;
|
|
9296
9311
|
try {
|
|
9297
|
-
parsed =
|
|
9312
|
+
parsed = YAML5.parse(content);
|
|
9298
9313
|
} catch {
|
|
9299
9314
|
throw new SopsDecryptionError(
|
|
9300
9315
|
`File '${filePath}' is not valid YAML. Cannot extract SOPS metadata.`,
|
|
@@ -9595,7 +9610,7 @@ var LintRunner = class {
|
|
|
9595
9610
|
/**
|
|
9596
9611
|
* Lint service identity configurations for drift issues.
|
|
9597
9612
|
*/
|
|
9598
|
-
async lintServiceIdentities(identities, manifest,
|
|
9613
|
+
async lintServiceIdentities(identities, manifest, repoRoot, existingCells) {
|
|
9599
9614
|
const issues = [];
|
|
9600
9615
|
const declaredEnvNames = new Set(manifest.environments.map((e) => e.name));
|
|
9601
9616
|
const declaredNsNames = new Set(manifest.namespaces.map((ns) => ns.name));
|
|
@@ -9726,7 +9741,7 @@ var path12 = __toESM(require("path"));
|
|
|
9726
9741
|
|
|
9727
9742
|
// src/import/parsers.ts
|
|
9728
9743
|
var path11 = __toESM(require("path"));
|
|
9729
|
-
var
|
|
9744
|
+
var YAML6 = __toESM(require("yaml"));
|
|
9730
9745
|
function detectFormat(filePath, content) {
|
|
9731
9746
|
const base = path11.basename(filePath);
|
|
9732
9747
|
const ext = path11.extname(filePath).toLowerCase();
|
|
@@ -9750,7 +9765,7 @@ function detectFormat(filePath, content) {
|
|
|
9750
9765
|
} catch {
|
|
9751
9766
|
}
|
|
9752
9767
|
try {
|
|
9753
|
-
const parsed =
|
|
9768
|
+
const parsed = YAML6.parse(content);
|
|
9754
9769
|
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
9755
9770
|
return "yaml";
|
|
9756
9771
|
}
|
|
@@ -9831,7 +9846,7 @@ function parseJson(content) {
|
|
|
9831
9846
|
function parseYaml(content) {
|
|
9832
9847
|
let parsed;
|
|
9833
9848
|
try {
|
|
9834
|
-
parsed =
|
|
9849
|
+
parsed = YAML6.parse(content);
|
|
9835
9850
|
} catch (err) {
|
|
9836
9851
|
throw new Error(`Invalid YAML: ${err.message}`);
|
|
9837
9852
|
}
|
|
@@ -9865,7 +9880,7 @@ function parseYaml(content) {
|
|
|
9865
9880
|
}
|
|
9866
9881
|
return { pairs, format: "yaml", skipped, warnings };
|
|
9867
9882
|
}
|
|
9868
|
-
function
|
|
9883
|
+
function parse7(content, format, filePath) {
|
|
9869
9884
|
const resolved = format === "auto" ? detectFormat(filePath ?? "", content) : format;
|
|
9870
9885
|
switch (resolved) {
|
|
9871
9886
|
case "dotenv":
|
|
@@ -9898,7 +9913,7 @@ var ImportRunner = class {
|
|
|
9898
9913
|
repoRoot,
|
|
9899
9914
|
manifest.file_pattern.replace("{namespace}", ns).replace("{environment}", env)
|
|
9900
9915
|
);
|
|
9901
|
-
const parsed =
|
|
9916
|
+
const parsed = parse7(content, options.format ?? "auto", sourcePath ?? "");
|
|
9902
9917
|
let candidates = Object.entries(parsed.pairs);
|
|
9903
9918
|
if (options.prefix) {
|
|
9904
9919
|
const prefix = options.prefix;
|
|
@@ -9954,7 +9969,7 @@ var ImportRunner = class {
|
|
|
9954
9969
|
// src/recipients/index.ts
|
|
9955
9970
|
var fs11 = __toESM(require("fs"));
|
|
9956
9971
|
var path13 = __toESM(require("path"));
|
|
9957
|
-
var
|
|
9972
|
+
var YAML7 = __toESM(require("yaml"));
|
|
9958
9973
|
function parseRecipientEntry(entry) {
|
|
9959
9974
|
if (typeof entry === "string") {
|
|
9960
9975
|
return { key: entry };
|
|
@@ -9978,11 +9993,11 @@ function toRecipient(entry) {
|
|
|
9978
9993
|
function readManifestYaml(repoRoot) {
|
|
9979
9994
|
const manifestPath = path13.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
9980
9995
|
const raw = fs11.readFileSync(manifestPath, "utf-8");
|
|
9981
|
-
return
|
|
9996
|
+
return YAML7.parse(raw);
|
|
9982
9997
|
}
|
|
9983
9998
|
function writeManifestYaml(repoRoot, doc) {
|
|
9984
9999
|
const manifestPath = path13.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
9985
|
-
fs11.writeFileSync(manifestPath,
|
|
10000
|
+
fs11.writeFileSync(manifestPath, YAML7.stringify(doc), "utf-8");
|
|
9986
10001
|
}
|
|
9987
10002
|
function getRecipientsArray(doc) {
|
|
9988
10003
|
const sops = doc.sops;
|
|
@@ -10217,7 +10232,7 @@ var RecipientManager = class {
|
|
|
10217
10232
|
// src/recipients/requests.ts
|
|
10218
10233
|
var fs12 = __toESM(require("fs"));
|
|
10219
10234
|
var path14 = __toESM(require("path"));
|
|
10220
|
-
var
|
|
10235
|
+
var YAML8 = __toESM(require("yaml"));
|
|
10221
10236
|
var REQUESTS_FILENAME = ".clef-requests.yaml";
|
|
10222
10237
|
var HEADER_COMMENT2 = "# Pending recipient access requests. Approve with: clef recipients approve <label>\n";
|
|
10223
10238
|
function requestsFilePath(repoRoot) {
|
|
@@ -10228,7 +10243,7 @@ function loadRequests(repoRoot) {
|
|
|
10228
10243
|
try {
|
|
10229
10244
|
if (!fs12.existsSync(filePath)) return [];
|
|
10230
10245
|
const content = fs12.readFileSync(filePath, "utf-8");
|
|
10231
|
-
const parsed =
|
|
10246
|
+
const parsed = YAML8.parse(content);
|
|
10232
10247
|
if (!parsed || !Array.isArray(parsed.requests)) return [];
|
|
10233
10248
|
return parsed.requests.map((r) => ({
|
|
10234
10249
|
key: r.key,
|
|
@@ -10260,7 +10275,7 @@ function saveRequests(repoRoot, requests) {
|
|
|
10260
10275
|
return raw;
|
|
10261
10276
|
})
|
|
10262
10277
|
};
|
|
10263
|
-
fs12.writeFileSync(filePath, HEADER_COMMENT2 +
|
|
10278
|
+
fs12.writeFileSync(filePath, HEADER_COMMENT2 + YAML8.stringify(data), "utf-8");
|
|
10264
10279
|
}
|
|
10265
10280
|
function upsertRequest(repoRoot, key, label, environment) {
|
|
10266
10281
|
const requests = loadRequests(repoRoot);
|
|
@@ -10298,7 +10313,7 @@ function findInList(requests, identifier) {
|
|
|
10298
10313
|
// src/drift/detector.ts
|
|
10299
10314
|
var fs13 = __toESM(require("fs"));
|
|
10300
10315
|
var path15 = __toESM(require("path"));
|
|
10301
|
-
var
|
|
10316
|
+
var YAML9 = __toESM(require("yaml"));
|
|
10302
10317
|
var DriftDetector = class {
|
|
10303
10318
|
parser = new ManifestParser();
|
|
10304
10319
|
matrix = new MatrixManager();
|
|
@@ -10385,7 +10400,7 @@ var DriftDetector = class {
|
|
|
10385
10400
|
try {
|
|
10386
10401
|
if (!fs13.existsSync(filePath)) return null;
|
|
10387
10402
|
const raw = fs13.readFileSync(filePath, "utf-8");
|
|
10388
|
-
const parsed =
|
|
10403
|
+
const parsed = YAML9.parse(raw);
|
|
10389
10404
|
if (parsed === null || parsed === void 0 || typeof parsed !== "object") return null;
|
|
10390
10405
|
return Object.keys(parsed).filter((k) => k !== "sops");
|
|
10391
10406
|
} catch {
|
|
@@ -10397,7 +10412,7 @@ var DriftDetector = class {
|
|
|
10397
10412
|
// src/report/generator.ts
|
|
10398
10413
|
var fs14 = __toESM(require("fs"));
|
|
10399
10414
|
var path16 = __toESM(require("path"));
|
|
10400
|
-
var
|
|
10415
|
+
var YAML10 = __toESM(require("yaml"));
|
|
10401
10416
|
|
|
10402
10417
|
// src/report/sanitizer.ts
|
|
10403
10418
|
var ReportSanitizer = class {
|
|
@@ -10705,7 +10720,7 @@ var ReportGenerator = class {
|
|
|
10705
10720
|
try {
|
|
10706
10721
|
if (!fs14.existsSync(filePath)) return 0;
|
|
10707
10722
|
const raw = fs14.readFileSync(filePath, "utf-8");
|
|
10708
|
-
const parsed =
|
|
10723
|
+
const parsed = YAML10.parse(raw);
|
|
10709
10724
|
if (parsed === null || parsed === void 0 || typeof parsed !== "object") return 0;
|
|
10710
10725
|
return Object.keys(parsed).filter((k) => k !== "sops").length;
|
|
10711
10726
|
} catch {
|
|
@@ -11042,7 +11057,7 @@ var SopsMergeDriver = class {
|
|
|
11042
11057
|
var fs15 = __toESM(require("fs"));
|
|
11043
11058
|
var os = __toESM(require("os"));
|
|
11044
11059
|
var path17 = __toESM(require("path"));
|
|
11045
|
-
var
|
|
11060
|
+
var YAML11 = __toESM(require("yaml"));
|
|
11046
11061
|
var PartialRotationError = class extends Error {
|
|
11047
11062
|
constructor(message, rotatedKeys) {
|
|
11048
11063
|
super(message);
|
|
@@ -11095,7 +11110,7 @@ var ServiceIdentityManager = class {
|
|
|
11095
11110
|
await this.registerRecipients(definition, manifest, repoRoot);
|
|
11096
11111
|
const manifestPath = path17.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
11097
11112
|
const raw = fs15.readFileSync(manifestPath, "utf-8");
|
|
11098
|
-
const doc =
|
|
11113
|
+
const doc = YAML11.parse(raw);
|
|
11099
11114
|
if (!Array.isArray(doc.service_identities)) {
|
|
11100
11115
|
doc.service_identities = [];
|
|
11101
11116
|
}
|
|
@@ -11107,7 +11122,7 @@ var ServiceIdentityManager = class {
|
|
|
11107
11122
|
});
|
|
11108
11123
|
const tmpCreate = path17.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
|
|
11109
11124
|
try {
|
|
11110
|
-
fs15.writeFileSync(tmpCreate,
|
|
11125
|
+
fs15.writeFileSync(tmpCreate, YAML11.stringify(doc), "utf-8");
|
|
11111
11126
|
fs15.renameSync(tmpCreate, manifestPath);
|
|
11112
11127
|
} finally {
|
|
11113
11128
|
try {
|
|
@@ -11129,6 +11144,95 @@ var ServiceIdentityManager = class {
|
|
|
11129
11144
|
get(manifest, name) {
|
|
11130
11145
|
return manifest.service_identities?.find((si) => si.name === name);
|
|
11131
11146
|
}
|
|
11147
|
+
/**
|
|
11148
|
+
* Delete a service identity: remove its recipients from scoped SOPS files
|
|
11149
|
+
* and remove it from the manifest.
|
|
11150
|
+
*/
|
|
11151
|
+
async delete(name, manifest, repoRoot) {
|
|
11152
|
+
const identity = this.get(manifest, name);
|
|
11153
|
+
if (!identity) {
|
|
11154
|
+
throw new Error(`Service identity '${name}' not found.`);
|
|
11155
|
+
}
|
|
11156
|
+
const cells = this.matrixManager.resolveMatrix(manifest, repoRoot).filter((c) => c.exists);
|
|
11157
|
+
for (const cell of cells) {
|
|
11158
|
+
if (!identity.namespaces.includes(cell.namespace)) continue;
|
|
11159
|
+
const envConfig = identity.environments[cell.environment];
|
|
11160
|
+
if (!envConfig?.recipient) continue;
|
|
11161
|
+
if (isKmsEnvelope(envConfig)) continue;
|
|
11162
|
+
try {
|
|
11163
|
+
await this.encryption.removeRecipient(cell.filePath, envConfig.recipient);
|
|
11164
|
+
} catch {
|
|
11165
|
+
}
|
|
11166
|
+
}
|
|
11167
|
+
const manifestPath = path17.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
11168
|
+
const raw = fs15.readFileSync(manifestPath, "utf-8");
|
|
11169
|
+
const doc = YAML11.parse(raw);
|
|
11170
|
+
const identities = doc.service_identities;
|
|
11171
|
+
if (Array.isArray(identities)) {
|
|
11172
|
+
doc.service_identities = identities.filter(
|
|
11173
|
+
(si) => si.name !== name
|
|
11174
|
+
);
|
|
11175
|
+
}
|
|
11176
|
+
const tmp = path17.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
|
|
11177
|
+
try {
|
|
11178
|
+
fs15.writeFileSync(tmp, YAML11.stringify(doc), "utf-8");
|
|
11179
|
+
fs15.renameSync(tmp, manifestPath);
|
|
11180
|
+
} finally {
|
|
11181
|
+
try {
|
|
11182
|
+
fs15.unlinkSync(tmp);
|
|
11183
|
+
} catch {
|
|
11184
|
+
}
|
|
11185
|
+
}
|
|
11186
|
+
}
|
|
11187
|
+
/**
|
|
11188
|
+
* Update environment backends on an existing service identity.
|
|
11189
|
+
* Switches age → KMS (removes old recipient) or updates KMS config.
|
|
11190
|
+
* Returns new private keys for any environments switched from KMS → age.
|
|
11191
|
+
*/
|
|
11192
|
+
async updateEnvironments(name, kmsEnvConfigs, manifest, repoRoot) {
|
|
11193
|
+
const identity = this.get(manifest, name);
|
|
11194
|
+
if (!identity) {
|
|
11195
|
+
throw new Error(`Service identity '${name}' not found.`);
|
|
11196
|
+
}
|
|
11197
|
+
const manifestPath = path17.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
11198
|
+
const raw = fs15.readFileSync(manifestPath, "utf-8");
|
|
11199
|
+
const doc = YAML11.parse(raw);
|
|
11200
|
+
const identities = doc.service_identities;
|
|
11201
|
+
const siDoc = identities.find((si) => si.name === name);
|
|
11202
|
+
const envs = siDoc.environments;
|
|
11203
|
+
const cells = this.matrixManager.resolveMatrix(manifest, repoRoot).filter((c) => c.exists);
|
|
11204
|
+
const privateKeys = {};
|
|
11205
|
+
for (const [envName, kmsConfig] of Object.entries(kmsEnvConfigs)) {
|
|
11206
|
+
const oldConfig = identity.environments[envName];
|
|
11207
|
+
if (!oldConfig) {
|
|
11208
|
+
throw new Error(`Environment '${envName}' not found on identity '${name}'.`);
|
|
11209
|
+
}
|
|
11210
|
+
if (oldConfig.recipient) {
|
|
11211
|
+
const scopedCells = cells.filter(
|
|
11212
|
+
(c) => identity.namespaces.includes(c.namespace) && c.environment === envName
|
|
11213
|
+
);
|
|
11214
|
+
for (const cell of scopedCells) {
|
|
11215
|
+
try {
|
|
11216
|
+
await this.encryption.removeRecipient(cell.filePath, oldConfig.recipient);
|
|
11217
|
+
} catch {
|
|
11218
|
+
}
|
|
11219
|
+
}
|
|
11220
|
+
}
|
|
11221
|
+
envs[envName] = { kms: kmsConfig };
|
|
11222
|
+
identity.environments[envName] = { kms: kmsConfig };
|
|
11223
|
+
}
|
|
11224
|
+
const tmp = path17.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
|
|
11225
|
+
try {
|
|
11226
|
+
fs15.writeFileSync(tmp, YAML11.stringify(doc), "utf-8");
|
|
11227
|
+
fs15.renameSync(tmp, manifestPath);
|
|
11228
|
+
} finally {
|
|
11229
|
+
try {
|
|
11230
|
+
fs15.unlinkSync(tmp);
|
|
11231
|
+
} catch {
|
|
11232
|
+
}
|
|
11233
|
+
}
|
|
11234
|
+
return { privateKeys };
|
|
11235
|
+
}
|
|
11132
11236
|
/**
|
|
11133
11237
|
* Register a service identity's public keys as SOPS recipients on scoped matrix files.
|
|
11134
11238
|
*/
|
|
@@ -11161,7 +11265,7 @@ var ServiceIdentityManager = class {
|
|
|
11161
11265
|
}
|
|
11162
11266
|
const manifestPath = path17.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
11163
11267
|
const raw = fs15.readFileSync(manifestPath, "utf-8");
|
|
11164
|
-
const doc =
|
|
11268
|
+
const doc = YAML11.parse(raw);
|
|
11165
11269
|
const identities = doc.service_identities;
|
|
11166
11270
|
const siDoc = identities.find((si) => si.name === name);
|
|
11167
11271
|
const envs = siDoc.environments;
|
|
@@ -11216,7 +11320,7 @@ var ServiceIdentityManager = class {
|
|
|
11216
11320
|
}
|
|
11217
11321
|
const tmpRotate = path17.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
|
|
11218
11322
|
try {
|
|
11219
|
-
fs15.writeFileSync(tmpRotate,
|
|
11323
|
+
fs15.writeFileSync(tmpRotate, YAML11.stringify(doc), "utf-8");
|
|
11220
11324
|
fs15.renameSync(tmpRotate, manifestPath);
|
|
11221
11325
|
} finally {
|
|
11222
11326
|
try {
|
|
@@ -11376,7 +11480,8 @@ var ArtifactPacker = class {
|
|
|
11376
11480
|
try {
|
|
11377
11481
|
const e = new Encrypter();
|
|
11378
11482
|
e.addRecipient(ephemeralPublicKey);
|
|
11379
|
-
|
|
11483
|
+
const encrypted = await e.encrypt(plaintext);
|
|
11484
|
+
ciphertext = Buffer.from(encrypted).toString("base64");
|
|
11380
11485
|
} catch {
|
|
11381
11486
|
throw new Error("Failed to age-encrypt artifact with ephemeral key.");
|
|
11382
11487
|
}
|
|
@@ -11405,7 +11510,8 @@ var ArtifactPacker = class {
|
|
|
11405
11510
|
const { Encrypter } = await Promise.resolve().then(() => __toESM(require_age_encryption()));
|
|
11406
11511
|
const e = new Encrypter();
|
|
11407
11512
|
e.addRecipient(resolved.recipient);
|
|
11408
|
-
|
|
11513
|
+
const encrypted = await e.encrypt(plaintext);
|
|
11514
|
+
ciphertext = Buffer.from(encrypted).toString("base64");
|
|
11409
11515
|
} catch {
|
|
11410
11516
|
throw new Error("Failed to age-encrypt artifact. Check recipient key.");
|
|
11411
11517
|
}
|