@clef-sh/core 0.1.28 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- package/dist/artifact/packer.d.ts +4 -3
- package/dist/artifact/packer.d.ts.map +1 -1
- package/dist/artifact/resolve.d.ts +3 -2
- package/dist/artifact/resolve.d.ts.map +1 -1
- package/dist/compliance/run.d.ts.map +1 -1
- package/dist/diff/engine.d.ts +18 -8
- package/dist/diff/engine.d.ts.map +1 -1
- package/dist/import/index.d.ts +5 -5
- package/dist/import/index.d.ts.map +1 -1
- package/dist/index.d.mts +13 -10
- package/dist/index.d.ts +13 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1080 -832
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +1049 -791
- package/dist/index.mjs.map +4 -4
- package/dist/lint/runner.d.ts +7 -7
- package/dist/lint/runner.d.ts.map +1 -1
- package/dist/matrix/manager.d.ts +4 -16
- package/dist/matrix/manager.d.ts.map +1 -1
- package/dist/merge/driver.d.ts +2 -2
- package/dist/merge/driver.d.ts.map +1 -1
- package/dist/merge/metadata-driver.d.ts +5 -4
- package/dist/merge/metadata-driver.d.ts.map +1 -1
- package/dist/migration/backend.d.ts +10 -7
- package/dist/migration/backend.d.ts.map +1 -1
- package/dist/pack/backends/json-envelope.d.ts.map +1 -1
- package/dist/pack/types.d.ts +9 -3
- package/dist/pack/types.d.ts.map +1 -1
- package/dist/pending/metadata.d.ts +1 -3
- package/dist/pending/metadata.d.ts.map +1 -1
- package/dist/recipients/index.d.ts +4 -3
- package/dist/recipients/index.d.ts.map +1 -1
- package/dist/report/generator.d.ts +4 -3
- package/dist/report/generator.d.ts.map +1 -1
- package/dist/reset/manager.d.ts +21 -3
- package/dist/reset/manager.d.ts.map +1 -1
- package/dist/service-identity/manager.d.ts +6 -3
- package/dist/service-identity/manager.d.ts.map +1 -1
- package/dist/sops/client.d.ts +80 -55
- package/dist/sops/client.d.ts.map +1 -1
- package/dist/sops/linux-stdin-fifo.d.ts +31 -0
- package/dist/sops/linux-stdin-fifo.d.ts.map +1 -0
- package/dist/source/compose.d.ts +10 -0
- package/dist/source/compose.d.ts.map +1 -0
- package/dist/source/default-bulk.d.ts +12 -0
- package/dist/source/default-bulk.d.ts.map +1 -0
- package/dist/source/encryption-backend.d.ts +85 -0
- package/dist/source/encryption-backend.d.ts.map +1 -0
- package/dist/source/errors.d.ts +19 -0
- package/dist/source/errors.d.ts.map +1 -0
- package/dist/source/filesystem-storage-backend.d.ts +26 -0
- package/dist/source/filesystem-storage-backend.d.ts.map +1 -0
- package/dist/source/guards.d.ts +14 -0
- package/dist/source/guards.d.ts.map +1 -0
- package/dist/source/index.d.ts +10 -0
- package/dist/source/index.d.ts.map +1 -0
- package/dist/source/mock-source.d.ts +89 -0
- package/dist/source/mock-source.d.ts.map +1 -0
- package/dist/source/storage-backend.d.ts +61 -0
- package/dist/source/storage-backend.d.ts.map +1 -0
- package/dist/source/types.d.ts +212 -0
- package/dist/source/types.d.ts.map +1 -0
- package/dist/structure/manager.d.ts +17 -3
- package/dist/structure/manager.d.ts.map +1 -1
- package/dist/sync/manager.d.ts +7 -6
- package/dist/sync/manager.d.ts.map +1 -1
- package/dist/types/index.d.ts +10 -23
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/bulk/ops.d.ts +0 -57
- package/dist/bulk/ops.d.ts.map +0 -1
package/dist/index.mjs
CHANGED
|
@@ -306,13 +306,13 @@ var require_lib = __commonJS({
|
|
|
306
306
|
"../../node_modules/write-file-atomic/lib/index.js"(exports, module) {
|
|
307
307
|
"use strict";
|
|
308
308
|
module.exports = writeFile;
|
|
309
|
-
module.exports.sync =
|
|
309
|
+
module.exports.sync = writeFileSync8;
|
|
310
310
|
module.exports._getTmpname = getTmpname;
|
|
311
311
|
module.exports._cleanupOnExit = cleanupOnExit;
|
|
312
|
-
var
|
|
312
|
+
var fs23 = __require("fs");
|
|
313
313
|
var crypto6 = __require("node:crypto");
|
|
314
314
|
var { onExit } = require_cjs();
|
|
315
|
-
var
|
|
315
|
+
var path28 = __require("path");
|
|
316
316
|
var { promisify } = __require("util");
|
|
317
317
|
var activeFiles = {};
|
|
318
318
|
var threadId = (function getId() {
|
|
@@ -330,7 +330,7 @@ var require_lib = __commonJS({
|
|
|
330
330
|
function cleanupOnExit(tmpfile) {
|
|
331
331
|
return () => {
|
|
332
332
|
try {
|
|
333
|
-
|
|
333
|
+
fs23.unlinkSync(typeof tmpfile === "function" ? tmpfile() : tmpfile);
|
|
334
334
|
} catch {
|
|
335
335
|
}
|
|
336
336
|
};
|
|
@@ -365,13 +365,13 @@ var require_lib = __commonJS({
|
|
|
365
365
|
let fd;
|
|
366
366
|
let tmpfile;
|
|
367
367
|
const removeOnExitHandler = onExit(cleanupOnExit(() => tmpfile));
|
|
368
|
-
const absoluteName =
|
|
368
|
+
const absoluteName = path28.resolve(filename);
|
|
369
369
|
try {
|
|
370
370
|
await serializeActiveFile(absoluteName);
|
|
371
|
-
const truename = await promisify(
|
|
371
|
+
const truename = await promisify(fs23.realpath)(filename).catch(() => filename);
|
|
372
372
|
tmpfile = getTmpname(truename);
|
|
373
373
|
if (!options.mode || !options.chown) {
|
|
374
|
-
const stats = await promisify(
|
|
374
|
+
const stats = await promisify(fs23.stat)(truename).catch(() => {
|
|
375
375
|
});
|
|
376
376
|
if (stats) {
|
|
377
377
|
if (options.mode == null) {
|
|
@@ -382,45 +382,45 @@ var require_lib = __commonJS({
|
|
|
382
382
|
}
|
|
383
383
|
}
|
|
384
384
|
}
|
|
385
|
-
fd = await promisify(
|
|
385
|
+
fd = await promisify(fs23.open)(tmpfile, "w", options.mode);
|
|
386
386
|
if (options.tmpfileCreated) {
|
|
387
387
|
await options.tmpfileCreated(tmpfile);
|
|
388
388
|
}
|
|
389
389
|
if (ArrayBuffer.isView(data)) {
|
|
390
|
-
await promisify(
|
|
390
|
+
await promisify(fs23.write)(fd, data, 0, data.length, 0);
|
|
391
391
|
} else if (data != null) {
|
|
392
|
-
await promisify(
|
|
392
|
+
await promisify(fs23.write)(fd, String(data), 0, String(options.encoding || "utf8"));
|
|
393
393
|
}
|
|
394
394
|
if (options.fsync !== false) {
|
|
395
|
-
await promisify(
|
|
395
|
+
await promisify(fs23.fsync)(fd);
|
|
396
396
|
}
|
|
397
|
-
await promisify(
|
|
397
|
+
await promisify(fs23.close)(fd);
|
|
398
398
|
fd = null;
|
|
399
399
|
if (options.chown) {
|
|
400
|
-
await promisify(
|
|
400
|
+
await promisify(fs23.chown)(tmpfile, options.chown.uid, options.chown.gid).catch((err) => {
|
|
401
401
|
if (!isChownErrOk(err)) {
|
|
402
402
|
throw err;
|
|
403
403
|
}
|
|
404
404
|
});
|
|
405
405
|
}
|
|
406
406
|
if (options.mode) {
|
|
407
|
-
await promisify(
|
|
407
|
+
await promisify(fs23.chmod)(tmpfile, options.mode).catch((err) => {
|
|
408
408
|
if (!isChownErrOk(err)) {
|
|
409
409
|
throw err;
|
|
410
410
|
}
|
|
411
411
|
});
|
|
412
412
|
}
|
|
413
|
-
await promisify(
|
|
413
|
+
await promisify(fs23.rename)(tmpfile, truename);
|
|
414
414
|
} finally {
|
|
415
415
|
if (fd) {
|
|
416
|
-
await promisify(
|
|
416
|
+
await promisify(fs23.close)(fd).catch(
|
|
417
417
|
/* istanbul ignore next */
|
|
418
418
|
() => {
|
|
419
419
|
}
|
|
420
420
|
);
|
|
421
421
|
}
|
|
422
422
|
removeOnExitHandler();
|
|
423
|
-
await promisify(
|
|
423
|
+
await promisify(fs23.unlink)(tmpfile).catch(() => {
|
|
424
424
|
});
|
|
425
425
|
activeFiles[absoluteName].shift();
|
|
426
426
|
if (activeFiles[absoluteName].length > 0) {
|
|
@@ -446,20 +446,20 @@ var require_lib = __commonJS({
|
|
|
446
446
|
}
|
|
447
447
|
return promise;
|
|
448
448
|
}
|
|
449
|
-
function
|
|
449
|
+
function writeFileSync8(filename, data, options) {
|
|
450
450
|
if (typeof options === "string") {
|
|
451
451
|
options = { encoding: options };
|
|
452
452
|
} else if (!options) {
|
|
453
453
|
options = {};
|
|
454
454
|
}
|
|
455
455
|
try {
|
|
456
|
-
filename =
|
|
456
|
+
filename = fs23.realpathSync(filename);
|
|
457
457
|
} catch (ex) {
|
|
458
458
|
}
|
|
459
459
|
const tmpfile = getTmpname(filename);
|
|
460
460
|
if (!options.mode || !options.chown) {
|
|
461
461
|
try {
|
|
462
|
-
const stats =
|
|
462
|
+
const stats = fs23.statSync(filename);
|
|
463
463
|
options = Object.assign({}, options);
|
|
464
464
|
if (!options.mode) {
|
|
465
465
|
options.mode = stats.mode;
|
|
@@ -475,23 +475,23 @@ var require_lib = __commonJS({
|
|
|
475
475
|
const removeOnExitHandler = onExit(cleanup);
|
|
476
476
|
let threw = true;
|
|
477
477
|
try {
|
|
478
|
-
fd =
|
|
478
|
+
fd = fs23.openSync(tmpfile, "w", options.mode || 438);
|
|
479
479
|
if (options.tmpfileCreated) {
|
|
480
480
|
options.tmpfileCreated(tmpfile);
|
|
481
481
|
}
|
|
482
482
|
if (ArrayBuffer.isView(data)) {
|
|
483
|
-
|
|
483
|
+
fs23.writeSync(fd, data, 0, data.length, 0);
|
|
484
484
|
} else if (data != null) {
|
|
485
|
-
|
|
485
|
+
fs23.writeSync(fd, String(data), 0, String(options.encoding || "utf8"));
|
|
486
486
|
}
|
|
487
487
|
if (options.fsync !== false) {
|
|
488
|
-
|
|
488
|
+
fs23.fsyncSync(fd);
|
|
489
489
|
}
|
|
490
|
-
|
|
490
|
+
fs23.closeSync(fd);
|
|
491
491
|
fd = null;
|
|
492
492
|
if (options.chown) {
|
|
493
493
|
try {
|
|
494
|
-
|
|
494
|
+
fs23.chownSync(tmpfile, options.chown.uid, options.chown.gid);
|
|
495
495
|
} catch (err) {
|
|
496
496
|
if (!isChownErrOk(err)) {
|
|
497
497
|
throw err;
|
|
@@ -500,19 +500,19 @@ var require_lib = __commonJS({
|
|
|
500
500
|
}
|
|
501
501
|
if (options.mode) {
|
|
502
502
|
try {
|
|
503
|
-
|
|
503
|
+
fs23.chmodSync(tmpfile, options.mode);
|
|
504
504
|
} catch (err) {
|
|
505
505
|
if (!isChownErrOk(err)) {
|
|
506
506
|
throw err;
|
|
507
507
|
}
|
|
508
508
|
}
|
|
509
509
|
}
|
|
510
|
-
|
|
510
|
+
fs23.renameSync(tmpfile, filename);
|
|
511
511
|
threw = false;
|
|
512
512
|
} finally {
|
|
513
513
|
if (fd) {
|
|
514
514
|
try {
|
|
515
|
-
|
|
515
|
+
fs23.closeSync(fd);
|
|
516
516
|
} catch (ex) {
|
|
517
517
|
}
|
|
518
518
|
}
|
|
@@ -551,54 +551,54 @@ var require_polyfills = __commonJS({
|
|
|
551
551
|
}
|
|
552
552
|
var chdir;
|
|
553
553
|
module.exports = patch;
|
|
554
|
-
function patch(
|
|
554
|
+
function patch(fs23) {
|
|
555
555
|
if (constants.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
|
|
556
|
-
patchLchmod(
|
|
557
|
-
}
|
|
558
|
-
if (!
|
|
559
|
-
patchLutimes(
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
if (
|
|
580
|
-
|
|
556
|
+
patchLchmod(fs23);
|
|
557
|
+
}
|
|
558
|
+
if (!fs23.lutimes) {
|
|
559
|
+
patchLutimes(fs23);
|
|
560
|
+
}
|
|
561
|
+
fs23.chown = chownFix(fs23.chown);
|
|
562
|
+
fs23.fchown = chownFix(fs23.fchown);
|
|
563
|
+
fs23.lchown = chownFix(fs23.lchown);
|
|
564
|
+
fs23.chmod = chmodFix(fs23.chmod);
|
|
565
|
+
fs23.fchmod = chmodFix(fs23.fchmod);
|
|
566
|
+
fs23.lchmod = chmodFix(fs23.lchmod);
|
|
567
|
+
fs23.chownSync = chownFixSync(fs23.chownSync);
|
|
568
|
+
fs23.fchownSync = chownFixSync(fs23.fchownSync);
|
|
569
|
+
fs23.lchownSync = chownFixSync(fs23.lchownSync);
|
|
570
|
+
fs23.chmodSync = chmodFixSync(fs23.chmodSync);
|
|
571
|
+
fs23.fchmodSync = chmodFixSync(fs23.fchmodSync);
|
|
572
|
+
fs23.lchmodSync = chmodFixSync(fs23.lchmodSync);
|
|
573
|
+
fs23.stat = statFix(fs23.stat);
|
|
574
|
+
fs23.fstat = statFix(fs23.fstat);
|
|
575
|
+
fs23.lstat = statFix(fs23.lstat);
|
|
576
|
+
fs23.statSync = statFixSync(fs23.statSync);
|
|
577
|
+
fs23.fstatSync = statFixSync(fs23.fstatSync);
|
|
578
|
+
fs23.lstatSync = statFixSync(fs23.lstatSync);
|
|
579
|
+
if (fs23.chmod && !fs23.lchmod) {
|
|
580
|
+
fs23.lchmod = function(path28, mode, cb) {
|
|
581
581
|
if (cb) process.nextTick(cb);
|
|
582
582
|
};
|
|
583
|
-
|
|
583
|
+
fs23.lchmodSync = function() {
|
|
584
584
|
};
|
|
585
585
|
}
|
|
586
|
-
if (
|
|
587
|
-
|
|
586
|
+
if (fs23.chown && !fs23.lchown) {
|
|
587
|
+
fs23.lchown = function(path28, uid, gid, cb) {
|
|
588
588
|
if (cb) process.nextTick(cb);
|
|
589
589
|
};
|
|
590
|
-
|
|
590
|
+
fs23.lchownSync = function() {
|
|
591
591
|
};
|
|
592
592
|
}
|
|
593
593
|
if (platform === "win32") {
|
|
594
|
-
|
|
594
|
+
fs23.rename = typeof fs23.rename !== "function" ? fs23.rename : (function(fs$rename) {
|
|
595
595
|
function rename(from, to, cb) {
|
|
596
596
|
var start = Date.now();
|
|
597
597
|
var backoff = 0;
|
|
598
598
|
fs$rename(from, to, function CB(er) {
|
|
599
599
|
if (er && (er.code === "EACCES" || er.code === "EPERM" || er.code === "EBUSY") && Date.now() - start < 6e4) {
|
|
600
600
|
setTimeout(function() {
|
|
601
|
-
|
|
601
|
+
fs23.stat(to, function(stater, st) {
|
|
602
602
|
if (stater && stater.code === "ENOENT")
|
|
603
603
|
fs$rename(from, to, CB);
|
|
604
604
|
else
|
|
@@ -614,9 +614,9 @@ var require_polyfills = __commonJS({
|
|
|
614
614
|
}
|
|
615
615
|
if (Object.setPrototypeOf) Object.setPrototypeOf(rename, fs$rename);
|
|
616
616
|
return rename;
|
|
617
|
-
})(
|
|
617
|
+
})(fs23.rename);
|
|
618
618
|
}
|
|
619
|
-
|
|
619
|
+
fs23.read = typeof fs23.read !== "function" ? fs23.read : (function(fs$read) {
|
|
620
620
|
function read(fd, buffer, offset, length, position, callback_) {
|
|
621
621
|
var callback;
|
|
622
622
|
if (callback_ && typeof callback_ === "function") {
|
|
@@ -624,22 +624,22 @@ var require_polyfills = __commonJS({
|
|
|
624
624
|
callback = function(er, _, __) {
|
|
625
625
|
if (er && er.code === "EAGAIN" && eagCounter < 10) {
|
|
626
626
|
eagCounter++;
|
|
627
|
-
return fs$read.call(
|
|
627
|
+
return fs$read.call(fs23, fd, buffer, offset, length, position, callback);
|
|
628
628
|
}
|
|
629
629
|
callback_.apply(this, arguments);
|
|
630
630
|
};
|
|
631
631
|
}
|
|
632
|
-
return fs$read.call(
|
|
632
|
+
return fs$read.call(fs23, fd, buffer, offset, length, position, callback);
|
|
633
633
|
}
|
|
634
634
|
if (Object.setPrototypeOf) Object.setPrototypeOf(read, fs$read);
|
|
635
635
|
return read;
|
|
636
|
-
})(
|
|
637
|
-
|
|
636
|
+
})(fs23.read);
|
|
637
|
+
fs23.readSync = typeof fs23.readSync !== "function" ? fs23.readSync : /* @__PURE__ */ (function(fs$readSync) {
|
|
638
638
|
return function(fd, buffer, offset, length, position) {
|
|
639
639
|
var eagCounter = 0;
|
|
640
640
|
while (true) {
|
|
641
641
|
try {
|
|
642
|
-
return fs$readSync.call(
|
|
642
|
+
return fs$readSync.call(fs23, fd, buffer, offset, length, position);
|
|
643
643
|
} catch (er) {
|
|
644
644
|
if (er.code === "EAGAIN" && eagCounter < 10) {
|
|
645
645
|
eagCounter++;
|
|
@@ -649,11 +649,11 @@ var require_polyfills = __commonJS({
|
|
|
649
649
|
}
|
|
650
650
|
}
|
|
651
651
|
};
|
|
652
|
-
})(
|
|
653
|
-
function patchLchmod(
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
652
|
+
})(fs23.readSync);
|
|
653
|
+
function patchLchmod(fs24) {
|
|
654
|
+
fs24.lchmod = function(path28, mode, callback) {
|
|
655
|
+
fs24.open(
|
|
656
|
+
path28,
|
|
657
657
|
constants.O_WRONLY | constants.O_SYMLINK,
|
|
658
658
|
mode,
|
|
659
659
|
function(err, fd) {
|
|
@@ -661,80 +661,80 @@ var require_polyfills = __commonJS({
|
|
|
661
661
|
if (callback) callback(err);
|
|
662
662
|
return;
|
|
663
663
|
}
|
|
664
|
-
|
|
665
|
-
|
|
664
|
+
fs24.fchmod(fd, mode, function(err2) {
|
|
665
|
+
fs24.close(fd, function(err22) {
|
|
666
666
|
if (callback) callback(err2 || err22);
|
|
667
667
|
});
|
|
668
668
|
});
|
|
669
669
|
}
|
|
670
670
|
);
|
|
671
671
|
};
|
|
672
|
-
|
|
673
|
-
var fd =
|
|
672
|
+
fs24.lchmodSync = function(path28, mode) {
|
|
673
|
+
var fd = fs24.openSync(path28, constants.O_WRONLY | constants.O_SYMLINK, mode);
|
|
674
674
|
var threw = true;
|
|
675
675
|
var ret;
|
|
676
676
|
try {
|
|
677
|
-
ret =
|
|
677
|
+
ret = fs24.fchmodSync(fd, mode);
|
|
678
678
|
threw = false;
|
|
679
679
|
} finally {
|
|
680
680
|
if (threw) {
|
|
681
681
|
try {
|
|
682
|
-
|
|
682
|
+
fs24.closeSync(fd);
|
|
683
683
|
} catch (er) {
|
|
684
684
|
}
|
|
685
685
|
} else {
|
|
686
|
-
|
|
686
|
+
fs24.closeSync(fd);
|
|
687
687
|
}
|
|
688
688
|
}
|
|
689
689
|
return ret;
|
|
690
690
|
};
|
|
691
691
|
}
|
|
692
|
-
function patchLutimes(
|
|
693
|
-
if (constants.hasOwnProperty("O_SYMLINK") &&
|
|
694
|
-
|
|
695
|
-
|
|
692
|
+
function patchLutimes(fs24) {
|
|
693
|
+
if (constants.hasOwnProperty("O_SYMLINK") && fs24.futimes) {
|
|
694
|
+
fs24.lutimes = function(path28, at, mt, cb) {
|
|
695
|
+
fs24.open(path28, constants.O_SYMLINK, function(er, fd) {
|
|
696
696
|
if (er) {
|
|
697
697
|
if (cb) cb(er);
|
|
698
698
|
return;
|
|
699
699
|
}
|
|
700
|
-
|
|
701
|
-
|
|
700
|
+
fs24.futimes(fd, at, mt, function(er2) {
|
|
701
|
+
fs24.close(fd, function(er22) {
|
|
702
702
|
if (cb) cb(er2 || er22);
|
|
703
703
|
});
|
|
704
704
|
});
|
|
705
705
|
});
|
|
706
706
|
};
|
|
707
|
-
|
|
708
|
-
var fd =
|
|
707
|
+
fs24.lutimesSync = function(path28, at, mt) {
|
|
708
|
+
var fd = fs24.openSync(path28, constants.O_SYMLINK);
|
|
709
709
|
var ret;
|
|
710
710
|
var threw = true;
|
|
711
711
|
try {
|
|
712
|
-
ret =
|
|
712
|
+
ret = fs24.futimesSync(fd, at, mt);
|
|
713
713
|
threw = false;
|
|
714
714
|
} finally {
|
|
715
715
|
if (threw) {
|
|
716
716
|
try {
|
|
717
|
-
|
|
717
|
+
fs24.closeSync(fd);
|
|
718
718
|
} catch (er) {
|
|
719
719
|
}
|
|
720
720
|
} else {
|
|
721
|
-
|
|
721
|
+
fs24.closeSync(fd);
|
|
722
722
|
}
|
|
723
723
|
}
|
|
724
724
|
return ret;
|
|
725
725
|
};
|
|
726
|
-
} else if (
|
|
727
|
-
|
|
726
|
+
} else if (fs24.futimes) {
|
|
727
|
+
fs24.lutimes = function(_a, _b, _c, cb) {
|
|
728
728
|
if (cb) process.nextTick(cb);
|
|
729
729
|
};
|
|
730
|
-
|
|
730
|
+
fs24.lutimesSync = function() {
|
|
731
731
|
};
|
|
732
732
|
}
|
|
733
733
|
}
|
|
734
734
|
function chmodFix(orig) {
|
|
735
735
|
if (!orig) return orig;
|
|
736
736
|
return function(target, mode, cb) {
|
|
737
|
-
return orig.call(
|
|
737
|
+
return orig.call(fs23, target, mode, function(er) {
|
|
738
738
|
if (chownErOk(er)) er = null;
|
|
739
739
|
if (cb) cb.apply(this, arguments);
|
|
740
740
|
});
|
|
@@ -744,7 +744,7 @@ var require_polyfills = __commonJS({
|
|
|
744
744
|
if (!orig) return orig;
|
|
745
745
|
return function(target, mode) {
|
|
746
746
|
try {
|
|
747
|
-
return orig.call(
|
|
747
|
+
return orig.call(fs23, target, mode);
|
|
748
748
|
} catch (er) {
|
|
749
749
|
if (!chownErOk(er)) throw er;
|
|
750
750
|
}
|
|
@@ -753,7 +753,7 @@ var require_polyfills = __commonJS({
|
|
|
753
753
|
function chownFix(orig) {
|
|
754
754
|
if (!orig) return orig;
|
|
755
755
|
return function(target, uid, gid, cb) {
|
|
756
|
-
return orig.call(
|
|
756
|
+
return orig.call(fs23, target, uid, gid, function(er) {
|
|
757
757
|
if (chownErOk(er)) er = null;
|
|
758
758
|
if (cb) cb.apply(this, arguments);
|
|
759
759
|
});
|
|
@@ -763,7 +763,7 @@ var require_polyfills = __commonJS({
|
|
|
763
763
|
if (!orig) return orig;
|
|
764
764
|
return function(target, uid, gid) {
|
|
765
765
|
try {
|
|
766
|
-
return orig.call(
|
|
766
|
+
return orig.call(fs23, target, uid, gid);
|
|
767
767
|
} catch (er) {
|
|
768
768
|
if (!chownErOk(er)) throw er;
|
|
769
769
|
}
|
|
@@ -783,13 +783,13 @@ var require_polyfills = __commonJS({
|
|
|
783
783
|
}
|
|
784
784
|
if (cb) cb.apply(this, arguments);
|
|
785
785
|
}
|
|
786
|
-
return options ? orig.call(
|
|
786
|
+
return options ? orig.call(fs23, target, options, callback) : orig.call(fs23, target, callback);
|
|
787
787
|
};
|
|
788
788
|
}
|
|
789
789
|
function statFixSync(orig) {
|
|
790
790
|
if (!orig) return orig;
|
|
791
791
|
return function(target, options) {
|
|
792
|
-
var stats = options ? orig.call(
|
|
792
|
+
var stats = options ? orig.call(fs23, target, options) : orig.call(fs23, target);
|
|
793
793
|
if (stats) {
|
|
794
794
|
if (stats.uid < 0) stats.uid += 4294967296;
|
|
795
795
|
if (stats.gid < 0) stats.gid += 4294967296;
|
|
@@ -818,16 +818,16 @@ var require_legacy_streams = __commonJS({
|
|
|
818
818
|
"../../node_modules/graceful-fs/legacy-streams.js"(exports, module) {
|
|
819
819
|
var Stream = __require("stream").Stream;
|
|
820
820
|
module.exports = legacy;
|
|
821
|
-
function legacy(
|
|
821
|
+
function legacy(fs23) {
|
|
822
822
|
return {
|
|
823
823
|
ReadStream,
|
|
824
824
|
WriteStream
|
|
825
825
|
};
|
|
826
|
-
function ReadStream(
|
|
827
|
-
if (!(this instanceof ReadStream)) return new ReadStream(
|
|
826
|
+
function ReadStream(path28, options) {
|
|
827
|
+
if (!(this instanceof ReadStream)) return new ReadStream(path28, options);
|
|
828
828
|
Stream.call(this);
|
|
829
829
|
var self = this;
|
|
830
|
-
this.path =
|
|
830
|
+
this.path = path28;
|
|
831
831
|
this.fd = null;
|
|
832
832
|
this.readable = true;
|
|
833
833
|
this.paused = false;
|
|
@@ -861,7 +861,7 @@ var require_legacy_streams = __commonJS({
|
|
|
861
861
|
});
|
|
862
862
|
return;
|
|
863
863
|
}
|
|
864
|
-
|
|
864
|
+
fs23.open(this.path, this.flags, this.mode, function(err, fd) {
|
|
865
865
|
if (err) {
|
|
866
866
|
self.emit("error", err);
|
|
867
867
|
self.readable = false;
|
|
@@ -872,10 +872,10 @@ var require_legacy_streams = __commonJS({
|
|
|
872
872
|
self._read();
|
|
873
873
|
});
|
|
874
874
|
}
|
|
875
|
-
function WriteStream(
|
|
876
|
-
if (!(this instanceof WriteStream)) return new WriteStream(
|
|
875
|
+
function WriteStream(path28, options) {
|
|
876
|
+
if (!(this instanceof WriteStream)) return new WriteStream(path28, options);
|
|
877
877
|
Stream.call(this);
|
|
878
|
-
this.path =
|
|
878
|
+
this.path = path28;
|
|
879
879
|
this.fd = null;
|
|
880
880
|
this.writable = true;
|
|
881
881
|
this.flags = "w";
|
|
@@ -900,7 +900,7 @@ var require_legacy_streams = __commonJS({
|
|
|
900
900
|
this.busy = false;
|
|
901
901
|
this._queue = [];
|
|
902
902
|
if (this.fd === null) {
|
|
903
|
-
this._open =
|
|
903
|
+
this._open = fs23.open;
|
|
904
904
|
this._queue.push([this._open, this.path, this.flags, this.mode, void 0]);
|
|
905
905
|
this.flush();
|
|
906
906
|
}
|
|
@@ -935,7 +935,7 @@ var require_clone = __commonJS({
|
|
|
935
935
|
// ../../node_modules/graceful-fs/graceful-fs.js
|
|
936
936
|
var require_graceful_fs = __commonJS({
|
|
937
937
|
"../../node_modules/graceful-fs/graceful-fs.js"(exports, module) {
|
|
938
|
-
var
|
|
938
|
+
var fs23 = __require("fs");
|
|
939
939
|
var polyfills = require_polyfills();
|
|
940
940
|
var legacy = require_legacy_streams();
|
|
941
941
|
var clone = require_clone();
|
|
@@ -967,12 +967,12 @@ var require_graceful_fs = __commonJS({
|
|
|
967
967
|
m = "GFS4: " + m.split(/\n/).join("\nGFS4: ");
|
|
968
968
|
console.error(m);
|
|
969
969
|
};
|
|
970
|
-
if (!
|
|
970
|
+
if (!fs23[gracefulQueue]) {
|
|
971
971
|
queue = global[gracefulQueue] || [];
|
|
972
|
-
publishQueue(
|
|
973
|
-
|
|
972
|
+
publishQueue(fs23, queue);
|
|
973
|
+
fs23.close = (function(fs$close) {
|
|
974
974
|
function close(fd, cb) {
|
|
975
|
-
return fs$close.call(
|
|
975
|
+
return fs$close.call(fs23, fd, function(err) {
|
|
976
976
|
if (!err) {
|
|
977
977
|
resetQueue();
|
|
978
978
|
}
|
|
@@ -984,48 +984,48 @@ var require_graceful_fs = __commonJS({
|
|
|
984
984
|
value: fs$close
|
|
985
985
|
});
|
|
986
986
|
return close;
|
|
987
|
-
})(
|
|
988
|
-
|
|
989
|
-
function
|
|
990
|
-
fs$closeSync.apply(
|
|
987
|
+
})(fs23.close);
|
|
988
|
+
fs23.closeSync = (function(fs$closeSync) {
|
|
989
|
+
function closeSync3(fd) {
|
|
990
|
+
fs$closeSync.apply(fs23, arguments);
|
|
991
991
|
resetQueue();
|
|
992
992
|
}
|
|
993
|
-
Object.defineProperty(
|
|
993
|
+
Object.defineProperty(closeSync3, previousSymbol, {
|
|
994
994
|
value: fs$closeSync
|
|
995
995
|
});
|
|
996
|
-
return
|
|
997
|
-
})(
|
|
996
|
+
return closeSync3;
|
|
997
|
+
})(fs23.closeSync);
|
|
998
998
|
if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
|
|
999
999
|
process.on("exit", function() {
|
|
1000
|
-
debug(
|
|
1001
|
-
__require("assert").equal(
|
|
1000
|
+
debug(fs23[gracefulQueue]);
|
|
1001
|
+
__require("assert").equal(fs23[gracefulQueue].length, 0);
|
|
1002
1002
|
});
|
|
1003
1003
|
}
|
|
1004
1004
|
}
|
|
1005
1005
|
var queue;
|
|
1006
1006
|
if (!global[gracefulQueue]) {
|
|
1007
|
-
publishQueue(global,
|
|
1008
|
-
}
|
|
1009
|
-
module.exports = patch(clone(
|
|
1010
|
-
if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !
|
|
1011
|
-
module.exports = patch(
|
|
1012
|
-
|
|
1013
|
-
}
|
|
1014
|
-
function patch(
|
|
1015
|
-
polyfills(
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
var fs$readFile =
|
|
1020
|
-
|
|
1021
|
-
function readFile(
|
|
1007
|
+
publishQueue(global, fs23[gracefulQueue]);
|
|
1008
|
+
}
|
|
1009
|
+
module.exports = patch(clone(fs23));
|
|
1010
|
+
if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs23.__patched) {
|
|
1011
|
+
module.exports = patch(fs23);
|
|
1012
|
+
fs23.__patched = true;
|
|
1013
|
+
}
|
|
1014
|
+
function patch(fs24) {
|
|
1015
|
+
polyfills(fs24);
|
|
1016
|
+
fs24.gracefulify = patch;
|
|
1017
|
+
fs24.createReadStream = createReadStream;
|
|
1018
|
+
fs24.createWriteStream = createWriteStream;
|
|
1019
|
+
var fs$readFile = fs24.readFile;
|
|
1020
|
+
fs24.readFile = readFile;
|
|
1021
|
+
function readFile(path28, options, cb) {
|
|
1022
1022
|
if (typeof options === "function")
|
|
1023
1023
|
cb = options, options = null;
|
|
1024
|
-
return go$readFile(
|
|
1025
|
-
function go$readFile(
|
|
1026
|
-
return fs$readFile(
|
|
1024
|
+
return go$readFile(path28, options, cb);
|
|
1025
|
+
function go$readFile(path29, options2, cb2, startTime) {
|
|
1026
|
+
return fs$readFile(path29, options2, function(err) {
|
|
1027
1027
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
1028
|
-
enqueue([go$readFile, [
|
|
1028
|
+
enqueue([go$readFile, [path29, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
1029
1029
|
else {
|
|
1030
1030
|
if (typeof cb2 === "function")
|
|
1031
1031
|
cb2.apply(this, arguments);
|
|
@@ -1033,16 +1033,16 @@ var require_graceful_fs = __commonJS({
|
|
|
1033
1033
|
});
|
|
1034
1034
|
}
|
|
1035
1035
|
}
|
|
1036
|
-
var fs$writeFile =
|
|
1037
|
-
|
|
1038
|
-
function writeFile(
|
|
1036
|
+
var fs$writeFile = fs24.writeFile;
|
|
1037
|
+
fs24.writeFile = writeFile;
|
|
1038
|
+
function writeFile(path28, data, options, cb) {
|
|
1039
1039
|
if (typeof options === "function")
|
|
1040
1040
|
cb = options, options = null;
|
|
1041
|
-
return go$writeFile(
|
|
1042
|
-
function go$writeFile(
|
|
1043
|
-
return fs$writeFile(
|
|
1041
|
+
return go$writeFile(path28, data, options, cb);
|
|
1042
|
+
function go$writeFile(path29, data2, options2, cb2, startTime) {
|
|
1043
|
+
return fs$writeFile(path29, data2, options2, function(err) {
|
|
1044
1044
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
1045
|
-
enqueue([go$writeFile, [
|
|
1045
|
+
enqueue([go$writeFile, [path29, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
1046
1046
|
else {
|
|
1047
1047
|
if (typeof cb2 === "function")
|
|
1048
1048
|
cb2.apply(this, arguments);
|
|
@@ -1050,17 +1050,17 @@ var require_graceful_fs = __commonJS({
|
|
|
1050
1050
|
});
|
|
1051
1051
|
}
|
|
1052
1052
|
}
|
|
1053
|
-
var fs$appendFile =
|
|
1053
|
+
var fs$appendFile = fs24.appendFile;
|
|
1054
1054
|
if (fs$appendFile)
|
|
1055
|
-
|
|
1056
|
-
function appendFile(
|
|
1055
|
+
fs24.appendFile = appendFile;
|
|
1056
|
+
function appendFile(path28, data, options, cb) {
|
|
1057
1057
|
if (typeof options === "function")
|
|
1058
1058
|
cb = options, options = null;
|
|
1059
|
-
return go$appendFile(
|
|
1060
|
-
function go$appendFile(
|
|
1061
|
-
return fs$appendFile(
|
|
1059
|
+
return go$appendFile(path28, data, options, cb);
|
|
1060
|
+
function go$appendFile(path29, data2, options2, cb2, startTime) {
|
|
1061
|
+
return fs$appendFile(path29, data2, options2, function(err) {
|
|
1062
1062
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
1063
|
-
enqueue([go$appendFile, [
|
|
1063
|
+
enqueue([go$appendFile, [path29, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
1064
1064
|
else {
|
|
1065
1065
|
if (typeof cb2 === "function")
|
|
1066
1066
|
cb2.apply(this, arguments);
|
|
@@ -1068,9 +1068,9 @@ var require_graceful_fs = __commonJS({
|
|
|
1068
1068
|
});
|
|
1069
1069
|
}
|
|
1070
1070
|
}
|
|
1071
|
-
var fs$copyFile =
|
|
1071
|
+
var fs$copyFile = fs24.copyFile;
|
|
1072
1072
|
if (fs$copyFile)
|
|
1073
|
-
|
|
1073
|
+
fs24.copyFile = copyFile;
|
|
1074
1074
|
function copyFile(src, dest, flags, cb) {
|
|
1075
1075
|
if (typeof flags === "function") {
|
|
1076
1076
|
cb = flags;
|
|
@@ -1088,34 +1088,34 @@ var require_graceful_fs = __commonJS({
|
|
|
1088
1088
|
});
|
|
1089
1089
|
}
|
|
1090
1090
|
}
|
|
1091
|
-
var fs$readdir =
|
|
1092
|
-
|
|
1091
|
+
var fs$readdir = fs24.readdir;
|
|
1092
|
+
fs24.readdir = readdir;
|
|
1093
1093
|
var noReaddirOptionVersions = /^v[0-5]\./;
|
|
1094
|
-
function readdir(
|
|
1094
|
+
function readdir(path28, options, cb) {
|
|
1095
1095
|
if (typeof options === "function")
|
|
1096
1096
|
cb = options, options = null;
|
|
1097
|
-
var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(
|
|
1098
|
-
return fs$readdir(
|
|
1099
|
-
|
|
1097
|
+
var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path29, options2, cb2, startTime) {
|
|
1098
|
+
return fs$readdir(path29, fs$readdirCallback(
|
|
1099
|
+
path29,
|
|
1100
1100
|
options2,
|
|
1101
1101
|
cb2,
|
|
1102
1102
|
startTime
|
|
1103
1103
|
));
|
|
1104
|
-
} : function go$readdir2(
|
|
1105
|
-
return fs$readdir(
|
|
1106
|
-
|
|
1104
|
+
} : function go$readdir2(path29, options2, cb2, startTime) {
|
|
1105
|
+
return fs$readdir(path29, options2, fs$readdirCallback(
|
|
1106
|
+
path29,
|
|
1107
1107
|
options2,
|
|
1108
1108
|
cb2,
|
|
1109
1109
|
startTime
|
|
1110
1110
|
));
|
|
1111
1111
|
};
|
|
1112
|
-
return go$readdir(
|
|
1113
|
-
function fs$readdirCallback(
|
|
1112
|
+
return go$readdir(path28, options, cb);
|
|
1113
|
+
function fs$readdirCallback(path29, options2, cb2, startTime) {
|
|
1114
1114
|
return function(err, files) {
|
|
1115
1115
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
1116
1116
|
enqueue([
|
|
1117
1117
|
go$readdir,
|
|
1118
|
-
[
|
|
1118
|
+
[path29, options2, cb2],
|
|
1119
1119
|
err,
|
|
1120
1120
|
startTime || Date.now(),
|
|
1121
1121
|
Date.now()
|
|
@@ -1130,21 +1130,21 @@ var require_graceful_fs = __commonJS({
|
|
|
1130
1130
|
}
|
|
1131
1131
|
}
|
|
1132
1132
|
if (process.version.substr(0, 4) === "v0.8") {
|
|
1133
|
-
var legStreams = legacy(
|
|
1133
|
+
var legStreams = legacy(fs24);
|
|
1134
1134
|
ReadStream = legStreams.ReadStream;
|
|
1135
1135
|
WriteStream = legStreams.WriteStream;
|
|
1136
1136
|
}
|
|
1137
|
-
var fs$ReadStream =
|
|
1137
|
+
var fs$ReadStream = fs24.ReadStream;
|
|
1138
1138
|
if (fs$ReadStream) {
|
|
1139
1139
|
ReadStream.prototype = Object.create(fs$ReadStream.prototype);
|
|
1140
1140
|
ReadStream.prototype.open = ReadStream$open;
|
|
1141
1141
|
}
|
|
1142
|
-
var fs$WriteStream =
|
|
1142
|
+
var fs$WriteStream = fs24.WriteStream;
|
|
1143
1143
|
if (fs$WriteStream) {
|
|
1144
1144
|
WriteStream.prototype = Object.create(fs$WriteStream.prototype);
|
|
1145
1145
|
WriteStream.prototype.open = WriteStream$open;
|
|
1146
1146
|
}
|
|
1147
|
-
Object.defineProperty(
|
|
1147
|
+
Object.defineProperty(fs24, "ReadStream", {
|
|
1148
1148
|
get: function() {
|
|
1149
1149
|
return ReadStream;
|
|
1150
1150
|
},
|
|
@@ -1154,7 +1154,7 @@ var require_graceful_fs = __commonJS({
|
|
|
1154
1154
|
enumerable: true,
|
|
1155
1155
|
configurable: true
|
|
1156
1156
|
});
|
|
1157
|
-
Object.defineProperty(
|
|
1157
|
+
Object.defineProperty(fs24, "WriteStream", {
|
|
1158
1158
|
get: function() {
|
|
1159
1159
|
return WriteStream;
|
|
1160
1160
|
},
|
|
@@ -1165,7 +1165,7 @@ var require_graceful_fs = __commonJS({
|
|
|
1165
1165
|
configurable: true
|
|
1166
1166
|
});
|
|
1167
1167
|
var FileReadStream = ReadStream;
|
|
1168
|
-
Object.defineProperty(
|
|
1168
|
+
Object.defineProperty(fs24, "FileReadStream", {
|
|
1169
1169
|
get: function() {
|
|
1170
1170
|
return FileReadStream;
|
|
1171
1171
|
},
|
|
@@ -1176,7 +1176,7 @@ var require_graceful_fs = __commonJS({
|
|
|
1176
1176
|
configurable: true
|
|
1177
1177
|
});
|
|
1178
1178
|
var FileWriteStream = WriteStream;
|
|
1179
|
-
Object.defineProperty(
|
|
1179
|
+
Object.defineProperty(fs24, "FileWriteStream", {
|
|
1180
1180
|
get: function() {
|
|
1181
1181
|
return FileWriteStream;
|
|
1182
1182
|
},
|
|
@@ -1186,7 +1186,7 @@ var require_graceful_fs = __commonJS({
|
|
|
1186
1186
|
enumerable: true,
|
|
1187
1187
|
configurable: true
|
|
1188
1188
|
});
|
|
1189
|
-
function ReadStream(
|
|
1189
|
+
function ReadStream(path28, options) {
|
|
1190
1190
|
if (this instanceof ReadStream)
|
|
1191
1191
|
return fs$ReadStream.apply(this, arguments), this;
|
|
1192
1192
|
else
|
|
@@ -1206,7 +1206,7 @@ var require_graceful_fs = __commonJS({
|
|
|
1206
1206
|
}
|
|
1207
1207
|
});
|
|
1208
1208
|
}
|
|
1209
|
-
function WriteStream(
|
|
1209
|
+
function WriteStream(path28, options) {
|
|
1210
1210
|
if (this instanceof WriteStream)
|
|
1211
1211
|
return fs$WriteStream.apply(this, arguments), this;
|
|
1212
1212
|
else
|
|
@@ -1224,22 +1224,22 @@ var require_graceful_fs = __commonJS({
|
|
|
1224
1224
|
}
|
|
1225
1225
|
});
|
|
1226
1226
|
}
|
|
1227
|
-
function createReadStream(
|
|
1228
|
-
return new
|
|
1227
|
+
function createReadStream(path28, options) {
|
|
1228
|
+
return new fs24.ReadStream(path28, options);
|
|
1229
1229
|
}
|
|
1230
|
-
function createWriteStream(
|
|
1231
|
-
return new
|
|
1230
|
+
function createWriteStream(path28, options) {
|
|
1231
|
+
return new fs24.WriteStream(path28, options);
|
|
1232
1232
|
}
|
|
1233
|
-
var fs$open =
|
|
1234
|
-
|
|
1235
|
-
function open(
|
|
1233
|
+
var fs$open = fs24.open;
|
|
1234
|
+
fs24.open = open;
|
|
1235
|
+
function open(path28, flags, mode, cb) {
|
|
1236
1236
|
if (typeof mode === "function")
|
|
1237
1237
|
cb = mode, mode = null;
|
|
1238
|
-
return go$open(
|
|
1239
|
-
function go$open(
|
|
1240
|
-
return fs$open(
|
|
1238
|
+
return go$open(path28, flags, mode, cb);
|
|
1239
|
+
function go$open(path29, flags2, mode2, cb2, startTime) {
|
|
1240
|
+
return fs$open(path29, flags2, mode2, function(err, fd) {
|
|
1241
1241
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
1242
|
-
enqueue([go$open, [
|
|
1242
|
+
enqueue([go$open, [path29, flags2, mode2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
1243
1243
|
else {
|
|
1244
1244
|
if (typeof cb2 === "function")
|
|
1245
1245
|
cb2.apply(this, arguments);
|
|
@@ -1247,20 +1247,20 @@ var require_graceful_fs = __commonJS({
|
|
|
1247
1247
|
});
|
|
1248
1248
|
}
|
|
1249
1249
|
}
|
|
1250
|
-
return
|
|
1250
|
+
return fs24;
|
|
1251
1251
|
}
|
|
1252
1252
|
function enqueue(elem) {
|
|
1253
1253
|
debug("ENQUEUE", elem[0].name, elem[1]);
|
|
1254
|
-
|
|
1254
|
+
fs23[gracefulQueue].push(elem);
|
|
1255
1255
|
retry();
|
|
1256
1256
|
}
|
|
1257
1257
|
var retryTimer;
|
|
1258
1258
|
function resetQueue() {
|
|
1259
1259
|
var now = Date.now();
|
|
1260
|
-
for (var i = 0; i <
|
|
1261
|
-
if (
|
|
1262
|
-
|
|
1263
|
-
|
|
1260
|
+
for (var i = 0; i < fs23[gracefulQueue].length; ++i) {
|
|
1261
|
+
if (fs23[gracefulQueue][i].length > 2) {
|
|
1262
|
+
fs23[gracefulQueue][i][3] = now;
|
|
1263
|
+
fs23[gracefulQueue][i][4] = now;
|
|
1264
1264
|
}
|
|
1265
1265
|
}
|
|
1266
1266
|
retry();
|
|
@@ -1268,9 +1268,9 @@ var require_graceful_fs = __commonJS({
|
|
|
1268
1268
|
function retry() {
|
|
1269
1269
|
clearTimeout(retryTimer);
|
|
1270
1270
|
retryTimer = void 0;
|
|
1271
|
-
if (
|
|
1271
|
+
if (fs23[gracefulQueue].length === 0)
|
|
1272
1272
|
return;
|
|
1273
|
-
var elem =
|
|
1273
|
+
var elem = fs23[gracefulQueue].shift();
|
|
1274
1274
|
var fn = elem[0];
|
|
1275
1275
|
var args = elem[1];
|
|
1276
1276
|
var err = elem[2];
|
|
@@ -1292,7 +1292,7 @@ var require_graceful_fs = __commonJS({
|
|
|
1292
1292
|
debug("RETRY", fn.name, args);
|
|
1293
1293
|
fn.apply(null, args.concat([startTime]));
|
|
1294
1294
|
} else {
|
|
1295
|
-
|
|
1295
|
+
fs23[gracefulQueue].push(elem);
|
|
1296
1296
|
}
|
|
1297
1297
|
}
|
|
1298
1298
|
if (retryTimer === void 0) {
|
|
@@ -1727,10 +1727,10 @@ var require_mtime_precision = __commonJS({
|
|
|
1727
1727
|
"../../node_modules/proper-lockfile/lib/mtime-precision.js"(exports, module) {
|
|
1728
1728
|
"use strict";
|
|
1729
1729
|
var cacheSymbol = /* @__PURE__ */ Symbol();
|
|
1730
|
-
function probe(file,
|
|
1731
|
-
const cachedPrecision =
|
|
1730
|
+
function probe(file, fs23, callback) {
|
|
1731
|
+
const cachedPrecision = fs23[cacheSymbol];
|
|
1732
1732
|
if (cachedPrecision) {
|
|
1733
|
-
return
|
|
1733
|
+
return fs23.stat(file, (err, stat) => {
|
|
1734
1734
|
if (err) {
|
|
1735
1735
|
return callback(err);
|
|
1736
1736
|
}
|
|
@@ -1738,16 +1738,16 @@ var require_mtime_precision = __commonJS({
|
|
|
1738
1738
|
});
|
|
1739
1739
|
}
|
|
1740
1740
|
const mtime = new Date(Math.ceil(Date.now() / 1e3) * 1e3 + 5);
|
|
1741
|
-
|
|
1741
|
+
fs23.utimes(file, mtime, mtime, (err) => {
|
|
1742
1742
|
if (err) {
|
|
1743
1743
|
return callback(err);
|
|
1744
1744
|
}
|
|
1745
|
-
|
|
1745
|
+
fs23.stat(file, (err2, stat) => {
|
|
1746
1746
|
if (err2) {
|
|
1747
1747
|
return callback(err2);
|
|
1748
1748
|
}
|
|
1749
1749
|
const precision = stat.mtime.getTime() % 1e3 === 0 ? "s" : "ms";
|
|
1750
|
-
Object.defineProperty(
|
|
1750
|
+
Object.defineProperty(fs23, cacheSymbol, { value: precision });
|
|
1751
1751
|
callback(null, stat.mtime, precision);
|
|
1752
1752
|
});
|
|
1753
1753
|
});
|
|
@@ -1768,8 +1768,8 @@ var require_mtime_precision = __commonJS({
|
|
|
1768
1768
|
var require_lockfile = __commonJS({
|
|
1769
1769
|
"../../node_modules/proper-lockfile/lib/lockfile.js"(exports, module) {
|
|
1770
1770
|
"use strict";
|
|
1771
|
-
var
|
|
1772
|
-
var
|
|
1771
|
+
var path28 = __require("path");
|
|
1772
|
+
var fs23 = require_graceful_fs();
|
|
1773
1773
|
var retry = require_retry2();
|
|
1774
1774
|
var onExit = require_signal_exit();
|
|
1775
1775
|
var mtimePrecision = require_mtime_precision();
|
|
@@ -1779,7 +1779,7 @@ var require_lockfile = __commonJS({
|
|
|
1779
1779
|
}
|
|
1780
1780
|
function resolveCanonicalPath(file, options, callback) {
|
|
1781
1781
|
if (!options.realpath) {
|
|
1782
|
-
return callback(null,
|
|
1782
|
+
return callback(null, path28.resolve(file));
|
|
1783
1783
|
}
|
|
1784
1784
|
options.fs.realpath(file, callback);
|
|
1785
1785
|
}
|
|
@@ -1900,7 +1900,7 @@ var require_lockfile = __commonJS({
|
|
|
1900
1900
|
update: null,
|
|
1901
1901
|
realpath: true,
|
|
1902
1902
|
retries: 0,
|
|
1903
|
-
fs:
|
|
1903
|
+
fs: fs23,
|
|
1904
1904
|
onCompromised: (err) => {
|
|
1905
1905
|
throw err;
|
|
1906
1906
|
},
|
|
@@ -1944,7 +1944,7 @@ var require_lockfile = __commonJS({
|
|
|
1944
1944
|
}
|
|
1945
1945
|
function unlock(file, options, callback) {
|
|
1946
1946
|
options = {
|
|
1947
|
-
fs:
|
|
1947
|
+
fs: fs23,
|
|
1948
1948
|
realpath: true,
|
|
1949
1949
|
...options
|
|
1950
1950
|
};
|
|
@@ -1966,7 +1966,7 @@ var require_lockfile = __commonJS({
|
|
|
1966
1966
|
options = {
|
|
1967
1967
|
stale: 1e4,
|
|
1968
1968
|
realpath: true,
|
|
1969
|
-
fs:
|
|
1969
|
+
fs: fs23,
|
|
1970
1970
|
...options
|
|
1971
1971
|
};
|
|
1972
1972
|
options.stale = Math.max(options.stale || 0, 2e3);
|
|
@@ -2005,16 +2005,16 @@ var require_lockfile = __commonJS({
|
|
|
2005
2005
|
var require_adapter = __commonJS({
|
|
2006
2006
|
"../../node_modules/proper-lockfile/lib/adapter.js"(exports, module) {
|
|
2007
2007
|
"use strict";
|
|
2008
|
-
var
|
|
2009
|
-
function createSyncFs(
|
|
2008
|
+
var fs23 = require_graceful_fs();
|
|
2009
|
+
function createSyncFs(fs24) {
|
|
2010
2010
|
const methods = ["mkdir", "realpath", "stat", "rmdir", "utimes"];
|
|
2011
|
-
const newFs = { ...
|
|
2011
|
+
const newFs = { ...fs24 };
|
|
2012
2012
|
methods.forEach((method) => {
|
|
2013
2013
|
newFs[method] = (...args) => {
|
|
2014
2014
|
const callback = args.pop();
|
|
2015
2015
|
let ret;
|
|
2016
2016
|
try {
|
|
2017
|
-
ret =
|
|
2017
|
+
ret = fs24[`${method}Sync`](...args);
|
|
2018
2018
|
} catch (err) {
|
|
2019
2019
|
return callback(err);
|
|
2020
2020
|
}
|
|
@@ -2052,7 +2052,7 @@ var require_adapter = __commonJS({
|
|
|
2052
2052
|
}
|
|
2053
2053
|
function toSyncOptions(options) {
|
|
2054
2054
|
options = { ...options };
|
|
2055
|
-
options.fs = createSyncFs(options.fs ||
|
|
2055
|
+
options.fs = createSyncFs(options.fs || fs23);
|
|
2056
2056
|
if (typeof options.retries === "number" && options.retries > 0 || options.retries && typeof options.retries.retries === "number" && options.retries.retries > 0) {
|
|
2057
2057
|
throw Object.assign(new Error("Cannot use retries with the sync api"), { code: "ESYNC" });
|
|
2058
2058
|
}
|
|
@@ -3447,10 +3447,6 @@ async function getPendingKeys(filePath) {
|
|
|
3447
3447
|
const metadata = await loadMetadata(filePath);
|
|
3448
3448
|
return metadata.pending.map((p) => p.key);
|
|
3449
3449
|
}
|
|
3450
|
-
async function isPending(filePath, key) {
|
|
3451
|
-
const metadata = await loadMetadata(filePath);
|
|
3452
|
-
return metadata.pending.some((p) => p.key === key);
|
|
3453
|
-
}
|
|
3454
3450
|
async function recordRotation(filePath, keys, rotatedBy, now = /* @__PURE__ */ new Date()) {
|
|
3455
3451
|
const metadata = await loadMetadata(filePath);
|
|
3456
3452
|
for (const key of keys) {
|
|
@@ -3486,14 +3482,6 @@ async function getRotations(filePath) {
|
|
|
3486
3482
|
function generateRandomValue() {
|
|
3487
3483
|
return crypto.randomBytes(32).toString("hex");
|
|
3488
3484
|
}
|
|
3489
|
-
async function markPendingWithRetry(filePath, keys, setBy, retryDelayMs = 200) {
|
|
3490
|
-
try {
|
|
3491
|
-
await markPending(filePath, keys, setBy);
|
|
3492
|
-
} catch {
|
|
3493
|
-
await new Promise((r) => setTimeout(r, retryDelayMs));
|
|
3494
|
-
await markPending(filePath, keys, setBy);
|
|
3495
|
-
}
|
|
3496
|
-
}
|
|
3497
3485
|
|
|
3498
3486
|
// src/sops/keys.ts
|
|
3499
3487
|
import * as fs6 from "fs";
|
|
@@ -3543,34 +3531,17 @@ var MatrixManager = class {
|
|
|
3543
3531
|
detectMissingCells(manifest, repoRoot) {
|
|
3544
3532
|
return this.resolveMatrix(manifest, repoRoot).filter((cell) => !cell.exists);
|
|
3545
3533
|
}
|
|
3546
|
-
/**
|
|
3547
|
-
* Create an empty encrypted SOPS file for a missing matrix cell.
|
|
3548
|
-
*
|
|
3549
|
-
* @param cell - The cell to scaffold (must not already exist).
|
|
3550
|
-
* @param sopsClient - SOPS client used to write the initial encrypted file.
|
|
3551
|
-
* @param manifest - Parsed manifest used to determine the encryption backend.
|
|
3552
|
-
*/
|
|
3553
|
-
async scaffoldCell(cell, sopsClient, manifest) {
|
|
3554
|
-
const dir = path5.dirname(cell.filePath);
|
|
3555
|
-
if (!fs7.existsSync(dir)) {
|
|
3556
|
-
fs7.mkdirSync(dir, { recursive: true });
|
|
3557
|
-
}
|
|
3558
|
-
await sopsClient.encrypt(cell.filePath, {}, manifest, cell.environment);
|
|
3559
|
-
}
|
|
3560
3534
|
/**
|
|
3561
3535
|
* Read each cell and return key counts, pending counts, and cross-environment issues.
|
|
3562
3536
|
*
|
|
3563
|
-
*
|
|
3564
|
-
*
|
|
3565
|
-
*
|
|
3566
|
-
* decrypt-based implementation later (e.g. for backends that don't expose
|
|
3567
|
-
* key names without decryption).
|
|
3537
|
+
* Keys are read from the plaintext YAML structure directly — no
|
|
3538
|
+
* decryption needed. A future backend that doesn't expose key names
|
|
3539
|
+
* without decryption would need its own implementation.
|
|
3568
3540
|
*
|
|
3569
3541
|
* @param manifest - Parsed manifest.
|
|
3570
3542
|
* @param repoRoot - Absolute path to the repository root.
|
|
3571
|
-
* @param _sopsClient - Reserved for future use; pass any `EncryptionBackend`.
|
|
3572
3543
|
*/
|
|
3573
|
-
async getMatrixStatus(manifest, repoRoot
|
|
3544
|
+
async getMatrixStatus(manifest, repoRoot) {
|
|
3574
3545
|
const cells = this.resolveMatrix(manifest, repoRoot);
|
|
3575
3546
|
const statuses = [];
|
|
3576
3547
|
const cellKeys = /* @__PURE__ */ new Map();
|
|
@@ -3886,7 +3857,6 @@ function orderedKeys(keys) {
|
|
|
3886
3857
|
}
|
|
3887
3858
|
|
|
3888
3859
|
// src/diff/engine.ts
|
|
3889
|
-
import * as path7 from "path";
|
|
3890
3860
|
var DiffEngine = class {
|
|
3891
3861
|
/**
|
|
3892
3862
|
* Compare two in-memory value maps and produce a sorted diff result.
|
|
@@ -3937,131 +3907,21 @@ var DiffEngine = class {
|
|
|
3937
3907
|
* @param namespace - Namespace containing both cells.
|
|
3938
3908
|
* @param envA - Name of environment A.
|
|
3939
3909
|
* @param envB - Name of environment B.
|
|
3940
|
-
* @param
|
|
3941
|
-
* @
|
|
3942
|
-
* @param repoRoot - Absolute path to the repository root.
|
|
3943
|
-
* @throws {@link SopsDecryptionError} If either file cannot be decrypted.
|
|
3910
|
+
* @param source - SecretSource that resolves both cells (substrate-agnostic).
|
|
3911
|
+
* @throws {@link SopsDecryptionError} If either cell cannot be decrypted.
|
|
3944
3912
|
*/
|
|
3945
|
-
async
|
|
3946
|
-
const fileA = path7.join(
|
|
3947
|
-
repoRoot,
|
|
3948
|
-
manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", envA)
|
|
3949
|
-
);
|
|
3950
|
-
const fileB = path7.join(
|
|
3951
|
-
repoRoot,
|
|
3952
|
-
manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", envB)
|
|
3953
|
-
);
|
|
3913
|
+
async diffCells(namespace, envA, envB, source) {
|
|
3954
3914
|
const [decryptedA, decryptedB] = await Promise.all([
|
|
3955
|
-
|
|
3956
|
-
|
|
3915
|
+
source.readCell({ namespace, environment: envA }),
|
|
3916
|
+
source.readCell({ namespace, environment: envB })
|
|
3957
3917
|
]);
|
|
3958
3918
|
return this.diff(decryptedA.values, decryptedB.values, envA, envB, namespace);
|
|
3959
3919
|
}
|
|
3960
3920
|
};
|
|
3961
3921
|
|
|
3962
|
-
// src/bulk/ops.ts
|
|
3963
|
-
import * as path8 from "path";
|
|
3964
|
-
var BulkOps = class {
|
|
3965
|
-
constructor(tx) {
|
|
3966
|
-
this.tx = tx;
|
|
3967
|
-
}
|
|
3968
|
-
tx;
|
|
3969
|
-
/**
|
|
3970
|
-
* Set a key to different values in multiple environments at once.
|
|
3971
|
-
*
|
|
3972
|
-
* @param namespace - Target namespace.
|
|
3973
|
-
* @param key - Secret key name to set.
|
|
3974
|
-
* @param values - Map of `{ environment: value }` pairs.
|
|
3975
|
-
* @param manifest - Parsed manifest.
|
|
3976
|
-
* @param sopsClient - SOPS client used to decrypt and re-encrypt each file.
|
|
3977
|
-
* @param repoRoot - Absolute path to the repository root.
|
|
3978
|
-
* @throws Whatever the underlying encrypt throws — the transaction rolls back.
|
|
3979
|
-
*/
|
|
3980
|
-
async setAcrossEnvironments(namespace, key, values, manifest, sopsClient, repoRoot) {
|
|
3981
|
-
const targets = manifest.environments.filter((env) => env.name in values).map((env) => ({
|
|
3982
|
-
env: env.name,
|
|
3983
|
-
filePath: path8.join(
|
|
3984
|
-
repoRoot,
|
|
3985
|
-
manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", env.name)
|
|
3986
|
-
)
|
|
3987
|
-
}));
|
|
3988
|
-
if (targets.length === 0) return;
|
|
3989
|
-
await this.tx.run(repoRoot, {
|
|
3990
|
-
description: `clef set: ${namespace}/${key} across ${targets.length} env(s)`,
|
|
3991
|
-
paths: targets.map((t) => path8.relative(repoRoot, t.filePath)),
|
|
3992
|
-
mutate: async () => {
|
|
3993
|
-
for (const target of targets) {
|
|
3994
|
-
const decrypted = await sopsClient.decrypt(target.filePath);
|
|
3995
|
-
decrypted.values[key] = values[target.env];
|
|
3996
|
-
await sopsClient.encrypt(target.filePath, decrypted.values, manifest, target.env);
|
|
3997
|
-
}
|
|
3998
|
-
}
|
|
3999
|
-
});
|
|
4000
|
-
}
|
|
4001
|
-
/**
|
|
4002
|
-
* Delete a key from every environment in a namespace.
|
|
4003
|
-
*
|
|
4004
|
-
* @param namespace - Target namespace.
|
|
4005
|
-
* @param key - Secret key name to delete.
|
|
4006
|
-
* @param manifest - Parsed manifest.
|
|
4007
|
-
* @param sopsClient - SOPS client.
|
|
4008
|
-
* @param repoRoot - Absolute path to the repository root.
|
|
4009
|
-
*/
|
|
4010
|
-
async deleteAcrossEnvironments(namespace, key, manifest, sopsClient, repoRoot) {
|
|
4011
|
-
const targets = manifest.environments.map((env) => ({
|
|
4012
|
-
env: env.name,
|
|
4013
|
-
filePath: path8.join(
|
|
4014
|
-
repoRoot,
|
|
4015
|
-
manifest.file_pattern.replace("{namespace}", namespace).replace("{environment}", env.name)
|
|
4016
|
-
)
|
|
4017
|
-
}));
|
|
4018
|
-
await this.tx.run(repoRoot, {
|
|
4019
|
-
description: `clef delete: ${namespace}/${key} from ${targets.length} env(s)`,
|
|
4020
|
-
paths: targets.map((t) => path8.relative(repoRoot, t.filePath)),
|
|
4021
|
-
mutate: async () => {
|
|
4022
|
-
for (const target of targets) {
|
|
4023
|
-
const decrypted = await sopsClient.decrypt(target.filePath);
|
|
4024
|
-
if (key in decrypted.values) {
|
|
4025
|
-
delete decrypted.values[key];
|
|
4026
|
-
await sopsClient.encrypt(target.filePath, decrypted.values, manifest, target.env);
|
|
4027
|
-
}
|
|
4028
|
-
}
|
|
4029
|
-
}
|
|
4030
|
-
});
|
|
4031
|
-
}
|
|
4032
|
-
/**
|
|
4033
|
-
* Copy a single key's value from one matrix cell to another.
|
|
4034
|
-
*
|
|
4035
|
-
* @param key - Secret key name to copy.
|
|
4036
|
-
* @param fromCell - Source matrix cell.
|
|
4037
|
-
* @param toCell - Destination matrix cell.
|
|
4038
|
-
* @param sopsClient - SOPS client.
|
|
4039
|
-
* @param manifest - Parsed manifest.
|
|
4040
|
-
* @param repoRoot - Absolute path to the repository root.
|
|
4041
|
-
* @throws `Error` if the key does not exist in the source cell.
|
|
4042
|
-
*/
|
|
4043
|
-
async copyValue(key, fromCell, toCell, sopsClient, manifest, repoRoot) {
|
|
4044
|
-
const source = await sopsClient.decrypt(fromCell.filePath);
|
|
4045
|
-
if (!(key in source.values)) {
|
|
4046
|
-
throw new Error(
|
|
4047
|
-
`Key '${key}' does not exist in ${fromCell.namespace}/${fromCell.environment}.`
|
|
4048
|
-
);
|
|
4049
|
-
}
|
|
4050
|
-
await this.tx.run(repoRoot, {
|
|
4051
|
-
description: `clef copy: ${key} from ${fromCell.namespace}/${fromCell.environment} to ${toCell.namespace}/${toCell.environment}`,
|
|
4052
|
-
paths: [path8.relative(repoRoot, toCell.filePath)],
|
|
4053
|
-
mutate: async () => {
|
|
4054
|
-
const dest = await sopsClient.decrypt(toCell.filePath);
|
|
4055
|
-
dest.values[key] = source.values[key];
|
|
4056
|
-
await sopsClient.encrypt(toCell.filePath, dest.values, manifest, toCell.environment);
|
|
4057
|
-
}
|
|
4058
|
-
});
|
|
4059
|
-
}
|
|
4060
|
-
};
|
|
4061
|
-
|
|
4062
3922
|
// src/git/integration.ts
|
|
4063
3923
|
import * as fs10 from "fs";
|
|
4064
|
-
import * as
|
|
3924
|
+
import * as path7 from "path";
|
|
4065
3925
|
var PRE_COMMIT_HOOK = `#!/bin/sh
|
|
4066
3926
|
# Clef pre-commit hook \u2014 blocks commits of files missing SOPS encryption metadata
|
|
4067
3927
|
# and scans staged files for plaintext secrets.
|
|
@@ -4237,17 +4097,17 @@ var GitIntegration = class {
|
|
|
4237
4097
|
* @returns The kind of operation in progress, or null if none.
|
|
4238
4098
|
*/
|
|
4239
4099
|
async isMidOperation(repoRoot) {
|
|
4240
|
-
const gitDir =
|
|
4241
|
-
if (fs10.existsSync(
|
|
4100
|
+
const gitDir = path7.join(repoRoot, ".git");
|
|
4101
|
+
if (fs10.existsSync(path7.join(gitDir, "MERGE_HEAD"))) {
|
|
4242
4102
|
return { midOp: true, kind: "merge" };
|
|
4243
4103
|
}
|
|
4244
|
-
if (fs10.existsSync(
|
|
4104
|
+
if (fs10.existsSync(path7.join(gitDir, "rebase-merge")) || fs10.existsSync(path7.join(gitDir, "rebase-apply"))) {
|
|
4245
4105
|
return { midOp: true, kind: "rebase" };
|
|
4246
4106
|
}
|
|
4247
|
-
if (fs10.existsSync(
|
|
4107
|
+
if (fs10.existsSync(path7.join(gitDir, "CHERRY_PICK_HEAD"))) {
|
|
4248
4108
|
return { midOp: true, kind: "cherry-pick" };
|
|
4249
4109
|
}
|
|
4250
|
-
if (fs10.existsSync(
|
|
4110
|
+
if (fs10.existsSync(path7.join(gitDir, "REVERT_HEAD"))) {
|
|
4251
4111
|
return { midOp: true, kind: "revert" };
|
|
4252
4112
|
}
|
|
4253
4113
|
return { midOp: false };
|
|
@@ -4459,14 +4319,14 @@ var GitIntegration = class {
|
|
|
4459
4319
|
{ cwd: repoRoot }
|
|
4460
4320
|
);
|
|
4461
4321
|
const metadataGitConfig = metaConfig.exitCode === 0 && metaConfig.stdout.trim().length > 0;
|
|
4462
|
-
const attrFilePath =
|
|
4322
|
+
const attrFilePath = path7.join(repoRoot, ".gitattributes");
|
|
4463
4323
|
const attrContent = fs10.existsSync(attrFilePath) ? fs10.readFileSync(attrFilePath, "utf-8") : "";
|
|
4464
4324
|
const gitattributes = attrContent.includes("merge=sops");
|
|
4465
4325
|
const metadataGitattributes = attrContent.includes("merge=clef-metadata");
|
|
4466
4326
|
return { gitConfig, gitattributes, metadataGitConfig, metadataGitattributes };
|
|
4467
4327
|
}
|
|
4468
4328
|
async ensureGitattributes(repoRoot) {
|
|
4469
|
-
const attrPath =
|
|
4329
|
+
const attrPath = path7.join(repoRoot, ".gitattributes");
|
|
4470
4330
|
const existing = fs10.existsSync(attrPath) ? fs10.readFileSync(attrPath, "utf-8") : "";
|
|
4471
4331
|
let newContent = existing;
|
|
4472
4332
|
if (!existing.includes("merge=sops")) {
|
|
@@ -4501,9 +4361,9 @@ ${block}` : block;
|
|
|
4501
4361
|
* @throws {@link GitOperationError} On failure.
|
|
4502
4362
|
*/
|
|
4503
4363
|
async installPreCommitHook(repoRoot) {
|
|
4504
|
-
const hookPath =
|
|
4364
|
+
const hookPath = path7.join(repoRoot, ".git", "hooks", "pre-commit");
|
|
4505
4365
|
try {
|
|
4506
|
-
const hooksDir =
|
|
4366
|
+
const hooksDir = path7.dirname(hookPath);
|
|
4507
4367
|
if (!fs10.existsSync(hooksDir)) {
|
|
4508
4368
|
fs10.mkdirSync(hooksDir, { recursive: true });
|
|
4509
4369
|
}
|
|
@@ -4520,7 +4380,7 @@ ${block}` : block;
|
|
|
4520
4380
|
// src/tx/transaction-manager.ts
|
|
4521
4381
|
var lockfile = __toESM(require_proper_lockfile());
|
|
4522
4382
|
import * as fs11 from "fs";
|
|
4523
|
-
import * as
|
|
4383
|
+
import * as path8 from "path";
|
|
4524
4384
|
|
|
4525
4385
|
// src/tx/errors.ts
|
|
4526
4386
|
var TransactionLockError = class extends Error {
|
|
@@ -4568,15 +4428,15 @@ var TransactionManager = class {
|
|
|
4568
4428
|
async run(repoRoot, opts) {
|
|
4569
4429
|
const shouldCommit = opts.commit !== false;
|
|
4570
4430
|
const allowDirty = opts.allowDirty === true;
|
|
4571
|
-
const clefDir =
|
|
4431
|
+
const clefDir = path8.join(repoRoot, CLEF_DIR);
|
|
4572
4432
|
if (!fs11.existsSync(clefDir)) {
|
|
4573
4433
|
fs11.mkdirSync(clefDir, { recursive: true });
|
|
4574
4434
|
}
|
|
4575
|
-
const clefGitignore =
|
|
4435
|
+
const clefGitignore = path8.join(clefDir, ".gitignore");
|
|
4576
4436
|
if (!fs11.existsSync(clefGitignore)) {
|
|
4577
4437
|
fs11.writeFileSync(clefGitignore, "*\n");
|
|
4578
4438
|
}
|
|
4579
|
-
const lockPath =
|
|
4439
|
+
const lockPath = path8.join(clefDir, LOCK_FILE);
|
|
4580
4440
|
if (!fs11.existsSync(lockPath)) {
|
|
4581
4441
|
fs11.writeFileSync(lockPath, "");
|
|
4582
4442
|
}
|
|
@@ -4714,7 +4574,6 @@ var TransactionManager = class {
|
|
|
4714
4574
|
};
|
|
4715
4575
|
|
|
4716
4576
|
// src/sops/client.ts
|
|
4717
|
-
var import_write_file_atomic3 = __toESM(require_lib());
|
|
4718
4577
|
import * as fs14 from "fs";
|
|
4719
4578
|
import * as net from "net";
|
|
4720
4579
|
import { randomBytes as randomBytes2 } from "crypto";
|
|
@@ -4722,11 +4581,11 @@ import * as YAML8 from "yaml";
|
|
|
4722
4581
|
|
|
4723
4582
|
// src/sops/resolver.ts
|
|
4724
4583
|
import * as fs13 from "fs";
|
|
4725
|
-
import * as
|
|
4584
|
+
import * as path10 from "path";
|
|
4726
4585
|
|
|
4727
4586
|
// src/sops/bundled.ts
|
|
4728
4587
|
import * as fs12 from "fs";
|
|
4729
|
-
import * as
|
|
4588
|
+
import * as path9 from "path";
|
|
4730
4589
|
function tryBundled() {
|
|
4731
4590
|
const platform = process.platform;
|
|
4732
4591
|
const arch = process.arch;
|
|
@@ -4738,8 +4597,8 @@ function tryBundled() {
|
|
|
4738
4597
|
const binName = platform === "win32" ? "sops.exe" : "sops";
|
|
4739
4598
|
try {
|
|
4740
4599
|
const packageMain = __require.resolve(`${packageName}/package.json`);
|
|
4741
|
-
const packageDir =
|
|
4742
|
-
const binPath =
|
|
4600
|
+
const packageDir = path9.dirname(packageMain);
|
|
4601
|
+
const binPath = path9.join(packageDir, "bin", binName);
|
|
4743
4602
|
return fs12.existsSync(binPath) ? binPath : null;
|
|
4744
4603
|
} catch {
|
|
4745
4604
|
return null;
|
|
@@ -4748,7 +4607,7 @@ function tryBundled() {
|
|
|
4748
4607
|
|
|
4749
4608
|
// src/sops/resolver.ts
|
|
4750
4609
|
function validateSopsPath(candidate) {
|
|
4751
|
-
if (!
|
|
4610
|
+
if (!path10.isAbsolute(candidate)) {
|
|
4752
4611
|
throw new Error(`CLEF_SOPS_PATH must be an absolute path, got '${candidate}'.`);
|
|
4753
4612
|
}
|
|
4754
4613
|
const segments = candidate.split(/[/\\]/);
|
|
@@ -4927,6 +4786,17 @@ function isClefHsmArn(arn) {
|
|
|
4927
4786
|
function formatFromPath(filePath) {
|
|
4928
4787
|
return filePath.endsWith(".json") ? "json" : "yaml";
|
|
4929
4788
|
}
|
|
4789
|
+
async function openInputPipe(content) {
|
|
4790
|
+
if (process.platform === "win32") {
|
|
4791
|
+
const pipe = await openWindowsInputPipe(content);
|
|
4792
|
+
return { inputArg: pipe.inputArg, cleanup: pipe.cleanup };
|
|
4793
|
+
}
|
|
4794
|
+
return { inputArg: "/dev/stdin", cleanup: () => {
|
|
4795
|
+
}, runnerStdin: content };
|
|
4796
|
+
}
|
|
4797
|
+
function nullConfigPath() {
|
|
4798
|
+
return process.platform === "win32" ? "NUL" : "/dev/null";
|
|
4799
|
+
}
|
|
4930
4800
|
function openWindowsInputPipe(content) {
|
|
4931
4801
|
const pipeName = `\\\\.\\pipe\\clef-sops-${randomBytes2(8).toString("hex")}`;
|
|
4932
4802
|
return new Promise((resolve2, reject) => {
|
|
@@ -4974,6 +4844,10 @@ var SopsClient = class {
|
|
|
4974
4844
|
runner;
|
|
4975
4845
|
ageKeyFile;
|
|
4976
4846
|
ageKey;
|
|
4847
|
+
/** {@link EncryptionBackend} identifier. */
|
|
4848
|
+
id = "sops";
|
|
4849
|
+
/** {@link EncryptionBackend} short description (used by `clef doctor`). */
|
|
4850
|
+
description = "SOPS-based encryption via the bundled `sops` binary";
|
|
4977
4851
|
sopsCommand;
|
|
4978
4852
|
keyserviceArgs;
|
|
4979
4853
|
buildSopsEnv() {
|
|
@@ -4987,14 +4861,18 @@ var SopsClient = class {
|
|
|
4987
4861
|
return Object.keys(env).length > 0 ? env : void 0;
|
|
4988
4862
|
}
|
|
4989
4863
|
/**
|
|
4990
|
-
* Decrypt a SOPS-encrypted file
|
|
4864
|
+
* Decrypt a SOPS-encrypted file by path. The only remaining file-path
|
|
4865
|
+
* entry point on this class — kept for the merge driver, which
|
|
4866
|
+
* receives temp filesystem paths from git that don't map onto a
|
|
4867
|
+
* `CellRef`. Production `SecretSource` consumers should call
|
|
4868
|
+
* `source.readCell` instead.
|
|
4991
4869
|
*
|
|
4992
4870
|
* @param filePath - Path to the `.enc.yaml` or `.enc.json` file.
|
|
4993
4871
|
* @returns {@link DecryptedFile} with plaintext values in memory only.
|
|
4994
4872
|
* @throws {@link SopsKeyNotFoundError} If no matching decryption key is available.
|
|
4995
4873
|
* @throws {@link SopsDecryptionError} On any other decryption failure.
|
|
4996
4874
|
*/
|
|
4997
|
-
async
|
|
4875
|
+
async decryptFile(filePath) {
|
|
4998
4876
|
await assertSops(this.runner, this.sopsCommand);
|
|
4999
4877
|
const fmt = formatFromPath(filePath);
|
|
5000
4878
|
const env = this.buildSopsEnv();
|
|
@@ -5030,170 +4908,9 @@ var SopsClient = class {
|
|
|
5030
4908
|
for (const [key, value] of Object.entries(parsed)) {
|
|
5031
4909
|
values[key] = String(value);
|
|
5032
4910
|
}
|
|
5033
|
-
const metadata =
|
|
4911
|
+
const metadata = this.parseMetadataFromFile(filePath);
|
|
5034
4912
|
return { values, metadata };
|
|
5035
4913
|
}
|
|
5036
|
-
/**
|
|
5037
|
-
* Encrypt a key/value map and write it to an encrypted SOPS file.
|
|
5038
|
-
*
|
|
5039
|
-
* @param filePath - Destination path for the encrypted file.
|
|
5040
|
-
* @param values - Flat key/value map to encrypt.
|
|
5041
|
-
* @param manifest - Manifest used to determine the encryption backend and key configuration.
|
|
5042
|
-
* @param environment - Optional environment name. When provided, per-env backend overrides
|
|
5043
|
-
* are resolved from the manifest. When omitted, the global `sops.default_backend` is used.
|
|
5044
|
-
* @throws {@link SopsEncryptionError} On encryption or write failure.
|
|
5045
|
-
*/
|
|
5046
|
-
async encrypt(filePath, values, manifest, environment) {
|
|
5047
|
-
await assertSops(this.runner, this.sopsCommand);
|
|
5048
|
-
const fmt = formatFromPath(filePath);
|
|
5049
|
-
const content = fmt === "json" ? JSON.stringify(values, null, 2) : YAML8.stringify(values);
|
|
5050
|
-
const args = this.buildEncryptArgs(filePath, manifest, environment);
|
|
5051
|
-
const env = this.buildSopsEnv();
|
|
5052
|
-
let inputArg;
|
|
5053
|
-
let pipeCleanup;
|
|
5054
|
-
if (process.platform === "win32") {
|
|
5055
|
-
const pipe = await openWindowsInputPipe(content);
|
|
5056
|
-
inputArg = pipe.inputArg;
|
|
5057
|
-
pipeCleanup = pipe.cleanup;
|
|
5058
|
-
} else {
|
|
5059
|
-
inputArg = "/dev/stdin";
|
|
5060
|
-
}
|
|
5061
|
-
let result;
|
|
5062
|
-
try {
|
|
5063
|
-
const configPath = process.platform === "win32" ? "NUL" : "/dev/null";
|
|
5064
|
-
result = await this.runner.run(
|
|
5065
|
-
this.sopsCommand,
|
|
5066
|
-
[
|
|
5067
|
-
"--config",
|
|
5068
|
-
configPath,
|
|
5069
|
-
"encrypt",
|
|
5070
|
-
...this.keyserviceArgs,
|
|
5071
|
-
...args,
|
|
5072
|
-
"--input-type",
|
|
5073
|
-
fmt,
|
|
5074
|
-
"--output-type",
|
|
5075
|
-
fmt,
|
|
5076
|
-
"--filename-override",
|
|
5077
|
-
filePath,
|
|
5078
|
-
inputArg
|
|
5079
|
-
],
|
|
5080
|
-
{
|
|
5081
|
-
// stdin is still piped on Unix (/dev/stdin reads from it);
|
|
5082
|
-
// on Windows the named pipe server feeds content directly.
|
|
5083
|
-
...process.platform !== "win32" ? { stdin: content } : {},
|
|
5084
|
-
...env ? { env } : {}
|
|
5085
|
-
}
|
|
5086
|
-
);
|
|
5087
|
-
} finally {
|
|
5088
|
-
pipeCleanup?.();
|
|
5089
|
-
}
|
|
5090
|
-
if (result.exitCode !== 0) {
|
|
5091
|
-
throw new SopsEncryptionError(
|
|
5092
|
-
`Failed to encrypt '${filePath}': ${result.stderr.trim()}`,
|
|
5093
|
-
filePath
|
|
5094
|
-
);
|
|
5095
|
-
}
|
|
5096
|
-
try {
|
|
5097
|
-
await (0, import_write_file_atomic3.default)(filePath, result.stdout);
|
|
5098
|
-
} catch (err) {
|
|
5099
|
-
throw new SopsEncryptionError(
|
|
5100
|
-
`Failed to write encrypted data to '${filePath}': ${err.message}`,
|
|
5101
|
-
filePath
|
|
5102
|
-
);
|
|
5103
|
-
}
|
|
5104
|
-
}
|
|
5105
|
-
/**
|
|
5106
|
-
* Rotate encryption by adding a new age recipient key to an existing SOPS file.
|
|
5107
|
-
*
|
|
5108
|
-
* @param filePath - Path to the encrypted file to re-encrypt.
|
|
5109
|
-
* @param newKey - New age public key to add as a recipient.
|
|
5110
|
-
* @throws {@link SopsEncryptionError} On failure.
|
|
5111
|
-
*/
|
|
5112
|
-
async reEncrypt(filePath, newKey) {
|
|
5113
|
-
await this.addRecipient(filePath, newKey);
|
|
5114
|
-
}
|
|
5115
|
-
/**
|
|
5116
|
-
* Add an age recipient to an existing SOPS file.
|
|
5117
|
-
*
|
|
5118
|
-
* @param filePath - Path to the encrypted file.
|
|
5119
|
-
* @param key - age public key to add as a recipient.
|
|
5120
|
-
* @throws {@link SopsEncryptionError} On failure.
|
|
5121
|
-
*/
|
|
5122
|
-
async addRecipient(filePath, key) {
|
|
5123
|
-
await assertSops(this.runner, this.sopsCommand);
|
|
5124
|
-
const env = this.buildSopsEnv();
|
|
5125
|
-
const result = await this.runner.run(
|
|
5126
|
-
this.sopsCommand,
|
|
5127
|
-
["rotate", ...this.keyserviceArgs, "-i", "--add-age", key, filePath],
|
|
5128
|
-
{
|
|
5129
|
-
...env ? { env } : {}
|
|
5130
|
-
}
|
|
5131
|
-
);
|
|
5132
|
-
if (result.exitCode !== 0) {
|
|
5133
|
-
throw new SopsEncryptionError(
|
|
5134
|
-
`Failed to add recipient to '${filePath}': ${result.stderr.trim()}`,
|
|
5135
|
-
filePath
|
|
5136
|
-
);
|
|
5137
|
-
}
|
|
5138
|
-
}
|
|
5139
|
-
/**
|
|
5140
|
-
* Remove an age recipient from an existing SOPS file.
|
|
5141
|
-
*
|
|
5142
|
-
* @param filePath - Path to the encrypted file.
|
|
5143
|
-
* @param key - age public key to remove.
|
|
5144
|
-
* @throws {@link SopsEncryptionError} On failure.
|
|
5145
|
-
*/
|
|
5146
|
-
async removeRecipient(filePath, key) {
|
|
5147
|
-
await assertSops(this.runner, this.sopsCommand);
|
|
5148
|
-
const env = this.buildSopsEnv();
|
|
5149
|
-
const result = await this.runner.run(
|
|
5150
|
-
this.sopsCommand,
|
|
5151
|
-
["rotate", ...this.keyserviceArgs, "-i", "--rm-age", key, filePath],
|
|
5152
|
-
{
|
|
5153
|
-
...env ? { env } : {}
|
|
5154
|
-
}
|
|
5155
|
-
);
|
|
5156
|
-
if (result.exitCode !== 0) {
|
|
5157
|
-
throw new SopsEncryptionError(
|
|
5158
|
-
`Failed to remove recipient from '${filePath}': ${result.stderr.trim()}`,
|
|
5159
|
-
filePath
|
|
5160
|
-
);
|
|
5161
|
-
}
|
|
5162
|
-
}
|
|
5163
|
-
/**
|
|
5164
|
-
* Check whether a file contains valid SOPS encryption metadata.
|
|
5165
|
-
*
|
|
5166
|
-
* @param filePath - Path to the file to check.
|
|
5167
|
-
* @returns `true` if valid SOPS metadata is present; `false` otherwise. Never throws.
|
|
5168
|
-
*/
|
|
5169
|
-
async validateEncryption(filePath) {
|
|
5170
|
-
await assertSops(this.runner, this.sopsCommand);
|
|
5171
|
-
try {
|
|
5172
|
-
await this.getMetadata(filePath);
|
|
5173
|
-
return true;
|
|
5174
|
-
} catch {
|
|
5175
|
-
return false;
|
|
5176
|
-
}
|
|
5177
|
-
}
|
|
5178
|
-
/**
|
|
5179
|
-
* Extract SOPS metadata (backend, recipients, last-modified timestamp) from an encrypted file
|
|
5180
|
-
* without decrypting its values.
|
|
5181
|
-
*
|
|
5182
|
-
* @param filePath - Path to the encrypted file.
|
|
5183
|
-
* @returns {@link SopsMetadata} parsed from the file's `sops:` block.
|
|
5184
|
-
* @throws {@link SopsDecryptionError} If the file cannot be read or parsed.
|
|
5185
|
-
*/
|
|
5186
|
-
async getMetadata(filePath) {
|
|
5187
|
-
await assertSops(this.runner, this.sopsCommand);
|
|
5188
|
-
const env = this.buildSopsEnv();
|
|
5189
|
-
const result = await this.runner.run(this.sopsCommand, ["filestatus", filePath], {
|
|
5190
|
-
...env ? { env } : {}
|
|
5191
|
-
});
|
|
5192
|
-
if (result.exitCode !== 0) {
|
|
5193
|
-
return this.parseMetadataFromFile(filePath);
|
|
5194
|
-
}
|
|
5195
|
-
return this.parseMetadataFromFile(filePath);
|
|
5196
|
-
}
|
|
5197
4914
|
/**
|
|
5198
4915
|
* Determine whether a decrypt failure is caused by a missing/mismatched key (vs. some other
|
|
5199
4916
|
* SOPS error) without relying on stderr message text.
|
|
@@ -5237,20 +4954,30 @@ var SopsClient = class {
|
|
|
5237
4954
|
filePath
|
|
5238
4955
|
);
|
|
5239
4956
|
}
|
|
4957
|
+
return this.parseMetadataFromContent(content, filePath);
|
|
4958
|
+
}
|
|
4959
|
+
/**
|
|
4960
|
+
* Parse SOPS metadata from a string (no IO). Used by both
|
|
4961
|
+
* `parseMetadataFromFile` (after reading from disk) and the blob-shaped
|
|
4962
|
+
* `getMetadataFromBlob` (which receives ciphertext directly from a
|
|
4963
|
+
* BlobStore). The `label` is woven into error messages so callers can
|
|
4964
|
+
* include the file path or cell ref the content came from.
|
|
4965
|
+
*/
|
|
4966
|
+
parseMetadataFromContent(content, label) {
|
|
5240
4967
|
let parsed;
|
|
5241
4968
|
try {
|
|
5242
4969
|
parsed = YAML8.parse(content);
|
|
5243
4970
|
} catch {
|
|
5244
4971
|
throw new SopsDecryptionError(
|
|
5245
|
-
|
|
5246
|
-
|
|
4972
|
+
`${label} is not valid YAML. Cannot extract SOPS metadata.`,
|
|
4973
|
+
label
|
|
5247
4974
|
);
|
|
5248
4975
|
}
|
|
5249
4976
|
const sops = parsed?.sops;
|
|
5250
4977
|
if (!sops) {
|
|
5251
4978
|
throw new SopsDecryptionError(
|
|
5252
|
-
|
|
5253
|
-
|
|
4979
|
+
`${label} does not contain SOPS metadata. It may not be encrypted.`,
|
|
4980
|
+
label
|
|
5254
4981
|
);
|
|
5255
4982
|
}
|
|
5256
4983
|
const backend = this.detectBackend(sops);
|
|
@@ -5313,7 +5040,7 @@ var SopsClient = class {
|
|
|
5313
5040
|
}
|
|
5314
5041
|
}
|
|
5315
5042
|
}
|
|
5316
|
-
buildEncryptArgs(
|
|
5043
|
+
buildEncryptArgs(manifest, environment) {
|
|
5317
5044
|
const args = [];
|
|
5318
5045
|
const config = environment ? resolveBackendConfig(manifest, environment) : {
|
|
5319
5046
|
backend: manifest.sops.default_backend,
|
|
@@ -5361,11 +5088,255 @@ var SopsClient = class {
|
|
|
5361
5088
|
}
|
|
5362
5089
|
return args;
|
|
5363
5090
|
}
|
|
5091
|
+
// ── Blob-shaped methods ─────────────────────────────────────────────────
|
|
5092
|
+
//
|
|
5093
|
+
// These mirror the file-path methods above but operate on opaque
|
|
5094
|
+
// ciphertext bytes via SOPS' stdin/stdout. They are the substrate-
|
|
5095
|
+
// agnostic primitives used by the `composeSecretSource` factory to
|
|
5096
|
+
// wrap any `BlobStore` (filesystem, postgres, etc.) into a full
|
|
5097
|
+
// `SecretSource`. Plaintext never leaves the SOPS subprocess.
|
|
5098
|
+
/**
|
|
5099
|
+
* {@link EncryptionBackend.decrypt} — decrypt SOPS-encrypted bytes (e.g.
|
|
5100
|
+
* read from a `StorageBackend`) and return plaintext values + metadata.
|
|
5101
|
+
* Plaintext lives only in memory.
|
|
5102
|
+
*/
|
|
5103
|
+
async decrypt(blob, ctx) {
|
|
5104
|
+
await assertSops(this.runner, this.sopsCommand);
|
|
5105
|
+
const env = this.buildSopsEnv();
|
|
5106
|
+
const pipe = await openInputPipe(blob);
|
|
5107
|
+
let result;
|
|
5108
|
+
try {
|
|
5109
|
+
result = await this.runner.run(
|
|
5110
|
+
this.sopsCommand,
|
|
5111
|
+
[
|
|
5112
|
+
"decrypt",
|
|
5113
|
+
...this.keyserviceArgs,
|
|
5114
|
+
"--input-type",
|
|
5115
|
+
ctx.format,
|
|
5116
|
+
"--output-type",
|
|
5117
|
+
ctx.format,
|
|
5118
|
+
pipe.inputArg
|
|
5119
|
+
],
|
|
5120
|
+
{
|
|
5121
|
+
...pipe.runnerStdin !== void 0 ? { stdin: pipe.runnerStdin } : {},
|
|
5122
|
+
...env ? { env } : {}
|
|
5123
|
+
}
|
|
5124
|
+
);
|
|
5125
|
+
} finally {
|
|
5126
|
+
pipe.cleanup();
|
|
5127
|
+
}
|
|
5128
|
+
if (result.exitCode !== 0) {
|
|
5129
|
+
const errorType = await this.classifyDecryptErrorFromContent(blob);
|
|
5130
|
+
if (errorType === "key-not-found") {
|
|
5131
|
+
throw new SopsKeyNotFoundError(`No decryption key found for cell. ${result.stderr.trim()}`);
|
|
5132
|
+
}
|
|
5133
|
+
throw new SopsDecryptionError(`Failed to decrypt cell: ${result.stderr.trim()}`);
|
|
5134
|
+
}
|
|
5135
|
+
let parsed;
|
|
5136
|
+
try {
|
|
5137
|
+
parsed = YAML8.parse(result.stdout) ?? {};
|
|
5138
|
+
} catch {
|
|
5139
|
+
throw new SopsDecryptionError("Decrypted content is not valid YAML.");
|
|
5140
|
+
}
|
|
5141
|
+
const values = {};
|
|
5142
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
5143
|
+
values[key] = String(value);
|
|
5144
|
+
}
|
|
5145
|
+
const metadata = this.parseMetadataFromContent(blob, "<cell>");
|
|
5146
|
+
return { values, metadata };
|
|
5147
|
+
}
|
|
5148
|
+
/**
|
|
5149
|
+
* {@link EncryptionBackend.encrypt} — encrypt plaintext values into a
|
|
5150
|
+
* SOPS-formatted ciphertext blob. Returns the bytes as a string;
|
|
5151
|
+
* caller (typically a `StorageBackend`) decides where to put them.
|
|
5152
|
+
* Plaintext is piped via stdin only.
|
|
5153
|
+
*/
|
|
5154
|
+
async encrypt(values, ctx) {
|
|
5155
|
+
await assertSops(this.runner, this.sopsCommand);
|
|
5156
|
+
const content = ctx.format === "json" ? JSON.stringify(values, null, 2) : YAML8.stringify(values);
|
|
5157
|
+
const args = this.buildEncryptArgs(ctx.manifest, ctx.environment);
|
|
5158
|
+
const env = this.buildSopsEnv();
|
|
5159
|
+
const pipe = await openInputPipe(content);
|
|
5160
|
+
let result;
|
|
5161
|
+
try {
|
|
5162
|
+
result = await this.runner.run(
|
|
5163
|
+
this.sopsCommand,
|
|
5164
|
+
[
|
|
5165
|
+
"--config",
|
|
5166
|
+
nullConfigPath(),
|
|
5167
|
+
"encrypt",
|
|
5168
|
+
...this.keyserviceArgs,
|
|
5169
|
+
...args,
|
|
5170
|
+
"--input-type",
|
|
5171
|
+
ctx.format,
|
|
5172
|
+
"--output-type",
|
|
5173
|
+
ctx.format,
|
|
5174
|
+
pipe.inputArg
|
|
5175
|
+
],
|
|
5176
|
+
{
|
|
5177
|
+
...pipe.runnerStdin !== void 0 ? { stdin: pipe.runnerStdin } : {},
|
|
5178
|
+
...env ? { env } : {}
|
|
5179
|
+
}
|
|
5180
|
+
);
|
|
5181
|
+
} finally {
|
|
5182
|
+
pipe.cleanup();
|
|
5183
|
+
}
|
|
5184
|
+
if (result.exitCode !== 0) {
|
|
5185
|
+
throw new SopsEncryptionError(`Failed to encrypt cell: ${result.stderr.trim()}`);
|
|
5186
|
+
}
|
|
5187
|
+
return result.stdout;
|
|
5188
|
+
}
|
|
5189
|
+
/**
|
|
5190
|
+
* {@link EncryptionBackend.rotate} — add or remove recipients from an
|
|
5191
|
+
* encrypted SOPS blob via stdin/stdout. Drops the in-place `-i` flag
|
|
5192
|
+
* the deleted file-path-shaped methods used, so SOPS writes the
|
|
5193
|
+
* rotated ciphertext to stdout instead of back to a file. Plaintext
|
|
5194
|
+
* stays inside the SOPS subprocess; no plaintext window exists in
|
|
5195
|
+
* this Node process.
|
|
5196
|
+
*
|
|
5197
|
+
* Single SOPS invocation can both add and remove recipients
|
|
5198
|
+
* simultaneously (matches the CLI flag set).
|
|
5199
|
+
*/
|
|
5200
|
+
async rotate(blob, opts, ctx) {
|
|
5201
|
+
await assertSops(this.runner, this.sopsCommand);
|
|
5202
|
+
const env = this.buildSopsEnv();
|
|
5203
|
+
const pipe = await openInputPipe(blob);
|
|
5204
|
+
const flagArgs = [];
|
|
5205
|
+
if (opts.addAge) flagArgs.push("--add-age", opts.addAge);
|
|
5206
|
+
if (opts.rmAge) flagArgs.push("--rm-age", opts.rmAge);
|
|
5207
|
+
if (opts.addKms) flagArgs.push("--add-kms", opts.addKms);
|
|
5208
|
+
if (opts.rmKms) flagArgs.push("--rm-kms", opts.rmKms);
|
|
5209
|
+
if (opts.addGcpKms) flagArgs.push("--add-gcp-kms", opts.addGcpKms);
|
|
5210
|
+
if (opts.rmGcpKms) flagArgs.push("--rm-gcp-kms", opts.rmGcpKms);
|
|
5211
|
+
if (opts.addAzureKv) flagArgs.push("--add-azure-kv", opts.addAzureKv);
|
|
5212
|
+
if (opts.rmAzureKv) flagArgs.push("--rm-azure-kv", opts.rmAzureKv);
|
|
5213
|
+
if (opts.addPgp) flagArgs.push("--add-pgp", opts.addPgp);
|
|
5214
|
+
if (opts.rmPgp) flagArgs.push("--rm-pgp", opts.rmPgp);
|
|
5215
|
+
let result;
|
|
5216
|
+
try {
|
|
5217
|
+
result = await this.runner.run(
|
|
5218
|
+
this.sopsCommand,
|
|
5219
|
+
[
|
|
5220
|
+
"--config",
|
|
5221
|
+
nullConfigPath(),
|
|
5222
|
+
"rotate",
|
|
5223
|
+
...this.keyserviceArgs,
|
|
5224
|
+
...flagArgs,
|
|
5225
|
+
"--input-type",
|
|
5226
|
+
ctx.format,
|
|
5227
|
+
"--output-type",
|
|
5228
|
+
ctx.format,
|
|
5229
|
+
pipe.inputArg
|
|
5230
|
+
],
|
|
5231
|
+
{
|
|
5232
|
+
...pipe.runnerStdin !== void 0 ? { stdin: pipe.runnerStdin } : {},
|
|
5233
|
+
...env ? { env } : {}
|
|
5234
|
+
}
|
|
5235
|
+
);
|
|
5236
|
+
} finally {
|
|
5237
|
+
pipe.cleanup();
|
|
5238
|
+
}
|
|
5239
|
+
if (result.exitCode !== 0) {
|
|
5240
|
+
throw new SopsEncryptionError(`Failed to rotate cell: ${result.stderr.trim()}`);
|
|
5241
|
+
}
|
|
5242
|
+
return result.stdout;
|
|
5243
|
+
}
|
|
5244
|
+
/**
|
|
5245
|
+
* {@link EncryptionBackend.getMetadata} — extract SOPS metadata from a
|
|
5246
|
+
* ciphertext blob without decrypting. Pure parser, no IO, no
|
|
5247
|
+
* subprocess.
|
|
5248
|
+
*/
|
|
5249
|
+
getMetadata(content) {
|
|
5250
|
+
return this.parseMetadataFromContent(content, "<cell>");
|
|
5251
|
+
}
|
|
5252
|
+
/**
|
|
5253
|
+
* {@link EncryptionBackend.validateEncryption} — whether `content` is a
|
|
5254
|
+
* valid SOPS-encrypted blob (parses + has the `sops:` metadata
|
|
5255
|
+
* block). Never throws.
|
|
5256
|
+
*/
|
|
5257
|
+
validateEncryption(content) {
|
|
5258
|
+
try {
|
|
5259
|
+
this.parseMetadataFromContent(content, "<cell>");
|
|
5260
|
+
return true;
|
|
5261
|
+
} catch {
|
|
5262
|
+
return false;
|
|
5263
|
+
}
|
|
5264
|
+
}
|
|
5265
|
+
/**
|
|
5266
|
+
* Blob-shaped variant of `classifyDecryptError`. Same logic as the
|
|
5267
|
+
* file-path version but reads metadata from the in-memory ciphertext
|
|
5268
|
+
* instead of disk.
|
|
5269
|
+
*/
|
|
5270
|
+
async classifyDecryptErrorFromContent(content) {
|
|
5271
|
+
let metadata;
|
|
5272
|
+
try {
|
|
5273
|
+
metadata = this.parseMetadataFromContent(content, "<cell>");
|
|
5274
|
+
} catch {
|
|
5275
|
+
return "other";
|
|
5276
|
+
}
|
|
5277
|
+
if (metadata.backend !== "age") return "other";
|
|
5278
|
+
if (!this.ageKey && !this.ageKeyFile) return "key-not-found";
|
|
5279
|
+
let keyContent;
|
|
5280
|
+
try {
|
|
5281
|
+
keyContent = this.ageKey ?? fs14.readFileSync(this.ageKeyFile, "utf-8");
|
|
5282
|
+
} catch {
|
|
5283
|
+
return "key-not-found";
|
|
5284
|
+
}
|
|
5285
|
+
const privateKeys = keyContent.split("\n").map((line) => line.trim()).filter((line) => line.startsWith("AGE-SECRET-KEY-"));
|
|
5286
|
+
if (privateKeys.length === 0) return "key-not-found";
|
|
5287
|
+
try {
|
|
5288
|
+
const publicKeys = await Promise.all(privateKeys.map((k) => deriveAgePublicKey(k)));
|
|
5289
|
+
const recipients = new Set(metadata.recipients);
|
|
5290
|
+
return publicKeys.some((pk) => recipients.has(pk)) ? "other" : "key-not-found";
|
|
5291
|
+
} catch {
|
|
5292
|
+
return "other";
|
|
5293
|
+
}
|
|
5294
|
+
}
|
|
5364
5295
|
};
|
|
5365
5296
|
|
|
5297
|
+
// src/sops/linux-stdin-fifo.ts
|
|
5298
|
+
import * as os from "os";
|
|
5299
|
+
import * as path11 from "path";
|
|
5300
|
+
import { execFileSync, spawn } from "child_process";
|
|
5301
|
+
function shouldUseLinuxStdinFifo() {
|
|
5302
|
+
return process.platform === "linux" && !process.env.JEST_WORKER_ID;
|
|
5303
|
+
}
|
|
5304
|
+
function wrapWithLinuxStdinFifo(runner) {
|
|
5305
|
+
if (!shouldUseLinuxStdinFifo()) return runner;
|
|
5306
|
+
return {
|
|
5307
|
+
run: (cmd, args, opts) => {
|
|
5308
|
+
const stdinIdx = args.indexOf("/dev/stdin");
|
|
5309
|
+
if (stdinIdx < 0 || opts?.stdin === void 0) {
|
|
5310
|
+
return runner.run(cmd, args, opts);
|
|
5311
|
+
}
|
|
5312
|
+
const fifoDir = execFileSync("mktemp", ["-d", path11.join(os.tmpdir(), "clef-fifo-XXXXXX")]).toString().trim();
|
|
5313
|
+
const fifoPath = path11.join(fifoDir, "input");
|
|
5314
|
+
execFileSync("mkfifo", [fifoPath]);
|
|
5315
|
+
const writer = spawn("dd", [`of=${fifoPath}`, "status=none"], {
|
|
5316
|
+
stdio: ["pipe", "ignore", "ignore"]
|
|
5317
|
+
});
|
|
5318
|
+
writer.stdin.write(opts.stdin);
|
|
5319
|
+
writer.stdin.end();
|
|
5320
|
+
const patchedArgs = [...args];
|
|
5321
|
+
patchedArgs[stdinIdx] = fifoPath;
|
|
5322
|
+
const { stdin: _stdin, ...restOpts } = opts;
|
|
5323
|
+
return runner.run(cmd, patchedArgs, restOpts).finally(() => {
|
|
5324
|
+
try {
|
|
5325
|
+
writer.kill();
|
|
5326
|
+
} catch {
|
|
5327
|
+
}
|
|
5328
|
+
try {
|
|
5329
|
+
execFileSync("rm", ["-rf", fifoDir]);
|
|
5330
|
+
} catch {
|
|
5331
|
+
}
|
|
5332
|
+
});
|
|
5333
|
+
}
|
|
5334
|
+
};
|
|
5335
|
+
}
|
|
5336
|
+
|
|
5366
5337
|
// src/hsm/bundled.ts
|
|
5367
5338
|
import * as fs15 from "fs";
|
|
5368
|
-
import * as
|
|
5339
|
+
import * as path12 from "path";
|
|
5369
5340
|
function tryBundledKeyservice() {
|
|
5370
5341
|
const platform = process.platform;
|
|
5371
5342
|
const arch = process.arch;
|
|
@@ -5377,8 +5348,8 @@ function tryBundledKeyservice() {
|
|
|
5377
5348
|
const binName = "clef-keyservice";
|
|
5378
5349
|
try {
|
|
5379
5350
|
const packageMain = __require.resolve(`${packageName}/package.json`);
|
|
5380
|
-
const packageDir =
|
|
5381
|
-
const binPath =
|
|
5351
|
+
const packageDir = path12.dirname(packageMain);
|
|
5352
|
+
const binPath = path12.join(packageDir, "bin", binName);
|
|
5382
5353
|
return fs15.existsSync(binPath) ? binPath : null;
|
|
5383
5354
|
} catch {
|
|
5384
5355
|
return null;
|
|
@@ -5387,9 +5358,9 @@ function tryBundledKeyservice() {
|
|
|
5387
5358
|
|
|
5388
5359
|
// src/hsm/resolver.ts
|
|
5389
5360
|
import * as fs16 from "fs";
|
|
5390
|
-
import * as
|
|
5361
|
+
import * as path13 from "path";
|
|
5391
5362
|
function validateKeyservicePath(candidate) {
|
|
5392
|
-
if (!
|
|
5363
|
+
if (!path13.isAbsolute(candidate)) {
|
|
5393
5364
|
throw new Error(`CLEF_KEYSERVICE_PATH must be an absolute path, got '${candidate}'.`);
|
|
5394
5365
|
}
|
|
5395
5366
|
const segments = candidate.split(/[/\\]/);
|
|
@@ -5424,7 +5395,7 @@ function resetKeyserviceResolution() {
|
|
|
5424
5395
|
}
|
|
5425
5396
|
|
|
5426
5397
|
// src/hsm/keyservice.ts
|
|
5427
|
-
import { spawn } from "child_process";
|
|
5398
|
+
import { spawn as spawn2 } from "child_process";
|
|
5428
5399
|
import * as readline from "readline";
|
|
5429
5400
|
var PORT_REGEX = /^PORT=(\d+)$/;
|
|
5430
5401
|
var STARTUP_TIMEOUT_MS = 5e3;
|
|
@@ -5442,7 +5413,7 @@ async function spawnKeyservice(options) {
|
|
|
5442
5413
|
...options.pin ? { CLEF_PKCS11_PIN: options.pin } : {},
|
|
5443
5414
|
...options.pinFile ? { CLEF_PKCS11_PIN_FILE: options.pinFile } : {}
|
|
5444
5415
|
};
|
|
5445
|
-
const child =
|
|
5416
|
+
const child = spawn2(options.binaryPath, args, {
|
|
5446
5417
|
stdio: ["ignore", "pipe", "pipe"],
|
|
5447
5418
|
env: childEnv
|
|
5448
5419
|
});
|
|
@@ -5518,16 +5489,16 @@ function killGracefully(child) {
|
|
|
5518
5489
|
}
|
|
5519
5490
|
|
|
5520
5491
|
// src/lint/runner.ts
|
|
5521
|
-
import * as
|
|
5492
|
+
import * as path14 from "path";
|
|
5522
5493
|
var LintRunner = class {
|
|
5523
|
-
constructor(matrixManager, schemaValidator,
|
|
5494
|
+
constructor(matrixManager, schemaValidator, source) {
|
|
5524
5495
|
this.matrixManager = matrixManager;
|
|
5525
5496
|
this.schemaValidator = schemaValidator;
|
|
5526
|
-
this.
|
|
5497
|
+
this.source = source;
|
|
5527
5498
|
}
|
|
5528
5499
|
matrixManager;
|
|
5529
5500
|
schemaValidator;
|
|
5530
|
-
|
|
5501
|
+
source;
|
|
5531
5502
|
/**
|
|
5532
5503
|
* Lint the entire matrix: check missing files, schema errors, SOPS integrity,
|
|
5533
5504
|
* single-recipient warnings, and cross-environment key drift.
|
|
@@ -5554,8 +5525,9 @@ var LintRunner = class {
|
|
|
5554
5525
|
fileCount = existingCells.length;
|
|
5555
5526
|
const namespaceKeys = {};
|
|
5556
5527
|
for (const cell of existingCells) {
|
|
5528
|
+
const ref = { namespace: cell.namespace, environment: cell.environment };
|
|
5557
5529
|
try {
|
|
5558
|
-
const isValid = await this.
|
|
5530
|
+
const isValid = await this.source.validateEncryption(ref);
|
|
5559
5531
|
if (!isValid) {
|
|
5560
5532
|
issues.push({
|
|
5561
5533
|
severity: "error",
|
|
@@ -5576,7 +5548,7 @@ var LintRunner = class {
|
|
|
5576
5548
|
continue;
|
|
5577
5549
|
}
|
|
5578
5550
|
try {
|
|
5579
|
-
const decrypted = await this.
|
|
5551
|
+
const decrypted = await this.source.readCell(ref);
|
|
5580
5552
|
const keys = Object.keys(decrypted.values);
|
|
5581
5553
|
if (!namespaceKeys[cell.namespace]) {
|
|
5582
5554
|
namespaceKeys[cell.namespace] = {};
|
|
@@ -5621,7 +5593,7 @@ var LintRunner = class {
|
|
|
5621
5593
|
}
|
|
5622
5594
|
const ns = manifest.namespaces.find((n) => n.name === cell.namespace);
|
|
5623
5595
|
if (ns?.schema) {
|
|
5624
|
-
const schemaPath =
|
|
5596
|
+
const schemaPath = path14.join(repoRoot, ns.schema);
|
|
5625
5597
|
try {
|
|
5626
5598
|
const schema = this.schemaValidator.loadSchema(schemaPath);
|
|
5627
5599
|
const result = this.schemaValidator.validate(decrypted.values, schema);
|
|
@@ -5664,7 +5636,8 @@ var LintRunner = class {
|
|
|
5664
5636
|
}
|
|
5665
5637
|
}
|
|
5666
5638
|
try {
|
|
5667
|
-
const
|
|
5639
|
+
const meta = await this.source.getPendingMetadata(ref);
|
|
5640
|
+
const pendingKeys = meta.pending.map((p) => p.key);
|
|
5668
5641
|
pendingCount += pendingKeys.length;
|
|
5669
5642
|
for (const pendingKey of pendingKeys) {
|
|
5670
5643
|
issues.push({
|
|
@@ -5717,7 +5690,6 @@ var LintRunner = class {
|
|
|
5717
5690
|
const siIssues = await this.lintServiceIdentities(
|
|
5718
5691
|
manifest.service_identities,
|
|
5719
5692
|
manifest,
|
|
5720
|
-
repoRoot,
|
|
5721
5693
|
existingCells
|
|
5722
5694
|
);
|
|
5723
5695
|
issues.push(...siIssues);
|
|
@@ -5727,18 +5699,27 @@ var LintRunner = class {
|
|
|
5727
5699
|
return { issues, fileCount: fileCount + missingCells.length, pendingCount };
|
|
5728
5700
|
}
|
|
5729
5701
|
/**
|
|
5730
|
-
* Cross-reference
|
|
5702
|
+
* Cross-reference cell metadata against the cipher's plaintext key
|
|
5731
5703
|
* names for each existing cell. Reports orphan rotation records and
|
|
5732
|
-
* dual-state (pending + rotation) inconsistencies. Uses
|
|
5733
|
-
*
|
|
5704
|
+
* dual-state (pending + rotation) inconsistencies. Uses the source's
|
|
5705
|
+
* `listKeys` (no decryption).
|
|
5734
5706
|
*/
|
|
5735
5707
|
async lintMetadataConsistency(cells) {
|
|
5736
5708
|
const issues = [];
|
|
5737
5709
|
for (const cell of cells) {
|
|
5738
|
-
const
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5710
|
+
const ref = { namespace: cell.namespace, environment: cell.environment };
|
|
5711
|
+
let cipherKeys;
|
|
5712
|
+
try {
|
|
5713
|
+
cipherKeys = new Set(await this.source.listKeys(ref));
|
|
5714
|
+
} catch {
|
|
5715
|
+
continue;
|
|
5716
|
+
}
|
|
5717
|
+
let metadata;
|
|
5718
|
+
try {
|
|
5719
|
+
metadata = await this.source.getPendingMetadata(ref);
|
|
5720
|
+
} catch {
|
|
5721
|
+
continue;
|
|
5722
|
+
}
|
|
5742
5723
|
for (const record of metadata.rotations) {
|
|
5743
5724
|
if (!cipherKeys.has(record.key)) {
|
|
5744
5725
|
issues.push({
|
|
@@ -5769,7 +5750,7 @@ var LintRunner = class {
|
|
|
5769
5750
|
/**
|
|
5770
5751
|
* Lint service identity configurations for drift issues.
|
|
5771
5752
|
*/
|
|
5772
|
-
async lintServiceIdentities(identities, manifest,
|
|
5753
|
+
async lintServiceIdentities(identities, manifest, existingCells) {
|
|
5773
5754
|
const issues = [];
|
|
5774
5755
|
const declaredEnvNames = new Set(manifest.environments.map((e) => e.name));
|
|
5775
5756
|
const declaredNsNames = new Set(manifest.namespaces.map((ns) => ns.name));
|
|
@@ -5810,9 +5791,10 @@ var LintRunner = class {
|
|
|
5810
5791
|
const envConfig = si.environments[cell.environment];
|
|
5811
5792
|
if (!envConfig) continue;
|
|
5812
5793
|
if (!envConfig.recipient) continue;
|
|
5794
|
+
const ref = { namespace: cell.namespace, environment: cell.environment };
|
|
5813
5795
|
if (si.namespaces.includes(cell.namespace)) {
|
|
5814
5796
|
try {
|
|
5815
|
-
const metadata = await this.
|
|
5797
|
+
const metadata = await this.source.getCellMetadata(ref);
|
|
5816
5798
|
if (!metadata.recipients.includes(envConfig.recipient)) {
|
|
5817
5799
|
issues.push({
|
|
5818
5800
|
severity: "warning",
|
|
@@ -5826,7 +5808,7 @@ var LintRunner = class {
|
|
|
5826
5808
|
}
|
|
5827
5809
|
} else {
|
|
5828
5810
|
try {
|
|
5829
|
-
const metadata = await this.
|
|
5811
|
+
const metadata = await this.source.getCellMetadata(ref);
|
|
5830
5812
|
if (metadata.recipients.includes(envConfig.recipient)) {
|
|
5831
5813
|
issues.push({
|
|
5832
5814
|
severity: "warning",
|
|
@@ -5852,7 +5834,10 @@ var LintRunner = class {
|
|
|
5852
5834
|
async fix(manifest, repoRoot) {
|
|
5853
5835
|
const missingCells = this.matrixManager.detectMissingCells(manifest, repoRoot);
|
|
5854
5836
|
for (const cell of missingCells) {
|
|
5855
|
-
await this.
|
|
5837
|
+
await this.source.scaffoldCell(
|
|
5838
|
+
{ namespace: cell.namespace, environment: cell.environment },
|
|
5839
|
+
manifest
|
|
5840
|
+
);
|
|
5856
5841
|
}
|
|
5857
5842
|
return this.run(manifest, repoRoot);
|
|
5858
5843
|
}
|
|
@@ -5907,15 +5892,12 @@ Use 'clef exec' to inject secrets directly into a process, or 'clef export --for
|
|
|
5907
5892
|
}
|
|
5908
5893
|
};
|
|
5909
5894
|
|
|
5910
|
-
// src/import/index.ts
|
|
5911
|
-
import * as path17 from "path";
|
|
5912
|
-
|
|
5913
5895
|
// src/import/parsers.ts
|
|
5914
|
-
import * as
|
|
5896
|
+
import * as path15 from "path";
|
|
5915
5897
|
import * as YAML9 from "yaml";
|
|
5916
5898
|
function detectFormat(filePath, content) {
|
|
5917
|
-
const base =
|
|
5918
|
-
const ext =
|
|
5899
|
+
const base = path15.basename(filePath);
|
|
5900
|
+
const ext = path15.extname(filePath).toLowerCase();
|
|
5919
5901
|
if (base === ".env" || base.startsWith(".env.")) {
|
|
5920
5902
|
return "dotenv";
|
|
5921
5903
|
}
|
|
@@ -6065,11 +6047,11 @@ function parse9(content, format, filePath) {
|
|
|
6065
6047
|
|
|
6066
6048
|
// src/import/index.ts
|
|
6067
6049
|
var ImportRunner = class {
|
|
6068
|
-
constructor(
|
|
6069
|
-
this.
|
|
6050
|
+
constructor(source, tx) {
|
|
6051
|
+
this.source = source;
|
|
6070
6052
|
this.tx = tx;
|
|
6071
6053
|
}
|
|
6072
|
-
|
|
6054
|
+
source;
|
|
6073
6055
|
tx;
|
|
6074
6056
|
/**
|
|
6075
6057
|
* Parse a source file and import its key/value pairs into a target `namespace/environment` cell.
|
|
@@ -6083,10 +6065,8 @@ var ImportRunner = class {
|
|
|
6083
6065
|
*/
|
|
6084
6066
|
async import(target, sourcePath, content, manifest, repoRoot, options) {
|
|
6085
6067
|
const [ns, env] = target.split("/");
|
|
6086
|
-
const
|
|
6087
|
-
|
|
6088
|
-
manifest.file_pattern.replace("{namespace}", ns).replace("{environment}", env)
|
|
6089
|
-
);
|
|
6068
|
+
const ref = { namespace: ns, environment: env };
|
|
6069
|
+
const relCellPath = manifest.file_pattern.replace("{namespace}", ns).replace("{environment}", env);
|
|
6090
6070
|
const parsed = parse9(content, options.format ?? "auto", sourcePath ?? "");
|
|
6091
6071
|
let candidates = Object.entries(parsed.pairs);
|
|
6092
6072
|
if (options.prefix) {
|
|
@@ -6104,7 +6084,7 @@ var ImportRunner = class {
|
|
|
6104
6084
|
if (options.dryRun) {
|
|
6105
6085
|
let existingKeys;
|
|
6106
6086
|
try {
|
|
6107
|
-
const decrypted2 = await this.
|
|
6087
|
+
const decrypted2 = await this.source.readCell(ref);
|
|
6108
6088
|
existingKeys = new Set(Object.keys(decrypted2.values));
|
|
6109
6089
|
} catch {
|
|
6110
6090
|
existingKeys = /* @__PURE__ */ new Set();
|
|
@@ -6118,7 +6098,7 @@ var ImportRunner = class {
|
|
|
6118
6098
|
}
|
|
6119
6099
|
return { imported, skipped, failed, warnings, dryRun: true };
|
|
6120
6100
|
}
|
|
6121
|
-
const decrypted = await this.
|
|
6101
|
+
const decrypted = await this.source.readCell(ref);
|
|
6122
6102
|
const newValues = { ...decrypted.values };
|
|
6123
6103
|
const rotatedKeys = [];
|
|
6124
6104
|
for (const [key, value] of candidates) {
|
|
@@ -6135,7 +6115,6 @@ var ImportRunner = class {
|
|
|
6135
6115
|
if (imported.length === 0) {
|
|
6136
6116
|
return { imported, skipped, failed, warnings, dryRun: false };
|
|
6137
6117
|
}
|
|
6138
|
-
const relCellPath = path17.relative(repoRoot, filePath);
|
|
6139
6118
|
const relMetaPath = relCellPath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml");
|
|
6140
6119
|
await this.tx.run(repoRoot, {
|
|
6141
6120
|
description: `clef import ${target}: ${imported.length} key(s)`,
|
|
@@ -6143,9 +6122,9 @@ var ImportRunner = class {
|
|
|
6143
6122
|
// callback are staged and rolled back atomically with the ciphertext.
|
|
6144
6123
|
paths: [relCellPath, relMetaPath],
|
|
6145
6124
|
mutate: async () => {
|
|
6146
|
-
await this.
|
|
6125
|
+
await this.source.writeCell(ref, newValues);
|
|
6147
6126
|
if (options.rotatedBy && rotatedKeys.length > 0) {
|
|
6148
|
-
await recordRotation(
|
|
6127
|
+
await this.source.recordRotation(ref, rotatedKeys, options.rotatedBy);
|
|
6149
6128
|
}
|
|
6150
6129
|
}
|
|
6151
6130
|
});
|
|
@@ -6154,7 +6133,7 @@ var ImportRunner = class {
|
|
|
6154
6133
|
};
|
|
6155
6134
|
|
|
6156
6135
|
// src/recipients/index.ts
|
|
6157
|
-
import * as
|
|
6136
|
+
import * as path16 from "path";
|
|
6158
6137
|
function parseRecipientEntry(entry) {
|
|
6159
6138
|
if (typeof entry === "string") {
|
|
6160
6139
|
return { key: entry };
|
|
@@ -6222,12 +6201,12 @@ function ensureEnvironmentRecipientsArray(doc, envName) {
|
|
|
6222
6201
|
return env.recipients;
|
|
6223
6202
|
}
|
|
6224
6203
|
var RecipientManager = class {
|
|
6225
|
-
constructor(
|
|
6226
|
-
this.
|
|
6204
|
+
constructor(source, matrixManager, tx) {
|
|
6205
|
+
this.source = source;
|
|
6227
6206
|
this.matrixManager = matrixManager;
|
|
6228
6207
|
this.tx = tx;
|
|
6229
6208
|
}
|
|
6230
|
-
|
|
6209
|
+
source;
|
|
6231
6210
|
matrixManager;
|
|
6232
6211
|
tx;
|
|
6233
6212
|
/**
|
|
@@ -6282,7 +6261,7 @@ var RecipientManager = class {
|
|
|
6282
6261
|
const reEncryptedFiles = [];
|
|
6283
6262
|
await this.tx.run(repoRoot, {
|
|
6284
6263
|
description: environment ? `clef recipients add ${keyPreview(normalizedKey)} -e ${environment}` : `clef recipients add ${keyPreview(normalizedKey)}`,
|
|
6285
|
-
paths: [...cells.map((c) =>
|
|
6264
|
+
paths: [...cells.map((c) => path16.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME],
|
|
6286
6265
|
mutate: async () => {
|
|
6287
6266
|
const doc = readManifestYaml(repoRoot);
|
|
6288
6267
|
const recipients = environment ? ensureEnvironmentRecipientsArray(doc, environment) : ensureRecipientsArray(doc);
|
|
@@ -6293,7 +6272,8 @@ var RecipientManager = class {
|
|
|
6293
6272
|
}
|
|
6294
6273
|
writeManifestYaml(repoRoot, doc);
|
|
6295
6274
|
for (const cell of cells) {
|
|
6296
|
-
|
|
6275
|
+
const ref = { namespace: cell.namespace, environment: cell.environment };
|
|
6276
|
+
await this.source.rotate(ref, { addAge: normalizedKey });
|
|
6297
6277
|
reEncryptedFiles.push(cell.filePath);
|
|
6298
6278
|
}
|
|
6299
6279
|
}
|
|
@@ -6341,7 +6321,7 @@ var RecipientManager = class {
|
|
|
6341
6321
|
const reEncryptedFiles = [];
|
|
6342
6322
|
await this.tx.run(repoRoot, {
|
|
6343
6323
|
description: environment ? `clef recipients remove ${keyPreview(trimmedKey)} -e ${environment}` : `clef recipients remove ${keyPreview(trimmedKey)}`,
|
|
6344
|
-
paths: [...cells.map((c) =>
|
|
6324
|
+
paths: [...cells.map((c) => path16.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME],
|
|
6345
6325
|
mutate: async () => {
|
|
6346
6326
|
const doc = readManifestYaml(repoRoot);
|
|
6347
6327
|
const recipients = environment ? ensureEnvironmentRecipientsArray(doc, environment) : ensureRecipientsArray(doc);
|
|
@@ -6349,7 +6329,8 @@ var RecipientManager = class {
|
|
|
6349
6329
|
recipients.splice(idx, 1);
|
|
6350
6330
|
writeManifestYaml(repoRoot, doc);
|
|
6351
6331
|
for (const cell of cells) {
|
|
6352
|
-
|
|
6332
|
+
const ref = { namespace: cell.namespace, environment: cell.environment };
|
|
6333
|
+
await this.source.rotate(ref, { rmAge: trimmedKey });
|
|
6353
6334
|
reEncryptedFiles.push(cell.filePath);
|
|
6354
6335
|
}
|
|
6355
6336
|
}
|
|
@@ -6371,12 +6352,12 @@ var RecipientManager = class {
|
|
|
6371
6352
|
|
|
6372
6353
|
// src/recipients/requests.ts
|
|
6373
6354
|
import * as fs17 from "fs";
|
|
6374
|
-
import * as
|
|
6355
|
+
import * as path17 from "path";
|
|
6375
6356
|
import * as YAML10 from "yaml";
|
|
6376
6357
|
var REQUESTS_FILENAME = ".clef-requests.yaml";
|
|
6377
6358
|
var HEADER_COMMENT2 = "# Pending recipient access requests. Approve with: clef recipients approve <label>\n";
|
|
6378
6359
|
function requestsFilePath(repoRoot) {
|
|
6379
|
-
return
|
|
6360
|
+
return path17.join(repoRoot, REQUESTS_FILENAME);
|
|
6380
6361
|
}
|
|
6381
6362
|
function loadRequests(repoRoot) {
|
|
6382
6363
|
const filePath = requestsFilePath(repoRoot);
|
|
@@ -6451,7 +6432,7 @@ function findInList(requests, identifier) {
|
|
|
6451
6432
|
}
|
|
6452
6433
|
|
|
6453
6434
|
// src/drift/detector.ts
|
|
6454
|
-
import * as
|
|
6435
|
+
import * as path18 from "path";
|
|
6455
6436
|
var DriftDetector = class {
|
|
6456
6437
|
parser = new ManifestParser();
|
|
6457
6438
|
matrix = new MatrixManager();
|
|
@@ -6464,8 +6445,8 @@ var DriftDetector = class {
|
|
|
6464
6445
|
* @returns Drift result with any issues found.
|
|
6465
6446
|
*/
|
|
6466
6447
|
detect(localRoot, remoteRoot, namespaceFilter) {
|
|
6467
|
-
const localManifest = this.parser.parse(
|
|
6468
|
-
const remoteManifest = this.parser.parse(
|
|
6448
|
+
const localManifest = this.parser.parse(path18.join(localRoot, CLEF_MANIFEST_FILENAME));
|
|
6449
|
+
const remoteManifest = this.parser.parse(path18.join(remoteRoot, CLEF_MANIFEST_FILENAME));
|
|
6469
6450
|
const localCells = this.matrix.resolveMatrix(localManifest, localRoot);
|
|
6470
6451
|
const remoteCells = this.matrix.resolveMatrix(remoteManifest, remoteRoot);
|
|
6471
6452
|
const localEnvNames = localManifest.environments.map((e) => e.name);
|
|
@@ -6529,7 +6510,7 @@ var DriftDetector = class {
|
|
|
6529
6510
|
};
|
|
6530
6511
|
|
|
6531
6512
|
// src/report/generator.ts
|
|
6532
|
-
import * as
|
|
6513
|
+
import * as path19 from "path";
|
|
6533
6514
|
|
|
6534
6515
|
// src/report/sanitizer.ts
|
|
6535
6516
|
var ReportSanitizer = class {
|
|
@@ -6666,14 +6647,14 @@ var ReportSanitizer = class {
|
|
|
6666
6647
|
|
|
6667
6648
|
// src/report/generator.ts
|
|
6668
6649
|
var ReportGenerator = class {
|
|
6669
|
-
constructor(runner,
|
|
6650
|
+
constructor(runner, source, matrixManager, schemaValidator) {
|
|
6670
6651
|
this.runner = runner;
|
|
6671
|
-
this.
|
|
6652
|
+
this.source = source;
|
|
6672
6653
|
this.matrixManager = matrixManager;
|
|
6673
6654
|
this.schemaValidator = schemaValidator;
|
|
6674
6655
|
}
|
|
6675
6656
|
runner;
|
|
6676
|
-
|
|
6657
|
+
source;
|
|
6677
6658
|
matrixManager;
|
|
6678
6659
|
schemaValidator;
|
|
6679
6660
|
/**
|
|
@@ -6689,7 +6670,7 @@ var ReportGenerator = class {
|
|
|
6689
6670
|
let manifest = null;
|
|
6690
6671
|
try {
|
|
6691
6672
|
const parser = new ManifestParser();
|
|
6692
|
-
manifest = parser.parse(
|
|
6673
|
+
manifest = parser.parse(path19.join(repoRoot, "clef.yaml"));
|
|
6693
6674
|
} catch {
|
|
6694
6675
|
const emptyManifest = {
|
|
6695
6676
|
manifestVersion: 0,
|
|
@@ -6810,16 +6791,17 @@ var ReportGenerator = class {
|
|
|
6810
6791
|
metadata: null
|
|
6811
6792
|
};
|
|
6812
6793
|
}
|
|
6794
|
+
const ref = { namespace: cell.namespace, environment: cell.environment };
|
|
6813
6795
|
const keyCount = this.readKeyCount(cell.filePath);
|
|
6814
6796
|
let pendingCount = 0;
|
|
6815
6797
|
try {
|
|
6816
|
-
const
|
|
6817
|
-
pendingCount = pending.length;
|
|
6798
|
+
const meta = await this.source.getPendingMetadata(ref);
|
|
6799
|
+
pendingCount = meta.pending.length;
|
|
6818
6800
|
} catch {
|
|
6819
6801
|
}
|
|
6820
6802
|
let metadata = null;
|
|
6821
6803
|
try {
|
|
6822
|
-
const sopsMetadata = await this.
|
|
6804
|
+
const sopsMetadata = await this.source.getCellMetadata(ref);
|
|
6823
6805
|
metadata = {
|
|
6824
6806
|
backend: sopsMetadata.backend,
|
|
6825
6807
|
recipients: sopsMetadata.recipients,
|
|
@@ -6842,7 +6824,7 @@ var ReportGenerator = class {
|
|
|
6842
6824
|
}
|
|
6843
6825
|
async buildPolicy(manifest, repoRoot) {
|
|
6844
6826
|
try {
|
|
6845
|
-
const lintRunner = new LintRunner(this.matrixManager, this.schemaValidator, this.
|
|
6827
|
+
const lintRunner = new LintRunner(this.matrixManager, this.schemaValidator, this.source);
|
|
6846
6828
|
const lintResult = await lintRunner.run(manifest, repoRoot);
|
|
6847
6829
|
return new ReportSanitizer().sanitize(lintResult.issues);
|
|
6848
6830
|
} catch {
|
|
@@ -7159,9 +7141,9 @@ var SopsMergeDriver = class {
|
|
|
7159
7141
|
*/
|
|
7160
7142
|
async mergeFiles(basePath, oursPath, theirsPath) {
|
|
7161
7143
|
const [baseDecrypted, oursDecrypted, theirsDecrypted] = await Promise.all([
|
|
7162
|
-
this.sopsClient.
|
|
7163
|
-
this.sopsClient.
|
|
7164
|
-
this.sopsClient.
|
|
7144
|
+
this.sopsClient.decryptFile(basePath),
|
|
7145
|
+
this.sopsClient.decryptFile(oursPath),
|
|
7146
|
+
this.sopsClient.decryptFile(theirsPath)
|
|
7165
7147
|
]);
|
|
7166
7148
|
return this.merge(baseDecrypted.values, oursDecrypted.values, theirsDecrypted.values);
|
|
7167
7149
|
}
|
|
@@ -7278,22 +7260,26 @@ function mergeMetadataFiles(_basePath, oursPath, theirsPath) {
|
|
|
7278
7260
|
}
|
|
7279
7261
|
|
|
7280
7262
|
// src/service-identity/manager.ts
|
|
7281
|
-
import * as
|
|
7263
|
+
import * as path20 from "path";
|
|
7282
7264
|
var ServiceIdentityManager = class {
|
|
7283
|
-
constructor(
|
|
7284
|
-
this.
|
|
7265
|
+
constructor(source, matrixManager, tx) {
|
|
7266
|
+
this.source = source;
|
|
7285
7267
|
this.matrixManager = matrixManager;
|
|
7286
7268
|
this.tx = tx;
|
|
7287
7269
|
}
|
|
7288
|
-
|
|
7270
|
+
source;
|
|
7289
7271
|
matrixManager;
|
|
7290
7272
|
tx;
|
|
7273
|
+
/** Helper: cell → ref for the source seam. */
|
|
7274
|
+
ref(cell) {
|
|
7275
|
+
return { namespace: cell.namespace, environment: cell.environment };
|
|
7276
|
+
}
|
|
7291
7277
|
/**
|
|
7292
7278
|
* Compute repo-relative paths for a set of cells plus the manifest. Used
|
|
7293
7279
|
* to seed TransactionManager.run's `paths` argument.
|
|
7294
7280
|
*/
|
|
7295
7281
|
txPaths(repoRoot, cells) {
|
|
7296
|
-
return [...cells.map((c) =>
|
|
7282
|
+
return [...cells.map((c) => path20.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME];
|
|
7297
7283
|
}
|
|
7298
7284
|
/**
|
|
7299
7285
|
* Create a new service identity with per-environment age key pairs or KMS envelope config.
|
|
@@ -7385,7 +7371,7 @@ var ServiceIdentityManager = class {
|
|
|
7385
7371
|
if (!envConfig?.recipient) continue;
|
|
7386
7372
|
if (isKmsEnvelope(envConfig)) continue;
|
|
7387
7373
|
try {
|
|
7388
|
-
await this.
|
|
7374
|
+
await this.source.rotate(this.ref(cell), { rmAge: envConfig.recipient });
|
|
7389
7375
|
} catch {
|
|
7390
7376
|
}
|
|
7391
7377
|
}
|
|
@@ -7435,7 +7421,7 @@ var ServiceIdentityManager = class {
|
|
|
7435
7421
|
const scopedCells = cells.filter((c) => c.environment === envName);
|
|
7436
7422
|
for (const cell of scopedCells) {
|
|
7437
7423
|
try {
|
|
7438
|
-
await this.
|
|
7424
|
+
await this.source.rotate(this.ref(cell), { rmAge: oldConfig.recipient });
|
|
7439
7425
|
} catch {
|
|
7440
7426
|
}
|
|
7441
7427
|
}
|
|
@@ -7462,7 +7448,7 @@ var ServiceIdentityManager = class {
|
|
|
7462
7448
|
if (isKmsEnvelope(envConfig)) continue;
|
|
7463
7449
|
if (!envConfig.recipient) continue;
|
|
7464
7450
|
try {
|
|
7465
|
-
await this.
|
|
7451
|
+
await this.source.rotate(this.ref(cell), { addAge: envConfig.recipient });
|
|
7466
7452
|
} catch (err) {
|
|
7467
7453
|
const message = err instanceof Error ? err.message : String(err);
|
|
7468
7454
|
if (!message.includes("already")) {
|
|
@@ -7510,7 +7496,7 @@ var ServiceIdentityManager = class {
|
|
|
7510
7496
|
if (isKmsEnvelope(envConfig)) continue;
|
|
7511
7497
|
if (!envConfig.recipient) continue;
|
|
7512
7498
|
try {
|
|
7513
|
-
await this.
|
|
7499
|
+
await this.source.rotate(this.ref(cell), { addAge: envConfig.recipient });
|
|
7514
7500
|
affectedFiles.push(cell.filePath);
|
|
7515
7501
|
} catch (err) {
|
|
7516
7502
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -7571,7 +7557,7 @@ var ServiceIdentityManager = class {
|
|
|
7571
7557
|
if (isKmsEnvelope(envConfig)) continue;
|
|
7572
7558
|
if (!envConfig.recipient) continue;
|
|
7573
7559
|
try {
|
|
7574
|
-
await this.
|
|
7560
|
+
await this.source.rotate(this.ref(cell), { rmAge: envConfig.recipient });
|
|
7575
7561
|
affectedFiles.push(cell.filePath);
|
|
7576
7562
|
} catch {
|
|
7577
7563
|
}
|
|
@@ -7640,7 +7626,7 @@ var ServiceIdentityManager = class {
|
|
|
7640
7626
|
if (!identity.pack_only && !isKmsEnvelope(envConfig) && envConfig.recipient) {
|
|
7641
7627
|
for (const cell of cells) {
|
|
7642
7628
|
try {
|
|
7643
|
-
await this.
|
|
7629
|
+
await this.source.rotate(this.ref(cell), { addAge: envConfig.recipient });
|
|
7644
7630
|
} catch (err) {
|
|
7645
7631
|
const message = err instanceof Error ? err.message : String(err);
|
|
7646
7632
|
if (!message.includes("already")) {
|
|
@@ -7717,10 +7703,10 @@ var ServiceIdentityManager = class {
|
|
|
7717
7703
|
const scopedCells = cells.filter((c) => c.environment === envName);
|
|
7718
7704
|
for (const cell of scopedCells) {
|
|
7719
7705
|
try {
|
|
7720
|
-
await this.
|
|
7706
|
+
await this.source.rotate(this.ref(cell), { rmAge: oldRecipient });
|
|
7721
7707
|
} catch {
|
|
7722
7708
|
}
|
|
7723
|
-
await this.
|
|
7709
|
+
await this.source.rotate(this.ref(cell), { addAge: newPublicKey });
|
|
7724
7710
|
}
|
|
7725
7711
|
}
|
|
7726
7712
|
}
|
|
@@ -7779,7 +7765,7 @@ var ServiceIdentityManager = class {
|
|
|
7779
7765
|
if (!envConfig.recipient) continue;
|
|
7780
7766
|
if (si.namespaces.includes(cell.namespace)) {
|
|
7781
7767
|
try {
|
|
7782
|
-
const metadata = await this.
|
|
7768
|
+
const metadata = await this.source.getCellMetadata(this.ref(cell));
|
|
7783
7769
|
if (!metadata.recipients.includes(envConfig.recipient)) {
|
|
7784
7770
|
issues.push({
|
|
7785
7771
|
identity: si.name,
|
|
@@ -7794,7 +7780,7 @@ var ServiceIdentityManager = class {
|
|
|
7794
7780
|
}
|
|
7795
7781
|
} else {
|
|
7796
7782
|
try {
|
|
7797
|
-
const metadata = await this.
|
|
7783
|
+
const metadata = await this.source.getCellMetadata(this.ref(cell));
|
|
7798
7784
|
if (metadata.recipients.includes(envConfig.recipient)) {
|
|
7799
7785
|
issues.push({
|
|
7800
7786
|
identity: si.name,
|
|
@@ -7816,15 +7802,15 @@ var ServiceIdentityManager = class {
|
|
|
7816
7802
|
|
|
7817
7803
|
// src/structure/manager.ts
|
|
7818
7804
|
import * as fs19 from "fs";
|
|
7819
|
-
import * as
|
|
7805
|
+
import * as path21 from "path";
|
|
7820
7806
|
var StructureManager = class {
|
|
7821
|
-
constructor(matrixManager,
|
|
7807
|
+
constructor(matrixManager, buildSource, tx) {
|
|
7822
7808
|
this.matrixManager = matrixManager;
|
|
7823
|
-
this.
|
|
7809
|
+
this.buildSource = buildSource;
|
|
7824
7810
|
this.tx = tx;
|
|
7825
7811
|
}
|
|
7826
7812
|
matrixManager;
|
|
7827
|
-
|
|
7813
|
+
buildSource;
|
|
7828
7814
|
tx;
|
|
7829
7815
|
// ── add ──────────────────────────────────────────────────────────────────
|
|
7830
7816
|
/**
|
|
@@ -7840,7 +7826,7 @@ var StructureManager = class {
|
|
|
7840
7826
|
this.assertValidIdentifier("namespace", name);
|
|
7841
7827
|
const newCellPaths = manifest.environments.map((env) => ({
|
|
7842
7828
|
environment: env.name,
|
|
7843
|
-
filePath:
|
|
7829
|
+
filePath: path21.join(
|
|
7844
7830
|
repoRoot,
|
|
7845
7831
|
manifest.file_pattern.replace("{namespace}", name).replace("{environment}", env.name)
|
|
7846
7832
|
)
|
|
@@ -7848,7 +7834,7 @@ var StructureManager = class {
|
|
|
7848
7834
|
for (const cell of newCellPaths) {
|
|
7849
7835
|
if (fs19.existsSync(cell.filePath)) {
|
|
7850
7836
|
throw new Error(
|
|
7851
|
-
`Cannot add namespace '${name}': file '${
|
|
7837
|
+
`Cannot add namespace '${name}': file '${path21.relative(repoRoot, cell.filePath)}' already exists.`
|
|
7852
7838
|
);
|
|
7853
7839
|
}
|
|
7854
7840
|
}
|
|
@@ -7867,21 +7853,14 @@ var StructureManager = class {
|
|
|
7867
7853
|
await this.tx.run(repoRoot, {
|
|
7868
7854
|
description: `clef namespace add ${name}`,
|
|
7869
7855
|
paths: [
|
|
7870
|
-
...newCellPaths.map((c) =>
|
|
7856
|
+
...newCellPaths.map((c) => path21.relative(repoRoot, c.filePath)),
|
|
7871
7857
|
CLEF_MANIFEST_FILENAME
|
|
7872
7858
|
],
|
|
7873
7859
|
mutate: async () => {
|
|
7860
|
+
const source = this.buildSource(updatedManifest);
|
|
7874
7861
|
for (const cell of newCellPaths) {
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
namespace: name,
|
|
7878
|
-
environment: cell.environment,
|
|
7879
|
-
filePath: cell.filePath,
|
|
7880
|
-
exists: false
|
|
7881
|
-
},
|
|
7882
|
-
this.encryption,
|
|
7883
|
-
updatedManifest
|
|
7884
|
-
);
|
|
7862
|
+
const ref = { namespace: name, environment: cell.environment };
|
|
7863
|
+
await source.scaffoldCell(ref, updatedManifest);
|
|
7885
7864
|
}
|
|
7886
7865
|
const doc = readManifestYaml(repoRoot);
|
|
7887
7866
|
const namespaces = doc.namespaces;
|
|
@@ -7912,7 +7891,7 @@ var StructureManager = class {
|
|
|
7912
7891
|
this.assertValidIdentifier("environment", name);
|
|
7913
7892
|
const newCellPaths = manifest.namespaces.map((ns) => ({
|
|
7914
7893
|
namespace: ns.name,
|
|
7915
|
-
filePath:
|
|
7894
|
+
filePath: path21.join(
|
|
7916
7895
|
repoRoot,
|
|
7917
7896
|
manifest.file_pattern.replace("{namespace}", ns.name).replace("{environment}", name)
|
|
7918
7897
|
)
|
|
@@ -7920,7 +7899,7 @@ var StructureManager = class {
|
|
|
7920
7899
|
for (const cell of newCellPaths) {
|
|
7921
7900
|
if (fs19.existsSync(cell.filePath)) {
|
|
7922
7901
|
throw new Error(
|
|
7923
|
-
`Cannot add environment '${name}': file '${
|
|
7902
|
+
`Cannot add environment '${name}': file '${path21.relative(repoRoot, cell.filePath)}' already exists.`
|
|
7924
7903
|
);
|
|
7925
7904
|
}
|
|
7926
7905
|
}
|
|
@@ -7939,21 +7918,14 @@ var StructureManager = class {
|
|
|
7939
7918
|
await this.tx.run(repoRoot, {
|
|
7940
7919
|
description: `clef env add ${name}`,
|
|
7941
7920
|
paths: [
|
|
7942
|
-
...newCellPaths.map((c) =>
|
|
7921
|
+
...newCellPaths.map((c) => path21.relative(repoRoot, c.filePath)),
|
|
7943
7922
|
CLEF_MANIFEST_FILENAME
|
|
7944
7923
|
],
|
|
7945
7924
|
mutate: async () => {
|
|
7925
|
+
const source = this.buildSource(updatedManifest);
|
|
7946
7926
|
for (const cell of newCellPaths) {
|
|
7947
|
-
|
|
7948
|
-
|
|
7949
|
-
namespace: cell.namespace,
|
|
7950
|
-
environment: name,
|
|
7951
|
-
filePath: cell.filePath,
|
|
7952
|
-
exists: false
|
|
7953
|
-
},
|
|
7954
|
-
this.encryption,
|
|
7955
|
-
updatedManifest
|
|
7956
|
-
);
|
|
7927
|
+
const ref = { namespace: cell.namespace, environment: name };
|
|
7928
|
+
await source.scaffoldCell(ref, updatedManifest);
|
|
7957
7929
|
}
|
|
7958
7930
|
const doc = readManifestYaml(repoRoot);
|
|
7959
7931
|
const environments = doc.environments;
|
|
@@ -8096,7 +8068,7 @@ var StructureManager = class {
|
|
|
8096
8068
|
for (const pair of renamePairs) {
|
|
8097
8069
|
if (fs19.existsSync(pair.to)) {
|
|
8098
8070
|
throw new Error(
|
|
8099
|
-
`Rename target '${
|
|
8071
|
+
`Rename target '${path21.relative(repoRoot, pair.to)}' already exists. Move or remove it first.`
|
|
8100
8072
|
);
|
|
8101
8073
|
}
|
|
8102
8074
|
}
|
|
@@ -8139,7 +8111,7 @@ var StructureManager = class {
|
|
|
8139
8111
|
for (const pair of renamePairs) {
|
|
8140
8112
|
if (fs19.existsSync(pair.to)) {
|
|
8141
8113
|
throw new Error(
|
|
8142
|
-
`Rename target '${
|
|
8114
|
+
`Rename target '${path21.relative(repoRoot, pair.to)}' already exists. Move or remove it first.`
|
|
8143
8115
|
);
|
|
8144
8116
|
}
|
|
8145
8117
|
}
|
|
@@ -8189,7 +8161,7 @@ var StructureManager = class {
|
|
|
8189
8161
|
swapAxisInCellPath(repoRoot, manifest, cell, axis, newName) {
|
|
8190
8162
|
const ns = axis === "namespace" ? newName : cell.namespace;
|
|
8191
8163
|
const env = axis === "environment" ? newName : cell.environment;
|
|
8192
|
-
return
|
|
8164
|
+
return path21.join(
|
|
8193
8165
|
repoRoot,
|
|
8194
8166
|
manifest.file_pattern.replace("{namespace}", ns).replace("{environment}", env)
|
|
8195
8167
|
);
|
|
@@ -8201,8 +8173,8 @@ var StructureManager = class {
|
|
|
8201
8173
|
txPaths(repoRoot, renamePairs) {
|
|
8202
8174
|
const paths = /* @__PURE__ */ new Set();
|
|
8203
8175
|
for (const pair of renamePairs) {
|
|
8204
|
-
paths.add(
|
|
8205
|
-
paths.add(
|
|
8176
|
+
paths.add(path21.relative(repoRoot, pair.from));
|
|
8177
|
+
paths.add(path21.relative(repoRoot, pair.to));
|
|
8206
8178
|
}
|
|
8207
8179
|
paths.add(CLEF_MANIFEST_FILENAME);
|
|
8208
8180
|
return [...paths];
|
|
@@ -8213,7 +8185,7 @@ var StructureManager = class {
|
|
|
8213
8185
|
*/
|
|
8214
8186
|
applyRenames(pairs) {
|
|
8215
8187
|
for (const pair of pairs) {
|
|
8216
|
-
const targetDir =
|
|
8188
|
+
const targetDir = path21.dirname(pair.to);
|
|
8217
8189
|
if (!fs19.existsSync(targetDir)) {
|
|
8218
8190
|
fs19.mkdirSync(targetDir, { recursive: true });
|
|
8219
8191
|
}
|
|
@@ -8228,10 +8200,10 @@ var StructureManager = class {
|
|
|
8228
8200
|
deletePaths(repoRoot, cells) {
|
|
8229
8201
|
const paths = /* @__PURE__ */ new Set();
|
|
8230
8202
|
for (const cell of cells) {
|
|
8231
|
-
paths.add(
|
|
8203
|
+
paths.add(path21.relative(repoRoot, cell.filePath));
|
|
8232
8204
|
const meta = cell.filePath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml");
|
|
8233
8205
|
if (fs19.existsSync(meta)) {
|
|
8234
|
-
paths.add(
|
|
8206
|
+
paths.add(path21.relative(repoRoot, meta));
|
|
8235
8207
|
}
|
|
8236
8208
|
}
|
|
8237
8209
|
paths.add(CLEF_MANIFEST_FILENAME);
|
|
@@ -8346,7 +8318,7 @@ function renameKeyPreservingOrder(obj, oldKey, newKey) {
|
|
|
8346
8318
|
}
|
|
8347
8319
|
|
|
8348
8320
|
// src/artifact/resolve.ts
|
|
8349
|
-
async function resolveIdentitySecrets(identityName, environment, manifest, repoRoot,
|
|
8321
|
+
async function resolveIdentitySecrets(identityName, environment, manifest, repoRoot, source, matrixManager) {
|
|
8350
8322
|
const identity = manifest.service_identities?.find((si) => si.name === identityName);
|
|
8351
8323
|
if (!identity) {
|
|
8352
8324
|
throw new Error(`Service identity '${identityName}' not found in manifest.`);
|
|
@@ -8362,7 +8334,10 @@ async function resolveIdentitySecrets(identityName, environment, manifest, repoR
|
|
|
8362
8334
|
(c) => c.exists && identity.namespaces.includes(c.namespace) && c.environment === environment
|
|
8363
8335
|
);
|
|
8364
8336
|
for (const cell of cells) {
|
|
8365
|
-
const decrypted = await
|
|
8337
|
+
const decrypted = await source.readCell({
|
|
8338
|
+
namespace: cell.namespace,
|
|
8339
|
+
environment: cell.environment
|
|
8340
|
+
});
|
|
8366
8341
|
const bucket = allValues[cell.namespace] ??= {};
|
|
8367
8342
|
for (const [key, value] of Object.entries(decrypted.values)) {
|
|
8368
8343
|
if (key in bucket && bucket[key] !== value) {
|
|
@@ -8386,14 +8361,14 @@ import * as crypto4 from "crypto";
|
|
|
8386
8361
|
|
|
8387
8362
|
// src/artifact/output.ts
|
|
8388
8363
|
import * as fs20 from "fs";
|
|
8389
|
-
import * as
|
|
8364
|
+
import * as path22 from "path";
|
|
8390
8365
|
var FilePackOutput = class {
|
|
8391
8366
|
constructor(outputPath) {
|
|
8392
8367
|
this.outputPath = outputPath;
|
|
8393
8368
|
}
|
|
8394
8369
|
outputPath;
|
|
8395
8370
|
async write(_artifact, json) {
|
|
8396
|
-
const outputDir =
|
|
8371
|
+
const outputDir = path22.dirname(this.outputPath);
|
|
8397
8372
|
if (!fs20.existsSync(outputDir)) {
|
|
8398
8373
|
fs20.mkdirSync(outputDir, { recursive: true });
|
|
8399
8374
|
}
|
|
@@ -8440,17 +8415,6 @@ function buildSigningPayload(artifact) {
|
|
|
8440
8415
|
];
|
|
8441
8416
|
return Buffer.from(fields.join("\n"), "utf-8");
|
|
8442
8417
|
}
|
|
8443
|
-
function generateSigningKeyPair() {
|
|
8444
|
-
const pair = crypto2.generateKeyPairSync("ed25519");
|
|
8445
|
-
return {
|
|
8446
|
-
publicKey: pair.publicKey.export({ type: "spki", format: "der" }).toString(
|
|
8447
|
-
"base64"
|
|
8448
|
-
),
|
|
8449
|
-
privateKey: pair.privateKey.export({ type: "pkcs8", format: "der" }).toString(
|
|
8450
|
-
"base64"
|
|
8451
|
-
)
|
|
8452
|
-
};
|
|
8453
|
-
}
|
|
8454
8418
|
function signEd25519(payload, privateKeyBase64) {
|
|
8455
8419
|
const keyObj = crypto2.createPrivateKey({
|
|
8456
8420
|
key: Buffer.from(privateKeyBase64, "base64"),
|
|
@@ -8486,17 +8450,6 @@ function verifySignature(payload, signatureBase64, publicKeyBase64) {
|
|
|
8486
8450
|
}
|
|
8487
8451
|
throw new Error(`Unsupported key type for signature verification: ${keyType}`);
|
|
8488
8452
|
}
|
|
8489
|
-
function detectAlgorithm(publicKeyBase64) {
|
|
8490
|
-
const keyObj = crypto2.createPublicKey({
|
|
8491
|
-
key: Buffer.from(publicKeyBase64, "base64"),
|
|
8492
|
-
format: "der",
|
|
8493
|
-
type: "spki"
|
|
8494
|
-
});
|
|
8495
|
-
const keyType = keyObj.asymmetricKeyType;
|
|
8496
|
-
if (keyType === "ed25519") return "Ed25519";
|
|
8497
|
-
if (keyType === "ec") return "ECDSA_SHA256";
|
|
8498
|
-
throw new Error(`Unsupported key type: ${keyType}`);
|
|
8499
|
-
}
|
|
8500
8453
|
|
|
8501
8454
|
// src/artifact/hash.ts
|
|
8502
8455
|
import * as crypto3 from "crypto";
|
|
@@ -8506,12 +8459,12 @@ function computeCiphertextHash(ciphertext) {
|
|
|
8506
8459
|
|
|
8507
8460
|
// src/artifact/packer.ts
|
|
8508
8461
|
var ArtifactPacker = class {
|
|
8509
|
-
constructor(
|
|
8510
|
-
this.
|
|
8462
|
+
constructor(source, matrixManager, kms) {
|
|
8463
|
+
this.source = source;
|
|
8511
8464
|
this.matrixManager = matrixManager;
|
|
8512
8465
|
this.kms = kms;
|
|
8513
8466
|
}
|
|
8514
|
-
|
|
8467
|
+
source;
|
|
8515
8468
|
matrixManager;
|
|
8516
8469
|
kms;
|
|
8517
8470
|
/**
|
|
@@ -8529,7 +8482,7 @@ var ArtifactPacker = class {
|
|
|
8529
8482
|
config.environment,
|
|
8530
8483
|
manifest,
|
|
8531
8484
|
repoRoot,
|
|
8532
|
-
this.
|
|
8485
|
+
this.source,
|
|
8533
8486
|
this.matrixManager
|
|
8534
8487
|
);
|
|
8535
8488
|
const plaintext = JSON.stringify(resolved.values);
|
|
@@ -8914,11 +8867,7 @@ var JsonEnvelopeBackend = class {
|
|
|
8914
8867
|
}
|
|
8915
8868
|
async pack(req) {
|
|
8916
8869
|
const opts = req.backendOptions;
|
|
8917
|
-
const packer = new ArtifactPacker(
|
|
8918
|
-
req.services.encryption,
|
|
8919
|
-
new MatrixManager(),
|
|
8920
|
-
req.services.kms
|
|
8921
|
-
);
|
|
8870
|
+
const packer = new ArtifactPacker(req.services.source, new MatrixManager(), req.services.kms);
|
|
8922
8871
|
const output = opts.output ?? (opts.outputPath ? new FilePackOutput(opts.outputPath) : void 0);
|
|
8923
8872
|
const result = await packer.pack(
|
|
8924
8873
|
{
|
|
@@ -8947,7 +8896,7 @@ var JsonEnvelopeBackend = class {
|
|
|
8947
8896
|
var VALID_KMS_PROVIDERS = ["aws", "gcp", "azure"];
|
|
8948
8897
|
|
|
8949
8898
|
// src/migration/backend.ts
|
|
8950
|
-
import * as
|
|
8899
|
+
import * as path23 from "path";
|
|
8951
8900
|
import * as YAML12 from "yaml";
|
|
8952
8901
|
var BACKEND_KEY_FIELDS = {
|
|
8953
8902
|
age: void 0,
|
|
@@ -8975,23 +8924,24 @@ function metadataMatchesTarget(meta, target) {
|
|
|
8975
8924
|
}
|
|
8976
8925
|
var BackendMigrator = class {
|
|
8977
8926
|
/**
|
|
8978
|
-
* @param
|
|
8927
|
+
* @param buildSource - Factory that builds a `SecretSource` bound to a
|
|
8928
|
+
* given manifest. Called twice during a real migration: once with the
|
|
8929
|
+
* pre-migration manifest (for classification + decrypt) and once with
|
|
8930
|
+
* the post-mutation manifest (for re-encrypt + verify). The factory
|
|
8931
|
+
* pattern is required because the encryption layer of a composed
|
|
8932
|
+
* source is bound to a manifest at construction.
|
|
8979
8933
|
* @param matrixManager - Matrix resolver.
|
|
8980
8934
|
* @param tx - Transaction manager that wraps the migration in a single git commit
|
|
8981
8935
|
* so a partial failure rolls back ALL files + the manifest via `git reset --hard`.
|
|
8982
|
-
* @param targetEncryption - Optional separate backend for encrypt. Use when migrating
|
|
8983
|
-
* from cloud (decrypt via keyservice) to another backend (encrypt via local credentials).
|
|
8984
8936
|
*/
|
|
8985
|
-
constructor(
|
|
8937
|
+
constructor(buildSource, matrixManager, tx) {
|
|
8938
|
+
this.buildSource = buildSource;
|
|
8986
8939
|
this.matrixManager = matrixManager;
|
|
8987
8940
|
this.tx = tx;
|
|
8988
|
-
this.decryptBackend = encryption;
|
|
8989
|
-
this.encryptBackend = targetEncryption ?? encryption;
|
|
8990
8941
|
}
|
|
8942
|
+
buildSource;
|
|
8991
8943
|
matrixManager;
|
|
8992
8944
|
tx;
|
|
8993
|
-
decryptBackend;
|
|
8994
|
-
encryptBackend;
|
|
8995
8945
|
async migrate(manifest, repoRoot, options, onProgress) {
|
|
8996
8946
|
const { target, environment, dryRun, skipVerify } = options;
|
|
8997
8947
|
if (environment) {
|
|
@@ -9011,10 +8961,12 @@ var BackendMigrator = class {
|
|
|
9011
8961
|
warnings: ["No encrypted files found to migrate."]
|
|
9012
8962
|
};
|
|
9013
8963
|
}
|
|
8964
|
+
const sourceBefore = this.buildSource(manifest);
|
|
9014
8965
|
const toMigrate = [];
|
|
9015
8966
|
const skippedFiles = [];
|
|
9016
8967
|
for (const cell of targetCells) {
|
|
9017
|
-
const
|
|
8968
|
+
const ref = { namespace: cell.namespace, environment: cell.environment };
|
|
8969
|
+
const meta = await sourceBefore.getCellMetadata(ref);
|
|
9018
8970
|
if (metadataMatchesTarget(meta, target)) {
|
|
9019
8971
|
skippedFiles.push(cell.filePath);
|
|
9020
8972
|
onProgress?.({
|
|
@@ -9065,11 +9017,12 @@ var BackendMigrator = class {
|
|
|
9065
9017
|
const migratedFiles = [];
|
|
9066
9018
|
let migrationFailed = false;
|
|
9067
9019
|
let migrationError;
|
|
9020
|
+
let sourceAfter;
|
|
9068
9021
|
try {
|
|
9069
9022
|
await this.tx.run(repoRoot, {
|
|
9070
9023
|
description: environment ? `clef migrate-backend ${target.backend}: ${environment}` : `clef migrate-backend ${target.backend}`,
|
|
9071
9024
|
paths: [
|
|
9072
|
-
...toMigrate.map((c) =>
|
|
9025
|
+
...toMigrate.map((c) => path23.relative(repoRoot, c.filePath)),
|
|
9073
9026
|
CLEF_MANIFEST_FILENAME
|
|
9074
9027
|
],
|
|
9075
9028
|
mutate: async () => {
|
|
@@ -9077,19 +9030,16 @@ var BackendMigrator = class {
|
|
|
9077
9030
|
this.updateManifestDoc(doc, target, environment);
|
|
9078
9031
|
writeManifestYaml(repoRoot, doc);
|
|
9079
9032
|
const updatedManifest = YAML12.parse(YAML12.stringify(doc));
|
|
9033
|
+
sourceAfter = this.buildSource(updatedManifest);
|
|
9080
9034
|
for (const cell of toMigrate) {
|
|
9081
9035
|
onProgress?.({
|
|
9082
9036
|
type: "migrate",
|
|
9083
9037
|
file: cell.filePath,
|
|
9084
9038
|
message: `Migrating ${cell.namespace}/${cell.environment}...`
|
|
9085
9039
|
});
|
|
9086
|
-
const
|
|
9087
|
-
await
|
|
9088
|
-
|
|
9089
|
-
decrypted.values,
|
|
9090
|
-
updatedManifest,
|
|
9091
|
-
cell.environment
|
|
9092
|
-
);
|
|
9040
|
+
const ref = { namespace: cell.namespace, environment: cell.environment };
|
|
9041
|
+
const decrypted = await sourceBefore.readCell(ref);
|
|
9042
|
+
await sourceAfter.writeCell(ref, decrypted.values);
|
|
9093
9043
|
migratedFiles.push(cell.filePath);
|
|
9094
9044
|
}
|
|
9095
9045
|
}
|
|
@@ -9119,7 +9069,7 @@ var BackendMigrator = class {
|
|
|
9119
9069
|
}
|
|
9120
9070
|
const verifiedFiles = [];
|
|
9121
9071
|
const warnings = [];
|
|
9122
|
-
if (!skipVerify) {
|
|
9072
|
+
if (!skipVerify && sourceAfter) {
|
|
9123
9073
|
for (const cell of toMigrate) {
|
|
9124
9074
|
try {
|
|
9125
9075
|
onProgress?.({
|
|
@@ -9127,7 +9077,8 @@ var BackendMigrator = class {
|
|
|
9127
9077
|
file: cell.filePath,
|
|
9128
9078
|
message: `Verifying ${cell.namespace}/${cell.environment}...`
|
|
9129
9079
|
});
|
|
9130
|
-
|
|
9080
|
+
const ref = { namespace: cell.namespace, environment: cell.environment };
|
|
9081
|
+
await sourceAfter.readCell(ref);
|
|
9131
9082
|
verifiedFiles.push(cell.filePath);
|
|
9132
9083
|
} catch (err) {
|
|
9133
9084
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -9172,16 +9123,16 @@ var BackendMigrator = class {
|
|
|
9172
9123
|
};
|
|
9173
9124
|
|
|
9174
9125
|
// src/reset/manager.ts
|
|
9175
|
-
import * as
|
|
9126
|
+
import * as path24 from "path";
|
|
9176
9127
|
var ResetManager = class {
|
|
9177
|
-
constructor(matrixManager,
|
|
9128
|
+
constructor(matrixManager, buildSource, schemaValidator, tx) {
|
|
9178
9129
|
this.matrixManager = matrixManager;
|
|
9179
|
-
this.
|
|
9130
|
+
this.buildSource = buildSource;
|
|
9180
9131
|
this.schemaValidator = schemaValidator;
|
|
9181
9132
|
this.tx = tx;
|
|
9182
9133
|
}
|
|
9183
9134
|
matrixManager;
|
|
9184
|
-
|
|
9135
|
+
buildSource;
|
|
9185
9136
|
schemaValidator;
|
|
9186
9137
|
tx;
|
|
9187
9138
|
async reset(opts, manifest, repoRoot) {
|
|
@@ -9201,11 +9152,11 @@ var ResetManager = class {
|
|
|
9201
9152
|
txPaths.push(CLEF_MANIFEST_FILENAME);
|
|
9202
9153
|
}
|
|
9203
9154
|
for (const cell of targetCells) {
|
|
9204
|
-
txPaths.push(
|
|
9155
|
+
txPaths.push(path24.relative(repoRoot, cell.filePath));
|
|
9205
9156
|
const cellKeys = keyPlan.get(cell.namespace) ?? [];
|
|
9206
9157
|
if (cellKeys.length > 0) {
|
|
9207
9158
|
txPaths.push(
|
|
9208
|
-
|
|
9159
|
+
path24.relative(repoRoot, cell.filePath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml"))
|
|
9209
9160
|
);
|
|
9210
9161
|
}
|
|
9211
9162
|
}
|
|
@@ -9222,17 +9173,14 @@ var ResetManager = class {
|
|
|
9222
9173
|
writeManifestYaml(repoRoot, doc);
|
|
9223
9174
|
effectiveManifest = withBackendOverride(manifest, affectedEnvs, opts.backend, opts.key);
|
|
9224
9175
|
}
|
|
9176
|
+
const source = this.buildSource(effectiveManifest);
|
|
9225
9177
|
for (const cell of targetCells) {
|
|
9226
9178
|
const keys = keyPlan.get(cell.namespace) ?? [];
|
|
9227
9179
|
const placeholders = this.buildPlaceholders(keys);
|
|
9228
|
-
|
|
9229
|
-
|
|
9230
|
-
placeholders,
|
|
9231
|
-
effectiveManifest,
|
|
9232
|
-
cell.environment
|
|
9233
|
-
);
|
|
9180
|
+
const ref = { namespace: cell.namespace, environment: cell.environment };
|
|
9181
|
+
await source.writeCell(ref, placeholders);
|
|
9234
9182
|
if (keys.length > 0) {
|
|
9235
|
-
await
|
|
9183
|
+
await source.markPending(ref, keys, "clef reset");
|
|
9236
9184
|
pendingKeysByCell[cell.filePath] = keys;
|
|
9237
9185
|
}
|
|
9238
9186
|
scaffoldedCells.push(cell.filePath);
|
|
@@ -9293,7 +9241,7 @@ var ResetManager = class {
|
|
|
9293
9241
|
for (const namespace of namespaces) {
|
|
9294
9242
|
const nsDef = manifest.namespaces.find((n) => n.name === namespace);
|
|
9295
9243
|
if (nsDef?.schema) {
|
|
9296
|
-
const schema = this.schemaValidator.loadSchema(
|
|
9244
|
+
const schema = this.schemaValidator.loadSchema(path24.join(repoRoot, nsDef.schema));
|
|
9297
9245
|
plan.set(namespace, Object.keys(schema.keys));
|
|
9298
9246
|
continue;
|
|
9299
9247
|
}
|
|
@@ -9372,15 +9320,15 @@ function withBackendOverride(manifest, envNames, backend, key) {
|
|
|
9372
9320
|
}
|
|
9373
9321
|
|
|
9374
9322
|
// src/sync/manager.ts
|
|
9375
|
-
import * as
|
|
9323
|
+
import * as path25 from "path";
|
|
9376
9324
|
var SyncManager = class {
|
|
9377
|
-
constructor(matrixManager,
|
|
9325
|
+
constructor(matrixManager, source, tx) {
|
|
9378
9326
|
this.matrixManager = matrixManager;
|
|
9379
|
-
this.
|
|
9327
|
+
this.source = source;
|
|
9380
9328
|
this.tx = tx;
|
|
9381
9329
|
}
|
|
9382
9330
|
matrixManager;
|
|
9383
|
-
|
|
9331
|
+
source;
|
|
9384
9332
|
tx;
|
|
9385
9333
|
/**
|
|
9386
9334
|
* Compute what sync would do without mutating anything.
|
|
@@ -9397,8 +9345,13 @@ var SyncManager = class {
|
|
|
9397
9345
|
const targetCells = opts.namespace ? existingCells.filter((c) => c.namespace === opts.namespace) : existingCells;
|
|
9398
9346
|
const keysByNsEnv = {};
|
|
9399
9347
|
for (const cell of targetCells) {
|
|
9400
|
-
const
|
|
9401
|
-
|
|
9348
|
+
const ref = { namespace: cell.namespace, environment: cell.environment };
|
|
9349
|
+
let keys;
|
|
9350
|
+
try {
|
|
9351
|
+
keys = await this.source.listKeys(ref);
|
|
9352
|
+
} catch {
|
|
9353
|
+
continue;
|
|
9354
|
+
}
|
|
9402
9355
|
if (!keysByNsEnv[cell.namespace]) keysByNsEnv[cell.namespace] = {};
|
|
9403
9356
|
keysByNsEnv[cell.namespace][cell.environment] = new Set(keys);
|
|
9404
9357
|
}
|
|
@@ -9444,7 +9397,7 @@ var SyncManager = class {
|
|
|
9444
9397
|
}
|
|
9445
9398
|
const txPaths = [];
|
|
9446
9399
|
for (const cell of syncPlan.cells) {
|
|
9447
|
-
const rel =
|
|
9400
|
+
const rel = path25.relative(repoRoot, cell.filePath);
|
|
9448
9401
|
txPaths.push(rel);
|
|
9449
9402
|
txPaths.push(rel.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml"));
|
|
9450
9403
|
}
|
|
@@ -9457,17 +9410,13 @@ var SyncManager = class {
|
|
|
9457
9410
|
paths: txPaths,
|
|
9458
9411
|
mutate: async () => {
|
|
9459
9412
|
for (const cell of syncPlan.cells) {
|
|
9460
|
-
const
|
|
9413
|
+
const ref = { namespace: cell.namespace, environment: cell.environment };
|
|
9414
|
+
const decrypted = await this.source.readCell(ref);
|
|
9461
9415
|
for (const key of cell.missingKeys) {
|
|
9462
9416
|
decrypted.values[key] = generateRandomValue();
|
|
9463
9417
|
}
|
|
9464
|
-
await this.
|
|
9465
|
-
|
|
9466
|
-
decrypted.values,
|
|
9467
|
-
manifest,
|
|
9468
|
-
cell.environment
|
|
9469
|
-
);
|
|
9470
|
-
await markPendingWithRetry(cell.filePath, cell.missingKeys, "clef sync");
|
|
9418
|
+
await this.source.writeCell(ref, decrypted.values);
|
|
9419
|
+
await this.source.markPending(ref, cell.missingKeys, "clef sync");
|
|
9471
9420
|
const cellLabel = `${cell.namespace}/${cell.environment}`;
|
|
9472
9421
|
modifiedCells.push(cellLabel);
|
|
9473
9422
|
scaffoldedKeys[cellLabel] = cell.missingKeys;
|
|
@@ -9727,13 +9676,272 @@ var ComplianceGenerator = class {
|
|
|
9727
9676
|
};
|
|
9728
9677
|
|
|
9729
9678
|
// src/compliance/run.ts
|
|
9730
|
-
import * as
|
|
9679
|
+
import * as path27 from "path";
|
|
9680
|
+
|
|
9681
|
+
// src/source/compose.ts
|
|
9682
|
+
import * as YAML14 from "yaml";
|
|
9683
|
+
|
|
9684
|
+
// src/source/default-bulk.ts
|
|
9685
|
+
function defaultBulk(source) {
|
|
9686
|
+
return {
|
|
9687
|
+
async bulkSet(namespace, key, valuesByEnv, _manifest) {
|
|
9688
|
+
for (const [environment, value] of Object.entries(valuesByEnv)) {
|
|
9689
|
+
const cell = { namespace, environment };
|
|
9690
|
+
const existing = await source.cellExists(cell) ? (await source.readCell(cell)).values : {};
|
|
9691
|
+
await source.writeCell(cell, { ...existing, [key]: value });
|
|
9692
|
+
}
|
|
9693
|
+
},
|
|
9694
|
+
async bulkDelete(namespace, key, manifest) {
|
|
9695
|
+
for (const env of manifest.environments) {
|
|
9696
|
+
const cell = { namespace, environment: env.name };
|
|
9697
|
+
if (!await source.cellExists(cell)) continue;
|
|
9698
|
+
const data = await source.readCell(cell);
|
|
9699
|
+
if (!(key in data.values)) continue;
|
|
9700
|
+
const next = { ...data.values };
|
|
9701
|
+
delete next[key];
|
|
9702
|
+
await source.writeCell(cell, next);
|
|
9703
|
+
}
|
|
9704
|
+
},
|
|
9705
|
+
async copyValue(key, from, to, _manifest) {
|
|
9706
|
+
const src = await source.readCell(from);
|
|
9707
|
+
if (!(key in src.values)) {
|
|
9708
|
+
throw new Error(
|
|
9709
|
+
`Cannot copy: key '${key}' not present in ${from.namespace}/${from.environment}`
|
|
9710
|
+
);
|
|
9711
|
+
}
|
|
9712
|
+
const dst = await source.cellExists(to) ? (await source.readCell(to)).values : {};
|
|
9713
|
+
await source.writeCell(to, { ...dst, [key]: src.values[key] });
|
|
9714
|
+
}
|
|
9715
|
+
};
|
|
9716
|
+
}
|
|
9717
|
+
|
|
9718
|
+
// src/source/compose.ts
|
|
9719
|
+
function composeSecretSource(storage, encryption, manifest) {
|
|
9720
|
+
return new ComposedSecretSource(storage, encryption, manifest);
|
|
9721
|
+
}
|
|
9722
|
+
var ComposedSecretSource = class {
|
|
9723
|
+
constructor(storage, encryption, manifest) {
|
|
9724
|
+
this.storage = storage;
|
|
9725
|
+
this.encryption = encryption;
|
|
9726
|
+
this.manifest = manifest;
|
|
9727
|
+
this.id = `${storage.id}+${encryption.id}`;
|
|
9728
|
+
this.description = `${storage.description} / ${encryption.description}`;
|
|
9729
|
+
}
|
|
9730
|
+
storage;
|
|
9731
|
+
encryption;
|
|
9732
|
+
manifest;
|
|
9733
|
+
id;
|
|
9734
|
+
description;
|
|
9735
|
+
context(cell) {
|
|
9736
|
+
return {
|
|
9737
|
+
manifest: this.manifest,
|
|
9738
|
+
environment: cell.environment,
|
|
9739
|
+
format: this.storage.blobFormat(cell)
|
|
9740
|
+
};
|
|
9741
|
+
}
|
|
9742
|
+
// ── Core SecretSource ──────────────────────────────────────────────────
|
|
9743
|
+
async readCell(cell) {
|
|
9744
|
+
const blob = await this.storage.readBlob(cell);
|
|
9745
|
+
return this.encryption.decrypt(blob, this.context(cell));
|
|
9746
|
+
}
|
|
9747
|
+
async writeCell(cell, values) {
|
|
9748
|
+
const blob = await this.encryption.encrypt(values, this.context(cell));
|
|
9749
|
+
await this.storage.writeBlob(cell, blob);
|
|
9750
|
+
}
|
|
9751
|
+
async deleteCell(cell) {
|
|
9752
|
+
await this.storage.deleteBlob(cell);
|
|
9753
|
+
}
|
|
9754
|
+
async cellExists(cell) {
|
|
9755
|
+
return this.storage.blobExists(cell);
|
|
9756
|
+
}
|
|
9757
|
+
/**
|
|
9758
|
+
* List cell keys WITHOUT decrypting. SOPS files store key names in
|
|
9759
|
+
* plaintext at the top level of the YAML/JSON document — we read the
|
|
9760
|
+
* blob and return everything except the `sops:` metadata block.
|
|
9761
|
+
*
|
|
9762
|
+
* NOTE: this is currently SOPS-shaped. A future non-SOPS
|
|
9763
|
+
* `EncryptionBackend` whose ciphertext doesn't expose key names in
|
|
9764
|
+
* the clear would need its own listing strategy — likely a
|
|
9765
|
+
* `listKeys(blob)` method on `EncryptionBackend`. Deferred until a
|
|
9766
|
+
* second backend exists.
|
|
9767
|
+
*/
|
|
9768
|
+
async listKeys(cell) {
|
|
9769
|
+
if (!await this.storage.blobExists(cell)) return [];
|
|
9770
|
+
const blob = await this.storage.readBlob(cell);
|
|
9771
|
+
const parsed = YAML14.parse(blob);
|
|
9772
|
+
if (!parsed || typeof parsed !== "object") return [];
|
|
9773
|
+
return Object.keys(parsed).filter((k) => k !== "sops");
|
|
9774
|
+
}
|
|
9775
|
+
async getCellMetadata(cell) {
|
|
9776
|
+
const blob = await this.storage.readBlob(cell);
|
|
9777
|
+
return this.encryption.getMetadata(blob);
|
|
9778
|
+
}
|
|
9779
|
+
async scaffoldCell(cell, manifest) {
|
|
9780
|
+
if (await this.storage.blobExists(cell)) return;
|
|
9781
|
+
const blob = await this.encryption.encrypt(
|
|
9782
|
+
{},
|
|
9783
|
+
{
|
|
9784
|
+
manifest,
|
|
9785
|
+
environment: cell.environment,
|
|
9786
|
+
format: this.storage.blobFormat(cell)
|
|
9787
|
+
}
|
|
9788
|
+
);
|
|
9789
|
+
await this.storage.writeBlob(cell, blob);
|
|
9790
|
+
}
|
|
9791
|
+
// ── Pending / rotation metadata ────────────────────────────────────────
|
|
9792
|
+
async getPendingMetadata(cell) {
|
|
9793
|
+
return this.storage.readPendingMetadata(cell);
|
|
9794
|
+
}
|
|
9795
|
+
async markPending(cell, keys, setBy) {
|
|
9796
|
+
const meta = await this.storage.readPendingMetadata(cell);
|
|
9797
|
+
const now = /* @__PURE__ */ new Date();
|
|
9798
|
+
for (const key of keys) {
|
|
9799
|
+
if (!meta.pending.find((p) => p.key === key)) {
|
|
9800
|
+
meta.pending.push({ key, since: now, setBy });
|
|
9801
|
+
}
|
|
9802
|
+
}
|
|
9803
|
+
await this.storage.writePendingMetadata(cell, meta);
|
|
9804
|
+
}
|
|
9805
|
+
async markResolved(cell, keys) {
|
|
9806
|
+
const meta = await this.storage.readPendingMetadata(cell);
|
|
9807
|
+
meta.pending = meta.pending.filter((p) => !keys.includes(p.key));
|
|
9808
|
+
await this.storage.writePendingMetadata(cell, meta);
|
|
9809
|
+
}
|
|
9810
|
+
async recordRotation(cell, keys, rotatedBy) {
|
|
9811
|
+
const meta = await this.storage.readPendingMetadata(cell);
|
|
9812
|
+
const now = /* @__PURE__ */ new Date();
|
|
9813
|
+
for (const key of keys) {
|
|
9814
|
+
const existing = meta.rotations.find((r) => r.key === key);
|
|
9815
|
+
if (existing) {
|
|
9816
|
+
existing.lastRotatedAt = now;
|
|
9817
|
+
existing.rotatedBy = rotatedBy;
|
|
9818
|
+
existing.rotationCount += 1;
|
|
9819
|
+
} else {
|
|
9820
|
+
meta.rotations.push({ key, lastRotatedAt: now, rotatedBy, rotationCount: 1 });
|
|
9821
|
+
}
|
|
9822
|
+
}
|
|
9823
|
+
meta.pending = meta.pending.filter((p) => !keys.includes(p.key));
|
|
9824
|
+
await this.storage.writePendingMetadata(cell, meta);
|
|
9825
|
+
}
|
|
9826
|
+
async removeRotation(cell, keys) {
|
|
9827
|
+
const meta = await this.storage.readPendingMetadata(cell);
|
|
9828
|
+
meta.rotations = meta.rotations.filter((r) => !keys.includes(r.key));
|
|
9829
|
+
await this.storage.writePendingMetadata(cell, meta);
|
|
9830
|
+
}
|
|
9831
|
+
// ── Lintable ───────────────────────────────────────────────────────────
|
|
9832
|
+
async validateEncryption(cell) {
|
|
9833
|
+
if (!await this.storage.blobExists(cell)) return false;
|
|
9834
|
+
const blob = await this.storage.readBlob(cell);
|
|
9835
|
+
return this.encryption.validateEncryption(blob);
|
|
9836
|
+
}
|
|
9837
|
+
async checkRecipientDrift(cell, expected) {
|
|
9838
|
+
const blob = await this.storage.readBlob(cell);
|
|
9839
|
+
const meta = this.encryption.getMetadata(blob);
|
|
9840
|
+
const actual = new Set(meta.recipients);
|
|
9841
|
+
const expectedSet = new Set(expected);
|
|
9842
|
+
return {
|
|
9843
|
+
missing: expected.filter((r) => !actual.has(r)),
|
|
9844
|
+
unexpected: meta.recipients.filter((r) => !expectedSet.has(r))
|
|
9845
|
+
};
|
|
9846
|
+
}
|
|
9847
|
+
// ── Rotatable ──────────────────────────────────────────────────────────
|
|
9848
|
+
async rotate(cell, opts) {
|
|
9849
|
+
const blob = await this.storage.readBlob(cell);
|
|
9850
|
+
const rotated = await this.encryption.rotate(blob, opts, this.context(cell));
|
|
9851
|
+
await this.storage.writeBlob(cell, rotated);
|
|
9852
|
+
}
|
|
9853
|
+
// ── Bulk ───────────────────────────────────────────────────────────────
|
|
9854
|
+
//
|
|
9855
|
+
// Default looped implementation. A future StorageBackend that supports
|
|
9856
|
+
// batch operations (e.g. PostgresStorageBackend with row-level UPDATE
|
|
9857
|
+
// batching) can override these by wrapping `composeSecretSource`'s
|
|
9858
|
+
// output and replacing just the bulk methods.
|
|
9859
|
+
bulkSet = (namespace, key, valuesByEnv, manifest) => defaultBulk(this).bulkSet(namespace, key, valuesByEnv, manifest);
|
|
9860
|
+
bulkDelete = (namespace, key, manifest) => defaultBulk(this).bulkDelete(namespace, key, manifest);
|
|
9861
|
+
copyValue = (key, from, to, manifest) => defaultBulk(this).copyValue(key, from, to, manifest);
|
|
9862
|
+
};
|
|
9863
|
+
|
|
9864
|
+
// src/source/filesystem-storage-backend.ts
|
|
9865
|
+
import * as fs22 from "fs";
|
|
9866
|
+
import * as path26 from "path";
|
|
9867
|
+
import { randomBytes as randomBytes4 } from "crypto";
|
|
9868
|
+
var FilesystemStorageBackend = class {
|
|
9869
|
+
constructor(manifest, repoRoot) {
|
|
9870
|
+
this.manifest = manifest;
|
|
9871
|
+
this.repoRoot = repoRoot;
|
|
9872
|
+
}
|
|
9873
|
+
manifest;
|
|
9874
|
+
repoRoot;
|
|
9875
|
+
id = "filesystem";
|
|
9876
|
+
description = "Filesystem-backed cell storage (default substrate)";
|
|
9877
|
+
/**
|
|
9878
|
+
* Resolve a cell reference to its absolute filesystem path. Public —
|
|
9879
|
+
* used by substrate-specific trait implementations.
|
|
9880
|
+
*/
|
|
9881
|
+
cellPath(cell) {
|
|
9882
|
+
const relativePath = this.manifest.file_pattern.replace("{namespace}", cell.namespace).replace("{environment}", cell.environment);
|
|
9883
|
+
return path26.join(this.repoRoot, relativePath);
|
|
9884
|
+
}
|
|
9885
|
+
/** The repo root, exposed for filesystem-shaped trait implementations. */
|
|
9886
|
+
getRepoRoot() {
|
|
9887
|
+
return this.repoRoot;
|
|
9888
|
+
}
|
|
9889
|
+
blobFormat(cell) {
|
|
9890
|
+
return this.cellPath(cell).endsWith(".json") ? "json" : "yaml";
|
|
9891
|
+
}
|
|
9892
|
+
async readBlob(cell) {
|
|
9893
|
+
const filePath = this.cellPath(cell);
|
|
9894
|
+
return fs22.readFileSync(filePath, "utf-8");
|
|
9895
|
+
}
|
|
9896
|
+
async writeBlob(cell, blob) {
|
|
9897
|
+
const filePath = this.cellPath(cell);
|
|
9898
|
+
const dir = path26.dirname(filePath);
|
|
9899
|
+
if (!fs22.existsSync(dir)) {
|
|
9900
|
+
fs22.mkdirSync(dir, { recursive: true });
|
|
9901
|
+
}
|
|
9902
|
+
const tmpPath = `${filePath}.${Date.now()}.${randomBytes4(4).toString("hex")}.tmp`;
|
|
9903
|
+
const handle = fs22.openSync(tmpPath, "w");
|
|
9904
|
+
try {
|
|
9905
|
+
fs22.writeFileSync(handle, blob);
|
|
9906
|
+
fs22.fsyncSync(handle);
|
|
9907
|
+
} finally {
|
|
9908
|
+
fs22.closeSync(handle);
|
|
9909
|
+
}
|
|
9910
|
+
fs22.renameSync(tmpPath, filePath);
|
|
9911
|
+
}
|
|
9912
|
+
async deleteBlob(cell) {
|
|
9913
|
+
const filePath = this.cellPath(cell);
|
|
9914
|
+
if (fs22.existsSync(filePath)) {
|
|
9915
|
+
fs22.unlinkSync(filePath);
|
|
9916
|
+
}
|
|
9917
|
+
const sidecar = this.sidecarPath(filePath);
|
|
9918
|
+
if (fs22.existsSync(sidecar)) {
|
|
9919
|
+
fs22.unlinkSync(sidecar);
|
|
9920
|
+
}
|
|
9921
|
+
}
|
|
9922
|
+
async blobExists(cell) {
|
|
9923
|
+
return fs22.existsSync(this.cellPath(cell));
|
|
9924
|
+
}
|
|
9925
|
+
async readPendingMetadata(cell) {
|
|
9926
|
+
return loadMetadata(this.cellPath(cell));
|
|
9927
|
+
}
|
|
9928
|
+
async writePendingMetadata(cell, meta) {
|
|
9929
|
+
await saveMetadata(this.cellPath(cell), meta);
|
|
9930
|
+
}
|
|
9931
|
+
sidecarPath(filePath) {
|
|
9932
|
+
const dir = path26.dirname(filePath);
|
|
9933
|
+
const base = path26.basename(filePath).replace(/\.enc\.(yaml|json)$/, "");
|
|
9934
|
+
return path26.join(dir, `${base}.clef-meta.yaml`);
|
|
9935
|
+
}
|
|
9936
|
+
};
|
|
9937
|
+
|
|
9938
|
+
// src/compliance/run.ts
|
|
9731
9939
|
var UNKNOWN = "unknown";
|
|
9732
9940
|
async function runCompliance(opts) {
|
|
9733
9941
|
const start = Date.now();
|
|
9734
9942
|
const repoRoot = opts.repoRoot ?? process.cwd();
|
|
9735
|
-
const manifestPath = opts.manifestPath ??
|
|
9736
|
-
const policyPath = opts.policyPath ??
|
|
9943
|
+
const manifestPath = opts.manifestPath ?? path27.join(repoRoot, "clef.yaml");
|
|
9944
|
+
const policyPath = opts.policyPath ?? path27.join(repoRoot, CLEF_POLICY_FILENAME);
|
|
9737
9945
|
const include = {
|
|
9738
9946
|
scan: opts.include?.scan ?? true,
|
|
9739
9947
|
lint: opts.include?.lint ?? true,
|
|
@@ -9745,6 +9953,11 @@ async function runCompliance(opts) {
|
|
|
9745
9953
|
const sopsClient = new SopsClient(opts.runner, opts.ageKeyFile, opts.ageKey, opts.sopsPath);
|
|
9746
9954
|
const matrixManager = new MatrixManager();
|
|
9747
9955
|
const schemaValidator = new SchemaValidator();
|
|
9956
|
+
const lintSource = composeSecretSource(
|
|
9957
|
+
new FilesystemStorageBackend(manifest, repoRoot),
|
|
9958
|
+
sopsClient,
|
|
9959
|
+
manifest
|
|
9960
|
+
);
|
|
9748
9961
|
const [sha, repo, files, scanResult, lintResult] = await Promise.all([
|
|
9749
9962
|
opts.sha !== void 0 ? Promise.resolve(opts.sha) : detectSha(opts.runner, repoRoot),
|
|
9750
9963
|
opts.repo !== void 0 ? Promise.resolve(opts.repo) : detectRepo(opts.runner, repoRoot),
|
|
@@ -9753,12 +9966,12 @@ async function runCompliance(opts) {
|
|
|
9753
9966
|
repoRoot,
|
|
9754
9967
|
policy,
|
|
9755
9968
|
matrixManager,
|
|
9756
|
-
|
|
9969
|
+
source: lintSource,
|
|
9757
9970
|
filter: opts.filter,
|
|
9758
9971
|
now
|
|
9759
9972
|
}) : Promise.resolve([]),
|
|
9760
9973
|
include.scan ? new ScanRunner(opts.runner).scan(repoRoot, manifest) : Promise.resolve(emptyScan()),
|
|
9761
|
-
include.lint ? new LintRunner(matrixManager, schemaValidator,
|
|
9974
|
+
include.lint ? new LintRunner(matrixManager, schemaValidator, lintSource).run(manifest, repoRoot) : Promise.resolve(emptyLint())
|
|
9762
9975
|
]);
|
|
9763
9976
|
const adjustedLint = downgradeDecryptIssues(lintResult);
|
|
9764
9977
|
const document = new ComplianceGenerator().generate({
|
|
@@ -9778,8 +9991,11 @@ async function evaluateMatrix(args) {
|
|
|
9778
9991
|
const cells = args.matrixManager.resolveMatrix(args.manifest, args.repoRoot).filter((c) => applyFilter(c.namespace, c.environment, args.filter)).filter((c) => c.exists);
|
|
9779
9992
|
return Promise.all(
|
|
9780
9993
|
cells.map(async (cell) => {
|
|
9781
|
-
const metadata = await args.
|
|
9782
|
-
|
|
9994
|
+
const metadata = await args.source.getCellMetadata({
|
|
9995
|
+
namespace: cell.namespace,
|
|
9996
|
+
environment: cell.environment
|
|
9997
|
+
});
|
|
9998
|
+
const relPath = path27.relative(args.repoRoot, cell.filePath).replace(/\\/g, "/");
|
|
9783
9999
|
const keys = readSopsKeyNames(cell.filePath) ?? [];
|
|
9784
10000
|
const rotations = await getRotations(cell.filePath);
|
|
9785
10001
|
return evaluator.evaluateFile(relPath, cell.environment, metadata, keys, rotations, args.now);
|
|
@@ -9837,10 +10053,61 @@ async function detectRepo(runner, repoRoot) {
|
|
|
9837
10053
|
const match = url.match(/[:/]([^/:]+)\/([^/]+?)(?:\.git)?\/?$/);
|
|
9838
10054
|
return match ? `${match[1]}/${match[2]}` : UNKNOWN;
|
|
9839
10055
|
}
|
|
10056
|
+
|
|
10057
|
+
// src/source/guards.ts
|
|
10058
|
+
function isFn(o, name) {
|
|
10059
|
+
return typeof o === "object" && o !== null && typeof o[name] === "function";
|
|
10060
|
+
}
|
|
10061
|
+
function isLintable(s) {
|
|
10062
|
+
return isFn(s, "validateEncryption") && isFn(s, "checkRecipientDrift");
|
|
10063
|
+
}
|
|
10064
|
+
function isRotatable(s) {
|
|
10065
|
+
return isFn(s, "rotate");
|
|
10066
|
+
}
|
|
10067
|
+
function isRecipientManaged(s) {
|
|
10068
|
+
return isFn(s, "listRecipients") && isFn(s, "addRecipient") && isFn(s, "removeRecipient");
|
|
10069
|
+
}
|
|
10070
|
+
function isMergeAware(s) {
|
|
10071
|
+
return isFn(s, "mergeCells") && isFn(s, "installMergeDriver");
|
|
10072
|
+
}
|
|
10073
|
+
function isMigratable(s) {
|
|
10074
|
+
return isFn(s, "migrateBackend");
|
|
10075
|
+
}
|
|
10076
|
+
function isBulk(s) {
|
|
10077
|
+
return isFn(s, "bulkSet") && isFn(s, "bulkDelete") && isFn(s, "copyValue");
|
|
10078
|
+
}
|
|
10079
|
+
function isStructural(s) {
|
|
10080
|
+
return isFn(s, "addNamespace") && isFn(s, "addEnvironment") && isFn(s, "renameNamespace") && isFn(s, "renameEnvironment");
|
|
10081
|
+
}
|
|
10082
|
+
function describeCapabilities(s) {
|
|
10083
|
+
return {
|
|
10084
|
+
lint: isLintable(s),
|
|
10085
|
+
rotate: isRotatable(s),
|
|
10086
|
+
recipients: isRecipientManaged(s),
|
|
10087
|
+
merge: isMergeAware(s),
|
|
10088
|
+
migrate: isMigratable(s),
|
|
10089
|
+
bulk: isBulk(s),
|
|
10090
|
+
structural: isStructural(s)
|
|
10091
|
+
};
|
|
10092
|
+
}
|
|
10093
|
+
|
|
10094
|
+
// src/source/errors.ts
|
|
10095
|
+
var SourceCapabilityUnsupportedError = class extends ClefError {
|
|
10096
|
+
constructor(capability, sourceId) {
|
|
10097
|
+
super(
|
|
10098
|
+
`'${capability}' is not supported by the '${sourceId}' source.`,
|
|
10099
|
+
`Switch to a source that implements ${capability}, or use a different command.`
|
|
10100
|
+
);
|
|
10101
|
+
this.capability = capability;
|
|
10102
|
+
this.sourceId = sourceId;
|
|
10103
|
+
this.name = "SourceCapabilityUnsupportedError";
|
|
10104
|
+
}
|
|
10105
|
+
capability;
|
|
10106
|
+
sourceId;
|
|
10107
|
+
};
|
|
9840
10108
|
export {
|
|
9841
10109
|
ArtifactPacker,
|
|
9842
10110
|
BackendMigrator,
|
|
9843
|
-
BulkOps,
|
|
9844
10111
|
CLEF_MANIFEST_FILENAME,
|
|
9845
10112
|
CLEF_POLICY_FILENAME,
|
|
9846
10113
|
CLEF_REPORT_SCHEMA_VERSION,
|
|
@@ -9854,6 +10121,7 @@ export {
|
|
|
9854
10121
|
DiffEngine,
|
|
9855
10122
|
DriftDetector,
|
|
9856
10123
|
FilePackOutput,
|
|
10124
|
+
FilesystemStorageBackend,
|
|
9857
10125
|
GitIntegration,
|
|
9858
10126
|
GitOperationError,
|
|
9859
10127
|
ImportRunner,
|
|
@@ -9870,7 +10138,6 @@ export {
|
|
|
9870
10138
|
PolicyValidationError,
|
|
9871
10139
|
REQUESTS_FILENAME,
|
|
9872
10140
|
REQUIREMENTS,
|
|
9873
|
-
REVEAL_WARNING,
|
|
9874
10141
|
RecipientManager,
|
|
9875
10142
|
ReportGenerator,
|
|
9876
10143
|
ReportSanitizer,
|
|
@@ -9887,6 +10154,7 @@ export {
|
|
|
9887
10154
|
SopsMergeDriver,
|
|
9888
10155
|
SopsMissingError,
|
|
9889
10156
|
SopsVersionError,
|
|
10157
|
+
SourceCapabilityUnsupportedError,
|
|
9890
10158
|
StructureManager,
|
|
9891
10159
|
SyncManager,
|
|
9892
10160
|
TransactionLockError,
|
|
@@ -9906,11 +10174,11 @@ export {
|
|
|
9906
10174
|
checkAll,
|
|
9907
10175
|
checkDependency,
|
|
9908
10176
|
collectCIContext,
|
|
10177
|
+
composeSecretSource,
|
|
9909
10178
|
computeCiphertextHash,
|
|
9910
10179
|
deriveAgePublicKey,
|
|
10180
|
+
describeCapabilities,
|
|
9911
10181
|
describeScope,
|
|
9912
|
-
detectAlgorithm,
|
|
9913
|
-
detectFormat,
|
|
9914
10182
|
emptyTemplate,
|
|
9915
10183
|
exampleTemplate,
|
|
9916
10184
|
findRequest,
|
|
@@ -9918,29 +10186,24 @@ export {
|
|
|
9918
10186
|
formatRevealWarning,
|
|
9919
10187
|
generateAgeIdentity,
|
|
9920
10188
|
generateRandomValue,
|
|
9921
|
-
|
|
9922
|
-
getPendingKeys,
|
|
9923
|
-
getRotations,
|
|
10189
|
+
isBulk,
|
|
9924
10190
|
isClefHsmArn,
|
|
9925
10191
|
isHighEntropy,
|
|
9926
10192
|
isKmsEnvelope,
|
|
10193
|
+
isLintable,
|
|
10194
|
+
isMergeAware,
|
|
10195
|
+
isMigratable,
|
|
9927
10196
|
isPackedArtifact,
|
|
9928
|
-
|
|
10197
|
+
isRecipientManaged,
|
|
10198
|
+
isRotatable,
|
|
10199
|
+
isStructural,
|
|
9929
10200
|
keyPreview,
|
|
9930
|
-
loadIgnoreRules,
|
|
9931
|
-
loadMetadata,
|
|
9932
10201
|
loadRequests,
|
|
9933
10202
|
markPending,
|
|
9934
|
-
markPendingWithRetry,
|
|
9935
10203
|
markResolved,
|
|
9936
10204
|
matchPatterns,
|
|
9937
|
-
mergeMetadataContents,
|
|
9938
10205
|
mergeMetadataFiles,
|
|
9939
|
-
metadataPath,
|
|
9940
10206
|
parse9 as parse,
|
|
9941
|
-
parseDotenv,
|
|
9942
|
-
parseIgnoreContent,
|
|
9943
|
-
parseJson,
|
|
9944
10207
|
parseSignerKey,
|
|
9945
10208
|
parseYaml,
|
|
9946
10209
|
pkcs11UriToSyntheticArn,
|
|
@@ -9958,14 +10221,8 @@ export {
|
|
|
9958
10221
|
resolveRecipientsForEnvironment,
|
|
9959
10222
|
resolveSopsPath,
|
|
9960
10223
|
runCompliance,
|
|
9961
|
-
saveMetadata,
|
|
9962
10224
|
saveRequests,
|
|
9963
|
-
|
|
9964
|
-
shannonEntropy,
|
|
9965
|
-
shouldIgnoreFile,
|
|
9966
|
-
shouldIgnoreMatch,
|
|
9967
|
-
signEd25519,
|
|
9968
|
-
signKms,
|
|
10225
|
+
shouldUseLinuxStdinFifo,
|
|
9969
10226
|
spawnKeyservice,
|
|
9970
10227
|
syntheticArnToPkcs11Uri,
|
|
9971
10228
|
tryBundledKeyservice,
|
|
@@ -9975,6 +10232,7 @@ export {
|
|
|
9975
10232
|
validatePackedArtifact,
|
|
9976
10233
|
validateResetScope,
|
|
9977
10234
|
verifySignature,
|
|
10235
|
+
wrapWithLinuxStdinFifo,
|
|
9978
10236
|
writeManifestYaml,
|
|
9979
10237
|
writeManifestYamlRaw,
|
|
9980
10238
|
writeSchema,
|