@clef-sh/core 0.1.6-beta.22 → 0.1.7-beta.43
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 +3 -1
- package/dist/artifact/packer.d.ts.map +1 -1
- package/dist/artifact/resolve.d.ts +5 -3
- package/dist/artifact/resolve.d.ts.map +1 -1
- package/dist/artifact/types.d.ts +17 -0
- package/dist/artifact/types.d.ts.map +1 -1
- package/dist/index.d.mts +5 -2
- package/dist/index.d.ts +5 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +620 -93
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +595 -77
- package/dist/index.mjs.map +4 -4
- package/dist/kms/index.d.ts +2 -0
- package/dist/kms/index.d.ts.map +1 -0
- package/dist/kms/types.d.ts +10 -0
- package/dist/kms/types.d.ts.map +1 -0
- package/dist/lint/runner.d.ts.map +1 -1
- package/dist/manifest/parser.d.ts.map +1 -1
- package/dist/recipients/requests.d.ts +28 -0
- package/dist/recipients/requests.d.ts.map +1 -0
- package/dist/report/ci-context.d.ts +9 -0
- package/dist/report/ci-context.d.ts.map +1 -0
- package/dist/report/cloud-client.d.ts +18 -0
- package/dist/report/cloud-client.d.ts.map +1 -0
- package/dist/report/index.d.ts +3 -0
- package/dist/report/index.d.ts.map +1 -1
- package/dist/report/sanitizer.d.ts +1 -1
- package/dist/report/transformer.d.ts +15 -0
- package/dist/report/transformer.d.ts.map +1 -0
- package/dist/service-identity/manager.d.ts +16 -5
- package/dist/service-identity/manager.d.ts.map +1 -1
- package/dist/sops/client.d.ts.map +1 -1
- package/dist/types/index.d.ts +106 -7
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -156,7 +156,7 @@ var require_age_encryption = __commonJS({
|
|
|
156
156
|
Object.assign(hashC, info);
|
|
157
157
|
return Object.freeze(hashC);
|
|
158
158
|
}
|
|
159
|
-
function
|
|
159
|
+
function randomBytes4(bytesLength = 32) {
|
|
160
160
|
const cr = typeof globalThis === "object" ? globalThis.crypto : null;
|
|
161
161
|
if (typeof cr?.getRandomValues !== "function")
|
|
162
162
|
throw new Error("crypto.getRandomValues must be defined");
|
|
@@ -608,7 +608,7 @@ var require_age_encryption = __commonJS({
|
|
|
608
608
|
};
|
|
609
609
|
}
|
|
610
610
|
// @__NO_SIDE_EFFECTS__
|
|
611
|
-
function
|
|
611
|
+
function join16(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__ */ join16(""));
|
|
742
|
+
var base64nopad = /* @__PURE__ */ chain(/* @__PURE__ */ radix2(6), /* @__PURE__ */ alphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"), /* @__PURE__ */ join16(""));
|
|
743
|
+
var BECH_ALPHABET = /* @__PURE__ */ chain(/* @__PURE__ */ alphabet("qpzry9x8gf2tvdw0s3jn54khce6mua7l"), /* @__PURE__ */ join16(""));
|
|
744
744
|
var POLYMOD_GENERATORS = [996825010, 642813549, 513874426, 1027748829, 705979059];
|
|
745
745
|
function bech32Polymod(pre) {
|
|
746
746
|
const b = pre >> 25;
|
|
@@ -4339,7 +4339,7 @@ var require_age_encryption = __commonJS({
|
|
|
4339
4339
|
Object.assign(hashC, info);
|
|
4340
4340
|
return Object.freeze(hashC);
|
|
4341
4341
|
}
|
|
4342
|
-
function
|
|
4342
|
+
function randomBytes42(bytesLength = 32) {
|
|
4343
4343
|
const cr = typeof globalThis === "object" ? globalThis.crypto : null;
|
|
4344
4344
|
if (typeof cr?.getRandomValues !== "function")
|
|
4345
4345
|
throw new Error("crypto.getRandomValues must be defined");
|
|
@@ -5007,7 +5007,7 @@ var require_age_encryption = __commonJS({
|
|
|
5007
5007
|
return values;
|
|
5008
5008
|
};
|
|
5009
5009
|
};
|
|
5010
|
-
var randomBytes5 =
|
|
5010
|
+
var randomBytes5 = randomBytes42;
|
|
5011
5011
|
function equalBytes2(a, b) {
|
|
5012
5012
|
if (a.length !== b.length)
|
|
5013
5013
|
return false;
|
|
@@ -5944,12 +5944,12 @@ var require_age_encryption = __commonJS({
|
|
|
5944
5944
|
return generateX25519Identity();
|
|
5945
5945
|
}
|
|
5946
5946
|
function generateX25519Identity() {
|
|
5947
|
-
const scalar =
|
|
5947
|
+
const scalar = randomBytes4(32);
|
|
5948
5948
|
const identity = bech32.encodeFromBytes("AGE-SECRET-KEY-", scalar).toUpperCase();
|
|
5949
5949
|
return Promise.resolve(identity);
|
|
5950
5950
|
}
|
|
5951
5951
|
function generateHybridIdentity() {
|
|
5952
|
-
const scalar =
|
|
5952
|
+
const scalar = randomBytes4(32);
|
|
5953
5953
|
const identity = bech32.encodeFromBytes("AGE-SECRET-KEY-PQ-", scalar).toUpperCase();
|
|
5954
5954
|
return Promise.resolve(identity);
|
|
5955
5955
|
}
|
|
@@ -6157,7 +6157,7 @@ var require_age_encryption = __commonJS({
|
|
|
6157
6157
|
this.recipient = res.bytes;
|
|
6158
6158
|
}
|
|
6159
6159
|
async wrapFileKey(fileKey) {
|
|
6160
|
-
const ephemeral =
|
|
6160
|
+
const ephemeral = randomBytes4(32);
|
|
6161
6161
|
const share = await scalarMultBase(ephemeral);
|
|
6162
6162
|
const secret = await scalarMult(ephemeral, this.recipient);
|
|
6163
6163
|
const salt = new Uint8Array(share.length + this.recipient.length);
|
|
@@ -6218,7 +6218,7 @@ var require_age_encryption = __commonJS({
|
|
|
6218
6218
|
this.logN = logN;
|
|
6219
6219
|
}
|
|
6220
6220
|
wrapFileKey(fileKey) {
|
|
6221
|
-
const salt =
|
|
6221
|
+
const salt = randomBytes4(16);
|
|
6222
6222
|
const label2 = "age-encryption.org/v1/scrypt";
|
|
6223
6223
|
const labelAndSalt = new Uint8Array(label2.length + 16);
|
|
6224
6224
|
labelAndSalt.set(new TextEncoder().encode(label2));
|
|
@@ -6553,7 +6553,7 @@ var require_age_encryption = __commonJS({
|
|
|
6553
6553
|
rp: { name: "", id: options.rpId },
|
|
6554
6554
|
user: {
|
|
6555
6555
|
name: options.keyName,
|
|
6556
|
-
id: domBuffer2(
|
|
6556
|
+
id: domBuffer2(randomBytes4(8)),
|
|
6557
6557
|
// avoid overwriting existing keys
|
|
6558
6558
|
displayName: ""
|
|
6559
6559
|
},
|
|
@@ -6623,7 +6623,7 @@ var require_age_encryption = __commonJS({
|
|
|
6623
6623
|
transports: this.transports,
|
|
6624
6624
|
type: "public-key"
|
|
6625
6625
|
}] : [],
|
|
6626
|
-
challenge: domBuffer2(
|
|
6626
|
+
challenge: domBuffer2(randomBytes4(16)),
|
|
6627
6627
|
extensions: { prf: { eval: prfInputs(nonce) } },
|
|
6628
6628
|
userVerification: "required",
|
|
6629
6629
|
// prf requires UV
|
|
@@ -6642,7 +6642,7 @@ var require_age_encryption = __commonJS({
|
|
|
6642
6642
|
* Implements {@link Recipient.wrapFileKey}.
|
|
6643
6643
|
*/
|
|
6644
6644
|
async wrapFileKey(fileKey) {
|
|
6645
|
-
const nonce =
|
|
6645
|
+
const nonce = randomBytes4(16);
|
|
6646
6646
|
const results = await this.getCredential(nonce);
|
|
6647
6647
|
const key = deriveKey(results);
|
|
6648
6648
|
return [new Stanza([label, base64nopad.encode(nonce)], encryptFileKey(fileKey, key))];
|
|
@@ -6765,7 +6765,7 @@ var require_age_encryption = __commonJS({
|
|
|
6765
6765
|
}
|
|
6766
6766
|
}
|
|
6767
6767
|
async encrypt(file) {
|
|
6768
|
-
const fileKey =
|
|
6768
|
+
const fileKey = randomBytes4(16);
|
|
6769
6769
|
const stanzas = [];
|
|
6770
6770
|
let recipients = this.recipients;
|
|
6771
6771
|
if (this.passphrase !== null) {
|
|
@@ -6778,7 +6778,7 @@ var require_age_encryption = __commonJS({
|
|
|
6778
6778
|
const hmacKey = hkdf(sha256, fileKey, void 0, labelHeader, 32);
|
|
6779
6779
|
const mac = hmac(sha256, hmacKey, encodeHeaderNoMAC(stanzas));
|
|
6780
6780
|
const header = encodeHeader(stanzas, mac);
|
|
6781
|
-
const nonce =
|
|
6781
|
+
const nonce = randomBytes4(16);
|
|
6782
6782
|
const labelPayload = new TextEncoder().encode("payload");
|
|
6783
6783
|
const streamKey = hkdf(sha256, fileKey, nonce, labelPayload, 32);
|
|
6784
6784
|
const encrypter = encryptSTREAM(streamKey);
|
|
@@ -6919,6 +6919,8 @@ __export(src_exports, {
|
|
|
6919
6919
|
CLEF_REPORT_SCHEMA_VERSION: () => CLEF_REPORT_SCHEMA_VERSION,
|
|
6920
6920
|
CLEF_SUPPORTED_EXTENSIONS: () => CLEF_SUPPORTED_EXTENSIONS,
|
|
6921
6921
|
ClefError: () => ClefError,
|
|
6922
|
+
CloudApiError: () => CloudApiError,
|
|
6923
|
+
CloudClient: () => CloudClient,
|
|
6922
6924
|
ConsumptionClient: () => ConsumptionClient,
|
|
6923
6925
|
DiffEngine: () => DiffEngine,
|
|
6924
6926
|
DriftDetector: () => DriftDetector,
|
|
@@ -6930,10 +6932,12 @@ __export(src_exports, {
|
|
|
6930
6932
|
ManifestValidationError: () => ManifestValidationError,
|
|
6931
6933
|
MatrixManager: () => MatrixManager,
|
|
6932
6934
|
PartialRotationError: () => PartialRotationError,
|
|
6935
|
+
REQUESTS_FILENAME: () => REQUESTS_FILENAME,
|
|
6933
6936
|
REQUIREMENTS: () => REQUIREMENTS,
|
|
6934
6937
|
RecipientManager: () => RecipientManager,
|
|
6935
6938
|
ReportGenerator: () => ReportGenerator,
|
|
6936
6939
|
ReportSanitizer: () => ReportSanitizer,
|
|
6940
|
+
ReportTransformer: () => ReportTransformer,
|
|
6937
6941
|
ScanRunner: () => ScanRunner,
|
|
6938
6942
|
SchemaLoadError: () => SchemaLoadError,
|
|
6939
6943
|
SchemaValidator: () => SchemaValidator,
|
|
@@ -6948,17 +6952,21 @@ __export(src_exports, {
|
|
|
6948
6952
|
assertSops: () => assertSops,
|
|
6949
6953
|
checkAll: () => checkAll,
|
|
6950
6954
|
checkDependency: () => checkDependency,
|
|
6955
|
+
collectCIContext: () => collectCIContext,
|
|
6951
6956
|
deriveAgePublicKey: () => deriveAgePublicKey,
|
|
6952
6957
|
detectFormat: () => detectFormat,
|
|
6958
|
+
findRequest: () => findRequest,
|
|
6953
6959
|
formatAgeKeyFile: () => formatAgeKeyFile,
|
|
6954
6960
|
generateAgeIdentity: () => generateAgeIdentity,
|
|
6955
6961
|
generateRandomValue: () => generateRandomValue,
|
|
6956
6962
|
getPendingKeys: () => getPendingKeys,
|
|
6957
6963
|
isHighEntropy: () => isHighEntropy,
|
|
6964
|
+
isKmsEnvelope: () => isKmsEnvelope,
|
|
6958
6965
|
isPending: () => isPending,
|
|
6959
6966
|
keyPreview: () => keyPreview,
|
|
6960
6967
|
loadIgnoreRules: () => loadIgnoreRules,
|
|
6961
6968
|
loadMetadata: () => loadMetadata,
|
|
6969
|
+
loadRequests: () => loadRequests,
|
|
6962
6970
|
markPending: () => markPending,
|
|
6963
6971
|
markPendingWithRetry: () => markPendingWithRetry,
|
|
6964
6972
|
markResolved: () => markResolved,
|
|
@@ -6970,15 +6978,19 @@ __export(src_exports, {
|
|
|
6970
6978
|
parseJson: () => parseJson,
|
|
6971
6979
|
parseYaml: () => parseYaml,
|
|
6972
6980
|
redactValue: () => redactValue,
|
|
6981
|
+
removeAccessRequest: () => removeRequest,
|
|
6982
|
+
requestsFilePath: () => requestsFilePath,
|
|
6973
6983
|
resetSopsResolution: () => resetSopsResolution,
|
|
6974
6984
|
resolveBackendConfig: () => resolveBackendConfig,
|
|
6975
6985
|
resolveIdentitySecrets: () => resolveIdentitySecrets,
|
|
6976
6986
|
resolveRecipientsForEnvironment: () => resolveRecipientsForEnvironment,
|
|
6977
6987
|
resolveSopsPath: () => resolveSopsPath,
|
|
6978
6988
|
saveMetadata: () => saveMetadata,
|
|
6989
|
+
saveRequests: () => saveRequests,
|
|
6979
6990
|
shannonEntropy: () => shannonEntropy,
|
|
6980
6991
|
shouldIgnoreFile: () => shouldIgnoreFile,
|
|
6981
6992
|
shouldIgnoreMatch: () => shouldIgnoreMatch,
|
|
6993
|
+
upsertRequest: () => upsertRequest,
|
|
6982
6994
|
validateAgePublicKey: () => validateAgePublicKey
|
|
6983
6995
|
});
|
|
6984
6996
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -6992,6 +7004,7 @@ function resolveBackendConfig(manifest, environment) {
|
|
|
6992
7004
|
backend: manifest.sops.default_backend,
|
|
6993
7005
|
aws_kms_arn: manifest.sops.aws_kms_arn,
|
|
6994
7006
|
gcp_kms_resource_id: manifest.sops.gcp_kms_resource_id,
|
|
7007
|
+
azure_kv_url: manifest.sops.azure_kv_url,
|
|
6995
7008
|
pgp_fingerprint: manifest.sops.pgp_fingerprint
|
|
6996
7009
|
};
|
|
6997
7010
|
}
|
|
@@ -7080,7 +7093,17 @@ Then run clef doctor to verify your setup.`
|
|
|
7080
7093
|
this.name = "SopsVersionError";
|
|
7081
7094
|
}
|
|
7082
7095
|
};
|
|
7096
|
+
function isKmsEnvelope(cfg) {
|
|
7097
|
+
return cfg.kms !== void 0;
|
|
7098
|
+
}
|
|
7083
7099
|
var CLEF_REPORT_SCHEMA_VERSION = 1;
|
|
7100
|
+
var CloudApiError = class extends ClefError {
|
|
7101
|
+
constructor(message, statusCode, fix) {
|
|
7102
|
+
super(message, fix);
|
|
7103
|
+
this.statusCode = statusCode;
|
|
7104
|
+
this.name = "CloudApiError";
|
|
7105
|
+
}
|
|
7106
|
+
};
|
|
7084
7107
|
|
|
7085
7108
|
// src/manifest/parser.ts
|
|
7086
7109
|
var fs = __toESM(require("fs"));
|
|
@@ -7122,14 +7145,15 @@ function keyPreview(key) {
|
|
|
7122
7145
|
|
|
7123
7146
|
// src/manifest/parser.ts
|
|
7124
7147
|
var CLEF_MANIFEST_FILENAME = "clef.yaml";
|
|
7125
|
-
var VALID_BACKENDS = ["age", "awskms", "gcpkms", "pgp"];
|
|
7148
|
+
var VALID_BACKENDS = ["age", "awskms", "gcpkms", "azurekv", "pgp"];
|
|
7126
7149
|
var VALID_TOP_LEVEL_KEYS = [
|
|
7127
7150
|
"version",
|
|
7128
7151
|
"environments",
|
|
7129
7152
|
"namespaces",
|
|
7130
7153
|
"sops",
|
|
7131
7154
|
"file_pattern",
|
|
7132
|
-
"service_identities"
|
|
7155
|
+
"service_identities",
|
|
7156
|
+
"cloud"
|
|
7133
7157
|
];
|
|
7134
7158
|
var ENV_NAME_PATTERN = /^[a-z][a-z0-9_-]*$/;
|
|
7135
7159
|
var FILE_PATTERN_REQUIRED_TOKENS = ["{namespace}", "{environment}"];
|
|
@@ -7269,6 +7293,12 @@ var ManifestParser = class {
|
|
|
7269
7293
|
"environments"
|
|
7270
7294
|
);
|
|
7271
7295
|
}
|
|
7296
|
+
if (backend === "azurekv" && typeof sopsOverride.azure_kv_url !== "string") {
|
|
7297
|
+
throw new ManifestValidationError(
|
|
7298
|
+
`Environment '${envObj.name}' uses 'azurekv' backend but is missing 'azure_kv_url'.`,
|
|
7299
|
+
"environments"
|
|
7300
|
+
);
|
|
7301
|
+
}
|
|
7272
7302
|
if (backend === "pgp" && typeof sopsOverride.pgp_fingerprint !== "string") {
|
|
7273
7303
|
throw new ManifestValidationError(
|
|
7274
7304
|
`Environment '${envObj.name}' uses 'pgp' backend but is missing 'pgp_fingerprint'.`,
|
|
@@ -7279,6 +7309,7 @@ var ManifestParser = class {
|
|
|
7279
7309
|
backend,
|
|
7280
7310
|
...typeof sopsOverride.aws_kms_arn === "string" ? { aws_kms_arn: sopsOverride.aws_kms_arn } : {},
|
|
7281
7311
|
...typeof sopsOverride.gcp_kms_resource_id === "string" ? { gcp_kms_resource_id: sopsOverride.gcp_kms_resource_id } : {},
|
|
7312
|
+
...typeof sopsOverride.azure_kv_url === "string" ? { azure_kv_url: sopsOverride.azure_kv_url } : {},
|
|
7282
7313
|
...typeof sopsOverride.pgp_fingerprint === "string" ? { pgp_fingerprint: sopsOverride.pgp_fingerprint } : {}
|
|
7283
7314
|
};
|
|
7284
7315
|
}
|
|
@@ -7405,7 +7436,7 @@ var ManifestParser = class {
|
|
|
7405
7436
|
const sopsObj = obj.sops;
|
|
7406
7437
|
if (!sopsObj.default_backend || typeof sopsObj.default_backend !== "string") {
|
|
7407
7438
|
throw new ManifestValidationError(
|
|
7408
|
-
"Field 'sops.default_backend' is required and must be one of: age, awskms, gcpkms, pgp.",
|
|
7439
|
+
"Field 'sops.default_backend' is required and must be one of: age, awskms, gcpkms, azurekv, pgp.",
|
|
7409
7440
|
"sops.default_backend"
|
|
7410
7441
|
);
|
|
7411
7442
|
}
|
|
@@ -7419,6 +7450,7 @@ var ManifestParser = class {
|
|
|
7419
7450
|
default_backend: sopsObj.default_backend,
|
|
7420
7451
|
...typeof sopsObj.aws_kms_arn === "string" ? { aws_kms_arn: sopsObj.aws_kms_arn } : {},
|
|
7421
7452
|
...typeof sopsObj.gcp_kms_resource_id === "string" ? { gcp_kms_resource_id: sopsObj.gcp_kms_resource_id } : {},
|
|
7453
|
+
...typeof sopsObj.azure_kv_url === "string" ? { azure_kv_url: sopsObj.azure_kv_url } : {},
|
|
7422
7454
|
...typeof sopsObj.pgp_fingerprint === "string" ? { pgp_fingerprint: sopsObj.pgp_fingerprint } : {}
|
|
7423
7455
|
};
|
|
7424
7456
|
for (const env of environments) {
|
|
@@ -7520,25 +7552,69 @@ var ManifestParser = class {
|
|
|
7520
7552
|
}
|
|
7521
7553
|
if (typeof envVal !== "object" || envVal === null) {
|
|
7522
7554
|
throw new ManifestValidationError(
|
|
7523
|
-
`Service identity '${siName}' environment '${envName}' must be an object with 'recipient'.`,
|
|
7555
|
+
`Service identity '${siName}' environment '${envName}' must be an object with 'recipient' or 'kms'.`,
|
|
7524
7556
|
"service_identities"
|
|
7525
7557
|
);
|
|
7526
7558
|
}
|
|
7527
7559
|
const envObj = envVal;
|
|
7528
|
-
|
|
7560
|
+
const hasRecipient = envObj.recipient !== void 0;
|
|
7561
|
+
const hasKms = envObj.kms !== void 0;
|
|
7562
|
+
if (hasRecipient && hasKms) {
|
|
7529
7563
|
throw new ManifestValidationError(
|
|
7530
|
-
`Service identity '${siName}' environment '${envName}'
|
|
7564
|
+
`Service identity '${siName}' environment '${envName}': 'recipient' and 'kms' are mutually exclusive.`,
|
|
7531
7565
|
"service_identities"
|
|
7532
7566
|
);
|
|
7533
7567
|
}
|
|
7534
|
-
|
|
7535
|
-
if (!recipientValidation.valid) {
|
|
7568
|
+
if (!hasRecipient && !hasKms) {
|
|
7536
7569
|
throw new ManifestValidationError(
|
|
7537
|
-
`Service identity '${siName}' environment '${envName}'
|
|
7570
|
+
`Service identity '${siName}' environment '${envName}' must have either 'recipient' or 'kms'.`,
|
|
7538
7571
|
"service_identities"
|
|
7539
7572
|
);
|
|
7540
7573
|
}
|
|
7541
|
-
|
|
7574
|
+
if (hasRecipient) {
|
|
7575
|
+
if (typeof envObj.recipient !== "string") {
|
|
7576
|
+
throw new ManifestValidationError(
|
|
7577
|
+
`Service identity '${siName}' environment '${envName}': 'recipient' must be a string.`,
|
|
7578
|
+
"service_identities"
|
|
7579
|
+
);
|
|
7580
|
+
}
|
|
7581
|
+
const recipientValidation = validateAgePublicKey(envObj.recipient);
|
|
7582
|
+
if (!recipientValidation.valid) {
|
|
7583
|
+
throw new ManifestValidationError(
|
|
7584
|
+
`Service identity '${siName}' environment '${envName}': ${recipientValidation.error}`,
|
|
7585
|
+
"service_identities"
|
|
7586
|
+
);
|
|
7587
|
+
}
|
|
7588
|
+
parsedEnvs[envName] = { recipient: recipientValidation.key };
|
|
7589
|
+
} else {
|
|
7590
|
+
const kmsObj = envObj.kms;
|
|
7591
|
+
if (typeof kmsObj !== "object" || kmsObj === null) {
|
|
7592
|
+
throw new ManifestValidationError(
|
|
7593
|
+
`Service identity '${siName}' environment '${envName}': 'kms' must be an object.`,
|
|
7594
|
+
"service_identities"
|
|
7595
|
+
);
|
|
7596
|
+
}
|
|
7597
|
+
const validProviders = ["aws", "gcp", "azure"];
|
|
7598
|
+
if (!kmsObj.provider || !validProviders.includes(kmsObj.provider)) {
|
|
7599
|
+
throw new ManifestValidationError(
|
|
7600
|
+
`Service identity '${siName}' environment '${envName}': kms.provider must be one of: ${validProviders.join(", ")}.`,
|
|
7601
|
+
"service_identities"
|
|
7602
|
+
);
|
|
7603
|
+
}
|
|
7604
|
+
if (!kmsObj.keyId || typeof kmsObj.keyId !== "string") {
|
|
7605
|
+
throw new ManifestValidationError(
|
|
7606
|
+
`Service identity '${siName}' environment '${envName}': kms.keyId must be a non-empty string.`,
|
|
7607
|
+
"service_identities"
|
|
7608
|
+
);
|
|
7609
|
+
}
|
|
7610
|
+
parsedEnvs[envName] = {
|
|
7611
|
+
kms: {
|
|
7612
|
+
provider: kmsObj.provider,
|
|
7613
|
+
keyId: kmsObj.keyId,
|
|
7614
|
+
region: typeof kmsObj.region === "string" ? kmsObj.region : void 0
|
|
7615
|
+
}
|
|
7616
|
+
};
|
|
7617
|
+
}
|
|
7542
7618
|
}
|
|
7543
7619
|
return {
|
|
7544
7620
|
name: siName,
|
|
@@ -7558,13 +7634,28 @@ var ManifestParser = class {
|
|
|
7558
7634
|
siNames.add(si.name);
|
|
7559
7635
|
}
|
|
7560
7636
|
}
|
|
7637
|
+
let cloud;
|
|
7638
|
+
if (obj.cloud !== void 0) {
|
|
7639
|
+
if (typeof obj.cloud !== "object" || obj.cloud === null || Array.isArray(obj.cloud)) {
|
|
7640
|
+
throw new ManifestValidationError("Field 'cloud' must be an object.", "cloud");
|
|
7641
|
+
}
|
|
7642
|
+
const cloudObj = obj.cloud;
|
|
7643
|
+
if (typeof cloudObj.integrationId !== "string" || cloudObj.integrationId.length === 0) {
|
|
7644
|
+
throw new ManifestValidationError(
|
|
7645
|
+
"Field 'cloud.integrationId' is required and must be a non-empty string.",
|
|
7646
|
+
"cloud"
|
|
7647
|
+
);
|
|
7648
|
+
}
|
|
7649
|
+
cloud = { integrationId: cloudObj.integrationId };
|
|
7650
|
+
}
|
|
7561
7651
|
return {
|
|
7562
7652
|
version: 1,
|
|
7563
7653
|
environments,
|
|
7564
7654
|
namespaces,
|
|
7565
7655
|
sops: sopsConfig,
|
|
7566
7656
|
file_pattern: obj.file_pattern,
|
|
7567
|
-
...serviceIdentities ? { service_identities: serviceIdentities } : {}
|
|
7657
|
+
...serviceIdentities ? { service_identities: serviceIdentities } : {},
|
|
7658
|
+
...cloud ? { cloud } : {}
|
|
7568
7659
|
};
|
|
7569
7660
|
}
|
|
7570
7661
|
/**
|
|
@@ -9227,6 +9318,8 @@ var SopsClient = class {
|
|
|
9227
9318
|
if (sops.kms && Array.isArray(sops.kms) && sops.kms.length > 0) return "awskms";
|
|
9228
9319
|
if (sops.gcp_kms && Array.isArray(sops.gcp_kms) && sops.gcp_kms.length > 0)
|
|
9229
9320
|
return "gcpkms";
|
|
9321
|
+
if (sops.azure_kv && Array.isArray(sops.azure_kv) && sops.azure_kv.length > 0)
|
|
9322
|
+
return "azurekv";
|
|
9230
9323
|
if (sops.pgp && Array.isArray(sops.pgp) && sops.pgp.length > 0) return "pgp";
|
|
9231
9324
|
return "age";
|
|
9232
9325
|
}
|
|
@@ -9244,6 +9337,14 @@ var SopsClient = class {
|
|
|
9244
9337
|
const entries = sops.gcp_kms;
|
|
9245
9338
|
return entries?.map((e) => String(e.resource_id ?? "")) ?? [];
|
|
9246
9339
|
}
|
|
9340
|
+
case "azurekv": {
|
|
9341
|
+
const entries = sops.azure_kv;
|
|
9342
|
+
return entries?.map((e) => {
|
|
9343
|
+
const vaultUrl = String(e.vaultUrl ?? e.vault_url ?? "");
|
|
9344
|
+
const name = String(e.name ?? e.key ?? "");
|
|
9345
|
+
return vaultUrl && name ? `${vaultUrl}/keys/${name}` : vaultUrl || name;
|
|
9346
|
+
}) ?? [];
|
|
9347
|
+
}
|
|
9247
9348
|
case "pgp": {
|
|
9248
9349
|
const entries = sops.pgp;
|
|
9249
9350
|
return entries?.map((e) => String(e.fp ?? "")) ?? [];
|
|
@@ -9256,6 +9357,7 @@ var SopsClient = class {
|
|
|
9256
9357
|
backend: manifest.sops.default_backend,
|
|
9257
9358
|
aws_kms_arn: manifest.sops.aws_kms_arn,
|
|
9258
9359
|
gcp_kms_resource_id: manifest.sops.gcp_kms_resource_id,
|
|
9360
|
+
azure_kv_url: manifest.sops.azure_kv_url,
|
|
9259
9361
|
pgp_fingerprint: manifest.sops.pgp_fingerprint
|
|
9260
9362
|
};
|
|
9261
9363
|
switch (config.backend) {
|
|
@@ -9271,6 +9373,11 @@ var SopsClient = class {
|
|
|
9271
9373
|
args.push("--gcp-kms", config.gcp_kms_resource_id);
|
|
9272
9374
|
}
|
|
9273
9375
|
break;
|
|
9376
|
+
case "azurekv":
|
|
9377
|
+
if (config.azure_kv_url) {
|
|
9378
|
+
args.push("--azure-kv", config.azure_kv_url);
|
|
9379
|
+
}
|
|
9380
|
+
break;
|
|
9274
9381
|
case "pgp":
|
|
9275
9382
|
if (config.pgp_fingerprint) {
|
|
9276
9383
|
args.push("--pgp", config.pgp_fingerprint);
|
|
@@ -9488,7 +9595,7 @@ var LintRunner = class {
|
|
|
9488
9595
|
/**
|
|
9489
9596
|
* Lint service identity configurations for drift issues.
|
|
9490
9597
|
*/
|
|
9491
|
-
async lintServiceIdentities(identities, manifest,
|
|
9598
|
+
async lintServiceIdentities(identities, manifest, repoRoot, existingCells) {
|
|
9492
9599
|
const issues = [];
|
|
9493
9600
|
const declaredEnvNames = new Set(manifest.environments.map((e) => e.name));
|
|
9494
9601
|
const declaredNsNames = new Set(manifest.namespaces.map((ns) => ns.name));
|
|
@@ -9516,6 +9623,7 @@ var LintRunner = class {
|
|
|
9516
9623
|
for (const cell of existingCells) {
|
|
9517
9624
|
const envConfig = si.environments[cell.environment];
|
|
9518
9625
|
if (!envConfig) continue;
|
|
9626
|
+
if (!envConfig.recipient) continue;
|
|
9519
9627
|
if (si.namespaces.includes(cell.namespace)) {
|
|
9520
9628
|
try {
|
|
9521
9629
|
const metadata = await this.sopsClient.getMetadata(cell.filePath);
|
|
@@ -10106,10 +10214,91 @@ var RecipientManager = class {
|
|
|
10106
10214
|
}
|
|
10107
10215
|
};
|
|
10108
10216
|
|
|
10109
|
-
// src/
|
|
10217
|
+
// src/recipients/requests.ts
|
|
10110
10218
|
var fs12 = __toESM(require("fs"));
|
|
10111
10219
|
var path14 = __toESM(require("path"));
|
|
10112
10220
|
var YAML7 = __toESM(require("yaml"));
|
|
10221
|
+
var REQUESTS_FILENAME = ".clef-requests.yaml";
|
|
10222
|
+
var HEADER_COMMENT2 = "# Pending recipient access requests. Approve with: clef recipients approve <label>\n";
|
|
10223
|
+
function requestsFilePath(repoRoot) {
|
|
10224
|
+
return path14.join(repoRoot, REQUESTS_FILENAME);
|
|
10225
|
+
}
|
|
10226
|
+
function loadRequests(repoRoot) {
|
|
10227
|
+
const filePath = requestsFilePath(repoRoot);
|
|
10228
|
+
try {
|
|
10229
|
+
if (!fs12.existsSync(filePath)) return [];
|
|
10230
|
+
const content = fs12.readFileSync(filePath, "utf-8");
|
|
10231
|
+
const parsed = YAML7.parse(content);
|
|
10232
|
+
if (!parsed || !Array.isArray(parsed.requests)) return [];
|
|
10233
|
+
return parsed.requests.map((r) => ({
|
|
10234
|
+
key: r.key,
|
|
10235
|
+
label: r.label,
|
|
10236
|
+
requestedAt: new Date(r.requested_at),
|
|
10237
|
+
environment: r.environment
|
|
10238
|
+
}));
|
|
10239
|
+
} catch {
|
|
10240
|
+
return [];
|
|
10241
|
+
}
|
|
10242
|
+
}
|
|
10243
|
+
function saveRequests(repoRoot, requests) {
|
|
10244
|
+
const filePath = requestsFilePath(repoRoot);
|
|
10245
|
+
if (requests.length === 0) {
|
|
10246
|
+
try {
|
|
10247
|
+
fs12.unlinkSync(filePath);
|
|
10248
|
+
} catch {
|
|
10249
|
+
}
|
|
10250
|
+
return;
|
|
10251
|
+
}
|
|
10252
|
+
const data = {
|
|
10253
|
+
requests: requests.map((r) => {
|
|
10254
|
+
const raw = {
|
|
10255
|
+
key: r.key,
|
|
10256
|
+
label: r.label,
|
|
10257
|
+
requested_at: r.requestedAt.toISOString()
|
|
10258
|
+
};
|
|
10259
|
+
if (r.environment) raw.environment = r.environment;
|
|
10260
|
+
return raw;
|
|
10261
|
+
})
|
|
10262
|
+
};
|
|
10263
|
+
fs12.writeFileSync(filePath, HEADER_COMMENT2 + YAML7.stringify(data), "utf-8");
|
|
10264
|
+
}
|
|
10265
|
+
function upsertRequest(repoRoot, key, label, environment) {
|
|
10266
|
+
const requests = loadRequests(repoRoot);
|
|
10267
|
+
const now = /* @__PURE__ */ new Date();
|
|
10268
|
+
const request = { key, label, requestedAt: now, environment };
|
|
10269
|
+
const existingIndex = requests.findIndex((r) => r.key === key);
|
|
10270
|
+
if (existingIndex >= 0) {
|
|
10271
|
+
requests[existingIndex] = request;
|
|
10272
|
+
} else {
|
|
10273
|
+
requests.push(request);
|
|
10274
|
+
}
|
|
10275
|
+
saveRequests(repoRoot, requests);
|
|
10276
|
+
return request;
|
|
10277
|
+
}
|
|
10278
|
+
function removeRequest(repoRoot, identifier) {
|
|
10279
|
+
const requests = loadRequests(repoRoot);
|
|
10280
|
+
const match = findInList(requests, identifier);
|
|
10281
|
+
if (!match) return null;
|
|
10282
|
+
const filtered = requests.filter((r) => r.key !== match.key);
|
|
10283
|
+
saveRequests(repoRoot, filtered);
|
|
10284
|
+
return match;
|
|
10285
|
+
}
|
|
10286
|
+
function findRequest(repoRoot, identifier) {
|
|
10287
|
+
const requests = loadRequests(repoRoot);
|
|
10288
|
+
return findInList(requests, identifier);
|
|
10289
|
+
}
|
|
10290
|
+
function findInList(requests, identifier) {
|
|
10291
|
+
const lower = identifier.toLowerCase();
|
|
10292
|
+
const byLabel = requests.find((r) => r.label.toLowerCase() === lower);
|
|
10293
|
+
if (byLabel) return byLabel;
|
|
10294
|
+
const byKey = requests.find((r) => r.key === identifier);
|
|
10295
|
+
return byKey ?? null;
|
|
10296
|
+
}
|
|
10297
|
+
|
|
10298
|
+
// src/drift/detector.ts
|
|
10299
|
+
var fs13 = __toESM(require("fs"));
|
|
10300
|
+
var path15 = __toESM(require("path"));
|
|
10301
|
+
var YAML8 = __toESM(require("yaml"));
|
|
10113
10302
|
var DriftDetector = class {
|
|
10114
10303
|
parser = new ManifestParser();
|
|
10115
10304
|
matrix = new MatrixManager();
|
|
@@ -10122,8 +10311,8 @@ var DriftDetector = class {
|
|
|
10122
10311
|
* @returns Drift result with any issues found.
|
|
10123
10312
|
*/
|
|
10124
10313
|
detect(localRoot, remoteRoot, namespaceFilter) {
|
|
10125
|
-
const localManifest = this.parser.parse(
|
|
10126
|
-
const remoteManifest = this.parser.parse(
|
|
10314
|
+
const localManifest = this.parser.parse(path15.join(localRoot, CLEF_MANIFEST_FILENAME));
|
|
10315
|
+
const remoteManifest = this.parser.parse(path15.join(remoteRoot, CLEF_MANIFEST_FILENAME));
|
|
10127
10316
|
const localCells = this.matrix.resolveMatrix(localManifest, localRoot);
|
|
10128
10317
|
const remoteCells = this.matrix.resolveMatrix(remoteManifest, remoteRoot);
|
|
10129
10318
|
const localEnvNames = localManifest.environments.map((e) => e.name);
|
|
@@ -10194,9 +10383,9 @@ var DriftDetector = class {
|
|
|
10194
10383
|
*/
|
|
10195
10384
|
readKeysFromFile(filePath) {
|
|
10196
10385
|
try {
|
|
10197
|
-
if (!
|
|
10198
|
-
const raw =
|
|
10199
|
-
const parsed =
|
|
10386
|
+
if (!fs13.existsSync(filePath)) return null;
|
|
10387
|
+
const raw = fs13.readFileSync(filePath, "utf-8");
|
|
10388
|
+
const parsed = YAML8.parse(raw);
|
|
10200
10389
|
if (parsed === null || parsed === void 0 || typeof parsed !== "object") return null;
|
|
10201
10390
|
return Object.keys(parsed).filter((k) => k !== "sops");
|
|
10202
10391
|
} catch {
|
|
@@ -10206,9 +10395,9 @@ var DriftDetector = class {
|
|
|
10206
10395
|
};
|
|
10207
10396
|
|
|
10208
10397
|
// src/report/generator.ts
|
|
10209
|
-
var
|
|
10210
|
-
var
|
|
10211
|
-
var
|
|
10398
|
+
var fs14 = __toESM(require("fs"));
|
|
10399
|
+
var path16 = __toESM(require("path"));
|
|
10400
|
+
var YAML9 = __toESM(require("yaml"));
|
|
10212
10401
|
|
|
10213
10402
|
// src/report/sanitizer.ts
|
|
10214
10403
|
var ReportSanitizer = class {
|
|
@@ -10364,7 +10553,7 @@ var ReportGenerator = class {
|
|
|
10364
10553
|
let manifest = null;
|
|
10365
10554
|
try {
|
|
10366
10555
|
const parser = new ManifestParser();
|
|
10367
|
-
manifest = parser.parse(
|
|
10556
|
+
manifest = parser.parse(path16.join(repoRoot, "clef.yaml"));
|
|
10368
10557
|
} catch {
|
|
10369
10558
|
const emptyManifest = {
|
|
10370
10559
|
manifestVersion: 0,
|
|
@@ -10514,9 +10703,9 @@ var ReportGenerator = class {
|
|
|
10514
10703
|
}
|
|
10515
10704
|
readKeyCount(filePath) {
|
|
10516
10705
|
try {
|
|
10517
|
-
if (!
|
|
10518
|
-
const raw =
|
|
10519
|
-
const parsed =
|
|
10706
|
+
if (!fs14.existsSync(filePath)) return 0;
|
|
10707
|
+
const raw = fs14.readFileSync(filePath, "utf-8");
|
|
10708
|
+
const parsed = YAML9.parse(raw);
|
|
10520
10709
|
if (parsed === null || parsed === void 0 || typeof parsed !== "object") return 0;
|
|
10521
10710
|
return Object.keys(parsed).filter((k) => k !== "sops").length;
|
|
10522
10711
|
} catch {
|
|
@@ -10569,6 +10758,202 @@ var ReportGenerator = class {
|
|
|
10569
10758
|
}
|
|
10570
10759
|
};
|
|
10571
10760
|
|
|
10761
|
+
// src/report/transformer.ts
|
|
10762
|
+
var ReportTransformer = class {
|
|
10763
|
+
transform(report) {
|
|
10764
|
+
const summary = this.buildSummary(report);
|
|
10765
|
+
const drift = this.buildDrift(report);
|
|
10766
|
+
const policyResults = this.buildPolicyResults(report.policy.issues);
|
|
10767
|
+
return {
|
|
10768
|
+
commitSha: report.repoIdentity.commitSha,
|
|
10769
|
+
branch: report.repoIdentity.branch,
|
|
10770
|
+
commitTimestamp: new Date(report.repoIdentity.commitTimestamp).getTime(),
|
|
10771
|
+
cliVersion: report.repoIdentity.clefVersion,
|
|
10772
|
+
summary,
|
|
10773
|
+
drift,
|
|
10774
|
+
policyResults
|
|
10775
|
+
};
|
|
10776
|
+
}
|
|
10777
|
+
buildSummary(report) {
|
|
10778
|
+
const namespaces = [...new Set(report.matrix.map((c) => c.namespace))];
|
|
10779
|
+
const environments = [...new Set(report.matrix.map((c) => c.environment))];
|
|
10780
|
+
const cells = report.matrix.map((cell) => this.buildCell(cell, report.policy.issues));
|
|
10781
|
+
const violations = report.policy.issues.filter((i) => i.severity === "error").length;
|
|
10782
|
+
return {
|
|
10783
|
+
filesScanned: report.matrix.length,
|
|
10784
|
+
namespaces,
|
|
10785
|
+
environments,
|
|
10786
|
+
cells,
|
|
10787
|
+
violations,
|
|
10788
|
+
passed: violations === 0
|
|
10789
|
+
};
|
|
10790
|
+
}
|
|
10791
|
+
buildCell(cell, issues) {
|
|
10792
|
+
const healthStatus = this.computeHealthStatus(cell, issues);
|
|
10793
|
+
const description = this.describeCell(cell, healthStatus);
|
|
10794
|
+
return {
|
|
10795
|
+
namespace: cell.namespace,
|
|
10796
|
+
environment: cell.environment,
|
|
10797
|
+
healthStatus,
|
|
10798
|
+
description
|
|
10799
|
+
};
|
|
10800
|
+
}
|
|
10801
|
+
computeHealthStatus(cell, issues) {
|
|
10802
|
+
if (!cell.exists) return "unknown";
|
|
10803
|
+
const cellIssues = issues.filter(
|
|
10804
|
+
(i) => i.namespace === cell.namespace && i.environment === cell.environment || i.file !== void 0 && i.file.includes(cell.namespace) && i.file.includes(cell.environment)
|
|
10805
|
+
);
|
|
10806
|
+
if (cellIssues.some((i) => i.severity === "error")) return "critical";
|
|
10807
|
+
if (cellIssues.some((i) => i.severity === "warning") || cell.pendingCount > 0) return "warning";
|
|
10808
|
+
return "healthy";
|
|
10809
|
+
}
|
|
10810
|
+
describeCell(cell, status) {
|
|
10811
|
+
switch (status) {
|
|
10812
|
+
case "unknown":
|
|
10813
|
+
return "File does not exist";
|
|
10814
|
+
case "critical":
|
|
10815
|
+
return "Has error-severity policy issues";
|
|
10816
|
+
case "warning":
|
|
10817
|
+
return cell.pendingCount > 0 ? `${cell.pendingCount} pending key(s) awaiting values` : "Has warning-severity policy issues";
|
|
10818
|
+
case "healthy":
|
|
10819
|
+
return `${cell.keyCount} key(s), no issues`;
|
|
10820
|
+
}
|
|
10821
|
+
}
|
|
10822
|
+
buildDrift(report) {
|
|
10823
|
+
const namespaces = [...new Set(report.matrix.map((c) => c.namespace))];
|
|
10824
|
+
const driftIssues = report.policy.issues.filter((i) => i.category === "drift");
|
|
10825
|
+
return namespaces.map((namespace) => {
|
|
10826
|
+
const nsIssues = driftIssues.filter((i) => i.namespace === namespace);
|
|
10827
|
+
const totalDrift = nsIssues.reduce((sum, i) => sum + (i.driftCount ?? 1), 0);
|
|
10828
|
+
return {
|
|
10829
|
+
namespace,
|
|
10830
|
+
isDrifted: totalDrift > 0,
|
|
10831
|
+
driftCount: totalDrift
|
|
10832
|
+
};
|
|
10833
|
+
});
|
|
10834
|
+
}
|
|
10835
|
+
buildPolicyResults(issues) {
|
|
10836
|
+
return issues.map((issue) => ({
|
|
10837
|
+
ruleId: `${issue.category}/${issue.severity}`,
|
|
10838
|
+
ruleName: issue.category,
|
|
10839
|
+
passed: issue.severity !== "error",
|
|
10840
|
+
severity: issue.severity,
|
|
10841
|
+
message: issue.message,
|
|
10842
|
+
...issue.namespace || issue.environment ? {
|
|
10843
|
+
scope: {
|
|
10844
|
+
...issue.namespace ? { namespace: issue.namespace } : {},
|
|
10845
|
+
...issue.environment ? { environment: issue.environment } : {}
|
|
10846
|
+
}
|
|
10847
|
+
} : {}
|
|
10848
|
+
}));
|
|
10849
|
+
}
|
|
10850
|
+
};
|
|
10851
|
+
|
|
10852
|
+
// src/report/cloud-client.ts
|
|
10853
|
+
var DEFAULT_RETRY_DELAY_MS = 1e3;
|
|
10854
|
+
var CloudClient = class {
|
|
10855
|
+
retryDelayMs;
|
|
10856
|
+
constructor(options) {
|
|
10857
|
+
this.retryDelayMs = options?.retryDelayMs ?? DEFAULT_RETRY_DELAY_MS;
|
|
10858
|
+
}
|
|
10859
|
+
async fetchIntegration(apiUrl, apiKey, integrationId) {
|
|
10860
|
+
const url = `${apiUrl}/api/v1/integrations/${encodeURIComponent(integrationId)}`;
|
|
10861
|
+
return this.request("GET", url, apiKey);
|
|
10862
|
+
}
|
|
10863
|
+
async submitReport(apiUrl, apiKey, report) {
|
|
10864
|
+
const url = `${apiUrl}/api/v1/reports`;
|
|
10865
|
+
return this.request("POST", url, apiKey, report);
|
|
10866
|
+
}
|
|
10867
|
+
async submitBatchReports(apiUrl, apiKey, batch) {
|
|
10868
|
+
const url = `${apiUrl}/api/v1/reports/batch`;
|
|
10869
|
+
return this.request("POST", url, apiKey, batch);
|
|
10870
|
+
}
|
|
10871
|
+
async request(method, url, apiKey, body) {
|
|
10872
|
+
const headers = {
|
|
10873
|
+
Authorization: `Bearer ${apiKey}`,
|
|
10874
|
+
"Content-Type": "application/json"
|
|
10875
|
+
};
|
|
10876
|
+
const init = {
|
|
10877
|
+
method,
|
|
10878
|
+
headers,
|
|
10879
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
10880
|
+
};
|
|
10881
|
+
let response;
|
|
10882
|
+
try {
|
|
10883
|
+
response = await fetch(url, init);
|
|
10884
|
+
} catch {
|
|
10885
|
+
await this.delay(this.retryDelayMs);
|
|
10886
|
+
try {
|
|
10887
|
+
response = await fetch(url, init);
|
|
10888
|
+
} catch (retryErr) {
|
|
10889
|
+
throw new CloudApiError(
|
|
10890
|
+
`Network error contacting Clef Pro: ${retryErr.message}`,
|
|
10891
|
+
0,
|
|
10892
|
+
"Check your network connection and CLEF_API_URL."
|
|
10893
|
+
);
|
|
10894
|
+
}
|
|
10895
|
+
}
|
|
10896
|
+
if (response.ok) {
|
|
10897
|
+
return await response.json();
|
|
10898
|
+
}
|
|
10899
|
+
if (response.status >= 500 && response.status < 600) {
|
|
10900
|
+
await this.delay(this.retryDelayMs);
|
|
10901
|
+
const retryResponse = await fetch(url, init);
|
|
10902
|
+
if (retryResponse.ok) {
|
|
10903
|
+
return await retryResponse.json();
|
|
10904
|
+
}
|
|
10905
|
+
throw this.buildError(retryResponse);
|
|
10906
|
+
}
|
|
10907
|
+
throw this.buildError(response);
|
|
10908
|
+
}
|
|
10909
|
+
buildError(response) {
|
|
10910
|
+
const hint = response.status === 401 || response.status === 403 ? "Check your API token (--api-token or CLEF_API_TOKEN)." : response.status === 404 ? "Check your cloud.integrationId in clef.yaml." : void 0;
|
|
10911
|
+
return new CloudApiError(
|
|
10912
|
+
`Clef Pro API returned ${response.status} ${response.statusText}`,
|
|
10913
|
+
response.status,
|
|
10914
|
+
hint
|
|
10915
|
+
);
|
|
10916
|
+
}
|
|
10917
|
+
delay(ms) {
|
|
10918
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
10919
|
+
}
|
|
10920
|
+
};
|
|
10921
|
+
|
|
10922
|
+
// src/report/ci-context.ts
|
|
10923
|
+
function collectCIContext() {
|
|
10924
|
+
const env = process.env;
|
|
10925
|
+
if (env.GITHUB_ACTIONS) {
|
|
10926
|
+
const serverUrl = env.GITHUB_SERVER_URL ?? "https://github.com";
|
|
10927
|
+
const repo = env.GITHUB_REPOSITORY ?? "";
|
|
10928
|
+
const runId = env.GITHUB_RUN_ID ?? "";
|
|
10929
|
+
const pipelineUrl = repo && runId ? `${serverUrl}/${repo}/actions/runs/${runId}` : void 0;
|
|
10930
|
+
return {
|
|
10931
|
+
provider: "github-actions",
|
|
10932
|
+
pipelineUrl,
|
|
10933
|
+
trigger: env.GITHUB_EVENT_NAME
|
|
10934
|
+
};
|
|
10935
|
+
}
|
|
10936
|
+
if (env.GITLAB_CI) {
|
|
10937
|
+
return {
|
|
10938
|
+
provider: "gitlab-ci",
|
|
10939
|
+
pipelineUrl: env.CI_PIPELINE_URL,
|
|
10940
|
+
trigger: env.CI_PIPELINE_SOURCE
|
|
10941
|
+
};
|
|
10942
|
+
}
|
|
10943
|
+
if (env.CIRCLECI) {
|
|
10944
|
+
return {
|
|
10945
|
+
provider: "circleci",
|
|
10946
|
+
pipelineUrl: env.CIRCLE_BUILD_URL
|
|
10947
|
+
};
|
|
10948
|
+
}
|
|
10949
|
+
if (env.CI) {
|
|
10950
|
+
return {
|
|
10951
|
+
provider: "unknown"
|
|
10952
|
+
};
|
|
10953
|
+
}
|
|
10954
|
+
return void 0;
|
|
10955
|
+
}
|
|
10956
|
+
|
|
10572
10957
|
// src/merge/driver.ts
|
|
10573
10958
|
var SopsMergeDriver = class {
|
|
10574
10959
|
constructor(sopsClient) {
|
|
@@ -10654,10 +11039,10 @@ var SopsMergeDriver = class {
|
|
|
10654
11039
|
};
|
|
10655
11040
|
|
|
10656
11041
|
// src/service-identity/manager.ts
|
|
10657
|
-
var
|
|
11042
|
+
var fs15 = __toESM(require("fs"));
|
|
10658
11043
|
var os = __toESM(require("os"));
|
|
10659
|
-
var
|
|
10660
|
-
var
|
|
11044
|
+
var path17 = __toESM(require("path"));
|
|
11045
|
+
var YAML10 = __toESM(require("yaml"));
|
|
10661
11046
|
var PartialRotationError = class extends Error {
|
|
10662
11047
|
constructor(message, rotatedKeys) {
|
|
10663
11048
|
super(message);
|
|
@@ -10671,12 +11056,15 @@ var ServiceIdentityManager = class {
|
|
|
10671
11056
|
this.matrixManager = matrixManager;
|
|
10672
11057
|
}
|
|
10673
11058
|
/**
|
|
10674
|
-
* Create a new service identity with per-environment age key pairs.
|
|
10675
|
-
*
|
|
11059
|
+
* Create a new service identity with per-environment age key pairs or KMS envelope config.
|
|
11060
|
+
* For age-only: generates keys, updates the manifest, and registers public keys as SOPS recipients.
|
|
11061
|
+
* For KMS: stores KMS config in manifest, no age keys generated.
|
|
10676
11062
|
*
|
|
10677
|
-
* @
|
|
11063
|
+
* @param kmsEnvConfigs - Optional per-environment KMS config. When provided, those envs use
|
|
11064
|
+
* KMS envelope encryption instead of generating age keys.
|
|
11065
|
+
* @returns The created identity definition and the per-environment private keys (empty for KMS envs).
|
|
10678
11066
|
*/
|
|
10679
|
-
async create(name, namespaces, description, manifest, repoRoot) {
|
|
11067
|
+
async create(name, namespaces, description, manifest, repoRoot, kmsEnvConfigs) {
|
|
10680
11068
|
if (manifest.service_identities?.some((si) => si.name === name)) {
|
|
10681
11069
|
throw new Error(`Service identity '${name}' already exists.`);
|
|
10682
11070
|
}
|
|
@@ -10689,9 +11077,14 @@ var ServiceIdentityManager = class {
|
|
|
10689
11077
|
const environments = {};
|
|
10690
11078
|
const privateKeys = {};
|
|
10691
11079
|
for (const env of manifest.environments) {
|
|
10692
|
-
const
|
|
10693
|
-
|
|
10694
|
-
|
|
11080
|
+
const kmsConfig = kmsEnvConfigs?.[env.name];
|
|
11081
|
+
if (kmsConfig) {
|
|
11082
|
+
environments[env.name] = { kms: kmsConfig };
|
|
11083
|
+
} else {
|
|
11084
|
+
const identity = await generateAgeIdentity();
|
|
11085
|
+
environments[env.name] = { recipient: identity.publicKey };
|
|
11086
|
+
privateKeys[env.name] = identity.privateKey;
|
|
11087
|
+
}
|
|
10695
11088
|
}
|
|
10696
11089
|
const definition = {
|
|
10697
11090
|
name,
|
|
@@ -10700,9 +11093,9 @@ var ServiceIdentityManager = class {
|
|
|
10700
11093
|
environments
|
|
10701
11094
|
};
|
|
10702
11095
|
await this.registerRecipients(definition, manifest, repoRoot);
|
|
10703
|
-
const manifestPath =
|
|
10704
|
-
const raw =
|
|
10705
|
-
const doc =
|
|
11096
|
+
const manifestPath = path17.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
11097
|
+
const raw = fs15.readFileSync(manifestPath, "utf-8");
|
|
11098
|
+
const doc = YAML10.parse(raw);
|
|
10706
11099
|
if (!Array.isArray(doc.service_identities)) {
|
|
10707
11100
|
doc.service_identities = [];
|
|
10708
11101
|
}
|
|
@@ -10712,9 +11105,16 @@ var ServiceIdentityManager = class {
|
|
|
10712
11105
|
namespaces,
|
|
10713
11106
|
environments
|
|
10714
11107
|
});
|
|
10715
|
-
const tmpCreate =
|
|
10716
|
-
|
|
10717
|
-
|
|
11108
|
+
const tmpCreate = path17.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
|
|
11109
|
+
try {
|
|
11110
|
+
fs15.writeFileSync(tmpCreate, YAML10.stringify(doc), "utf-8");
|
|
11111
|
+
fs15.renameSync(tmpCreate, manifestPath);
|
|
11112
|
+
} finally {
|
|
11113
|
+
try {
|
|
11114
|
+
fs15.unlinkSync(tmpCreate);
|
|
11115
|
+
} catch {
|
|
11116
|
+
}
|
|
11117
|
+
}
|
|
10718
11118
|
return { identity: definition, privateKeys };
|
|
10719
11119
|
}
|
|
10720
11120
|
/**
|
|
@@ -10729,6 +11129,55 @@ var ServiceIdentityManager = class {
|
|
|
10729
11129
|
get(manifest, name) {
|
|
10730
11130
|
return manifest.service_identities?.find((si) => si.name === name);
|
|
10731
11131
|
}
|
|
11132
|
+
/**
|
|
11133
|
+
* Update environment backends on an existing service identity.
|
|
11134
|
+
* Switches age → KMS (removes old recipient) or updates KMS config.
|
|
11135
|
+
* Returns new private keys for any environments switched from KMS → age.
|
|
11136
|
+
*/
|
|
11137
|
+
async updateEnvironments(name, kmsEnvConfigs, manifest, repoRoot) {
|
|
11138
|
+
const identity = this.get(manifest, name);
|
|
11139
|
+
if (!identity) {
|
|
11140
|
+
throw new Error(`Service identity '${name}' not found.`);
|
|
11141
|
+
}
|
|
11142
|
+
const manifestPath = path17.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
11143
|
+
const raw = fs15.readFileSync(manifestPath, "utf-8");
|
|
11144
|
+
const doc = YAML10.parse(raw);
|
|
11145
|
+
const identities = doc.service_identities;
|
|
11146
|
+
const siDoc = identities.find((si) => si.name === name);
|
|
11147
|
+
const envs = siDoc.environments;
|
|
11148
|
+
const cells = this.matrixManager.resolveMatrix(manifest, repoRoot).filter((c) => c.exists);
|
|
11149
|
+
const privateKeys = {};
|
|
11150
|
+
for (const [envName, kmsConfig] of Object.entries(kmsEnvConfigs)) {
|
|
11151
|
+
const oldConfig = identity.environments[envName];
|
|
11152
|
+
if (!oldConfig) {
|
|
11153
|
+
throw new Error(`Environment '${envName}' not found on identity '${name}'.`);
|
|
11154
|
+
}
|
|
11155
|
+
if (oldConfig.recipient) {
|
|
11156
|
+
const scopedCells = cells.filter(
|
|
11157
|
+
(c) => identity.namespaces.includes(c.namespace) && c.environment === envName
|
|
11158
|
+
);
|
|
11159
|
+
for (const cell of scopedCells) {
|
|
11160
|
+
try {
|
|
11161
|
+
await this.encryption.removeRecipient(cell.filePath, oldConfig.recipient);
|
|
11162
|
+
} catch {
|
|
11163
|
+
}
|
|
11164
|
+
}
|
|
11165
|
+
}
|
|
11166
|
+
envs[envName] = { kms: kmsConfig };
|
|
11167
|
+
identity.environments[envName] = { kms: kmsConfig };
|
|
11168
|
+
}
|
|
11169
|
+
const tmp = path17.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
|
|
11170
|
+
try {
|
|
11171
|
+
fs15.writeFileSync(tmp, YAML10.stringify(doc), "utf-8");
|
|
11172
|
+
fs15.renameSync(tmp, manifestPath);
|
|
11173
|
+
} finally {
|
|
11174
|
+
try {
|
|
11175
|
+
fs15.unlinkSync(tmp);
|
|
11176
|
+
} catch {
|
|
11177
|
+
}
|
|
11178
|
+
}
|
|
11179
|
+
return { privateKeys };
|
|
11180
|
+
}
|
|
10732
11181
|
/**
|
|
10733
11182
|
* Register a service identity's public keys as SOPS recipients on scoped matrix files.
|
|
10734
11183
|
*/
|
|
@@ -10738,9 +11187,15 @@ var ServiceIdentityManager = class {
|
|
|
10738
11187
|
if (!identity.namespaces.includes(cell.namespace)) continue;
|
|
10739
11188
|
const envConfig = identity.environments[cell.environment];
|
|
10740
11189
|
if (!envConfig) continue;
|
|
11190
|
+
if (isKmsEnvelope(envConfig)) continue;
|
|
11191
|
+
if (!envConfig.recipient) continue;
|
|
10741
11192
|
try {
|
|
10742
11193
|
await this.encryption.addRecipient(cell.filePath, envConfig.recipient);
|
|
10743
|
-
} catch {
|
|
11194
|
+
} catch (err) {
|
|
11195
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
11196
|
+
if (!message.includes("already")) {
|
|
11197
|
+
throw err;
|
|
11198
|
+
}
|
|
10744
11199
|
}
|
|
10745
11200
|
}
|
|
10746
11201
|
}
|
|
@@ -10753,9 +11208,9 @@ var ServiceIdentityManager = class {
|
|
|
10753
11208
|
if (!identity) {
|
|
10754
11209
|
throw new Error(`Service identity '${name}' not found.`);
|
|
10755
11210
|
}
|
|
10756
|
-
const manifestPath =
|
|
10757
|
-
const raw =
|
|
10758
|
-
const doc =
|
|
11211
|
+
const manifestPath = path17.join(repoRoot, CLEF_MANIFEST_FILENAME);
|
|
11212
|
+
const raw = fs15.readFileSync(manifestPath, "utf-8");
|
|
11213
|
+
const doc = YAML10.parse(raw);
|
|
10759
11214
|
const identities = doc.service_identities;
|
|
10760
11215
|
const siDoc = identities.find((si) => si.name === name);
|
|
10761
11216
|
const envs = siDoc.environments;
|
|
@@ -10764,7 +11219,12 @@ var ServiceIdentityManager = class {
|
|
|
10764
11219
|
const cells = this.matrixManager.resolveMatrix(manifest, repoRoot).filter((c) => c.exists);
|
|
10765
11220
|
try {
|
|
10766
11221
|
for (const envName of envsToRotate) {
|
|
10767
|
-
const
|
|
11222
|
+
const envConfig = identity.environments[envName];
|
|
11223
|
+
if (!envConfig) {
|
|
11224
|
+
throw new Error(`Environment '${envName}' not found on identity '${name}'.`);
|
|
11225
|
+
}
|
|
11226
|
+
if (isKmsEnvelope(envConfig)) continue;
|
|
11227
|
+
const oldRecipient = envConfig.recipient;
|
|
10768
11228
|
if (!oldRecipient) {
|
|
10769
11229
|
throw new Error(`Environment '${envName}' not found on identity '${name}'.`);
|
|
10770
11230
|
}
|
|
@@ -10803,9 +11263,16 @@ var ServiceIdentityManager = class {
|
|
|
10803
11263
|
}
|
|
10804
11264
|
throw err;
|
|
10805
11265
|
}
|
|
10806
|
-
const tmpRotate =
|
|
10807
|
-
|
|
10808
|
-
|
|
11266
|
+
const tmpRotate = path17.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
|
|
11267
|
+
try {
|
|
11268
|
+
fs15.writeFileSync(tmpRotate, YAML10.stringify(doc), "utf-8");
|
|
11269
|
+
fs15.renameSync(tmpRotate, manifestPath);
|
|
11270
|
+
} finally {
|
|
11271
|
+
try {
|
|
11272
|
+
fs15.unlinkSync(tmpRotate);
|
|
11273
|
+
} catch {
|
|
11274
|
+
}
|
|
11275
|
+
}
|
|
10809
11276
|
return newPrivateKeys;
|
|
10810
11277
|
}
|
|
10811
11278
|
/**
|
|
@@ -10842,6 +11309,8 @@ var ServiceIdentityManager = class {
|
|
|
10842
11309
|
for (const cell of cells) {
|
|
10843
11310
|
const envConfig = si.environments[cell.environment];
|
|
10844
11311
|
if (!envConfig) continue;
|
|
11312
|
+
if (isKmsEnvelope(envConfig)) continue;
|
|
11313
|
+
if (!envConfig.recipient) continue;
|
|
10845
11314
|
if (si.namespaces.includes(cell.namespace)) {
|
|
10846
11315
|
try {
|
|
10847
11316
|
const metadata = await this.encryption.getMetadata(cell.filePath);
|
|
@@ -10915,18 +11384,20 @@ async function resolveIdentitySecrets(identityName, environment, manifest, repoR
|
|
|
10915
11384
|
return {
|
|
10916
11385
|
values: allValues,
|
|
10917
11386
|
identity,
|
|
10918
|
-
recipient: envConfig.recipient
|
|
11387
|
+
recipient: envConfig.recipient,
|
|
11388
|
+
envConfig
|
|
10919
11389
|
};
|
|
10920
11390
|
}
|
|
10921
11391
|
|
|
10922
11392
|
// src/artifact/packer.ts
|
|
10923
|
-
var
|
|
10924
|
-
var
|
|
11393
|
+
var fs16 = __toESM(require("fs"));
|
|
11394
|
+
var path18 = __toESM(require("path"));
|
|
10925
11395
|
var crypto3 = __toESM(require("crypto"));
|
|
10926
11396
|
var ArtifactPacker = class {
|
|
10927
|
-
constructor(encryption, matrixManager) {
|
|
11397
|
+
constructor(encryption, matrixManager, kms) {
|
|
10928
11398
|
this.encryption = encryption;
|
|
10929
11399
|
this.matrixManager = matrixManager;
|
|
11400
|
+
this.kms = kms;
|
|
10930
11401
|
}
|
|
10931
11402
|
/**
|
|
10932
11403
|
* Pack an artifact: decrypt scoped SOPS files, age-encrypt the merged
|
|
@@ -10943,38 +11414,82 @@ var ArtifactPacker = class {
|
|
|
10943
11414
|
);
|
|
10944
11415
|
const plaintext = JSON.stringify(resolved.values);
|
|
10945
11416
|
let ciphertext;
|
|
10946
|
-
|
|
10947
|
-
|
|
10948
|
-
|
|
10949
|
-
|
|
10950
|
-
|
|
10951
|
-
|
|
10952
|
-
|
|
11417
|
+
let artifact;
|
|
11418
|
+
if (isKmsEnvelope(resolved.envConfig)) {
|
|
11419
|
+
if (!this.kms) {
|
|
11420
|
+
throw new Error("KMS provider required for envelope encryption but none was provided.");
|
|
11421
|
+
}
|
|
11422
|
+
const { generateIdentity, identityToRecipient, Encrypter } = await Promise.resolve().then(() => __toESM(require_age_encryption()));
|
|
11423
|
+
const ephemeralPrivateKey = await generateIdentity();
|
|
11424
|
+
const ephemeralPublicKey = await identityToRecipient(ephemeralPrivateKey);
|
|
11425
|
+
try {
|
|
11426
|
+
const e = new Encrypter();
|
|
11427
|
+
e.addRecipient(ephemeralPublicKey);
|
|
11428
|
+
const encrypted = await e.encrypt(plaintext);
|
|
11429
|
+
ciphertext = typeof encrypted === "string" ? encrypted : Buffer.from(encrypted).toString("base64");
|
|
11430
|
+
} catch {
|
|
11431
|
+
throw new Error("Failed to age-encrypt artifact with ephemeral key.");
|
|
11432
|
+
}
|
|
11433
|
+
const kmsConfig = resolved.envConfig.kms;
|
|
11434
|
+
const wrapped = await this.kms.wrap(kmsConfig.keyId, Buffer.from(ephemeralPrivateKey));
|
|
11435
|
+
const revision = `${Date.now()}-${crypto3.randomBytes(4).toString("hex")}`;
|
|
11436
|
+
const ciphertextHash = crypto3.createHash("sha256").update(ciphertext).digest("hex");
|
|
11437
|
+
artifact = {
|
|
11438
|
+
version: 1,
|
|
11439
|
+
identity: config.identity,
|
|
11440
|
+
environment: config.environment,
|
|
11441
|
+
packedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11442
|
+
revision,
|
|
11443
|
+
ciphertextHash,
|
|
11444
|
+
ciphertext,
|
|
11445
|
+
keys: Object.keys(resolved.values),
|
|
11446
|
+
envelope: {
|
|
11447
|
+
provider: kmsConfig.provider,
|
|
11448
|
+
keyId: kmsConfig.keyId,
|
|
11449
|
+
wrappedKey: wrapped.wrappedKey.toString("base64"),
|
|
11450
|
+
algorithm: wrapped.algorithm
|
|
11451
|
+
}
|
|
11452
|
+
};
|
|
11453
|
+
} else {
|
|
11454
|
+
try {
|
|
11455
|
+
const { Encrypter } = await Promise.resolve().then(() => __toESM(require_age_encryption()));
|
|
11456
|
+
const e = new Encrypter();
|
|
11457
|
+
e.addRecipient(resolved.recipient);
|
|
11458
|
+
const encrypted = await e.encrypt(plaintext);
|
|
11459
|
+
ciphertext = typeof encrypted === "string" ? encrypted : Buffer.from(encrypted).toString("base64");
|
|
11460
|
+
} catch {
|
|
11461
|
+
throw new Error("Failed to age-encrypt artifact. Check recipient key.");
|
|
11462
|
+
}
|
|
11463
|
+
const revision = `${Date.now()}-${crypto3.randomBytes(4).toString("hex")}`;
|
|
11464
|
+
const ciphertextHash = crypto3.createHash("sha256").update(ciphertext).digest("hex");
|
|
11465
|
+
artifact = {
|
|
11466
|
+
version: 1,
|
|
11467
|
+
identity: config.identity,
|
|
11468
|
+
environment: config.environment,
|
|
11469
|
+
packedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
11470
|
+
revision,
|
|
11471
|
+
ciphertextHash,
|
|
11472
|
+
ciphertext,
|
|
11473
|
+
keys: Object.keys(resolved.values)
|
|
11474
|
+
};
|
|
10953
11475
|
}
|
|
10954
|
-
const
|
|
10955
|
-
|
|
10956
|
-
|
|
10957
|
-
|
|
10958
|
-
|
|
10959
|
-
|
|
10960
|
-
packedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
10961
|
-
revision,
|
|
10962
|
-
ciphertextHash,
|
|
10963
|
-
ciphertext,
|
|
10964
|
-
keys: Object.keys(resolved.values)
|
|
10965
|
-
};
|
|
10966
|
-
const outputDir = path17.dirname(config.outputPath);
|
|
10967
|
-
if (!fs15.existsSync(outputDir)) {
|
|
10968
|
-
fs15.mkdirSync(outputDir, { recursive: true });
|
|
11476
|
+
const outputDir = path18.dirname(config.outputPath);
|
|
11477
|
+
if (!fs16.existsSync(outputDir)) {
|
|
11478
|
+
fs16.mkdirSync(outputDir, { recursive: true });
|
|
11479
|
+
}
|
|
11480
|
+
if (config.ttl && config.ttl > 0) {
|
|
11481
|
+
artifact.expiresAt = new Date(Date.now() + config.ttl * 1e3).toISOString();
|
|
10969
11482
|
}
|
|
10970
11483
|
const json = JSON.stringify(artifact, null, 2);
|
|
10971
|
-
|
|
11484
|
+
const tmpOutput = `${config.outputPath}.tmp.${process.pid}`;
|
|
11485
|
+
fs16.writeFileSync(tmpOutput, json, "utf-8");
|
|
11486
|
+
fs16.renameSync(tmpOutput, config.outputPath);
|
|
10972
11487
|
return {
|
|
10973
11488
|
outputPath: config.outputPath,
|
|
10974
11489
|
namespaceCount: resolved.identity.namespaces.length,
|
|
10975
11490
|
keyCount: Object.keys(resolved.values).length,
|
|
10976
11491
|
artifactSize: Buffer.byteLength(json, "utf-8"),
|
|
10977
|
-
revision
|
|
11492
|
+
revision: artifact.revision
|
|
10978
11493
|
};
|
|
10979
11494
|
}
|
|
10980
11495
|
};
|
|
@@ -10986,6 +11501,8 @@ var ArtifactPacker = class {
|
|
|
10986
11501
|
CLEF_REPORT_SCHEMA_VERSION,
|
|
10987
11502
|
CLEF_SUPPORTED_EXTENSIONS,
|
|
10988
11503
|
ClefError,
|
|
11504
|
+
CloudApiError,
|
|
11505
|
+
CloudClient,
|
|
10989
11506
|
ConsumptionClient,
|
|
10990
11507
|
DiffEngine,
|
|
10991
11508
|
DriftDetector,
|
|
@@ -10997,10 +11514,12 @@ var ArtifactPacker = class {
|
|
|
10997
11514
|
ManifestValidationError,
|
|
10998
11515
|
MatrixManager,
|
|
10999
11516
|
PartialRotationError,
|
|
11517
|
+
REQUESTS_FILENAME,
|
|
11000
11518
|
REQUIREMENTS,
|
|
11001
11519
|
RecipientManager,
|
|
11002
11520
|
ReportGenerator,
|
|
11003
11521
|
ReportSanitizer,
|
|
11522
|
+
ReportTransformer,
|
|
11004
11523
|
ScanRunner,
|
|
11005
11524
|
SchemaLoadError,
|
|
11006
11525
|
SchemaValidator,
|
|
@@ -11015,17 +11534,21 @@ var ArtifactPacker = class {
|
|
|
11015
11534
|
assertSops,
|
|
11016
11535
|
checkAll,
|
|
11017
11536
|
checkDependency,
|
|
11537
|
+
collectCIContext,
|
|
11018
11538
|
deriveAgePublicKey,
|
|
11019
11539
|
detectFormat,
|
|
11540
|
+
findRequest,
|
|
11020
11541
|
formatAgeKeyFile,
|
|
11021
11542
|
generateAgeIdentity,
|
|
11022
11543
|
generateRandomValue,
|
|
11023
11544
|
getPendingKeys,
|
|
11024
11545
|
isHighEntropy,
|
|
11546
|
+
isKmsEnvelope,
|
|
11025
11547
|
isPending,
|
|
11026
11548
|
keyPreview,
|
|
11027
11549
|
loadIgnoreRules,
|
|
11028
11550
|
loadMetadata,
|
|
11551
|
+
loadRequests,
|
|
11029
11552
|
markPending,
|
|
11030
11553
|
markPendingWithRetry,
|
|
11031
11554
|
markResolved,
|
|
@@ -11037,15 +11560,19 @@ var ArtifactPacker = class {
|
|
|
11037
11560
|
parseJson,
|
|
11038
11561
|
parseYaml,
|
|
11039
11562
|
redactValue,
|
|
11563
|
+
removeAccessRequest,
|
|
11564
|
+
requestsFilePath,
|
|
11040
11565
|
resetSopsResolution,
|
|
11041
11566
|
resolveBackendConfig,
|
|
11042
11567
|
resolveIdentitySecrets,
|
|
11043
11568
|
resolveRecipientsForEnvironment,
|
|
11044
11569
|
resolveSopsPath,
|
|
11045
11570
|
saveMetadata,
|
|
11571
|
+
saveRequests,
|
|
11046
11572
|
shannonEntropy,
|
|
11047
11573
|
shouldIgnoreFile,
|
|
11048
11574
|
shouldIgnoreMatch,
|
|
11575
|
+
upsertRequest,
|
|
11049
11576
|
validateAgePublicKey
|
|
11050
11577
|
});
|
|
11051
11578
|
/*! Bundled license information:
|