@clef-sh/core 0.1.10 → 0.1.11-beta.66
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/artifact/signer.d.ts +2 -2
- package/dist/artifact/signer.d.ts.map +1 -1
- package/dist/artifact/types.d.ts +0 -2
- package/dist/artifact/types.d.ts.map +1 -1
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +416 -207
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +402 -174
- package/dist/index.mjs.map +4 -4
- package/dist/manifest/io.d.ts +3 -0
- package/dist/manifest/io.d.ts.map +1 -0
- package/dist/manifest/parser.d.ts.map +1 -1
- package/dist/migration/backend.d.ts +39 -0
- package/dist/migration/backend.d.ts.map +1 -0
- package/dist/recipients/index.d.ts.map +1 -1
- package/dist/sops/client.d.ts.map +1 -1
- package/dist/types/index.d.ts +11 -3
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -608,7 +608,7 @@ var require_age_encryption = __commonJS({
|
|
|
608
608
|
};
|
|
609
609
|
}
|
|
610
610
|
// @__NO_SIDE_EFFECTS__
|
|
611
|
-
function
|
|
611
|
+
function join18(separator = "") {
|
|
612
612
|
astr("join", separator);
|
|
613
613
|
return {
|
|
614
614
|
encode: (from) => {
|
|
@@ -738,9 +738,9 @@ var require_age_encryption = __commonJS({
|
|
|
738
738
|
decode(s) {
|
|
739
739
|
return decodeBase64Builtin(s, false);
|
|
740
740
|
}
|
|
741
|
-
} : /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ padding(6), /* @__PURE__ */
|
|
742
|
-
var base64nopad = /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */
|
|
743
|
-
var BECH_ALPHABET = /* @__PURE__ */ chain(/* @__PURE__ */ alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), /* @__PURE__ */
|
|
741
|
+
} : /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ padding(6), /* @__PURE__ */ join18(""));
|
|
742
|
+
var base64nopad = /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ join18(""));
|
|
743
|
+
var BECH_ALPHABET = /* @__PURE__ */ chain(/* @__PURE__ */ alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), /* @__PURE__ */ join18(""));
|
|
744
744
|
var POLYMOD_GENERATORS = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
745
745
|
function bech32Polymod(pre) {
|
|
746
746
|
const b = pre >> 25;
|
|
@@ -5789,7 +5789,7 @@ var require_age_encryption = __commonJS({
|
|
|
5789
5789
|
return new TextDecoder().decode(bytes);
|
|
5790
5790
|
}
|
|
5791
5791
|
function flatten(arr) {
|
|
5792
|
-
const len = arr.reduce((sum, line) => sum + line.length, 0);
|
|
5792
|
+
const len = arr.reduce(((sum, line) => sum + line.length), 0);
|
|
5793
5793
|
const out = new Uint8Array(len);
|
|
5794
5794
|
let n = 0;
|
|
5795
5795
|
for (const a of arr) {
|
|
@@ -6911,9 +6911,10 @@ var require_age_encryption = __commonJS({
|
|
|
6911
6911
|
});
|
|
6912
6912
|
|
|
6913
6913
|
// src/index.ts
|
|
6914
|
-
var
|
|
6915
|
-
__export(
|
|
6914
|
+
var index_exports = {};
|
|
6915
|
+
__export(index_exports, {
|
|
6916
6916
|
ArtifactPacker: () => ArtifactPacker,
|
|
6917
|
+
BackendMigrator: () => BackendMigrator,
|
|
6917
6918
|
BulkOps: () => BulkOps,
|
|
6918
6919
|
CLEF_MANIFEST_FILENAME: () => CLEF_MANIFEST_FILENAME,
|
|
6919
6920
|
CLEF_REPORT_SCHEMA_VERSION: () => CLEF_REPORT_SCHEMA_VERSION,
|
|
@@ -6976,11 +6977,12 @@ __export(src_exports, {
|
|
|
6976
6977
|
markResolved: () => markResolved,
|
|
6977
6978
|
matchPatterns: () => matchPatterns,
|
|
6978
6979
|
metadataPath: () => metadataPath,
|
|
6979
|
-
parse: () =>
|
|
6980
|
+
parse: () => parse9,
|
|
6980
6981
|
parseDotenv: () => parseDotenv,
|
|
6981
6982
|
parseIgnoreContent: () => parseIgnoreContent,
|
|
6982
6983
|
parseJson: () => parseJson,
|
|
6983
6984
|
parseYaml: () => parseYaml,
|
|
6985
|
+
readManifestYaml: () => readManifestYaml,
|
|
6984
6986
|
redactValue: () => redactValue,
|
|
6985
6987
|
removeAccessRequest: () => removeRequest,
|
|
6986
6988
|
requestsFilePath: () => requestsFilePath,
|
|
@@ -6998,9 +7000,10 @@ __export(src_exports, {
|
|
|
6998
7000
|
signKms: () => signKms,
|
|
6999
7001
|
upsertRequest: () => upsertRequest,
|
|
7000
7002
|
validateAgePublicKey: () => validateAgePublicKey,
|
|
7001
|
-
verifySignature: () => verifySignature
|
|
7003
|
+
verifySignature: () => verifySignature,
|
|
7004
|
+
writeManifestYaml: () => writeManifestYaml
|
|
7002
7005
|
});
|
|
7003
|
-
module.exports = __toCommonJS(
|
|
7006
|
+
module.exports = __toCommonJS(index_exports);
|
|
7004
7007
|
|
|
7005
7008
|
// src/types/index.ts
|
|
7006
7009
|
var CLEF_SUPPORTED_EXTENSIONS = [".enc.yaml", ".enc.json"];
|
|
@@ -7459,8 +7462,26 @@ var ManifestParser = class {
|
|
|
7459
7462
|
"sops.default_backend"
|
|
7460
7463
|
);
|
|
7461
7464
|
}
|
|
7465
|
+
const ageObj = sopsObj.age;
|
|
7466
|
+
const ageRecipients = ageObj && Array.isArray(ageObj.recipients) ? ageObj.recipients : void 0;
|
|
7467
|
+
const parsedAge = ageRecipients ? {
|
|
7468
|
+
age: {
|
|
7469
|
+
recipients: ageRecipients.map((r) => {
|
|
7470
|
+
if (typeof r === "string") return r;
|
|
7471
|
+
if (typeof r === "object" && r !== null) {
|
|
7472
|
+
const obj2 = r;
|
|
7473
|
+
return {
|
|
7474
|
+
key: String(obj2.key ?? ""),
|
|
7475
|
+
...typeof obj2.label === "string" ? { label: obj2.label } : {}
|
|
7476
|
+
};
|
|
7477
|
+
}
|
|
7478
|
+
return String(r);
|
|
7479
|
+
})
|
|
7480
|
+
}
|
|
7481
|
+
} : {};
|
|
7462
7482
|
const sopsConfig = {
|
|
7463
7483
|
default_backend: sopsObj.default_backend,
|
|
7484
|
+
...parsedAge,
|
|
7464
7485
|
...typeof sopsObj.aws_kms_arn === "string" ? { aws_kms_arn: sopsObj.aws_kms_arn } : {},
|
|
7465
7486
|
...typeof sopsObj.gcp_kms_resource_id === "string" ? { gcp_kms_resource_id: sopsObj.gcp_kms_resource_id } : {},
|
|
7466
7487
|
...typeof sopsObj.azure_kv_url === "string" ? { azure_kv_url: sopsObj.azure_kv_url } : {},
|
|
@@ -7692,9 +7713,21 @@ var ManifestParser = class {
|
|
|
7692
7713
|
}
|
|
7693
7714
|
};
|
|
7694
7715
|
|
|
7716
|
+
// src/manifest/io.ts
|
|
7717
|
+
var fs2 = __toESM(require("fs"));
|
|
7718
|
+
var path = __toESM(require("path"));
|
|
7719
|
+
var YAML2 = __toESM(require("yaml"));
|
|
7720
|
+
function readManifestYaml(repoRoot) {
|
|
7721
|
+
const raw = fs2.readFileSync(path.join(repoRoot, CLEF_MANIFEST_FILENAME), "utf-8");
|
|
7722
|
+
return YAML2.parse(raw);
|
|
7723
|
+
}
|
|
7724
|
+
function writeManifestYaml(repoRoot, doc) {
|
|
7725
|
+
fs2.writeFileSync(path.join(repoRoot, CLEF_MANIFEST_FILENAME), YAML2.stringify(doc), "utf-8");
|
|
7726
|
+
}
|
|
7727
|
+
|
|
7695
7728
|
// src/scanner/index.ts
|
|
7696
|
-
var
|
|
7697
|
-
var
|
|
7729
|
+
var fs4 = __toESM(require("fs"));
|
|
7730
|
+
var path3 = __toESM(require("path"));
|
|
7698
7731
|
|
|
7699
7732
|
// src/scanner/patterns.ts
|
|
7700
7733
|
var PATTERNS = [
|
|
@@ -7754,12 +7787,12 @@ function matchPatterns(line, lineNumber, filePath) {
|
|
|
7754
7787
|
}
|
|
7755
7788
|
|
|
7756
7789
|
// src/scanner/ignore.ts
|
|
7757
|
-
var
|
|
7758
|
-
var
|
|
7790
|
+
var fs3 = __toESM(require("fs"));
|
|
7791
|
+
var path2 = __toESM(require("path"));
|
|
7759
7792
|
function loadIgnoreRules(repoRoot) {
|
|
7760
|
-
const ignorePath =
|
|
7793
|
+
const ignorePath = path2.join(repoRoot, ".clefignore");
|
|
7761
7794
|
try {
|
|
7762
|
-
const content =
|
|
7795
|
+
const content = fs3.readFileSync(ignorePath, "utf-8");
|
|
7763
7796
|
return parseIgnoreContent(content);
|
|
7764
7797
|
} catch {
|
|
7765
7798
|
return { files: [], patterns: [], paths: [] };
|
|
@@ -7814,8 +7847,8 @@ function matchesGlob(filePath, pattern) {
|
|
|
7814
7847
|
var ALWAYS_SKIP_EXTENSIONS = [".enc.yaml", ".enc.json"];
|
|
7815
7848
|
var ALWAYS_SKIP_NAMES = [
|
|
7816
7849
|
".clef-meta.yaml",
|
|
7817
|
-
".
|
|
7818
|
-
// contains
|
|
7850
|
+
"clef.yaml"
|
|
7851
|
+
// manifest — contains public keys and config, not secrets
|
|
7819
7852
|
];
|
|
7820
7853
|
var ALWAYS_SKIP_DIRS = ["node_modules", ".git"];
|
|
7821
7854
|
var MAX_FILE_SIZE = 1024 * 1024;
|
|
@@ -7842,9 +7875,9 @@ var ScanRunner = class {
|
|
|
7842
7875
|
for (const ns of manifest.namespaces) {
|
|
7843
7876
|
for (const env of manifest.environments) {
|
|
7844
7877
|
const relPath = manifest.file_pattern.replace("{namespace}", ns.name).replace("{environment}", env.name);
|
|
7845
|
-
const absPath =
|
|
7846
|
-
if (
|
|
7847
|
-
const content =
|
|
7878
|
+
const absPath = path3.join(repoRoot, relPath);
|
|
7879
|
+
if (fs4.existsSync(absPath)) {
|
|
7880
|
+
const content = fs4.readFileSync(absPath, "utf-8");
|
|
7848
7881
|
if (!content.includes("sops:") && !content.includes('"sops"')) {
|
|
7849
7882
|
unencryptedMatrixFiles.push(relPath);
|
|
7850
7883
|
}
|
|
@@ -7860,8 +7893,8 @@ var ScanRunner = class {
|
|
|
7860
7893
|
filesToScan = await this.getAllTrackedFiles(repoRoot);
|
|
7861
7894
|
}
|
|
7862
7895
|
for (const relFile of filesToScan) {
|
|
7863
|
-
const absFile =
|
|
7864
|
-
const relPath =
|
|
7896
|
+
const absFile = path3.isAbsolute(relFile) ? relFile : path3.join(repoRoot, relFile);
|
|
7897
|
+
const relPath = path3.relative(repoRoot, absFile).replace(/\\/g, "/");
|
|
7865
7898
|
if (this.shouldAlwaysSkip(relPath)) {
|
|
7866
7899
|
filesSkipped++;
|
|
7867
7900
|
continue;
|
|
@@ -7870,13 +7903,13 @@ var ScanRunner = class {
|
|
|
7870
7903
|
filesSkipped++;
|
|
7871
7904
|
continue;
|
|
7872
7905
|
}
|
|
7873
|
-
if (!
|
|
7906
|
+
if (!fs4.existsSync(absFile)) {
|
|
7874
7907
|
filesSkipped++;
|
|
7875
7908
|
continue;
|
|
7876
7909
|
}
|
|
7877
7910
|
let stat;
|
|
7878
7911
|
try {
|
|
7879
|
-
stat =
|
|
7912
|
+
stat = fs4.statSync(absFile);
|
|
7880
7913
|
} catch {
|
|
7881
7914
|
filesSkipped++;
|
|
7882
7915
|
continue;
|
|
@@ -7890,7 +7923,7 @@ var ScanRunner = class {
|
|
|
7890
7923
|
continue;
|
|
7891
7924
|
}
|
|
7892
7925
|
filesScanned++;
|
|
7893
|
-
const content =
|
|
7926
|
+
const content = fs4.readFileSync(absFile, "utf-8");
|
|
7894
7927
|
const lines = content.split("\n");
|
|
7895
7928
|
for (let i = 0; i < lines.length; i++) {
|
|
7896
7929
|
const line = lines[i];
|
|
@@ -7932,10 +7965,10 @@ var ScanRunner = class {
|
|
|
7932
7965
|
}
|
|
7933
7966
|
isBinary(filePath) {
|
|
7934
7967
|
try {
|
|
7935
|
-
const fd =
|
|
7968
|
+
const fd = fs4.openSync(filePath, "r");
|
|
7936
7969
|
const buf = Buffer.alloc(512);
|
|
7937
|
-
const bytesRead =
|
|
7938
|
-
|
|
7970
|
+
const bytesRead = fs4.readSync(fd, buf, 0, 512, 0);
|
|
7971
|
+
fs4.closeSync(fd);
|
|
7939
7972
|
for (let i = 0; i < bytesRead; i++) {
|
|
7940
7973
|
if (buf[i] === 0) return true;
|
|
7941
7974
|
}
|
|
@@ -7975,13 +8008,13 @@ var ScanRunner = class {
|
|
|
7975
8008
|
async getFilesInPaths(repoRoot, paths) {
|
|
7976
8009
|
const files = [];
|
|
7977
8010
|
for (const p of paths) {
|
|
7978
|
-
const absPath =
|
|
7979
|
-
if (!
|
|
7980
|
-
const stat =
|
|
8011
|
+
const absPath = path3.isAbsolute(p) ? p : path3.join(repoRoot, p);
|
|
8012
|
+
if (!fs4.existsSync(absPath)) continue;
|
|
8013
|
+
const stat = fs4.statSync(absPath);
|
|
7981
8014
|
if (stat.isDirectory()) {
|
|
7982
8015
|
files.push(...this.walkDir(absPath, repoRoot));
|
|
7983
8016
|
} else {
|
|
7984
|
-
files.push(
|
|
8017
|
+
files.push(path3.relative(repoRoot, absPath).replace(/\\/g, "/"));
|
|
7985
8018
|
}
|
|
7986
8019
|
}
|
|
7987
8020
|
return files;
|
|
@@ -7997,13 +8030,13 @@ var ScanRunner = class {
|
|
|
7997
8030
|
const files = [];
|
|
7998
8031
|
let entries;
|
|
7999
8032
|
try {
|
|
8000
|
-
entries =
|
|
8033
|
+
entries = fs4.readdirSync(dir, { withFileTypes: true });
|
|
8001
8034
|
} catch {
|
|
8002
8035
|
return files;
|
|
8003
8036
|
}
|
|
8004
8037
|
for (const entry of entries) {
|
|
8005
|
-
const fullPath =
|
|
8006
|
-
const relPath =
|
|
8038
|
+
const fullPath = path3.join(dir, entry.name);
|
|
8039
|
+
const relPath = path3.relative(repoRoot, fullPath).replace(/\\/g, "/");
|
|
8007
8040
|
if (entry.isDirectory()) {
|
|
8008
8041
|
if (!ALWAYS_SKIP_DIRS.includes(entry.name)) {
|
|
8009
8042
|
files.push(...this.walkDir(fullPath, repoRoot));
|
|
@@ -8017,29 +8050,29 @@ var ScanRunner = class {
|
|
|
8017
8050
|
};
|
|
8018
8051
|
|
|
8019
8052
|
// src/matrix/manager.ts
|
|
8020
|
-
var
|
|
8021
|
-
var
|
|
8022
|
-
var
|
|
8053
|
+
var fs7 = __toESM(require("fs"));
|
|
8054
|
+
var path5 = __toESM(require("path"));
|
|
8055
|
+
var YAML5 = __toESM(require("yaml"));
|
|
8023
8056
|
|
|
8024
8057
|
// src/pending/metadata.ts
|
|
8025
|
-
var
|
|
8026
|
-
var
|
|
8058
|
+
var fs5 = __toESM(require("fs"));
|
|
8059
|
+
var path4 = __toESM(require("path"));
|
|
8027
8060
|
var crypto2 = __toESM(require("crypto"));
|
|
8028
|
-
var
|
|
8061
|
+
var YAML3 = __toESM(require("yaml"));
|
|
8029
8062
|
function metadataPath(encryptedFilePath) {
|
|
8030
|
-
const dir =
|
|
8031
|
-
const base =
|
|
8032
|
-
return
|
|
8063
|
+
const dir = path4.dirname(encryptedFilePath);
|
|
8064
|
+
const base = path4.basename(encryptedFilePath).replace(/\.enc\.(yaml|json)$/, "");
|
|
8065
|
+
return path4.join(dir, `${base}.clef-meta.yaml`);
|
|
8033
8066
|
}
|
|
8034
8067
|
var HEADER_COMMENT = "# Managed by Clef. Do not edit manually.\n";
|
|
8035
8068
|
async function loadMetadata(filePath) {
|
|
8036
8069
|
const metaPath = metadataPath(filePath);
|
|
8037
8070
|
try {
|
|
8038
|
-
if (!
|
|
8071
|
+
if (!fs5.existsSync(metaPath)) {
|
|
8039
8072
|
return { version: 1, pending: [] };
|
|
8040
8073
|
}
|
|
8041
|
-
const content =
|
|
8042
|
-
const parsed =
|
|
8074
|
+
const content = fs5.readFileSync(metaPath, "utf-8");
|
|
8075
|
+
const parsed = YAML3.parse(content);
|
|
8043
8076
|
if (!parsed || !Array.isArray(parsed.pending)) {
|
|
8044
8077
|
return { version: 1, pending: [] };
|
|
8045
8078
|
}
|
|
@@ -8057,9 +8090,9 @@ async function loadMetadata(filePath) {
|
|
|
8057
8090
|
}
|
|
8058
8091
|
async function saveMetadata(filePath, metadata) {
|
|
8059
8092
|
const metaPath = metadataPath(filePath);
|
|
8060
|
-
const dir =
|
|
8061
|
-
if (!
|
|
8062
|
-
|
|
8093
|
+
const dir = path4.dirname(metaPath);
|
|
8094
|
+
if (!fs5.existsSync(dir)) {
|
|
8095
|
+
fs5.mkdirSync(dir, { recursive: true });
|
|
8063
8096
|
}
|
|
8064
8097
|
const data = {
|
|
8065
8098
|
version: metadata.version,
|
|
@@ -8069,7 +8102,7 @@ async function saveMetadata(filePath, metadata) {
|
|
|
8069
8102
|
setBy: p.setBy
|
|
8070
8103
|
}))
|
|
8071
8104
|
};
|
|
8072
|
-
|
|
8105
|
+
fs5.writeFileSync(metaPath, HEADER_COMMENT + YAML3.stringify(data), "utf-8");
|
|
8073
8106
|
}
|
|
8074
8107
|
async function markPending(filePath, keys, setBy) {
|
|
8075
8108
|
const metadata = await loadMetadata(filePath);
|
|
@@ -8110,12 +8143,12 @@ async function markPendingWithRetry(filePath, keys, setBy, retryDelayMs = 200) {
|
|
|
8110
8143
|
}
|
|
8111
8144
|
|
|
8112
8145
|
// src/sops/keys.ts
|
|
8113
|
-
var
|
|
8114
|
-
var
|
|
8146
|
+
var fs6 = __toESM(require("fs"));
|
|
8147
|
+
var YAML4 = __toESM(require("yaml"));
|
|
8115
8148
|
function readSopsKeyNames(filePath) {
|
|
8116
8149
|
try {
|
|
8117
|
-
const raw =
|
|
8118
|
-
const parsed =
|
|
8150
|
+
const raw = fs6.readFileSync(filePath, "utf-8");
|
|
8151
|
+
const parsed = YAML4.parse(raw);
|
|
8119
8152
|
if (parsed === null || parsed === void 0 || typeof parsed !== "object") return null;
|
|
8120
8153
|
return Object.keys(parsed).filter((k) => k !== "sops");
|
|
8121
8154
|
} catch {
|
|
@@ -8137,12 +8170,12 @@ var MatrixManager = class {
|
|
|
8137
8170
|
for (const ns of manifest.namespaces) {
|
|
8138
8171
|
for (const env of manifest.environments) {
|
|
8139
8172
|
const relativePath = manifest.file_pattern.replace("{namespace}", ns.name).replace("{environment}", env.name);
|
|
8140
|
-
const filePath =
|
|
8173
|
+
const filePath = path5.join(repoRoot, relativePath);
|
|
8141
8174
|
cells.push({
|
|
8142
8175
|
namespace: ns.name,
|
|
8143
8176
|
environment: env.name,
|
|
8144
8177
|
filePath,
|
|
8145
|
-
exists:
|
|
8178
|
+
exists: fs7.existsSync(filePath)
|
|
8146
8179
|
});
|
|
8147
8180
|
}
|
|
8148
8181
|
}
|
|
@@ -8165,9 +8198,9 @@ var MatrixManager = class {
|
|
|
8165
8198
|
* @param manifest - Parsed manifest used to determine the encryption backend.
|
|
8166
8199
|
*/
|
|
8167
8200
|
async scaffoldCell(cell, sopsClient, manifest) {
|
|
8168
|
-
const dir =
|
|
8169
|
-
if (!
|
|
8170
|
-
|
|
8201
|
+
const dir = path5.dirname(cell.filePath);
|
|
8202
|
+
if (!fs7.existsSync(dir)) {
|
|
8203
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
8171
8204
|
}
|
|
8172
8205
|
await sopsClient.encrypt(cell.filePath, {}, manifest, cell.environment);
|
|
8173
8206
|
}
|
|
@@ -8243,8 +8276,8 @@ var MatrixManager = class {
|
|
|
8243
8276
|
*/
|
|
8244
8277
|
readLastModified(filePath) {
|
|
8245
8278
|
try {
|
|
8246
|
-
const raw =
|
|
8247
|
-
const parsed =
|
|
8279
|
+
const raw = fs7.readFileSync(filePath, "utf-8");
|
|
8280
|
+
const parsed = YAML5.parse(raw);
|
|
8248
8281
|
const sops = parsed?.sops;
|
|
8249
8282
|
if (sops?.lastmodified) return new Date(String(sops.lastmodified));
|
|
8250
8283
|
return null;
|
|
@@ -8265,8 +8298,8 @@ var MatrixManager = class {
|
|
|
8265
8298
|
};
|
|
8266
8299
|
|
|
8267
8300
|
// src/schema/validator.ts
|
|
8268
|
-
var
|
|
8269
|
-
var
|
|
8301
|
+
var fs8 = __toESM(require("fs"));
|
|
8302
|
+
var YAML6 = __toESM(require("yaml"));
|
|
8270
8303
|
var SchemaValidator = class {
|
|
8271
8304
|
/**
|
|
8272
8305
|
* Read and parse a YAML schema file from disk.
|
|
@@ -8278,13 +8311,13 @@ var SchemaValidator = class {
|
|
|
8278
8311
|
loadSchema(filePath) {
|
|
8279
8312
|
let raw;
|
|
8280
8313
|
try {
|
|
8281
|
-
raw =
|
|
8314
|
+
raw = fs8.readFileSync(filePath, "utf-8");
|
|
8282
8315
|
} catch {
|
|
8283
8316
|
throw new SchemaLoadError(`Could not read schema file at '${filePath}'.`, filePath);
|
|
8284
8317
|
}
|
|
8285
8318
|
let parsed;
|
|
8286
8319
|
try {
|
|
8287
|
-
parsed =
|
|
8320
|
+
parsed = YAML6.parse(raw);
|
|
8288
8321
|
} catch {
|
|
8289
8322
|
throw new SchemaLoadError(`Schema file '${filePath}' contains invalid YAML.`, filePath);
|
|
8290
8323
|
}
|
|
@@ -8412,7 +8445,7 @@ var SchemaValidator = class {
|
|
|
8412
8445
|
};
|
|
8413
8446
|
|
|
8414
8447
|
// src/diff/engine.ts
|
|
8415
|
-
var
|
|
8448
|
+
var path6 = __toESM(require("path"));
|
|
8416
8449
|
var DiffEngine = class {
|
|
8417
8450
|
/**
|
|
8418
8451
|
* Compare two in-memory value maps and produce a sorted diff result.
|
|
@@ -8469,11 +8502,11 @@ var DiffEngine = class {
|
|
|
8469
8502
|
* @throws {@link SopsDecryptionError} If either file cannot be decrypted.
|
|
8470
8503
|
*/
|
|
8471
8504
|
async diffFiles(namespace, envA, envB, manifest, sopsClient, repoRoot) {
|
|
8472
|
-
const fileA =
|
|
8505
|
+
const fileA = path6.join(
|
|
8473
8506
|
repoRoot,
|
|
8474
8507
|
manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", envA)
|
|
8475
8508
|
);
|
|
8476
|
-
const fileB =
|
|
8509
|
+
const fileB = path6.join(
|
|
8477
8510
|
repoRoot,
|
|
8478
8511
|
manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", envB)
|
|
8479
8512
|
);
|
|
@@ -8486,7 +8519,7 @@ var DiffEngine = class {
|
|
|
8486
8519
|
};
|
|
8487
8520
|
|
|
8488
8521
|
// src/bulk/ops.ts
|
|
8489
|
-
var
|
|
8522
|
+
var path7 = __toESM(require("path"));
|
|
8490
8523
|
var BulkOps = class {
|
|
8491
8524
|
/**
|
|
8492
8525
|
* Set a key to different values in multiple environments at once.
|
|
@@ -8505,7 +8538,7 @@ var BulkOps = class {
|
|
|
8505
8538
|
if (!(env.name in values)) {
|
|
8506
8539
|
continue;
|
|
8507
8540
|
}
|
|
8508
|
-
const filePath =
|
|
8541
|
+
const filePath = path7.join(
|
|
8509
8542
|
repoRoot,
|
|
8510
8543
|
manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", env.name)
|
|
8511
8544
|
);
|
|
@@ -8539,7 +8572,7 @@ Successfully updated ${Object.keys(values).length - errors.length} environment(s
|
|
|
8539
8572
|
async deleteAcrossEnvironments(namespace, key, manifest, sopsClient, repoRoot) {
|
|
8540
8573
|
const errors = [];
|
|
8541
8574
|
for (const env of manifest.environments) {
|
|
8542
|
-
const filePath =
|
|
8575
|
+
const filePath = path7.join(
|
|
8543
8576
|
repoRoot,
|
|
8544
8577
|
manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", env.name)
|
|
8545
8578
|
);
|
|
@@ -8585,8 +8618,8 @@ ${details}`
|
|
|
8585
8618
|
};
|
|
8586
8619
|
|
|
8587
8620
|
// src/git/integration.ts
|
|
8588
|
-
var
|
|
8589
|
-
var
|
|
8621
|
+
var fs9 = __toESM(require("fs"));
|
|
8622
|
+
var path8 = __toESM(require("path"));
|
|
8590
8623
|
var PRE_COMMIT_HOOK = `#!/bin/sh
|
|
8591
8624
|
# Clef pre-commit hook \u2014 blocks commits of files missing SOPS encryption metadata
|
|
8592
8625
|
# and scans staged files for plaintext secrets.
|
|
@@ -8793,15 +8826,15 @@ var GitIntegration = class {
|
|
|
8793
8826
|
cwd: repoRoot
|
|
8794
8827
|
});
|
|
8795
8828
|
const gitConfig = configResult.exitCode === 0 && configResult.stdout.trim().length > 0;
|
|
8796
|
-
const attrFilePath =
|
|
8797
|
-
const attrContent =
|
|
8829
|
+
const attrFilePath = path8.join(repoRoot, ".gitattributes");
|
|
8830
|
+
const attrContent = fs9.existsSync(attrFilePath) ? fs9.readFileSync(attrFilePath, "utf-8") : "";
|
|
8798
8831
|
const gitattributes = attrContent.includes("merge=sops");
|
|
8799
8832
|
return { gitConfig, gitattributes };
|
|
8800
8833
|
}
|
|
8801
8834
|
async ensureGitattributes(repoRoot) {
|
|
8802
|
-
const attrPath =
|
|
8835
|
+
const attrPath = path8.join(repoRoot, ".gitattributes");
|
|
8803
8836
|
const mergeRule = "*.enc.yaml merge=sops\n*.enc.json merge=sops";
|
|
8804
|
-
const existing =
|
|
8837
|
+
const existing = fs9.existsSync(attrPath) ? fs9.readFileSync(attrPath, "utf-8") : "";
|
|
8805
8838
|
if (existing.includes("merge=sops")) {
|
|
8806
8839
|
return;
|
|
8807
8840
|
}
|
|
@@ -8828,7 +8861,7 @@ ${mergeRule}
|
|
|
8828
8861
|
* @throws {@link GitOperationError} On failure.
|
|
8829
8862
|
*/
|
|
8830
8863
|
async installPreCommitHook(repoRoot) {
|
|
8831
|
-
const hookPath =
|
|
8864
|
+
const hookPath = path8.join(repoRoot, ".git", "hooks", "pre-commit");
|
|
8832
8865
|
const result = await this.runner.run("tee", [hookPath], {
|
|
8833
8866
|
stdin: PRE_COMMIT_HOOK,
|
|
8834
8867
|
cwd: repoRoot
|
|
@@ -8849,18 +8882,18 @@ ${mergeRule}
|
|
|
8849
8882
|
};
|
|
8850
8883
|
|
|
8851
8884
|
// src/sops/client.ts
|
|
8852
|
-
var
|
|
8885
|
+
var fs12 = __toESM(require("fs"));
|
|
8853
8886
|
var net = __toESM(require("net"));
|
|
8854
8887
|
var import_crypto = require("crypto");
|
|
8855
|
-
var
|
|
8888
|
+
var YAML7 = __toESM(require("yaml"));
|
|
8856
8889
|
|
|
8857
8890
|
// src/sops/resolver.ts
|
|
8858
|
-
var
|
|
8859
|
-
var
|
|
8891
|
+
var fs11 = __toESM(require("fs"));
|
|
8892
|
+
var path10 = __toESM(require("path"));
|
|
8860
8893
|
|
|
8861
8894
|
// src/sops/bundled.ts
|
|
8862
|
-
var
|
|
8863
|
-
var
|
|
8895
|
+
var fs10 = __toESM(require("fs"));
|
|
8896
|
+
var path9 = __toESM(require("path"));
|
|
8864
8897
|
function tryBundled() {
|
|
8865
8898
|
const platform = process.platform;
|
|
8866
8899
|
const arch = process.arch;
|
|
@@ -8872,9 +8905,9 @@ function tryBundled() {
|
|
|
8872
8905
|
const binName = platform === "win32" ? "sops.exe" : "sops";
|
|
8873
8906
|
try {
|
|
8874
8907
|
const packageMain = require.resolve(`${packageName}/package.json`);
|
|
8875
|
-
const packageDir =
|
|
8876
|
-
const binPath =
|
|
8877
|
-
return
|
|
8908
|
+
const packageDir = path9.dirname(packageMain);
|
|
8909
|
+
const binPath = path9.join(packageDir, "bin", binName);
|
|
8910
|
+
return fs10.existsSync(binPath) ? binPath : null;
|
|
8878
8911
|
} catch {
|
|
8879
8912
|
return null;
|
|
8880
8913
|
}
|
|
@@ -8882,7 +8915,7 @@ function tryBundled() {
|
|
|
8882
8915
|
|
|
8883
8916
|
// src/sops/resolver.ts
|
|
8884
8917
|
function validateSopsPath(candidate) {
|
|
8885
|
-
if (!
|
|
8918
|
+
if (!path10.isAbsolute(candidate)) {
|
|
8886
8919
|
throw new Error(`CLEF_SOPS_PATH must be an absolute path, got '${candidate}'.`);
|
|
8887
8920
|
}
|
|
8888
8921
|
const segments = candidate.split(/[/\\]/);
|
|
@@ -8898,7 +8931,7 @@ function resolveSopsPath() {
|
|
|
8898
8931
|
const envPath = process.env.CLEF_SOPS_PATH?.trim();
|
|
8899
8932
|
if (envPath) {
|
|
8900
8933
|
validateSopsPath(envPath);
|
|
8901
|
-
if (!
|
|
8934
|
+
if (!fs11.existsSync(envPath)) {
|
|
8902
8935
|
throw new Error(`CLEF_SOPS_PATH points to '${envPath}' but the file does not exist.`);
|
|
8903
8936
|
}
|
|
8904
8937
|
cached = { path: envPath, source: "env" };
|
|
@@ -9106,7 +9139,7 @@ var SopsClient = class {
|
|
|
9106
9139
|
}
|
|
9107
9140
|
let parsed;
|
|
9108
9141
|
try {
|
|
9109
|
-
parsed =
|
|
9142
|
+
parsed = YAML7.parse(result.stdout) ?? {};
|
|
9110
9143
|
} catch {
|
|
9111
9144
|
throw new SopsDecryptionError(
|
|
9112
9145
|
`Decrypted content of '${filePath}' is not valid YAML.`,
|
|
@@ -9133,7 +9166,7 @@ var SopsClient = class {
|
|
|
9133
9166
|
async encrypt(filePath, values, manifest, environment) {
|
|
9134
9167
|
await assertSops(this.runner, this.sopsCommand);
|
|
9135
9168
|
const fmt = formatFromPath(filePath);
|
|
9136
|
-
const content = fmt === "json" ? JSON.stringify(values, null, 2) :
|
|
9169
|
+
const content = fmt === "json" ? JSON.stringify(values, null, 2) : YAML7.stringify(values);
|
|
9137
9170
|
const args = this.buildEncryptArgs(filePath, manifest, environment);
|
|
9138
9171
|
const env = this.buildSopsEnv();
|
|
9139
9172
|
let inputArg;
|
|
@@ -9147,9 +9180,12 @@ var SopsClient = class {
|
|
|
9147
9180
|
}
|
|
9148
9181
|
let result;
|
|
9149
9182
|
try {
|
|
9183
|
+
const configPath = process.platform === "win32" ? "NUL" : "/dev/null";
|
|
9150
9184
|
result = await this.runner.run(
|
|
9151
9185
|
this.sopsCommand,
|
|
9152
9186
|
[
|
|
9187
|
+
"--config",
|
|
9188
|
+
configPath,
|
|
9153
9189
|
"encrypt",
|
|
9154
9190
|
...args,
|
|
9155
9191
|
"--input-type",
|
|
@@ -9177,7 +9213,7 @@ var SopsClient = class {
|
|
|
9177
9213
|
);
|
|
9178
9214
|
}
|
|
9179
9215
|
try {
|
|
9180
|
-
|
|
9216
|
+
fs12.writeFileSync(filePath, result.stdout);
|
|
9181
9217
|
} catch {
|
|
9182
9218
|
throw new SopsEncryptionError(`Failed to write encrypted data to '${filePath}'.`, filePath);
|
|
9183
9219
|
}
|
|
@@ -9293,7 +9329,7 @@ var SopsClient = class {
|
|
|
9293
9329
|
if (!this.ageKey && !this.ageKeyFile) return "key-not-found";
|
|
9294
9330
|
let keyContent;
|
|
9295
9331
|
try {
|
|
9296
|
-
keyContent = this.ageKey ??
|
|
9332
|
+
keyContent = this.ageKey ?? fs12.readFileSync(this.ageKeyFile, "utf-8");
|
|
9297
9333
|
} catch {
|
|
9298
9334
|
return "key-not-found";
|
|
9299
9335
|
}
|
|
@@ -9310,7 +9346,7 @@ var SopsClient = class {
|
|
|
9310
9346
|
parseMetadataFromFile(filePath) {
|
|
9311
9347
|
let content;
|
|
9312
9348
|
try {
|
|
9313
|
-
content =
|
|
9349
|
+
content = fs12.readFileSync(filePath, "utf-8");
|
|
9314
9350
|
} catch {
|
|
9315
9351
|
throw new SopsDecryptionError(
|
|
9316
9352
|
`Could not read file '${filePath}' to extract SOPS metadata.`,
|
|
@@ -9319,7 +9355,7 @@ var SopsClient = class {
|
|
|
9319
9355
|
}
|
|
9320
9356
|
let parsed;
|
|
9321
9357
|
try {
|
|
9322
|
-
parsed =
|
|
9358
|
+
parsed = YAML7.parse(content);
|
|
9323
9359
|
} catch {
|
|
9324
9360
|
throw new SopsDecryptionError(
|
|
9325
9361
|
`File '${filePath}' is not valid YAML. Cannot extract SOPS metadata.`,
|
|
@@ -9386,8 +9422,15 @@ var SopsClient = class {
|
|
|
9386
9422
|
pgp_fingerprint: manifest.sops.pgp_fingerprint
|
|
9387
9423
|
};
|
|
9388
9424
|
switch (config.backend) {
|
|
9389
|
-
case "age":
|
|
9425
|
+
case "age": {
|
|
9426
|
+
const envRecipients = environment ? resolveRecipientsForEnvironment(manifest, environment) : void 0;
|
|
9427
|
+
const recipients = envRecipients ?? manifest.sops.age?.recipients ?? [];
|
|
9428
|
+
const keys = recipients.map((r) => typeof r === "string" ? r : r.key);
|
|
9429
|
+
if (keys.length > 0) {
|
|
9430
|
+
args.push("--age", keys.join(","));
|
|
9431
|
+
}
|
|
9390
9432
|
break;
|
|
9433
|
+
}
|
|
9391
9434
|
case "awskms":
|
|
9392
9435
|
if (config.aws_kms_arn) {
|
|
9393
9436
|
args.push("--kms", config.aws_kms_arn);
|
|
@@ -9414,7 +9457,7 @@ var SopsClient = class {
|
|
|
9414
9457
|
};
|
|
9415
9458
|
|
|
9416
9459
|
// src/lint/runner.ts
|
|
9417
|
-
var
|
|
9460
|
+
var path11 = __toESM(require("path"));
|
|
9418
9461
|
var LintRunner = class {
|
|
9419
9462
|
constructor(matrixManager, schemaValidator, sopsClient) {
|
|
9420
9463
|
this.matrixManager = matrixManager;
|
|
@@ -9514,7 +9557,7 @@ var LintRunner = class {
|
|
|
9514
9557
|
}
|
|
9515
9558
|
const ns = manifest.namespaces.find((n) => n.name === cell.namespace);
|
|
9516
9559
|
if (ns?.schema) {
|
|
9517
|
-
const schemaPath =
|
|
9560
|
+
const schemaPath = path11.join(repoRoot, ns.schema);
|
|
9518
9561
|
try {
|
|
9519
9562
|
const schema = this.schemaValidator.loadSchema(schemaPath);
|
|
9520
9563
|
const result = this.schemaValidator.validate(decrypted.values, schema);
|
|
@@ -9747,14 +9790,14 @@ Use 'clef exec' to inject secrets directly into a process, or 'clef export --for
|
|
|
9747
9790
|
};
|
|
9748
9791
|
|
|
9749
9792
|
// src/import/index.ts
|
|
9750
|
-
var
|
|
9793
|
+
var path13 = __toESM(require("path"));
|
|
9751
9794
|
|
|
9752
9795
|
// src/import/parsers.ts
|
|
9753
|
-
var
|
|
9754
|
-
var
|
|
9796
|
+
var path12 = __toESM(require("path"));
|
|
9797
|
+
var YAML8 = __toESM(require("yaml"));
|
|
9755
9798
|
function detectFormat(filePath, content) {
|
|
9756
|
-
const base =
|
|
9757
|
-
const ext =
|
|
9799
|
+
const base = path12.basename(filePath);
|
|
9800
|
+
const ext = path12.extname(filePath).toLowerCase();
|
|
9758
9801
|
if (base === ".env" || base.startsWith(".env.")) {
|
|
9759
9802
|
return "dotenv";
|
|
9760
9803
|
}
|
|
@@ -9775,7 +9818,7 @@ function detectFormat(filePath, content) {
|
|
|
9775
9818
|
} catch {
|
|
9776
9819
|
}
|
|
9777
9820
|
try {
|
|
9778
|
-
const parsed =
|
|
9821
|
+
const parsed = YAML8.parse(content);
|
|
9779
9822
|
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
9780
9823
|
return "yaml";
|
|
9781
9824
|
}
|
|
@@ -9856,7 +9899,7 @@ function parseJson(content) {
|
|
|
9856
9899
|
function parseYaml(content) {
|
|
9857
9900
|
let parsed;
|
|
9858
9901
|
try {
|
|
9859
|
-
parsed =
|
|
9902
|
+
parsed = YAML8.parse(content);
|
|
9860
9903
|
} catch (err) {
|
|
9861
9904
|
throw new Error(`Invalid YAML: ${err.message}`);
|
|
9862
9905
|
}
|
|
@@ -9890,7 +9933,7 @@ function parseYaml(content) {
|
|
|
9890
9933
|
}
|
|
9891
9934
|
return { pairs, format: "yaml", skipped, warnings };
|
|
9892
9935
|
}
|
|
9893
|
-
function
|
|
9936
|
+
function parse9(content, format, filePath) {
|
|
9894
9937
|
const resolved = format === "auto" ? detectFormat(filePath ?? "", content) : format;
|
|
9895
9938
|
switch (resolved) {
|
|
9896
9939
|
case "dotenv":
|
|
@@ -9919,11 +9962,11 @@ var ImportRunner = class {
|
|
|
9919
9962
|
*/
|
|
9920
9963
|
async import(target, sourcePath, content, manifest, repoRoot, options) {
|
|
9921
9964
|
const [ns, env] = target.split("/");
|
|
9922
|
-
const filePath =
|
|
9965
|
+
const filePath = path13.join(
|
|
9923
9966
|
repoRoot,
|
|
9924
9967
|
manifest.file_pattern.replace("{namespace}", ns).replace("{environment}", env)
|
|
9925
9968
|
);
|
|
9926
|
-
const parsed =
|
|
9969
|
+
const parsed = parse9(content, options.format ?? "auto", sourcePath ?? "");
|
|
9927
9970
|
let candidates = Object.entries(parsed.pairs);
|
|
9928
9971
|
if (options.prefix) {
|
|
9929
9972
|
const prefix = options.prefix;
|
|
@@ -9977,9 +10020,8 @@ var ImportRunner = class {
|
|
|
9977
10020
|
};
|
|
9978
10021
|
|
|
9979
10022
|
// src/recipients/index.ts
|
|
9980
|
-
var
|
|
9981
|
-
var
|
|
9982
|
-
var YAML8 = __toESM(require("yaml"));
|
|
10023
|
+
var fs13 = __toESM(require("fs"));
|
|
10024
|
+
var path14 = __toESM(require("path"));
|
|
9983
10025
|
function parseRecipientEntry(entry) {
|
|
9984
10026
|
if (typeof entry === "string") {
|
|
9985
10027
|
return { key: entry };
|
|
@@ -10000,15 +10042,6 @@ function toRecipient(entry) {
|
|
|
10000
10042
|
...entry.label ? { label: entry.label } : {}
|
|
10001
10043
|
};
|
|
10002
10044
|
}
|
|
10003
|
-
function readManifestYaml(repoRoot) {
|
|
10004
|
-
const manifestPath = path13.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
10005
|
-
const raw = fs12.readFileSync(manifestPath, "utf-8");
|
|
10006
|
-
return YAML8.parse(raw);
|
|
10007
|
-
}
|
|
10008
|
-
function writeManifestYaml(repoRoot, doc) {
|
|
10009
|
-
const manifestPath = path13.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
10010
|
-
fs12.writeFileSync(manifestPath, YAML8.stringify(doc), "utf-8");
|
|
10011
|
-
}
|
|
10012
10045
|
function getRecipientsArray(doc) {
|
|
10013
10046
|
const sops = doc.sops;
|
|
10014
10047
|
if (!sops) return [];
|
|
@@ -10107,8 +10140,8 @@ var RecipientManager = class {
|
|
|
10107
10140
|
if (currentKeys.includes(normalizedKey)) {
|
|
10108
10141
|
throw new Error(`Recipient '${keyPreview(normalizedKey)}' is already present.`);
|
|
10109
10142
|
}
|
|
10110
|
-
const manifestPath =
|
|
10111
|
-
const manifestBackup =
|
|
10143
|
+
const manifestPath = path14.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
10144
|
+
const manifestBackup = fs13.readFileSync(manifestPath, "utf-8");
|
|
10112
10145
|
const recipients = environment ? ensureEnvironmentRecipientsArray(doc, environment) : ensureRecipientsArray(doc);
|
|
10113
10146
|
if (label) {
|
|
10114
10147
|
recipients.push({ key: normalizedKey, label });
|
|
@@ -10123,16 +10156,16 @@ var RecipientManager = class {
|
|
|
10123
10156
|
const fileBackups = /* @__PURE__ */ new Map();
|
|
10124
10157
|
for (const cell of cells) {
|
|
10125
10158
|
try {
|
|
10126
|
-
fileBackups.set(cell.filePath,
|
|
10159
|
+
fileBackups.set(cell.filePath, fs13.readFileSync(cell.filePath, "utf-8"));
|
|
10127
10160
|
await this.encryption.addRecipient(cell.filePath, normalizedKey);
|
|
10128
10161
|
reEncryptedFiles.push(cell.filePath);
|
|
10129
10162
|
} catch {
|
|
10130
10163
|
failedFiles.push(cell.filePath);
|
|
10131
|
-
|
|
10164
|
+
fs13.writeFileSync(manifestPath, manifestBackup, "utf-8");
|
|
10132
10165
|
for (const reEncryptedFile of reEncryptedFiles) {
|
|
10133
10166
|
const backup = fileBackups.get(reEncryptedFile);
|
|
10134
10167
|
if (backup) {
|
|
10135
|
-
|
|
10168
|
+
fs13.writeFileSync(reEncryptedFile, backup, "utf-8");
|
|
10136
10169
|
}
|
|
10137
10170
|
}
|
|
10138
10171
|
const restoredDoc = readManifestYaml(repoRoot);
|
|
@@ -10185,8 +10218,8 @@ var RecipientManager = class {
|
|
|
10185
10218
|
throw new Error(`Recipient '${keyPreview(trimmedKey)}' is not in the manifest.`);
|
|
10186
10219
|
}
|
|
10187
10220
|
const removedEntry = parsed[matchIndex];
|
|
10188
|
-
const manifestPath =
|
|
10189
|
-
const manifestBackup =
|
|
10221
|
+
const manifestPath = path14.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
10222
|
+
const manifestBackup = fs13.readFileSync(manifestPath, "utf-8");
|
|
10190
10223
|
const recipients = environment ? ensureEnvironmentRecipientsArray(doc, environment) : ensureRecipientsArray(doc);
|
|
10191
10224
|
recipients.splice(matchIndex, 1);
|
|
10192
10225
|
writeManifestYaml(repoRoot, doc);
|
|
@@ -10197,16 +10230,16 @@ var RecipientManager = class {
|
|
|
10197
10230
|
const fileBackups = /* @__PURE__ */ new Map();
|
|
10198
10231
|
for (const cell of cells) {
|
|
10199
10232
|
try {
|
|
10200
|
-
fileBackups.set(cell.filePath,
|
|
10233
|
+
fileBackups.set(cell.filePath, fs13.readFileSync(cell.filePath, "utf-8"));
|
|
10201
10234
|
await this.encryption.removeRecipient(cell.filePath, trimmedKey);
|
|
10202
10235
|
reEncryptedFiles.push(cell.filePath);
|
|
10203
10236
|
} catch {
|
|
10204
10237
|
failedFiles.push(cell.filePath);
|
|
10205
|
-
|
|
10238
|
+
fs13.writeFileSync(manifestPath, manifestBackup, "utf-8");
|
|
10206
10239
|
for (const reEncryptedFile of reEncryptedFiles) {
|
|
10207
10240
|
const backup = fileBackups.get(reEncryptedFile);
|
|
10208
10241
|
if (backup) {
|
|
10209
|
-
|
|
10242
|
+
fs13.writeFileSync(reEncryptedFile, backup, "utf-8");
|
|
10210
10243
|
}
|
|
10211
10244
|
}
|
|
10212
10245
|
const restoredDoc = readManifestYaml(repoRoot);
|
|
@@ -10240,19 +10273,19 @@ var RecipientManager = class {
|
|
|
10240
10273
|
};
|
|
10241
10274
|
|
|
10242
10275
|
// src/recipients/requests.ts
|
|
10243
|
-
var
|
|
10244
|
-
var
|
|
10276
|
+
var fs14 = __toESM(require("fs"));
|
|
10277
|
+
var path15 = __toESM(require("path"));
|
|
10245
10278
|
var YAML9 = __toESM(require("yaml"));
|
|
10246
10279
|
var REQUESTS_FILENAME = ".clef-requests.yaml";
|
|
10247
10280
|
var HEADER_COMMENT2 = "# Pending recipient access requests. Approve with: clef recipients approve <label>\n";
|
|
10248
10281
|
function requestsFilePath(repoRoot) {
|
|
10249
|
-
return
|
|
10282
|
+
return path15.join(repoRoot, REQUESTS_FILENAME);
|
|
10250
10283
|
}
|
|
10251
10284
|
function loadRequests(repoRoot) {
|
|
10252
10285
|
const filePath = requestsFilePath(repoRoot);
|
|
10253
10286
|
try {
|
|
10254
|
-
if (!
|
|
10255
|
-
const content =
|
|
10287
|
+
if (!fs14.existsSync(filePath)) return [];
|
|
10288
|
+
const content = fs14.readFileSync(filePath, "utf-8");
|
|
10256
10289
|
const parsed = YAML9.parse(content);
|
|
10257
10290
|
if (!parsed || !Array.isArray(parsed.requests)) return [];
|
|
10258
10291
|
return parsed.requests.map((r) => ({
|
|
@@ -10269,7 +10302,7 @@ function saveRequests(repoRoot, requests) {
|
|
|
10269
10302
|
const filePath = requestsFilePath(repoRoot);
|
|
10270
10303
|
if (requests.length === 0) {
|
|
10271
10304
|
try {
|
|
10272
|
-
|
|
10305
|
+
fs14.unlinkSync(filePath);
|
|
10273
10306
|
} catch {
|
|
10274
10307
|
}
|
|
10275
10308
|
return;
|
|
@@ -10285,7 +10318,7 @@ function saveRequests(repoRoot, requests) {
|
|
|
10285
10318
|
return raw;
|
|
10286
10319
|
})
|
|
10287
10320
|
};
|
|
10288
|
-
|
|
10321
|
+
fs14.writeFileSync(filePath, HEADER_COMMENT2 + YAML9.stringify(data), "utf-8");
|
|
10289
10322
|
}
|
|
10290
10323
|
function upsertRequest(repoRoot, key, label, environment) {
|
|
10291
10324
|
const requests = loadRequests(repoRoot);
|
|
@@ -10321,7 +10354,7 @@ function findInList(requests, identifier) {
|
|
|
10321
10354
|
}
|
|
10322
10355
|
|
|
10323
10356
|
// src/drift/detector.ts
|
|
10324
|
-
var
|
|
10357
|
+
var path16 = __toESM(require("path"));
|
|
10325
10358
|
var DriftDetector = class {
|
|
10326
10359
|
parser = new ManifestParser();
|
|
10327
10360
|
matrix = new MatrixManager();
|
|
@@ -10334,8 +10367,8 @@ var DriftDetector = class {
|
|
|
10334
10367
|
* @returns Drift result with any issues found.
|
|
10335
10368
|
*/
|
|
10336
10369
|
detect(localRoot, remoteRoot, namespaceFilter) {
|
|
10337
|
-
const localManifest = this.parser.parse(
|
|
10338
|
-
const remoteManifest = this.parser.parse(
|
|
10370
|
+
const localManifest = this.parser.parse(path16.join(localRoot, CLEF_MANIFEST_FILENAME));
|
|
10371
|
+
const remoteManifest = this.parser.parse(path16.join(remoteRoot, CLEF_MANIFEST_FILENAME));
|
|
10339
10372
|
const localCells = this.matrix.resolveMatrix(localManifest, localRoot);
|
|
10340
10373
|
const remoteCells = this.matrix.resolveMatrix(remoteManifest, remoteRoot);
|
|
10341
10374
|
const localEnvNames = localManifest.environments.map((e) => e.name);
|
|
@@ -10399,7 +10432,7 @@ var DriftDetector = class {
|
|
|
10399
10432
|
};
|
|
10400
10433
|
|
|
10401
10434
|
// src/report/generator.ts
|
|
10402
|
-
var
|
|
10435
|
+
var path17 = __toESM(require("path"));
|
|
10403
10436
|
|
|
10404
10437
|
// src/report/sanitizer.ts
|
|
10405
10438
|
var ReportSanitizer = class {
|
|
@@ -10555,7 +10588,7 @@ var ReportGenerator = class {
|
|
|
10555
10588
|
let manifest = null;
|
|
10556
10589
|
try {
|
|
10557
10590
|
const parser = new ManifestParser();
|
|
10558
|
-
manifest = parser.parse(
|
|
10591
|
+
manifest = parser.parse(path17.join(repoRoot, "clef.yaml"));
|
|
10559
10592
|
} catch {
|
|
10560
10593
|
const emptyManifest = {
|
|
10561
10594
|
manifestVersion: 0,
|
|
@@ -11033,9 +11066,9 @@ var SopsMergeDriver = class {
|
|
|
11033
11066
|
};
|
|
11034
11067
|
|
|
11035
11068
|
// src/service-identity/manager.ts
|
|
11036
|
-
var
|
|
11069
|
+
var fs15 = __toESM(require("fs"));
|
|
11037
11070
|
var os = __toESM(require("os"));
|
|
11038
|
-
var
|
|
11071
|
+
var path18 = __toESM(require("path"));
|
|
11039
11072
|
var YAML10 = __toESM(require("yaml"));
|
|
11040
11073
|
var PartialRotationError = class extends Error {
|
|
11041
11074
|
constructor(message, rotatedKeys) {
|
|
@@ -11087,8 +11120,8 @@ var ServiceIdentityManager = class {
|
|
|
11087
11120
|
environments
|
|
11088
11121
|
};
|
|
11089
11122
|
await this.registerRecipients(definition, manifest, repoRoot);
|
|
11090
|
-
const manifestPath =
|
|
11091
|
-
const raw =
|
|
11123
|
+
const manifestPath = path18.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
11124
|
+
const raw = fs15.readFileSync(manifestPath, "utf-8");
|
|
11092
11125
|
const doc = YAML10.parse(raw);
|
|
11093
11126
|
if (!Array.isArray(doc.service_identities)) {
|
|
11094
11127
|
doc.service_identities = [];
|
|
@@ -11099,13 +11132,13 @@ var ServiceIdentityManager = class {
|
|
|
11099
11132
|
namespaces,
|
|
11100
11133
|
environments
|
|
11101
11134
|
});
|
|
11102
|
-
const tmpCreate =
|
|
11135
|
+
const tmpCreate = path18.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
|
|
11103
11136
|
try {
|
|
11104
|
-
|
|
11105
|
-
|
|
11137
|
+
fs15.writeFileSync(tmpCreate, YAML10.stringify(doc), "utf-8");
|
|
11138
|
+
fs15.renameSync(tmpCreate, manifestPath);
|
|
11106
11139
|
} finally {
|
|
11107
11140
|
try {
|
|
11108
|
-
|
|
11141
|
+
fs15.unlinkSync(tmpCreate);
|
|
11109
11142
|
} catch {
|
|
11110
11143
|
}
|
|
11111
11144
|
}
|
|
@@ -11143,8 +11176,8 @@ var ServiceIdentityManager = class {
|
|
|
11143
11176
|
} catch {
|
|
11144
11177
|
}
|
|
11145
11178
|
}
|
|
11146
|
-
const manifestPath =
|
|
11147
|
-
const raw =
|
|
11179
|
+
const manifestPath = path18.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
11180
|
+
const raw = fs15.readFileSync(manifestPath, "utf-8");
|
|
11148
11181
|
const doc = YAML10.parse(raw);
|
|
11149
11182
|
const identities = doc.service_identities;
|
|
11150
11183
|
if (Array.isArray(identities)) {
|
|
@@ -11152,13 +11185,13 @@ var ServiceIdentityManager = class {
|
|
|
11152
11185
|
(si) => si.name !== name
|
|
11153
11186
|
);
|
|
11154
11187
|
}
|
|
11155
|
-
const tmp =
|
|
11188
|
+
const tmp = path18.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
|
|
11156
11189
|
try {
|
|
11157
|
-
|
|
11158
|
-
|
|
11190
|
+
fs15.writeFileSync(tmp, YAML10.stringify(doc), "utf-8");
|
|
11191
|
+
fs15.renameSync(tmp, manifestPath);
|
|
11159
11192
|
} finally {
|
|
11160
11193
|
try {
|
|
11161
|
-
|
|
11194
|
+
fs15.unlinkSync(tmp);
|
|
11162
11195
|
} catch {
|
|
11163
11196
|
}
|
|
11164
11197
|
}
|
|
@@ -11173,8 +11206,8 @@ var ServiceIdentityManager = class {
|
|
|
11173
11206
|
if (!identity) {
|
|
11174
11207
|
throw new Error(`Service identity '${name}' not found.`);
|
|
11175
11208
|
}
|
|
11176
|
-
const manifestPath =
|
|
11177
|
-
const raw =
|
|
11209
|
+
const manifestPath = path18.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
11210
|
+
const raw = fs15.readFileSync(manifestPath, "utf-8");
|
|
11178
11211
|
const doc = YAML10.parse(raw);
|
|
11179
11212
|
const identities = doc.service_identities;
|
|
11180
11213
|
const siDoc = identities.find((si) => si.name === name);
|
|
@@ -11200,13 +11233,13 @@ var ServiceIdentityManager = class {
|
|
|
11200
11233
|
envs[envName] = { kms: kmsConfig };
|
|
11201
11234
|
identity.environments[envName] = { kms: kmsConfig };
|
|
11202
11235
|
}
|
|
11203
|
-
const tmp =
|
|
11236
|
+
const tmp = path18.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
|
|
11204
11237
|
try {
|
|
11205
|
-
|
|
11206
|
-
|
|
11238
|
+
fs15.writeFileSync(tmp, YAML10.stringify(doc), "utf-8");
|
|
11239
|
+
fs15.renameSync(tmp, manifestPath);
|
|
11207
11240
|
} finally {
|
|
11208
11241
|
try {
|
|
11209
|
-
|
|
11242
|
+
fs15.unlinkSync(tmp);
|
|
11210
11243
|
} catch {
|
|
11211
11244
|
}
|
|
11212
11245
|
}
|
|
@@ -11242,8 +11275,8 @@ var ServiceIdentityManager = class {
|
|
|
11242
11275
|
if (!identity) {
|
|
11243
11276
|
throw new Error(`Service identity '${name}' not found.`);
|
|
11244
11277
|
}
|
|
11245
|
-
const manifestPath =
|
|
11246
|
-
const raw =
|
|
11278
|
+
const manifestPath = path18.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
11279
|
+
const raw = fs15.readFileSync(manifestPath, "utf-8");
|
|
11247
11280
|
const doc = YAML10.parse(raw);
|
|
11248
11281
|
const identities = doc.service_identities;
|
|
11249
11282
|
const siDoc = identities.find((si) => si.name === name);
|
|
@@ -11297,13 +11330,13 @@ var ServiceIdentityManager = class {
|
|
|
11297
11330
|
}
|
|
11298
11331
|
throw err;
|
|
11299
11332
|
}
|
|
11300
|
-
const tmpRotate =
|
|
11333
|
+
const tmpRotate = path18.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
|
|
11301
11334
|
try {
|
|
11302
|
-
|
|
11303
|
-
|
|
11335
|
+
fs15.writeFileSync(tmpRotate, YAML10.stringify(doc), "utf-8");
|
|
11336
|
+
fs15.renameSync(tmpRotate, manifestPath);
|
|
11304
11337
|
} finally {
|
|
11305
11338
|
try {
|
|
11306
|
-
|
|
11339
|
+
fs15.unlinkSync(tmpRotate);
|
|
11307
11340
|
} catch {
|
|
11308
11341
|
}
|
|
11309
11342
|
}
|
|
@@ -11424,22 +11457,21 @@ async function resolveIdentitySecrets(identityName, environment, manifest, repoR
|
|
|
11424
11457
|
}
|
|
11425
11458
|
|
|
11426
11459
|
// src/artifact/packer.ts
|
|
11427
|
-
var
|
|
11428
|
-
var
|
|
11460
|
+
var fs16 = __toESM(require("fs"));
|
|
11461
|
+
var path19 = __toESM(require("path"));
|
|
11429
11462
|
var crypto4 = __toESM(require("crypto"));
|
|
11430
11463
|
|
|
11431
11464
|
// src/artifact/signer.ts
|
|
11432
11465
|
var crypto3 = __toESM(require("crypto"));
|
|
11433
11466
|
function buildSigningPayload(artifact) {
|
|
11434
11467
|
const fields = [
|
|
11435
|
-
"clef-sig-
|
|
11468
|
+
"clef-sig-v3",
|
|
11436
11469
|
String(artifact.version),
|
|
11437
11470
|
artifact.identity,
|
|
11438
11471
|
artifact.environment,
|
|
11439
11472
|
artifact.revision,
|
|
11440
11473
|
artifact.packedAt,
|
|
11441
11474
|
artifact.ciphertextHash,
|
|
11442
|
-
[...artifact.keys].sort().join(","),
|
|
11443
11475
|
artifact.expiresAt ?? "",
|
|
11444
11476
|
artifact.envelope?.provider ?? "",
|
|
11445
11477
|
artifact.envelope?.keyId ?? "",
|
|
@@ -11562,7 +11594,6 @@ var ArtifactPacker = class {
|
|
|
11562
11594
|
revision,
|
|
11563
11595
|
ciphertextHash,
|
|
11564
11596
|
ciphertext,
|
|
11565
|
-
keys: Object.keys(resolved.values),
|
|
11566
11597
|
envelope: {
|
|
11567
11598
|
provider: kmsConfig.provider,
|
|
11568
11599
|
keyId: kmsConfig.keyId,
|
|
@@ -11596,13 +11627,12 @@ var ArtifactPacker = class {
|
|
|
11596
11627
|
packedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11597
11628
|
revision,
|
|
11598
11629
|
ciphertextHash,
|
|
11599
|
-
ciphertext
|
|
11600
|
-
keys: Object.keys(resolved.values)
|
|
11630
|
+
ciphertext
|
|
11601
11631
|
};
|
|
11602
11632
|
}
|
|
11603
|
-
const outputDir =
|
|
11604
|
-
if (!
|
|
11605
|
-
|
|
11633
|
+
const outputDir = path19.dirname(config.outputPath);
|
|
11634
|
+
if (!fs16.existsSync(outputDir)) {
|
|
11635
|
+
fs16.mkdirSync(outputDir, { recursive: true });
|
|
11606
11636
|
}
|
|
11607
11637
|
if (config.ttl && config.ttl > 0) {
|
|
11608
11638
|
artifact.expiresAt = new Date(Date.now() + config.ttl * 1e3).toISOString();
|
|
@@ -11621,8 +11651,8 @@ var ArtifactPacker = class {
|
|
|
11621
11651
|
}
|
|
11622
11652
|
const json = JSON.stringify(artifact, null, 2);
|
|
11623
11653
|
const tmpOutput = `${config.outputPath}.tmp.${process.pid}`;
|
|
11624
|
-
|
|
11625
|
-
|
|
11654
|
+
fs16.writeFileSync(tmpOutput, json, "utf-8");
|
|
11655
|
+
fs16.renameSync(tmpOutput, config.outputPath);
|
|
11626
11656
|
return {
|
|
11627
11657
|
outputPath: config.outputPath,
|
|
11628
11658
|
namespaceCount: resolved.identity.namespaces.length,
|
|
@@ -11635,9 +11665,208 @@ var ArtifactPacker = class {
|
|
|
11635
11665
|
|
|
11636
11666
|
// src/kms/types.ts
|
|
11637
11667
|
var VALID_KMS_PROVIDERS = ["aws", "gcp", "azure"];
|
|
11668
|
+
|
|
11669
|
+
// src/migration/backend.ts
|
|
11670
|
+
var fs17 = __toESM(require("fs"));
|
|
11671
|
+
var path20 = __toESM(require("path"));
|
|
11672
|
+
var YAML11 = __toESM(require("yaml"));
|
|
11673
|
+
var BACKEND_KEY_FIELDS = {
|
|
11674
|
+
age: void 0,
|
|
11675
|
+
awskms: "aws_kms_arn",
|
|
11676
|
+
gcpkms: "gcp_kms_resource_id",
|
|
11677
|
+
azurekv: "azure_kv_url",
|
|
11678
|
+
pgp: "pgp_fingerprint"
|
|
11679
|
+
};
|
|
11680
|
+
var ALL_KEY_FIELDS = Object.values(BACKEND_KEY_FIELDS).filter(
|
|
11681
|
+
(v) => v !== void 0
|
|
11682
|
+
);
|
|
11683
|
+
function metadataMatchesTarget(meta, target) {
|
|
11684
|
+
if (meta.backend !== target.backend) return false;
|
|
11685
|
+
if (!target.key) return true;
|
|
11686
|
+
return meta.recipients.includes(target.key);
|
|
11687
|
+
}
|
|
11688
|
+
var BackendMigrator = class {
|
|
11689
|
+
constructor(encryption, matrixManager) {
|
|
11690
|
+
this.encryption = encryption;
|
|
11691
|
+
this.matrixManager = matrixManager;
|
|
11692
|
+
}
|
|
11693
|
+
async migrate(manifest, repoRoot, options, onProgress) {
|
|
11694
|
+
const { target, environment, dryRun, skipVerify } = options;
|
|
11695
|
+
if (environment) {
|
|
11696
|
+
const env = manifest.environments.find((e) => e.name === environment);
|
|
11697
|
+
if (!env) {
|
|
11698
|
+
throw new Error(`Environment '${environment}' not found in manifest.`);
|
|
11699
|
+
}
|
|
11700
|
+
}
|
|
11701
|
+
const allCells = this.matrixManager.resolveMatrix(manifest, repoRoot).filter((c) => c.exists);
|
|
11702
|
+
const targetCells = environment ? allCells.filter((c) => c.environment === environment) : allCells;
|
|
11703
|
+
if (targetCells.length === 0) {
|
|
11704
|
+
return {
|
|
11705
|
+
migratedFiles: [],
|
|
11706
|
+
skippedFiles: [],
|
|
11707
|
+
rolledBack: false,
|
|
11708
|
+
verifiedFiles: [],
|
|
11709
|
+
warnings: ["No encrypted files found to migrate."]
|
|
11710
|
+
};
|
|
11711
|
+
}
|
|
11712
|
+
const toMigrate = [];
|
|
11713
|
+
const skippedFiles = [];
|
|
11714
|
+
for (const cell of targetCells) {
|
|
11715
|
+
const meta = await this.encryption.getMetadata(cell.filePath);
|
|
11716
|
+
if (metadataMatchesTarget(meta, target)) {
|
|
11717
|
+
skippedFiles.push(cell.filePath);
|
|
11718
|
+
onProgress?.({
|
|
11719
|
+
type: "skip",
|
|
11720
|
+
file: cell.filePath,
|
|
11721
|
+
message: `${cell.namespace}/${cell.environment}: already on ${target.backend}, skipping`
|
|
11722
|
+
});
|
|
11723
|
+
} else {
|
|
11724
|
+
toMigrate.push(cell);
|
|
11725
|
+
}
|
|
11726
|
+
}
|
|
11727
|
+
if (toMigrate.length === 0) {
|
|
11728
|
+
return {
|
|
11729
|
+
migratedFiles: [],
|
|
11730
|
+
skippedFiles,
|
|
11731
|
+
rolledBack: false,
|
|
11732
|
+
verifiedFiles: [],
|
|
11733
|
+
warnings: ["All files already use the target backend and key. Nothing to migrate."]
|
|
11734
|
+
};
|
|
11735
|
+
}
|
|
11736
|
+
if (dryRun) {
|
|
11737
|
+
const warnings2 = [];
|
|
11738
|
+
for (const cell of toMigrate) {
|
|
11739
|
+
onProgress?.({
|
|
11740
|
+
type: "info",
|
|
11741
|
+
file: cell.filePath,
|
|
11742
|
+
message: `Would migrate ${cell.namespace}/${cell.environment} to ${target.backend}`
|
|
11743
|
+
});
|
|
11744
|
+
}
|
|
11745
|
+
if (environment) {
|
|
11746
|
+
warnings2.push(
|
|
11747
|
+
`Would add per-environment backend override for '${environment}' \u2192 ${target.backend}`
|
|
11748
|
+
);
|
|
11749
|
+
} else {
|
|
11750
|
+
warnings2.push(`Would update global default_backend \u2192 ${target.backend}`);
|
|
11751
|
+
}
|
|
11752
|
+
this.checkAgeRecipientsWarning(manifest, target, environment, warnings2);
|
|
11753
|
+
return {
|
|
11754
|
+
migratedFiles: [],
|
|
11755
|
+
skippedFiles,
|
|
11756
|
+
rolledBack: false,
|
|
11757
|
+
verifiedFiles: [],
|
|
11758
|
+
warnings: warnings2
|
|
11759
|
+
};
|
|
11760
|
+
}
|
|
11761
|
+
const manifestPath = path20.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
11762
|
+
const manifestBackup = fs17.readFileSync(manifestPath, "utf-8");
|
|
11763
|
+
const fileBackups = /* @__PURE__ */ new Map();
|
|
11764
|
+
const doc = readManifestYaml(repoRoot);
|
|
11765
|
+
this.updateManifestDoc(doc, target, environment);
|
|
11766
|
+
writeManifestYaml(repoRoot, doc);
|
|
11767
|
+
const updatedManifest = YAML11.parse(YAML11.stringify(doc));
|
|
11768
|
+
const migratedFiles = [];
|
|
11769
|
+
for (const cell of toMigrate) {
|
|
11770
|
+
try {
|
|
11771
|
+
fileBackups.set(cell.filePath, fs17.readFileSync(cell.filePath, "utf-8"));
|
|
11772
|
+
onProgress?.({
|
|
11773
|
+
type: "migrate",
|
|
11774
|
+
file: cell.filePath,
|
|
11775
|
+
message: `Migrating ${cell.namespace}/${cell.environment}...`
|
|
11776
|
+
});
|
|
11777
|
+
const decrypted = await this.encryption.decrypt(cell.filePath);
|
|
11778
|
+
await this.encryption.encrypt(
|
|
11779
|
+
cell.filePath,
|
|
11780
|
+
decrypted.values,
|
|
11781
|
+
updatedManifest,
|
|
11782
|
+
cell.environment
|
|
11783
|
+
);
|
|
11784
|
+
migratedFiles.push(cell.filePath);
|
|
11785
|
+
} catch (err) {
|
|
11786
|
+
this.rollback(manifestPath, manifestBackup, fileBackups);
|
|
11787
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
11788
|
+
onProgress?.({
|
|
11789
|
+
type: "warn",
|
|
11790
|
+
file: cell.filePath,
|
|
11791
|
+
message: `Migration failed: ${errorMsg}. All changes rolled back.`
|
|
11792
|
+
});
|
|
11793
|
+
return {
|
|
11794
|
+
migratedFiles: [],
|
|
11795
|
+
skippedFiles,
|
|
11796
|
+
rolledBack: true,
|
|
11797
|
+
error: `Failed on ${cell.namespace}/${cell.environment}: ${errorMsg}`,
|
|
11798
|
+
verifiedFiles: [],
|
|
11799
|
+
warnings: ["All changes have been rolled back."]
|
|
11800
|
+
};
|
|
11801
|
+
}
|
|
11802
|
+
}
|
|
11803
|
+
const verifiedFiles = [];
|
|
11804
|
+
const warnings = [];
|
|
11805
|
+
if (!skipVerify) {
|
|
11806
|
+
for (const cell of toMigrate) {
|
|
11807
|
+
try {
|
|
11808
|
+
onProgress?.({
|
|
11809
|
+
type: "verify",
|
|
11810
|
+
file: cell.filePath,
|
|
11811
|
+
message: `Verifying ${cell.namespace}/${cell.environment}...`
|
|
11812
|
+
});
|
|
11813
|
+
await this.encryption.decrypt(cell.filePath);
|
|
11814
|
+
verifiedFiles.push(cell.filePath);
|
|
11815
|
+
} catch (err) {
|
|
11816
|
+
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
11817
|
+
warnings.push(
|
|
11818
|
+
`Verification failed for ${cell.namespace}/${cell.environment}: ${errorMsg}`
|
|
11819
|
+
);
|
|
11820
|
+
}
|
|
11821
|
+
}
|
|
11822
|
+
}
|
|
11823
|
+
this.checkAgeRecipientsWarning(manifest, target, environment, warnings);
|
|
11824
|
+
return { migratedFiles, skippedFiles, rolledBack: false, verifiedFiles, warnings };
|
|
11825
|
+
}
|
|
11826
|
+
// ── Private helpers ──────────────────────────────────────────────────
|
|
11827
|
+
updateManifestDoc(doc, target, environment) {
|
|
11828
|
+
const keyField = BACKEND_KEY_FIELDS[target.backend];
|
|
11829
|
+
if (environment) {
|
|
11830
|
+
const environments = doc.environments;
|
|
11831
|
+
const envDoc = environments.find(
|
|
11832
|
+
(e) => e.name === environment
|
|
11833
|
+
);
|
|
11834
|
+
const sopsOverride = { backend: target.backend };
|
|
11835
|
+
if (keyField && target.key) {
|
|
11836
|
+
sopsOverride[keyField] = target.key;
|
|
11837
|
+
}
|
|
11838
|
+
envDoc.sops = sopsOverride;
|
|
11839
|
+
} else {
|
|
11840
|
+
const sops = doc.sops;
|
|
11841
|
+
sops.default_backend = target.backend;
|
|
11842
|
+
for (const field of ALL_KEY_FIELDS) {
|
|
11843
|
+
delete sops[field];
|
|
11844
|
+
}
|
|
11845
|
+
if (keyField && target.key) {
|
|
11846
|
+
sops[keyField] = target.key;
|
|
11847
|
+
}
|
|
11848
|
+
}
|
|
11849
|
+
}
|
|
11850
|
+
rollback(manifestPath, manifestBackup, fileBackups) {
|
|
11851
|
+
for (const [filePath, backup] of fileBackups) {
|
|
11852
|
+
fs17.writeFileSync(filePath, backup, "utf-8");
|
|
11853
|
+
}
|
|
11854
|
+
fs17.writeFileSync(manifestPath, manifestBackup, "utf-8");
|
|
11855
|
+
}
|
|
11856
|
+
checkAgeRecipientsWarning(manifest, target, environment, warnings) {
|
|
11857
|
+
if (target.backend === "age") return;
|
|
11858
|
+
const hasRecipients = environment ? manifest.environments.find((e) => e.name === environment)?.recipients?.length : manifest.environments.some((e) => e.recipients?.length);
|
|
11859
|
+
if (hasRecipients) {
|
|
11860
|
+
warnings.push(
|
|
11861
|
+
"Per-environment age recipients are no longer used for encryption on the migrated environments. Consider removing them from clef.yaml if they are no longer needed."
|
|
11862
|
+
);
|
|
11863
|
+
}
|
|
11864
|
+
}
|
|
11865
|
+
};
|
|
11638
11866
|
// Annotate the CommonJS export names for ESM import in node:
|
|
11639
11867
|
0 && (module.exports = {
|
|
11640
11868
|
ArtifactPacker,
|
|
11869
|
+
BackendMigrator,
|
|
11641
11870
|
BulkOps,
|
|
11642
11871
|
CLEF_MANIFEST_FILENAME,
|
|
11643
11872
|
CLEF_REPORT_SCHEMA_VERSION,
|
|
@@ -11705,6 +11934,7 @@ var VALID_KMS_PROVIDERS = ["aws", "gcp", "azure"];
|
|
|
11705
11934
|
parseIgnoreContent,
|
|
11706
11935
|
parseJson,
|
|
11707
11936
|
parseYaml,
|
|
11937
|
+
readManifestYaml,
|
|
11708
11938
|
redactValue,
|
|
11709
11939
|
removeAccessRequest,
|
|
11710
11940
|
requestsFilePath,
|
|
@@ -11722,10 +11952,13 @@ var VALID_KMS_PROVIDERS = ["aws", "gcp", "azure"];
|
|
|
11722
11952
|
signKms,
|
|
11723
11953
|
upsertRequest,
|
|
11724
11954
|
validateAgePublicKey,
|
|
11725
|
-
verifySignature
|
|
11955
|
+
verifySignature,
|
|
11956
|
+
writeManifestYaml
|
|
11726
11957
|
});
|
|
11727
11958
|
/*! Bundled license information:
|
|
11728
11959
|
|
|
11960
|
+
@noble/hashes/utils.js:
|
|
11961
|
+
@noble/hashes/utils.js:
|
|
11729
11962
|
@noble/hashes/utils.js:
|
|
11730
11963
|
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
11731
11964
|
|
|
@@ -11735,42 +11968,18 @@ var VALID_KMS_PROVIDERS = ["aws", "gcp", "azure"];
|
|
|
11735
11968
|
@noble/ciphers/utils.js:
|
|
11736
11969
|
(*! noble-ciphers - MIT License (c) 2023 Paul Miller (paulmillr.com) *)
|
|
11737
11970
|
|
|
11738
|
-
@noble/hashes/utils.js:
|
|
11739
|
-
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
11740
|
-
|
|
11741
11971
|
@noble/curves/utils.js:
|
|
11742
|
-
(*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
11743
|
-
|
|
11744
11972
|
@noble/curves/abstract/modular.js:
|
|
11745
|
-
(*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
11746
|
-
|
|
11747
11973
|
@noble/curves/abstract/curve.js:
|
|
11748
|
-
(*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
11749
|
-
|
|
11750
11974
|
@noble/curves/abstract/montgomery.js:
|
|
11751
|
-
(*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
11752
|
-
|
|
11753
11975
|
@noble/curves/abstract/weierstrass.js:
|
|
11754
|
-
(*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
11755
|
-
|
|
11756
11976
|
@noble/curves/ed25519.js:
|
|
11757
|
-
(*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
11758
|
-
|
|
11759
11977
|
@noble/curves/nist.js:
|
|
11760
11978
|
(*! noble-curves - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
11761
11979
|
|
|
11762
|
-
@noble/hashes/utils.js:
|
|
11763
|
-
(*! noble-hashes - MIT License (c) 2022 Paul Miller (paulmillr.com) *)
|
|
11764
|
-
|
|
11765
11980
|
@noble/post-quantum/utils.js:
|
|
11766
|
-
(*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) *)
|
|
11767
|
-
|
|
11768
11981
|
@noble/post-quantum/_crystals.js:
|
|
11769
|
-
(*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) *)
|
|
11770
|
-
|
|
11771
11982
|
@noble/post-quantum/ml-kem.js:
|
|
11772
|
-
(*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) *)
|
|
11773
|
-
|
|
11774
11983
|
@noble/post-quantum/hybrid.js:
|
|
11775
11984
|
(*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) *)
|
|
11776
11985
|
*/
|