@clef-sh/core 0.1.17 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/artifact/guards.d.ts +40 -0
- package/dist/artifact/guards.d.ts.map +1 -0
- package/dist/artifact/packer.d.ts.map +1 -1
- package/dist/artifact/types.d.ts +11 -2
- package/dist/artifact/types.d.ts.map +1 -1
- package/dist/compliance/generator.d.ts.map +1 -1
- package/dist/compliance/run.d.ts +19 -0
- package/dist/compliance/run.d.ts.map +1 -1
- package/dist/git/integration.d.ts +8 -5
- package/dist/git/integration.d.ts.map +1 -1
- package/dist/hsm/bundled.d.ts +10 -0
- package/dist/hsm/bundled.d.ts.map +1 -0
- package/dist/hsm/index.d.ts +4 -0
- package/dist/hsm/index.d.ts.map +1 -0
- package/dist/hsm/keyservice.d.ts +36 -0
- package/dist/hsm/keyservice.d.ts.map +1 -0
- package/dist/hsm/resolver.d.ts +22 -0
- package/dist/hsm/resolver.d.ts.map +1 -0
- package/dist/import/index.d.ts +7 -0
- package/dist/import/index.d.ts.map +1 -1
- package/dist/index.d.mts +14 -4
- package/dist/index.d.ts +14 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1129 -385
- package/dist/index.js.map +4 -4
- package/dist/index.mjs +1107 -381
- package/dist/index.mjs.map +4 -4
- package/dist/lint/runner.d.ts +7 -0
- package/dist/lint/runner.d.ts.map +1 -1
- package/dist/manifest/parser.d.ts.map +1 -1
- package/dist/merge/metadata-driver.d.ts +17 -0
- package/dist/merge/metadata-driver.d.ts.map +1 -0
- package/dist/migration/backend.d.ts.map +1 -1
- package/dist/pack/backends/json-envelope.d.ts +33 -0
- package/dist/pack/backends/json-envelope.d.ts.map +1 -0
- package/dist/pack/registry.d.ts +27 -0
- package/dist/pack/registry.d.ts.map +1 -0
- package/dist/pack/types.d.ts +78 -0
- package/dist/pack/types.d.ts.map +1 -0
- package/dist/pending/metadata.d.ts +40 -15
- package/dist/pending/metadata.d.ts.map +1 -1
- package/dist/policy/evaluator.d.ts +19 -9
- package/dist/policy/evaluator.d.ts.map +1 -1
- package/dist/policy/types.d.ts +40 -9
- package/dist/policy/types.d.ts.map +1 -1
- package/dist/scanner/index.d.ts +9 -1
- package/dist/scanner/index.d.ts.map +1 -1
- package/dist/scanner/patterns.d.ts +12 -0
- package/dist/scanner/patterns.d.ts.map +1 -1
- package/dist/sops/client.d.ts +11 -1
- package/dist/sops/client.d.ts.map +1 -1
- package/dist/sops/hsm-arn.d.ts +51 -0
- package/dist/sops/hsm-arn.d.ts.map +1 -0
- package/dist/types/index.d.ts +18 -2
- package/dist/types/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -301,13 +301,13 @@ var require_lib = __commonJS({
|
|
|
301
301
|
"node_modules/write-file-atomic/lib/index.js"(exports, module) {
|
|
302
302
|
"use strict";
|
|
303
303
|
module.exports = writeFile;
|
|
304
|
-
module.exports.sync =
|
|
304
|
+
module.exports.sync = writeFileSync7;
|
|
305
305
|
module.exports._getTmpname = getTmpname;
|
|
306
306
|
module.exports._cleanupOnExit = cleanupOnExit;
|
|
307
|
-
var
|
|
307
|
+
var fs21 = __require("fs");
|
|
308
308
|
var crypto4 = __require("node:crypto");
|
|
309
309
|
var { onExit } = require_cjs();
|
|
310
|
-
var
|
|
310
|
+
var path28 = __require("path");
|
|
311
311
|
var { promisify } = __require("util");
|
|
312
312
|
var activeFiles = {};
|
|
313
313
|
var threadId = (function getId() {
|
|
@@ -325,7 +325,7 @@ var require_lib = __commonJS({
|
|
|
325
325
|
function cleanupOnExit(tmpfile) {
|
|
326
326
|
return () => {
|
|
327
327
|
try {
|
|
328
|
-
|
|
328
|
+
fs21.unlinkSync(typeof tmpfile === "function" ? tmpfile() : tmpfile);
|
|
329
329
|
} catch {
|
|
330
330
|
}
|
|
331
331
|
};
|
|
@@ -360,13 +360,13 @@ var require_lib = __commonJS({
|
|
|
360
360
|
let fd;
|
|
361
361
|
let tmpfile;
|
|
362
362
|
const removeOnExitHandler = onExit(cleanupOnExit(() => tmpfile));
|
|
363
|
-
const absoluteName =
|
|
363
|
+
const absoluteName = path28.resolve(filename);
|
|
364
364
|
try {
|
|
365
365
|
await serializeActiveFile(absoluteName);
|
|
366
|
-
const truename = await promisify(
|
|
366
|
+
const truename = await promisify(fs21.realpath)(filename).catch(() => filename);
|
|
367
367
|
tmpfile = getTmpname(truename);
|
|
368
368
|
if (!options.mode || !options.chown) {
|
|
369
|
-
const stats = await promisify(
|
|
369
|
+
const stats = await promisify(fs21.stat)(truename).catch(() => {
|
|
370
370
|
});
|
|
371
371
|
if (stats) {
|
|
372
372
|
if (options.mode == null) {
|
|
@@ -377,45 +377,45 @@ var require_lib = __commonJS({
|
|
|
377
377
|
}
|
|
378
378
|
}
|
|
379
379
|
}
|
|
380
|
-
fd = await promisify(
|
|
380
|
+
fd = await promisify(fs21.open)(tmpfile, "w", options.mode);
|
|
381
381
|
if (options.tmpfileCreated) {
|
|
382
382
|
await options.tmpfileCreated(tmpfile);
|
|
383
383
|
}
|
|
384
384
|
if (ArrayBuffer.isView(data)) {
|
|
385
|
-
await promisify(
|
|
385
|
+
await promisify(fs21.write)(fd, data, 0, data.length, 0);
|
|
386
386
|
} else if (data != null) {
|
|
387
|
-
await promisify(
|
|
387
|
+
await promisify(fs21.write)(fd, String(data), 0, String(options.encoding || "utf8"));
|
|
388
388
|
}
|
|
389
389
|
if (options.fsync !== false) {
|
|
390
|
-
await promisify(
|
|
390
|
+
await promisify(fs21.fsync)(fd);
|
|
391
391
|
}
|
|
392
|
-
await promisify(
|
|
392
|
+
await promisify(fs21.close)(fd);
|
|
393
393
|
fd = null;
|
|
394
394
|
if (options.chown) {
|
|
395
|
-
await promisify(
|
|
395
|
+
await promisify(fs21.chown)(tmpfile, options.chown.uid, options.chown.gid).catch((err) => {
|
|
396
396
|
if (!isChownErrOk(err)) {
|
|
397
397
|
throw err;
|
|
398
398
|
}
|
|
399
399
|
});
|
|
400
400
|
}
|
|
401
401
|
if (options.mode) {
|
|
402
|
-
await promisify(
|
|
402
|
+
await promisify(fs21.chmod)(tmpfile, options.mode).catch((err) => {
|
|
403
403
|
if (!isChownErrOk(err)) {
|
|
404
404
|
throw err;
|
|
405
405
|
}
|
|
406
406
|
});
|
|
407
407
|
}
|
|
408
|
-
await promisify(
|
|
408
|
+
await promisify(fs21.rename)(tmpfile, truename);
|
|
409
409
|
} finally {
|
|
410
410
|
if (fd) {
|
|
411
|
-
await promisify(
|
|
411
|
+
await promisify(fs21.close)(fd).catch(
|
|
412
412
|
/* istanbul ignore next */
|
|
413
413
|
() => {
|
|
414
414
|
}
|
|
415
415
|
);
|
|
416
416
|
}
|
|
417
417
|
removeOnExitHandler();
|
|
418
|
-
await promisify(
|
|
418
|
+
await promisify(fs21.unlink)(tmpfile).catch(() => {
|
|
419
419
|
});
|
|
420
420
|
activeFiles[absoluteName].shift();
|
|
421
421
|
if (activeFiles[absoluteName].length > 0) {
|
|
@@ -441,20 +441,20 @@ var require_lib = __commonJS({
|
|
|
441
441
|
}
|
|
442
442
|
return promise;
|
|
443
443
|
}
|
|
444
|
-
function
|
|
444
|
+
function writeFileSync7(filename, data, options) {
|
|
445
445
|
if (typeof options === "string") {
|
|
446
446
|
options = { encoding: options };
|
|
447
447
|
} else if (!options) {
|
|
448
448
|
options = {};
|
|
449
449
|
}
|
|
450
450
|
try {
|
|
451
|
-
filename =
|
|
451
|
+
filename = fs21.realpathSync(filename);
|
|
452
452
|
} catch (ex) {
|
|
453
453
|
}
|
|
454
454
|
const tmpfile = getTmpname(filename);
|
|
455
455
|
if (!options.mode || !options.chown) {
|
|
456
456
|
try {
|
|
457
|
-
const stats =
|
|
457
|
+
const stats = fs21.statSync(filename);
|
|
458
458
|
options = Object.assign({}, options);
|
|
459
459
|
if (!options.mode) {
|
|
460
460
|
options.mode = stats.mode;
|
|
@@ -470,23 +470,23 @@ var require_lib = __commonJS({
|
|
|
470
470
|
const removeOnExitHandler = onExit(cleanup);
|
|
471
471
|
let threw = true;
|
|
472
472
|
try {
|
|
473
|
-
fd =
|
|
473
|
+
fd = fs21.openSync(tmpfile, "w", options.mode || 438);
|
|
474
474
|
if (options.tmpfileCreated) {
|
|
475
475
|
options.tmpfileCreated(tmpfile);
|
|
476
476
|
}
|
|
477
477
|
if (ArrayBuffer.isView(data)) {
|
|
478
|
-
|
|
478
|
+
fs21.writeSync(fd, data, 0, data.length, 0);
|
|
479
479
|
} else if (data != null) {
|
|
480
|
-
|
|
480
|
+
fs21.writeSync(fd, String(data), 0, String(options.encoding || "utf8"));
|
|
481
481
|
}
|
|
482
482
|
if (options.fsync !== false) {
|
|
483
|
-
|
|
483
|
+
fs21.fsyncSync(fd);
|
|
484
484
|
}
|
|
485
|
-
|
|
485
|
+
fs21.closeSync(fd);
|
|
486
486
|
fd = null;
|
|
487
487
|
if (options.chown) {
|
|
488
488
|
try {
|
|
489
|
-
|
|
489
|
+
fs21.chownSync(tmpfile, options.chown.uid, options.chown.gid);
|
|
490
490
|
} catch (err) {
|
|
491
491
|
if (!isChownErrOk(err)) {
|
|
492
492
|
throw err;
|
|
@@ -495,19 +495,19 @@ var require_lib = __commonJS({
|
|
|
495
495
|
}
|
|
496
496
|
if (options.mode) {
|
|
497
497
|
try {
|
|
498
|
-
|
|
498
|
+
fs21.chmodSync(tmpfile, options.mode);
|
|
499
499
|
} catch (err) {
|
|
500
500
|
if (!isChownErrOk(err)) {
|
|
501
501
|
throw err;
|
|
502
502
|
}
|
|
503
503
|
}
|
|
504
504
|
}
|
|
505
|
-
|
|
505
|
+
fs21.renameSync(tmpfile, filename);
|
|
506
506
|
threw = false;
|
|
507
507
|
} finally {
|
|
508
508
|
if (fd) {
|
|
509
509
|
try {
|
|
510
|
-
|
|
510
|
+
fs21.closeSync(fd);
|
|
511
511
|
} catch (ex) {
|
|
512
512
|
}
|
|
513
513
|
}
|
|
@@ -546,54 +546,54 @@ var require_polyfills = __commonJS({
|
|
|
546
546
|
}
|
|
547
547
|
var chdir;
|
|
548
548
|
module.exports = patch;
|
|
549
|
-
function patch(
|
|
549
|
+
function patch(fs21) {
|
|
550
550
|
if (constants.hasOwnProperty("O_SYMLINK") && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
|
|
551
|
-
patchLchmod(
|
|
552
|
-
}
|
|
553
|
-
if (!
|
|
554
|
-
patchLutimes(
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
if (
|
|
575
|
-
|
|
551
|
+
patchLchmod(fs21);
|
|
552
|
+
}
|
|
553
|
+
if (!fs21.lutimes) {
|
|
554
|
+
patchLutimes(fs21);
|
|
555
|
+
}
|
|
556
|
+
fs21.chown = chownFix(fs21.chown);
|
|
557
|
+
fs21.fchown = chownFix(fs21.fchown);
|
|
558
|
+
fs21.lchown = chownFix(fs21.lchown);
|
|
559
|
+
fs21.chmod = chmodFix(fs21.chmod);
|
|
560
|
+
fs21.fchmod = chmodFix(fs21.fchmod);
|
|
561
|
+
fs21.lchmod = chmodFix(fs21.lchmod);
|
|
562
|
+
fs21.chownSync = chownFixSync(fs21.chownSync);
|
|
563
|
+
fs21.fchownSync = chownFixSync(fs21.fchownSync);
|
|
564
|
+
fs21.lchownSync = chownFixSync(fs21.lchownSync);
|
|
565
|
+
fs21.chmodSync = chmodFixSync(fs21.chmodSync);
|
|
566
|
+
fs21.fchmodSync = chmodFixSync(fs21.fchmodSync);
|
|
567
|
+
fs21.lchmodSync = chmodFixSync(fs21.lchmodSync);
|
|
568
|
+
fs21.stat = statFix(fs21.stat);
|
|
569
|
+
fs21.fstat = statFix(fs21.fstat);
|
|
570
|
+
fs21.lstat = statFix(fs21.lstat);
|
|
571
|
+
fs21.statSync = statFixSync(fs21.statSync);
|
|
572
|
+
fs21.fstatSync = statFixSync(fs21.fstatSync);
|
|
573
|
+
fs21.lstatSync = statFixSync(fs21.lstatSync);
|
|
574
|
+
if (fs21.chmod && !fs21.lchmod) {
|
|
575
|
+
fs21.lchmod = function(path28, mode, cb) {
|
|
576
576
|
if (cb) process.nextTick(cb);
|
|
577
577
|
};
|
|
578
|
-
|
|
578
|
+
fs21.lchmodSync = function() {
|
|
579
579
|
};
|
|
580
580
|
}
|
|
581
|
-
if (
|
|
582
|
-
|
|
581
|
+
if (fs21.chown && !fs21.lchown) {
|
|
582
|
+
fs21.lchown = function(path28, uid, gid, cb) {
|
|
583
583
|
if (cb) process.nextTick(cb);
|
|
584
584
|
};
|
|
585
|
-
|
|
585
|
+
fs21.lchownSync = function() {
|
|
586
586
|
};
|
|
587
587
|
}
|
|
588
588
|
if (platform === "win32") {
|
|
589
|
-
|
|
589
|
+
fs21.rename = typeof fs21.rename !== "function" ? fs21.rename : (function(fs$rename) {
|
|
590
590
|
function rename(from, to, cb) {
|
|
591
591
|
var start = Date.now();
|
|
592
592
|
var backoff = 0;
|
|
593
593
|
fs$rename(from, to, function CB(er) {
|
|
594
594
|
if (er && (er.code === "EACCES" || er.code === "EPERM" || er.code === "EBUSY") && Date.now() - start < 6e4) {
|
|
595
595
|
setTimeout(function() {
|
|
596
|
-
|
|
596
|
+
fs21.stat(to, function(stater, st) {
|
|
597
597
|
if (stater && stater.code === "ENOENT")
|
|
598
598
|
fs$rename(from, to, CB);
|
|
599
599
|
else
|
|
@@ -609,9 +609,9 @@ var require_polyfills = __commonJS({
|
|
|
609
609
|
}
|
|
610
610
|
if (Object.setPrototypeOf) Object.setPrototypeOf(rename, fs$rename);
|
|
611
611
|
return rename;
|
|
612
|
-
})(
|
|
612
|
+
})(fs21.rename);
|
|
613
613
|
}
|
|
614
|
-
|
|
614
|
+
fs21.read = typeof fs21.read !== "function" ? fs21.read : (function(fs$read) {
|
|
615
615
|
function read(fd, buffer, offset, length, position, callback_) {
|
|
616
616
|
var callback;
|
|
617
617
|
if (callback_ && typeof callback_ === "function") {
|
|
@@ -619,22 +619,22 @@ var require_polyfills = __commonJS({
|
|
|
619
619
|
callback = function(er, _, __) {
|
|
620
620
|
if (er && er.code === "EAGAIN" && eagCounter < 10) {
|
|
621
621
|
eagCounter++;
|
|
622
|
-
return fs$read.call(
|
|
622
|
+
return fs$read.call(fs21, fd, buffer, offset, length, position, callback);
|
|
623
623
|
}
|
|
624
624
|
callback_.apply(this, arguments);
|
|
625
625
|
};
|
|
626
626
|
}
|
|
627
|
-
return fs$read.call(
|
|
627
|
+
return fs$read.call(fs21, fd, buffer, offset, length, position, callback);
|
|
628
628
|
}
|
|
629
629
|
if (Object.setPrototypeOf) Object.setPrototypeOf(read, fs$read);
|
|
630
630
|
return read;
|
|
631
|
-
})(
|
|
632
|
-
|
|
631
|
+
})(fs21.read);
|
|
632
|
+
fs21.readSync = typeof fs21.readSync !== "function" ? fs21.readSync : /* @__PURE__ */ (function(fs$readSync) {
|
|
633
633
|
return function(fd, buffer, offset, length, position) {
|
|
634
634
|
var eagCounter = 0;
|
|
635
635
|
while (true) {
|
|
636
636
|
try {
|
|
637
|
-
return fs$readSync.call(
|
|
637
|
+
return fs$readSync.call(fs21, fd, buffer, offset, length, position);
|
|
638
638
|
} catch (er) {
|
|
639
639
|
if (er.code === "EAGAIN" && eagCounter < 10) {
|
|
640
640
|
eagCounter++;
|
|
@@ -644,11 +644,11 @@ var require_polyfills = __commonJS({
|
|
|
644
644
|
}
|
|
645
645
|
}
|
|
646
646
|
};
|
|
647
|
-
})(
|
|
648
|
-
function patchLchmod(
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
647
|
+
})(fs21.readSync);
|
|
648
|
+
function patchLchmod(fs22) {
|
|
649
|
+
fs22.lchmod = function(path28, mode, callback) {
|
|
650
|
+
fs22.open(
|
|
651
|
+
path28,
|
|
652
652
|
constants.O_WRONLY | constants.O_SYMLINK,
|
|
653
653
|
mode,
|
|
654
654
|
function(err, fd) {
|
|
@@ -656,80 +656,80 @@ var require_polyfills = __commonJS({
|
|
|
656
656
|
if (callback) callback(err);
|
|
657
657
|
return;
|
|
658
658
|
}
|
|
659
|
-
|
|
660
|
-
|
|
659
|
+
fs22.fchmod(fd, mode, function(err2) {
|
|
660
|
+
fs22.close(fd, function(err22) {
|
|
661
661
|
if (callback) callback(err2 || err22);
|
|
662
662
|
});
|
|
663
663
|
});
|
|
664
664
|
}
|
|
665
665
|
);
|
|
666
666
|
};
|
|
667
|
-
|
|
668
|
-
var fd =
|
|
667
|
+
fs22.lchmodSync = function(path28, mode) {
|
|
668
|
+
var fd = fs22.openSync(path28, constants.O_WRONLY | constants.O_SYMLINK, mode);
|
|
669
669
|
var threw = true;
|
|
670
670
|
var ret;
|
|
671
671
|
try {
|
|
672
|
-
ret =
|
|
672
|
+
ret = fs22.fchmodSync(fd, mode);
|
|
673
673
|
threw = false;
|
|
674
674
|
} finally {
|
|
675
675
|
if (threw) {
|
|
676
676
|
try {
|
|
677
|
-
|
|
677
|
+
fs22.closeSync(fd);
|
|
678
678
|
} catch (er) {
|
|
679
679
|
}
|
|
680
680
|
} else {
|
|
681
|
-
|
|
681
|
+
fs22.closeSync(fd);
|
|
682
682
|
}
|
|
683
683
|
}
|
|
684
684
|
return ret;
|
|
685
685
|
};
|
|
686
686
|
}
|
|
687
|
-
function patchLutimes(
|
|
688
|
-
if (constants.hasOwnProperty("O_SYMLINK") &&
|
|
689
|
-
|
|
690
|
-
|
|
687
|
+
function patchLutimes(fs22) {
|
|
688
|
+
if (constants.hasOwnProperty("O_SYMLINK") && fs22.futimes) {
|
|
689
|
+
fs22.lutimes = function(path28, at, mt, cb) {
|
|
690
|
+
fs22.open(path28, constants.O_SYMLINK, function(er, fd) {
|
|
691
691
|
if (er) {
|
|
692
692
|
if (cb) cb(er);
|
|
693
693
|
return;
|
|
694
694
|
}
|
|
695
|
-
|
|
696
|
-
|
|
695
|
+
fs22.futimes(fd, at, mt, function(er2) {
|
|
696
|
+
fs22.close(fd, function(er22) {
|
|
697
697
|
if (cb) cb(er2 || er22);
|
|
698
698
|
});
|
|
699
699
|
});
|
|
700
700
|
});
|
|
701
701
|
};
|
|
702
|
-
|
|
703
|
-
var fd =
|
|
702
|
+
fs22.lutimesSync = function(path28, at, mt) {
|
|
703
|
+
var fd = fs22.openSync(path28, constants.O_SYMLINK);
|
|
704
704
|
var ret;
|
|
705
705
|
var threw = true;
|
|
706
706
|
try {
|
|
707
|
-
ret =
|
|
707
|
+
ret = fs22.futimesSync(fd, at, mt);
|
|
708
708
|
threw = false;
|
|
709
709
|
} finally {
|
|
710
710
|
if (threw) {
|
|
711
711
|
try {
|
|
712
|
-
|
|
712
|
+
fs22.closeSync(fd);
|
|
713
713
|
} catch (er) {
|
|
714
714
|
}
|
|
715
715
|
} else {
|
|
716
|
-
|
|
716
|
+
fs22.closeSync(fd);
|
|
717
717
|
}
|
|
718
718
|
}
|
|
719
719
|
return ret;
|
|
720
720
|
};
|
|
721
|
-
} else if (
|
|
722
|
-
|
|
721
|
+
} else if (fs22.futimes) {
|
|
722
|
+
fs22.lutimes = function(_a, _b, _c, cb) {
|
|
723
723
|
if (cb) process.nextTick(cb);
|
|
724
724
|
};
|
|
725
|
-
|
|
725
|
+
fs22.lutimesSync = function() {
|
|
726
726
|
};
|
|
727
727
|
}
|
|
728
728
|
}
|
|
729
729
|
function chmodFix(orig) {
|
|
730
730
|
if (!orig) return orig;
|
|
731
731
|
return function(target, mode, cb) {
|
|
732
|
-
return orig.call(
|
|
732
|
+
return orig.call(fs21, target, mode, function(er) {
|
|
733
733
|
if (chownErOk(er)) er = null;
|
|
734
734
|
if (cb) cb.apply(this, arguments);
|
|
735
735
|
});
|
|
@@ -739,7 +739,7 @@ var require_polyfills = __commonJS({
|
|
|
739
739
|
if (!orig) return orig;
|
|
740
740
|
return function(target, mode) {
|
|
741
741
|
try {
|
|
742
|
-
return orig.call(
|
|
742
|
+
return orig.call(fs21, target, mode);
|
|
743
743
|
} catch (er) {
|
|
744
744
|
if (!chownErOk(er)) throw er;
|
|
745
745
|
}
|
|
@@ -748,7 +748,7 @@ var require_polyfills = __commonJS({
|
|
|
748
748
|
function chownFix(orig) {
|
|
749
749
|
if (!orig) return orig;
|
|
750
750
|
return function(target, uid, gid, cb) {
|
|
751
|
-
return orig.call(
|
|
751
|
+
return orig.call(fs21, target, uid, gid, function(er) {
|
|
752
752
|
if (chownErOk(er)) er = null;
|
|
753
753
|
if (cb) cb.apply(this, arguments);
|
|
754
754
|
});
|
|
@@ -758,7 +758,7 @@ var require_polyfills = __commonJS({
|
|
|
758
758
|
if (!orig) return orig;
|
|
759
759
|
return function(target, uid, gid) {
|
|
760
760
|
try {
|
|
761
|
-
return orig.call(
|
|
761
|
+
return orig.call(fs21, target, uid, gid);
|
|
762
762
|
} catch (er) {
|
|
763
763
|
if (!chownErOk(er)) throw er;
|
|
764
764
|
}
|
|
@@ -778,13 +778,13 @@ var require_polyfills = __commonJS({
|
|
|
778
778
|
}
|
|
779
779
|
if (cb) cb.apply(this, arguments);
|
|
780
780
|
}
|
|
781
|
-
return options ? orig.call(
|
|
781
|
+
return options ? orig.call(fs21, target, options, callback) : orig.call(fs21, target, callback);
|
|
782
782
|
};
|
|
783
783
|
}
|
|
784
784
|
function statFixSync(orig) {
|
|
785
785
|
if (!orig) return orig;
|
|
786
786
|
return function(target, options) {
|
|
787
|
-
var stats = options ? orig.call(
|
|
787
|
+
var stats = options ? orig.call(fs21, target, options) : orig.call(fs21, target);
|
|
788
788
|
if (stats) {
|
|
789
789
|
if (stats.uid < 0) stats.uid += 4294967296;
|
|
790
790
|
if (stats.gid < 0) stats.gid += 4294967296;
|
|
@@ -813,16 +813,16 @@ var require_legacy_streams = __commonJS({
|
|
|
813
813
|
"../../node_modules/graceful-fs/legacy-streams.js"(exports, module) {
|
|
814
814
|
var Stream = __require("stream").Stream;
|
|
815
815
|
module.exports = legacy;
|
|
816
|
-
function legacy(
|
|
816
|
+
function legacy(fs21) {
|
|
817
817
|
return {
|
|
818
818
|
ReadStream,
|
|
819
819
|
WriteStream
|
|
820
820
|
};
|
|
821
|
-
function ReadStream(
|
|
822
|
-
if (!(this instanceof ReadStream)) return new ReadStream(
|
|
821
|
+
function ReadStream(path28, options) {
|
|
822
|
+
if (!(this instanceof ReadStream)) return new ReadStream(path28, options);
|
|
823
823
|
Stream.call(this);
|
|
824
824
|
var self = this;
|
|
825
|
-
this.path =
|
|
825
|
+
this.path = path28;
|
|
826
826
|
this.fd = null;
|
|
827
827
|
this.readable = true;
|
|
828
828
|
this.paused = false;
|
|
@@ -856,7 +856,7 @@ var require_legacy_streams = __commonJS({
|
|
|
856
856
|
});
|
|
857
857
|
return;
|
|
858
858
|
}
|
|
859
|
-
|
|
859
|
+
fs21.open(this.path, this.flags, this.mode, function(err, fd) {
|
|
860
860
|
if (err) {
|
|
861
861
|
self.emit("error", err);
|
|
862
862
|
self.readable = false;
|
|
@@ -867,10 +867,10 @@ var require_legacy_streams = __commonJS({
|
|
|
867
867
|
self._read();
|
|
868
868
|
});
|
|
869
869
|
}
|
|
870
|
-
function WriteStream(
|
|
871
|
-
if (!(this instanceof WriteStream)) return new WriteStream(
|
|
870
|
+
function WriteStream(path28, options) {
|
|
871
|
+
if (!(this instanceof WriteStream)) return new WriteStream(path28, options);
|
|
872
872
|
Stream.call(this);
|
|
873
|
-
this.path =
|
|
873
|
+
this.path = path28;
|
|
874
874
|
this.fd = null;
|
|
875
875
|
this.writable = true;
|
|
876
876
|
this.flags = "w";
|
|
@@ -895,7 +895,7 @@ var require_legacy_streams = __commonJS({
|
|
|
895
895
|
this.busy = false;
|
|
896
896
|
this._queue = [];
|
|
897
897
|
if (this.fd === null) {
|
|
898
|
-
this._open =
|
|
898
|
+
this._open = fs21.open;
|
|
899
899
|
this._queue.push([this._open, this.path, this.flags, this.mode, void 0]);
|
|
900
900
|
this.flush();
|
|
901
901
|
}
|
|
@@ -930,7 +930,7 @@ var require_clone = __commonJS({
|
|
|
930
930
|
// ../../node_modules/graceful-fs/graceful-fs.js
|
|
931
931
|
var require_graceful_fs = __commonJS({
|
|
932
932
|
"../../node_modules/graceful-fs/graceful-fs.js"(exports, module) {
|
|
933
|
-
var
|
|
933
|
+
var fs21 = __require("fs");
|
|
934
934
|
var polyfills = require_polyfills();
|
|
935
935
|
var legacy = require_legacy_streams();
|
|
936
936
|
var clone = require_clone();
|
|
@@ -962,12 +962,12 @@ var require_graceful_fs = __commonJS({
|
|
|
962
962
|
m = "GFS4: " + m.split(/\n/).join("\nGFS4: ");
|
|
963
963
|
console.error(m);
|
|
964
964
|
};
|
|
965
|
-
if (!
|
|
965
|
+
if (!fs21[gracefulQueue]) {
|
|
966
966
|
queue = global[gracefulQueue] || [];
|
|
967
|
-
publishQueue(
|
|
968
|
-
|
|
967
|
+
publishQueue(fs21, queue);
|
|
968
|
+
fs21.close = (function(fs$close) {
|
|
969
969
|
function close(fd, cb) {
|
|
970
|
-
return fs$close.call(
|
|
970
|
+
return fs$close.call(fs21, fd, function(err) {
|
|
971
971
|
if (!err) {
|
|
972
972
|
resetQueue();
|
|
973
973
|
}
|
|
@@ -979,48 +979,48 @@ var require_graceful_fs = __commonJS({
|
|
|
979
979
|
value: fs$close
|
|
980
980
|
});
|
|
981
981
|
return close;
|
|
982
|
-
})(
|
|
983
|
-
|
|
982
|
+
})(fs21.close);
|
|
983
|
+
fs21.closeSync = (function(fs$closeSync) {
|
|
984
984
|
function closeSync2(fd) {
|
|
985
|
-
fs$closeSync.apply(
|
|
985
|
+
fs$closeSync.apply(fs21, arguments);
|
|
986
986
|
resetQueue();
|
|
987
987
|
}
|
|
988
988
|
Object.defineProperty(closeSync2, previousSymbol, {
|
|
989
989
|
value: fs$closeSync
|
|
990
990
|
});
|
|
991
991
|
return closeSync2;
|
|
992
|
-
})(
|
|
992
|
+
})(fs21.closeSync);
|
|
993
993
|
if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || "")) {
|
|
994
994
|
process.on("exit", function() {
|
|
995
|
-
debug(
|
|
996
|
-
__require("assert").equal(
|
|
995
|
+
debug(fs21[gracefulQueue]);
|
|
996
|
+
__require("assert").equal(fs21[gracefulQueue].length, 0);
|
|
997
997
|
});
|
|
998
998
|
}
|
|
999
999
|
}
|
|
1000
1000
|
var queue;
|
|
1001
1001
|
if (!global[gracefulQueue]) {
|
|
1002
|
-
publishQueue(global,
|
|
1003
|
-
}
|
|
1004
|
-
module.exports = patch(clone(
|
|
1005
|
-
if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !
|
|
1006
|
-
module.exports = patch(
|
|
1007
|
-
|
|
1008
|
-
}
|
|
1009
|
-
function patch(
|
|
1010
|
-
polyfills(
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
var fs$readFile =
|
|
1015
|
-
|
|
1016
|
-
function readFile(
|
|
1002
|
+
publishQueue(global, fs21[gracefulQueue]);
|
|
1003
|
+
}
|
|
1004
|
+
module.exports = patch(clone(fs21));
|
|
1005
|
+
if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs21.__patched) {
|
|
1006
|
+
module.exports = patch(fs21);
|
|
1007
|
+
fs21.__patched = true;
|
|
1008
|
+
}
|
|
1009
|
+
function patch(fs22) {
|
|
1010
|
+
polyfills(fs22);
|
|
1011
|
+
fs22.gracefulify = patch;
|
|
1012
|
+
fs22.createReadStream = createReadStream;
|
|
1013
|
+
fs22.createWriteStream = createWriteStream;
|
|
1014
|
+
var fs$readFile = fs22.readFile;
|
|
1015
|
+
fs22.readFile = readFile;
|
|
1016
|
+
function readFile(path28, options, cb) {
|
|
1017
1017
|
if (typeof options === "function")
|
|
1018
1018
|
cb = options, options = null;
|
|
1019
|
-
return go$readFile(
|
|
1020
|
-
function go$readFile(
|
|
1021
|
-
return fs$readFile(
|
|
1019
|
+
return go$readFile(path28, options, cb);
|
|
1020
|
+
function go$readFile(path29, options2, cb2, startTime) {
|
|
1021
|
+
return fs$readFile(path29, options2, function(err) {
|
|
1022
1022
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
1023
|
-
enqueue([go$readFile, [
|
|
1023
|
+
enqueue([go$readFile, [path29, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
1024
1024
|
else {
|
|
1025
1025
|
if (typeof cb2 === "function")
|
|
1026
1026
|
cb2.apply(this, arguments);
|
|
@@ -1028,16 +1028,16 @@ var require_graceful_fs = __commonJS({
|
|
|
1028
1028
|
});
|
|
1029
1029
|
}
|
|
1030
1030
|
}
|
|
1031
|
-
var fs$writeFile =
|
|
1032
|
-
|
|
1033
|
-
function writeFile(
|
|
1031
|
+
var fs$writeFile = fs22.writeFile;
|
|
1032
|
+
fs22.writeFile = writeFile;
|
|
1033
|
+
function writeFile(path28, data, options, cb) {
|
|
1034
1034
|
if (typeof options === "function")
|
|
1035
1035
|
cb = options, options = null;
|
|
1036
|
-
return go$writeFile(
|
|
1037
|
-
function go$writeFile(
|
|
1038
|
-
return fs$writeFile(
|
|
1036
|
+
return go$writeFile(path28, data, options, cb);
|
|
1037
|
+
function go$writeFile(path29, data2, options2, cb2, startTime) {
|
|
1038
|
+
return fs$writeFile(path29, data2, options2, function(err) {
|
|
1039
1039
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
1040
|
-
enqueue([go$writeFile, [
|
|
1040
|
+
enqueue([go$writeFile, [path29, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
1041
1041
|
else {
|
|
1042
1042
|
if (typeof cb2 === "function")
|
|
1043
1043
|
cb2.apply(this, arguments);
|
|
@@ -1045,17 +1045,17 @@ var require_graceful_fs = __commonJS({
|
|
|
1045
1045
|
});
|
|
1046
1046
|
}
|
|
1047
1047
|
}
|
|
1048
|
-
var fs$appendFile =
|
|
1048
|
+
var fs$appendFile = fs22.appendFile;
|
|
1049
1049
|
if (fs$appendFile)
|
|
1050
|
-
|
|
1051
|
-
function appendFile(
|
|
1050
|
+
fs22.appendFile = appendFile;
|
|
1051
|
+
function appendFile(path28, data, options, cb) {
|
|
1052
1052
|
if (typeof options === "function")
|
|
1053
1053
|
cb = options, options = null;
|
|
1054
|
-
return go$appendFile(
|
|
1055
|
-
function go$appendFile(
|
|
1056
|
-
return fs$appendFile(
|
|
1054
|
+
return go$appendFile(path28, data, options, cb);
|
|
1055
|
+
function go$appendFile(path29, data2, options2, cb2, startTime) {
|
|
1056
|
+
return fs$appendFile(path29, data2, options2, function(err) {
|
|
1057
1057
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
1058
|
-
enqueue([go$appendFile, [
|
|
1058
|
+
enqueue([go$appendFile, [path29, data2, options2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
1059
1059
|
else {
|
|
1060
1060
|
if (typeof cb2 === "function")
|
|
1061
1061
|
cb2.apply(this, arguments);
|
|
@@ -1063,9 +1063,9 @@ var require_graceful_fs = __commonJS({
|
|
|
1063
1063
|
});
|
|
1064
1064
|
}
|
|
1065
1065
|
}
|
|
1066
|
-
var fs$copyFile =
|
|
1066
|
+
var fs$copyFile = fs22.copyFile;
|
|
1067
1067
|
if (fs$copyFile)
|
|
1068
|
-
|
|
1068
|
+
fs22.copyFile = copyFile;
|
|
1069
1069
|
function copyFile(src, dest, flags, cb) {
|
|
1070
1070
|
if (typeof flags === "function") {
|
|
1071
1071
|
cb = flags;
|
|
@@ -1083,34 +1083,34 @@ var require_graceful_fs = __commonJS({
|
|
|
1083
1083
|
});
|
|
1084
1084
|
}
|
|
1085
1085
|
}
|
|
1086
|
-
var fs$readdir =
|
|
1087
|
-
|
|
1086
|
+
var fs$readdir = fs22.readdir;
|
|
1087
|
+
fs22.readdir = readdir;
|
|
1088
1088
|
var noReaddirOptionVersions = /^v[0-5]\./;
|
|
1089
|
-
function readdir(
|
|
1089
|
+
function readdir(path28, options, cb) {
|
|
1090
1090
|
if (typeof options === "function")
|
|
1091
1091
|
cb = options, options = null;
|
|
1092
|
-
var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(
|
|
1093
|
-
return fs$readdir(
|
|
1094
|
-
|
|
1092
|
+
var go$readdir = noReaddirOptionVersions.test(process.version) ? function go$readdir2(path29, options2, cb2, startTime) {
|
|
1093
|
+
return fs$readdir(path29, fs$readdirCallback(
|
|
1094
|
+
path29,
|
|
1095
1095
|
options2,
|
|
1096
1096
|
cb2,
|
|
1097
1097
|
startTime
|
|
1098
1098
|
));
|
|
1099
|
-
} : function go$readdir2(
|
|
1100
|
-
return fs$readdir(
|
|
1101
|
-
|
|
1099
|
+
} : function go$readdir2(path29, options2, cb2, startTime) {
|
|
1100
|
+
return fs$readdir(path29, options2, fs$readdirCallback(
|
|
1101
|
+
path29,
|
|
1102
1102
|
options2,
|
|
1103
1103
|
cb2,
|
|
1104
1104
|
startTime
|
|
1105
1105
|
));
|
|
1106
1106
|
};
|
|
1107
|
-
return go$readdir(
|
|
1108
|
-
function fs$readdirCallback(
|
|
1107
|
+
return go$readdir(path28, options, cb);
|
|
1108
|
+
function fs$readdirCallback(path29, options2, cb2, startTime) {
|
|
1109
1109
|
return function(err, files) {
|
|
1110
1110
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
1111
1111
|
enqueue([
|
|
1112
1112
|
go$readdir,
|
|
1113
|
-
[
|
|
1113
|
+
[path29, options2, cb2],
|
|
1114
1114
|
err,
|
|
1115
1115
|
startTime || Date.now(),
|
|
1116
1116
|
Date.now()
|
|
@@ -1125,21 +1125,21 @@ var require_graceful_fs = __commonJS({
|
|
|
1125
1125
|
}
|
|
1126
1126
|
}
|
|
1127
1127
|
if (process.version.substr(0, 4) === "v0.8") {
|
|
1128
|
-
var legStreams = legacy(
|
|
1128
|
+
var legStreams = legacy(fs22);
|
|
1129
1129
|
ReadStream = legStreams.ReadStream;
|
|
1130
1130
|
WriteStream = legStreams.WriteStream;
|
|
1131
1131
|
}
|
|
1132
|
-
var fs$ReadStream =
|
|
1132
|
+
var fs$ReadStream = fs22.ReadStream;
|
|
1133
1133
|
if (fs$ReadStream) {
|
|
1134
1134
|
ReadStream.prototype = Object.create(fs$ReadStream.prototype);
|
|
1135
1135
|
ReadStream.prototype.open = ReadStream$open;
|
|
1136
1136
|
}
|
|
1137
|
-
var fs$WriteStream =
|
|
1137
|
+
var fs$WriteStream = fs22.WriteStream;
|
|
1138
1138
|
if (fs$WriteStream) {
|
|
1139
1139
|
WriteStream.prototype = Object.create(fs$WriteStream.prototype);
|
|
1140
1140
|
WriteStream.prototype.open = WriteStream$open;
|
|
1141
1141
|
}
|
|
1142
|
-
Object.defineProperty(
|
|
1142
|
+
Object.defineProperty(fs22, "ReadStream", {
|
|
1143
1143
|
get: function() {
|
|
1144
1144
|
return ReadStream;
|
|
1145
1145
|
},
|
|
@@ -1149,7 +1149,7 @@ var require_graceful_fs = __commonJS({
|
|
|
1149
1149
|
enumerable: true,
|
|
1150
1150
|
configurable: true
|
|
1151
1151
|
});
|
|
1152
|
-
Object.defineProperty(
|
|
1152
|
+
Object.defineProperty(fs22, "WriteStream", {
|
|
1153
1153
|
get: function() {
|
|
1154
1154
|
return WriteStream;
|
|
1155
1155
|
},
|
|
@@ -1160,7 +1160,7 @@ var require_graceful_fs = __commonJS({
|
|
|
1160
1160
|
configurable: true
|
|
1161
1161
|
});
|
|
1162
1162
|
var FileReadStream = ReadStream;
|
|
1163
|
-
Object.defineProperty(
|
|
1163
|
+
Object.defineProperty(fs22, "FileReadStream", {
|
|
1164
1164
|
get: function() {
|
|
1165
1165
|
return FileReadStream;
|
|
1166
1166
|
},
|
|
@@ -1171,7 +1171,7 @@ var require_graceful_fs = __commonJS({
|
|
|
1171
1171
|
configurable: true
|
|
1172
1172
|
});
|
|
1173
1173
|
var FileWriteStream = WriteStream;
|
|
1174
|
-
Object.defineProperty(
|
|
1174
|
+
Object.defineProperty(fs22, "FileWriteStream", {
|
|
1175
1175
|
get: function() {
|
|
1176
1176
|
return FileWriteStream;
|
|
1177
1177
|
},
|
|
@@ -1181,7 +1181,7 @@ var require_graceful_fs = __commonJS({
|
|
|
1181
1181
|
enumerable: true,
|
|
1182
1182
|
configurable: true
|
|
1183
1183
|
});
|
|
1184
|
-
function ReadStream(
|
|
1184
|
+
function ReadStream(path28, options) {
|
|
1185
1185
|
if (this instanceof ReadStream)
|
|
1186
1186
|
return fs$ReadStream.apply(this, arguments), this;
|
|
1187
1187
|
else
|
|
@@ -1201,7 +1201,7 @@ var require_graceful_fs = __commonJS({
|
|
|
1201
1201
|
}
|
|
1202
1202
|
});
|
|
1203
1203
|
}
|
|
1204
|
-
function WriteStream(
|
|
1204
|
+
function WriteStream(path28, options) {
|
|
1205
1205
|
if (this instanceof WriteStream)
|
|
1206
1206
|
return fs$WriteStream.apply(this, arguments), this;
|
|
1207
1207
|
else
|
|
@@ -1219,22 +1219,22 @@ var require_graceful_fs = __commonJS({
|
|
|
1219
1219
|
}
|
|
1220
1220
|
});
|
|
1221
1221
|
}
|
|
1222
|
-
function createReadStream(
|
|
1223
|
-
return new
|
|
1222
|
+
function createReadStream(path28, options) {
|
|
1223
|
+
return new fs22.ReadStream(path28, options);
|
|
1224
1224
|
}
|
|
1225
|
-
function createWriteStream(
|
|
1226
|
-
return new
|
|
1225
|
+
function createWriteStream(path28, options) {
|
|
1226
|
+
return new fs22.WriteStream(path28, options);
|
|
1227
1227
|
}
|
|
1228
|
-
var fs$open =
|
|
1229
|
-
|
|
1230
|
-
function open(
|
|
1228
|
+
var fs$open = fs22.open;
|
|
1229
|
+
fs22.open = open;
|
|
1230
|
+
function open(path28, flags, mode, cb) {
|
|
1231
1231
|
if (typeof mode === "function")
|
|
1232
1232
|
cb = mode, mode = null;
|
|
1233
|
-
return go$open(
|
|
1234
|
-
function go$open(
|
|
1235
|
-
return fs$open(
|
|
1233
|
+
return go$open(path28, flags, mode, cb);
|
|
1234
|
+
function go$open(path29, flags2, mode2, cb2, startTime) {
|
|
1235
|
+
return fs$open(path29, flags2, mode2, function(err, fd) {
|
|
1236
1236
|
if (err && (err.code === "EMFILE" || err.code === "ENFILE"))
|
|
1237
|
-
enqueue([go$open, [
|
|
1237
|
+
enqueue([go$open, [path29, flags2, mode2, cb2], err, startTime || Date.now(), Date.now()]);
|
|
1238
1238
|
else {
|
|
1239
1239
|
if (typeof cb2 === "function")
|
|
1240
1240
|
cb2.apply(this, arguments);
|
|
@@ -1242,20 +1242,20 @@ var require_graceful_fs = __commonJS({
|
|
|
1242
1242
|
});
|
|
1243
1243
|
}
|
|
1244
1244
|
}
|
|
1245
|
-
return
|
|
1245
|
+
return fs22;
|
|
1246
1246
|
}
|
|
1247
1247
|
function enqueue(elem) {
|
|
1248
1248
|
debug("ENQUEUE", elem[0].name, elem[1]);
|
|
1249
|
-
|
|
1249
|
+
fs21[gracefulQueue].push(elem);
|
|
1250
1250
|
retry();
|
|
1251
1251
|
}
|
|
1252
1252
|
var retryTimer;
|
|
1253
1253
|
function resetQueue() {
|
|
1254
1254
|
var now = Date.now();
|
|
1255
|
-
for (var i = 0; i <
|
|
1256
|
-
if (
|
|
1257
|
-
|
|
1258
|
-
|
|
1255
|
+
for (var i = 0; i < fs21[gracefulQueue].length; ++i) {
|
|
1256
|
+
if (fs21[gracefulQueue][i].length > 2) {
|
|
1257
|
+
fs21[gracefulQueue][i][3] = now;
|
|
1258
|
+
fs21[gracefulQueue][i][4] = now;
|
|
1259
1259
|
}
|
|
1260
1260
|
}
|
|
1261
1261
|
retry();
|
|
@@ -1263,9 +1263,9 @@ var require_graceful_fs = __commonJS({
|
|
|
1263
1263
|
function retry() {
|
|
1264
1264
|
clearTimeout(retryTimer);
|
|
1265
1265
|
retryTimer = void 0;
|
|
1266
|
-
if (
|
|
1266
|
+
if (fs21[gracefulQueue].length === 0)
|
|
1267
1267
|
return;
|
|
1268
|
-
var elem =
|
|
1268
|
+
var elem = fs21[gracefulQueue].shift();
|
|
1269
1269
|
var fn = elem[0];
|
|
1270
1270
|
var args = elem[1];
|
|
1271
1271
|
var err = elem[2];
|
|
@@ -1287,7 +1287,7 @@ var require_graceful_fs = __commonJS({
|
|
|
1287
1287
|
debug("RETRY", fn.name, args);
|
|
1288
1288
|
fn.apply(null, args.concat([startTime]));
|
|
1289
1289
|
} else {
|
|
1290
|
-
|
|
1290
|
+
fs21[gracefulQueue].push(elem);
|
|
1291
1291
|
}
|
|
1292
1292
|
}
|
|
1293
1293
|
if (retryTimer === void 0) {
|
|
@@ -1722,10 +1722,10 @@ var require_mtime_precision = __commonJS({
|
|
|
1722
1722
|
"../../node_modules/proper-lockfile/lib/mtime-precision.js"(exports, module) {
|
|
1723
1723
|
"use strict";
|
|
1724
1724
|
var cacheSymbol = /* @__PURE__ */ Symbol();
|
|
1725
|
-
function probe(file,
|
|
1726
|
-
const cachedPrecision =
|
|
1725
|
+
function probe(file, fs21, callback) {
|
|
1726
|
+
const cachedPrecision = fs21[cacheSymbol];
|
|
1727
1727
|
if (cachedPrecision) {
|
|
1728
|
-
return
|
|
1728
|
+
return fs21.stat(file, (err, stat) => {
|
|
1729
1729
|
if (err) {
|
|
1730
1730
|
return callback(err);
|
|
1731
1731
|
}
|
|
@@ -1733,16 +1733,16 @@ var require_mtime_precision = __commonJS({
|
|
|
1733
1733
|
});
|
|
1734
1734
|
}
|
|
1735
1735
|
const mtime = new Date(Math.ceil(Date.now() / 1e3) * 1e3 + 5);
|
|
1736
|
-
|
|
1736
|
+
fs21.utimes(file, mtime, mtime, (err) => {
|
|
1737
1737
|
if (err) {
|
|
1738
1738
|
return callback(err);
|
|
1739
1739
|
}
|
|
1740
|
-
|
|
1740
|
+
fs21.stat(file, (err2, stat) => {
|
|
1741
1741
|
if (err2) {
|
|
1742
1742
|
return callback(err2);
|
|
1743
1743
|
}
|
|
1744
1744
|
const precision = stat.mtime.getTime() % 1e3 === 0 ? "s" : "ms";
|
|
1745
|
-
Object.defineProperty(
|
|
1745
|
+
Object.defineProperty(fs21, cacheSymbol, { value: precision });
|
|
1746
1746
|
callback(null, stat.mtime, precision);
|
|
1747
1747
|
});
|
|
1748
1748
|
});
|
|
@@ -1763,8 +1763,8 @@ var require_mtime_precision = __commonJS({
|
|
|
1763
1763
|
var require_lockfile = __commonJS({
|
|
1764
1764
|
"../../node_modules/proper-lockfile/lib/lockfile.js"(exports, module) {
|
|
1765
1765
|
"use strict";
|
|
1766
|
-
var
|
|
1767
|
-
var
|
|
1766
|
+
var path28 = __require("path");
|
|
1767
|
+
var fs21 = require_graceful_fs();
|
|
1768
1768
|
var retry = require_retry2();
|
|
1769
1769
|
var onExit = require_signal_exit();
|
|
1770
1770
|
var mtimePrecision = require_mtime_precision();
|
|
@@ -1774,7 +1774,7 @@ var require_lockfile = __commonJS({
|
|
|
1774
1774
|
}
|
|
1775
1775
|
function resolveCanonicalPath(file, options, callback) {
|
|
1776
1776
|
if (!options.realpath) {
|
|
1777
|
-
return callback(null,
|
|
1777
|
+
return callback(null, path28.resolve(file));
|
|
1778
1778
|
}
|
|
1779
1779
|
options.fs.realpath(file, callback);
|
|
1780
1780
|
}
|
|
@@ -1895,7 +1895,7 @@ var require_lockfile = __commonJS({
|
|
|
1895
1895
|
update: null,
|
|
1896
1896
|
realpath: true,
|
|
1897
1897
|
retries: 0,
|
|
1898
|
-
fs:
|
|
1898
|
+
fs: fs21,
|
|
1899
1899
|
onCompromised: (err) => {
|
|
1900
1900
|
throw err;
|
|
1901
1901
|
},
|
|
@@ -1939,7 +1939,7 @@ var require_lockfile = __commonJS({
|
|
|
1939
1939
|
}
|
|
1940
1940
|
function unlock(file, options, callback) {
|
|
1941
1941
|
options = {
|
|
1942
|
-
fs:
|
|
1942
|
+
fs: fs21,
|
|
1943
1943
|
realpath: true,
|
|
1944
1944
|
...options
|
|
1945
1945
|
};
|
|
@@ -1961,7 +1961,7 @@ var require_lockfile = __commonJS({
|
|
|
1961
1961
|
options = {
|
|
1962
1962
|
stale: 1e4,
|
|
1963
1963
|
realpath: true,
|
|
1964
|
-
fs:
|
|
1964
|
+
fs: fs21,
|
|
1965
1965
|
...options
|
|
1966
1966
|
};
|
|
1967
1967
|
options.stale = Math.max(options.stale || 0, 2e3);
|
|
@@ -2000,16 +2000,16 @@ var require_lockfile = __commonJS({
|
|
|
2000
2000
|
var require_adapter = __commonJS({
|
|
2001
2001
|
"../../node_modules/proper-lockfile/lib/adapter.js"(exports, module) {
|
|
2002
2002
|
"use strict";
|
|
2003
|
-
var
|
|
2004
|
-
function createSyncFs(
|
|
2003
|
+
var fs21 = require_graceful_fs();
|
|
2004
|
+
function createSyncFs(fs22) {
|
|
2005
2005
|
const methods = ["mkdir", "realpath", "stat", "rmdir", "utimes"];
|
|
2006
|
-
const newFs = { ...
|
|
2006
|
+
const newFs = { ...fs22 };
|
|
2007
2007
|
methods.forEach((method) => {
|
|
2008
2008
|
newFs[method] = (...args) => {
|
|
2009
2009
|
const callback = args.pop();
|
|
2010
2010
|
let ret;
|
|
2011
2011
|
try {
|
|
2012
|
-
ret =
|
|
2012
|
+
ret = fs22[`${method}Sync`](...args);
|
|
2013
2013
|
} catch (err) {
|
|
2014
2014
|
return callback(err);
|
|
2015
2015
|
}
|
|
@@ -2047,7 +2047,7 @@ var require_adapter = __commonJS({
|
|
|
2047
2047
|
}
|
|
2048
2048
|
function toSyncOptions(options) {
|
|
2049
2049
|
options = { ...options };
|
|
2050
|
-
options.fs = createSyncFs(options.fs ||
|
|
2050
|
+
options.fs = createSyncFs(options.fs || fs21);
|
|
2051
2051
|
if (typeof options.retries === "number" && options.retries > 0 || options.retries && typeof options.retries.retries === "number" && options.retries.retries > 0) {
|
|
2052
2052
|
throw Object.assign(new Error("Cannot use retries with the sync api"), { code: "ESYNC" });
|
|
2053
2053
|
}
|
|
@@ -2107,7 +2107,8 @@ function resolveBackendConfig(manifest, environment) {
|
|
|
2107
2107
|
aws_kms_arn: manifest.sops.aws_kms_arn,
|
|
2108
2108
|
gcp_kms_resource_id: manifest.sops.gcp_kms_resource_id,
|
|
2109
2109
|
azure_kv_url: manifest.sops.azure_kv_url,
|
|
2110
|
-
pgp_fingerprint: manifest.sops.pgp_fingerprint
|
|
2110
|
+
pgp_fingerprint: manifest.sops.pgp_fingerprint,
|
|
2111
|
+
pkcs11_uri: manifest.sops.pkcs11_uri
|
|
2111
2112
|
};
|
|
2112
2113
|
}
|
|
2113
2114
|
function resolveRecipientsForEnvironment(manifest, environment) {
|
|
@@ -2254,7 +2255,8 @@ function keyPreview(key) {
|
|
|
2254
2255
|
|
|
2255
2256
|
// src/manifest/parser.ts
|
|
2256
2257
|
var CLEF_MANIFEST_FILENAME = "clef.yaml";
|
|
2257
|
-
var VALID_BACKENDS = ["age", "awskms", "gcpkms", "azurekv", "pgp"];
|
|
2258
|
+
var VALID_BACKENDS = ["age", "awskms", "gcpkms", "azurekv", "pgp", "hsm"];
|
|
2259
|
+
var PKCS11_URI_PATTERN = /^pkcs11:[a-zA-Z][a-zA-Z0-9_-]*=[^;]+/;
|
|
2258
2260
|
var VALID_TOP_LEVEL_KEYS = [
|
|
2259
2261
|
"version",
|
|
2260
2262
|
"environments",
|
|
@@ -2413,12 +2415,27 @@ var ManifestParser = class {
|
|
|
2413
2415
|
"environments"
|
|
2414
2416
|
);
|
|
2415
2417
|
}
|
|
2418
|
+
if (backend === "hsm") {
|
|
2419
|
+
if (typeof sopsOverride.pkcs11_uri !== "string") {
|
|
2420
|
+
throw new ManifestValidationError(
|
|
2421
|
+
`Environment '${envObj.name}' uses 'hsm' backend but is missing 'pkcs11_uri'.`,
|
|
2422
|
+
"environments"
|
|
2423
|
+
);
|
|
2424
|
+
}
|
|
2425
|
+
if (!PKCS11_URI_PATTERN.test(sopsOverride.pkcs11_uri)) {
|
|
2426
|
+
throw new ManifestValidationError(
|
|
2427
|
+
`Environment '${envObj.name}' has an invalid 'pkcs11_uri' '${sopsOverride.pkcs11_uri}'. Must start with 'pkcs11:' and contain at least one attribute (e.g. 'pkcs11:slot=0;label=clef-dek-wrapper').`,
|
|
2428
|
+
"environments"
|
|
2429
|
+
);
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2416
2432
|
result.sops = {
|
|
2417
2433
|
backend,
|
|
2418
2434
|
...typeof sopsOverride.aws_kms_arn === "string" ? { aws_kms_arn: sopsOverride.aws_kms_arn } : {},
|
|
2419
2435
|
...typeof sopsOverride.gcp_kms_resource_id === "string" ? { gcp_kms_resource_id: sopsOverride.gcp_kms_resource_id } : {},
|
|
2420
2436
|
...typeof sopsOverride.azure_kv_url === "string" ? { azure_kv_url: sopsOverride.azure_kv_url } : {},
|
|
2421
|
-
...typeof sopsOverride.pgp_fingerprint === "string" ? { pgp_fingerprint: sopsOverride.pgp_fingerprint } : {}
|
|
2437
|
+
...typeof sopsOverride.pgp_fingerprint === "string" ? { pgp_fingerprint: sopsOverride.pgp_fingerprint } : {},
|
|
2438
|
+
...typeof sopsOverride.pkcs11_uri === "string" ? { pkcs11_uri: sopsOverride.pkcs11_uri } : {}
|
|
2422
2439
|
};
|
|
2423
2440
|
}
|
|
2424
2441
|
if (envObj.recipients !== void 0) {
|
|
@@ -2550,7 +2567,7 @@ var ManifestParser = class {
|
|
|
2550
2567
|
const sopsObj = obj.sops;
|
|
2551
2568
|
if (!sopsObj.default_backend || typeof sopsObj.default_backend !== "string") {
|
|
2552
2569
|
throw new ManifestValidationError(
|
|
2553
|
-
|
|
2570
|
+
`Field 'sops.default_backend' is required and must be one of: ${VALID_BACKENDS.join(", ")}.`,
|
|
2554
2571
|
"sops.default_backend"
|
|
2555
2572
|
);
|
|
2556
2573
|
}
|
|
@@ -2577,13 +2594,32 @@ var ManifestParser = class {
|
|
|
2577
2594
|
})
|
|
2578
2595
|
}
|
|
2579
2596
|
} : {};
|
|
2597
|
+
if (sopsObj.pkcs11_uri !== void 0 && typeof sopsObj.pkcs11_uri !== "string") {
|
|
2598
|
+
throw new ManifestValidationError(
|
|
2599
|
+
"Field 'sops.pkcs11_uri' must be a string.",
|
|
2600
|
+
"sops.pkcs11_uri"
|
|
2601
|
+
);
|
|
2602
|
+
}
|
|
2603
|
+
if (typeof sopsObj.pkcs11_uri === "string" && !PKCS11_URI_PATTERN.test(sopsObj.pkcs11_uri)) {
|
|
2604
|
+
throw new ManifestValidationError(
|
|
2605
|
+
`Field 'sops.pkcs11_uri' has invalid format '${sopsObj.pkcs11_uri}'. Must start with 'pkcs11:' and contain at least one attribute (e.g. 'pkcs11:slot=0;label=clef-dek-wrapper').`,
|
|
2606
|
+
"sops.pkcs11_uri"
|
|
2607
|
+
);
|
|
2608
|
+
}
|
|
2609
|
+
if (sopsObj.default_backend === "hsm" && typeof sopsObj.pkcs11_uri !== "string") {
|
|
2610
|
+
throw new ManifestValidationError(
|
|
2611
|
+
"Field 'sops.pkcs11_uri' is required when sops.default_backend is 'hsm'.",
|
|
2612
|
+
"sops.pkcs11_uri"
|
|
2613
|
+
);
|
|
2614
|
+
}
|
|
2580
2615
|
const sopsConfig = {
|
|
2581
2616
|
default_backend: sopsObj.default_backend,
|
|
2582
2617
|
...parsedAge,
|
|
2583
2618
|
...typeof sopsObj.aws_kms_arn === "string" ? { aws_kms_arn: sopsObj.aws_kms_arn } : {},
|
|
2584
2619
|
...typeof sopsObj.gcp_kms_resource_id === "string" ? { gcp_kms_resource_id: sopsObj.gcp_kms_resource_id } : {},
|
|
2585
2620
|
...typeof sopsObj.azure_kv_url === "string" ? { azure_kv_url: sopsObj.azure_kv_url } : {},
|
|
2586
|
-
...typeof sopsObj.pgp_fingerprint === "string" ? { pgp_fingerprint: sopsObj.pgp_fingerprint } : {}
|
|
2621
|
+
...typeof sopsObj.pgp_fingerprint === "string" ? { pgp_fingerprint: sopsObj.pgp_fingerprint } : {},
|
|
2622
|
+
...typeof sopsObj.pkcs11_uri === "string" ? { pkcs11_uri: sopsObj.pkcs11_uri } : {}
|
|
2587
2623
|
};
|
|
2588
2624
|
for (const env of environments) {
|
|
2589
2625
|
if (env.recipients && env.recipients.length > 0) {
|
|
@@ -2842,6 +2878,20 @@ var PATTERNS = [
|
|
|
2842
2878
|
},
|
|
2843
2879
|
{ name: "Database URL", regex: /(?:postgres|mysql|mongodb|redis):\/\/[^:]+:[^@]+@/ }
|
|
2844
2880
|
];
|
|
2881
|
+
var PUBLIC_PREFIX_PATTERNS = [
|
|
2882
|
+
// reCAPTCHA v2, v3, and Enterprise site keys are exactly 40 chars and
|
|
2883
|
+
// begin with 6L[c-f]. Site keys are designed to be embedded in HTML.
|
|
2884
|
+
// https://developers.google.com/recaptcha/docs/faq
|
|
2885
|
+
{ name: "reCAPTCHA site key", regex: /^6L[c-f][0-9A-Za-z_-]{37}$/ },
|
|
2886
|
+
// Stripe publishable keys (client-side, distinct from sk_live_/sk_test_).
|
|
2887
|
+
{ name: "Stripe publishable key", regex: /^pk_(?:live|test)_[0-9a-zA-Z]{24,}$/ }
|
|
2888
|
+
];
|
|
2889
|
+
function matchPublicPrefix(value) {
|
|
2890
|
+
for (const def of PUBLIC_PREFIX_PATTERNS) {
|
|
2891
|
+
if (def.regex.test(value)) return { name: def.name };
|
|
2892
|
+
}
|
|
2893
|
+
return null;
|
|
2894
|
+
}
|
|
2845
2895
|
function shannonEntropy(str) {
|
|
2846
2896
|
if (str.length === 0) return 0;
|
|
2847
2897
|
const freq = /* @__PURE__ */ new Map();
|
|
@@ -3030,7 +3080,8 @@ var ScanRunner = class {
|
|
|
3030
3080
|
}
|
|
3031
3081
|
}
|
|
3032
3082
|
if (options.severity !== "high") {
|
|
3033
|
-
const
|
|
3083
|
+
const allowPublic = options.publicAllowlist !== false;
|
|
3084
|
+
const entropyHit = this.detectEntropy(line, lineNum, relPath, allowPublic);
|
|
3034
3085
|
if (entropyHit && !shouldIgnoreMatch(entropyHit, ignoreRules)) {
|
|
3035
3086
|
matches.push(entropyHit);
|
|
3036
3087
|
}
|
|
@@ -3071,13 +3122,14 @@ var ScanRunner = class {
|
|
|
3071
3122
|
return false;
|
|
3072
3123
|
}
|
|
3073
3124
|
}
|
|
3074
|
-
detectEntropy(line, lineNum, filePath) {
|
|
3125
|
+
detectEntropy(line, lineNum, filePath, allowPublic) {
|
|
3075
3126
|
const valuePattern = /(?:=|:\s*)["']?([A-Za-z0-9+/=_-]{20,})["']?/;
|
|
3076
3127
|
const match = valuePattern.exec(line);
|
|
3077
3128
|
if (!match) return null;
|
|
3078
3129
|
const value = match[1];
|
|
3079
3130
|
const entropy = shannonEntropy(value);
|
|
3080
3131
|
if (!isHighEntropy(value)) return null;
|
|
3132
|
+
if (allowPublic && matchPublicPrefix(value)) return null;
|
|
3081
3133
|
const varMatch = /(\w+)\s*(?:=|:)/.exec(line);
|
|
3082
3134
|
const varName = varMatch ? varMatch[1] : "";
|
|
3083
3135
|
const preview = varName ? `${varName}=\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022` : redactValue(value);
|
|
@@ -3159,41 +3211,50 @@ function metadataPath(encryptedFilePath) {
|
|
|
3159
3211
|
return path4.join(dir, `${base}.clef-meta.yaml`);
|
|
3160
3212
|
}
|
|
3161
3213
|
var HEADER_COMMENT = "# Managed by Clef. Do not edit manually.\n";
|
|
3214
|
+
function emptyMetadata() {
|
|
3215
|
+
return { version: 1, pending: [], rotations: [] };
|
|
3216
|
+
}
|
|
3162
3217
|
async function loadMetadata(filePath) {
|
|
3163
3218
|
const metaPath = metadataPath(filePath);
|
|
3164
3219
|
try {
|
|
3165
|
-
if (!fs5.existsSync(metaPath))
|
|
3166
|
-
return { version: 1, pending: [] };
|
|
3167
|
-
}
|
|
3220
|
+
if (!fs5.existsSync(metaPath)) return emptyMetadata();
|
|
3168
3221
|
const content = fs5.readFileSync(metaPath, "utf-8");
|
|
3169
3222
|
const parsed = YAML3.parse(content);
|
|
3170
|
-
if (!parsed ||
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3223
|
+
if (!parsed || typeof parsed !== "object") return emptyMetadata();
|
|
3224
|
+
const pendingRaw = Array.isArray(parsed.pending) ? parsed.pending : [];
|
|
3225
|
+
const pending = pendingRaw.filter(
|
|
3226
|
+
(p) => !!p && typeof p === "object" && typeof p.key === "string" && typeof p.since === "string" && typeof p.setBy === "string"
|
|
3227
|
+
).map((p) => ({ key: p.key, since: new Date(p.since), setBy: p.setBy }));
|
|
3228
|
+
const rotationsRaw = Array.isArray(parsed.rotations) ? parsed.rotations : [];
|
|
3229
|
+
const rotations = rotationsRaw.filter(
|
|
3230
|
+
(r) => !!r && typeof r === "object" && typeof r.key === "string" && typeof r.last_rotated_at === "string" && typeof r.rotated_by === "string" && typeof r.rotation_count === "number"
|
|
3231
|
+
).map((r) => ({
|
|
3232
|
+
key: r.key,
|
|
3233
|
+
lastRotatedAt: new Date(r.last_rotated_at),
|
|
3234
|
+
rotatedBy: r.rotated_by,
|
|
3235
|
+
rotationCount: r.rotation_count
|
|
3236
|
+
}));
|
|
3237
|
+
return { version: 1, pending, rotations };
|
|
3181
3238
|
} catch {
|
|
3182
|
-
return
|
|
3239
|
+
return emptyMetadata();
|
|
3183
3240
|
}
|
|
3184
3241
|
}
|
|
3185
3242
|
async function saveMetadata(filePath, metadata) {
|
|
3186
3243
|
const metaPath = metadataPath(filePath);
|
|
3187
3244
|
const dir = path4.dirname(metaPath);
|
|
3188
|
-
if (!fs5.existsSync(dir)) {
|
|
3189
|
-
fs5.mkdirSync(dir, { recursive: true });
|
|
3190
|
-
}
|
|
3245
|
+
if (!fs5.existsSync(dir)) fs5.mkdirSync(dir, { recursive: true });
|
|
3191
3246
|
const data = {
|
|
3192
3247
|
version: metadata.version,
|
|
3193
3248
|
pending: metadata.pending.map((p) => ({
|
|
3194
3249
|
key: p.key,
|
|
3195
3250
|
since: p.since.toISOString(),
|
|
3196
3251
|
setBy: p.setBy
|
|
3252
|
+
})),
|
|
3253
|
+
rotations: metadata.rotations.map((r) => ({
|
|
3254
|
+
key: r.key,
|
|
3255
|
+
last_rotated_at: r.lastRotatedAt.toISOString(),
|
|
3256
|
+
rotated_by: r.rotatedBy,
|
|
3257
|
+
rotation_count: r.rotationCount
|
|
3197
3258
|
}))
|
|
3198
3259
|
};
|
|
3199
3260
|
fs5.writeFileSync(metaPath, HEADER_COMMENT + YAML3.stringify(data), "utf-8");
|
|
@@ -3224,6 +3285,38 @@ async function isPending(filePath, key) {
|
|
|
3224
3285
|
const metadata = await loadMetadata(filePath);
|
|
3225
3286
|
return metadata.pending.some((p) => p.key === key);
|
|
3226
3287
|
}
|
|
3288
|
+
async function recordRotation(filePath, keys, rotatedBy, now = /* @__PURE__ */ new Date()) {
|
|
3289
|
+
const metadata = await loadMetadata(filePath);
|
|
3290
|
+
for (const key of keys) {
|
|
3291
|
+
const existing = metadata.rotations.findIndex((r) => r.key === key);
|
|
3292
|
+
if (existing >= 0) {
|
|
3293
|
+
metadata.rotations[existing] = {
|
|
3294
|
+
key,
|
|
3295
|
+
lastRotatedAt: now,
|
|
3296
|
+
rotatedBy,
|
|
3297
|
+
rotationCount: metadata.rotations[existing].rotationCount + 1
|
|
3298
|
+
};
|
|
3299
|
+
} else {
|
|
3300
|
+
metadata.rotations.push({
|
|
3301
|
+
key,
|
|
3302
|
+
lastRotatedAt: now,
|
|
3303
|
+
rotatedBy,
|
|
3304
|
+
rotationCount: 1
|
|
3305
|
+
});
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
metadata.pending = metadata.pending.filter((p) => !keys.includes(p.key));
|
|
3309
|
+
await saveMetadata(filePath, metadata);
|
|
3310
|
+
}
|
|
3311
|
+
async function removeRotation(filePath, keys) {
|
|
3312
|
+
const metadata = await loadMetadata(filePath);
|
|
3313
|
+
metadata.rotations = metadata.rotations.filter((r) => !keys.includes(r.key));
|
|
3314
|
+
await saveMetadata(filePath, metadata);
|
|
3315
|
+
}
|
|
3316
|
+
async function getRotations(filePath) {
|
|
3317
|
+
const metadata = await loadMetadata(filePath);
|
|
3318
|
+
return metadata.rotations;
|
|
3319
|
+
}
|
|
3227
3320
|
function generateRandomValue() {
|
|
3228
3321
|
return crypto.randomBytes(32).toString("hex");
|
|
3229
3322
|
}
|
|
@@ -4025,61 +4118,83 @@ var GitIntegration = class {
|
|
|
4025
4118
|
* @throws {@link GitOperationError} On failure.
|
|
4026
4119
|
*/
|
|
4027
4120
|
async installMergeDriver(repoRoot) {
|
|
4028
|
-
const
|
|
4029
|
-
"
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
)
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4121
|
+
const drivers = [
|
|
4122
|
+
{ config: "merge.sops", friendly: "SOPS-aware merge driver" },
|
|
4123
|
+
{ config: "merge.clef-metadata", friendly: "Clef metadata merge driver" }
|
|
4124
|
+
];
|
|
4125
|
+
for (const driver of drivers) {
|
|
4126
|
+
const nameResult = await this.runner.run(
|
|
4127
|
+
"git",
|
|
4128
|
+
["config", `${driver.config}.name`, driver.friendly],
|
|
4129
|
+
{ cwd: repoRoot }
|
|
4037
4130
|
);
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
4131
|
+
if (nameResult.exitCode !== 0) {
|
|
4132
|
+
throw new GitOperationError(
|
|
4133
|
+
`Failed to configure merge driver name: ${nameResult.stderr.trim()}`,
|
|
4134
|
+
"Ensure you are inside a git repository."
|
|
4135
|
+
);
|
|
4136
|
+
}
|
|
4137
|
+
const driverResult = await this.runner.run(
|
|
4138
|
+
"git",
|
|
4139
|
+
["config", `${driver.config}.driver`, "clef merge-driver %O %A %B"],
|
|
4140
|
+
{ cwd: repoRoot }
|
|
4048
4141
|
);
|
|
4142
|
+
if (driverResult.exitCode !== 0) {
|
|
4143
|
+
throw new GitOperationError(
|
|
4144
|
+
`Failed to configure merge driver command: ${driverResult.stderr.trim()}`,
|
|
4145
|
+
"Ensure you are inside a git repository."
|
|
4146
|
+
);
|
|
4147
|
+
}
|
|
4049
4148
|
}
|
|
4050
4149
|
await this.ensureGitattributes(repoRoot);
|
|
4051
4150
|
}
|
|
4052
4151
|
/**
|
|
4053
|
-
* Check whether
|
|
4054
|
-
*
|
|
4055
|
-
*
|
|
4056
|
-
*
|
|
4057
|
-
*
|
|
4152
|
+
* Check whether both Clef merge drivers are configured in `.git/config`
|
|
4153
|
+
* and `.gitattributes`. Reports separately on the SOPS driver
|
|
4154
|
+
* (`merge=sops` for `.enc.*`) and the metadata driver
|
|
4155
|
+
* (`merge=clef-metadata` for `.clef-meta.yaml`) so `clef doctor` can
|
|
4156
|
+
* prompt the user to run `clef hooks` when only the SOPS driver is
|
|
4157
|
+
* installed (older install, pre-metadata-merge).
|
|
4058
4158
|
*/
|
|
4059
4159
|
async checkMergeDriver(repoRoot) {
|
|
4060
|
-
const
|
|
4160
|
+
const sopsConfig = await this.runner.run("git", ["config", "--get", "merge.sops.driver"], {
|
|
4061
4161
|
cwd: repoRoot
|
|
4062
4162
|
});
|
|
4063
|
-
const gitConfig =
|
|
4163
|
+
const gitConfig = sopsConfig.exitCode === 0 && sopsConfig.stdout.trim().length > 0;
|
|
4164
|
+
const metaConfig = await this.runner.run(
|
|
4165
|
+
"git",
|
|
4166
|
+
["config", "--get", "merge.clef-metadata.driver"],
|
|
4167
|
+
{ cwd: repoRoot }
|
|
4168
|
+
);
|
|
4169
|
+
const metadataGitConfig = metaConfig.exitCode === 0 && metaConfig.stdout.trim().length > 0;
|
|
4064
4170
|
const attrFilePath = path8.join(repoRoot, ".gitattributes");
|
|
4065
4171
|
const attrContent = fs9.existsSync(attrFilePath) ? fs9.readFileSync(attrFilePath, "utf-8") : "";
|
|
4066
4172
|
const gitattributes = attrContent.includes("merge=sops");
|
|
4067
|
-
|
|
4173
|
+
const metadataGitattributes = attrContent.includes("merge=clef-metadata");
|
|
4174
|
+
return { gitConfig, gitattributes, metadataGitConfig, metadataGitattributes };
|
|
4068
4175
|
}
|
|
4069
4176
|
async ensureGitattributes(repoRoot) {
|
|
4070
4177
|
const attrPath = path8.join(repoRoot, ".gitattributes");
|
|
4071
|
-
const mergeRule = "*.enc.yaml merge=sops\n*.enc.json merge=sops";
|
|
4072
4178
|
const existing = fs9.existsSync(attrPath) ? fs9.readFileSync(attrPath, "utf-8") : "";
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4179
|
+
let newContent = existing;
|
|
4180
|
+
if (!existing.includes("merge=sops")) {
|
|
4181
|
+
const block = `# Clef: SOPS-aware merge driver for encrypted files
|
|
4182
|
+
*.enc.yaml merge=sops
|
|
4183
|
+
*.enc.json merge=sops
|
|
4184
|
+
`;
|
|
4185
|
+
newContent = newContent.trimEnd() ? `${newContent.trimEnd()}
|
|
4077
4186
|
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4081
|
-
|
|
4187
|
+
${block}` : block;
|
|
4188
|
+
}
|
|
4189
|
+
if (!newContent.includes("merge=clef-metadata")) {
|
|
4190
|
+
const block = `# Clef: rotation-aware merge driver for metadata sidecars
|
|
4191
|
+
*.clef-meta.yaml merge=clef-metadata
|
|
4082
4192
|
`;
|
|
4193
|
+
newContent = newContent.trimEnd() ? `${newContent.trimEnd()}
|
|
4194
|
+
|
|
4195
|
+
${block}` : block;
|
|
4196
|
+
}
|
|
4197
|
+
if (newContent === existing) return;
|
|
4083
4198
|
try {
|
|
4084
4199
|
fs9.writeFileSync(attrPath, newContent, "utf-8");
|
|
4085
4200
|
} catch (err) {
|
|
@@ -4469,6 +4584,39 @@ ${privateKey}
|
|
|
4469
4584
|
`;
|
|
4470
4585
|
}
|
|
4471
4586
|
|
|
4587
|
+
// src/sops/hsm-arn.ts
|
|
4588
|
+
var CLEF_HSM_ARN_RE = /^arn:aws[\w-]*:kms:[^:]+:\d+:alias\/clef-hsm\/(v\d+)\/([A-Za-z0-9_-]+)$/;
|
|
4589
|
+
var ARN_PREFIX = "arn:aws:kms:us-east-1:000000000000:alias/clef-hsm/v1/";
|
|
4590
|
+
var SUPPORTED_VERSION = "v1";
|
|
4591
|
+
function pkcs11UriToSyntheticArn(uri) {
|
|
4592
|
+
if (!uri.startsWith("pkcs11:")) {
|
|
4593
|
+
throw new Error(`Expected a pkcs11 URI starting with 'pkcs11:', got '${uri}'.`);
|
|
4594
|
+
}
|
|
4595
|
+
const payload = Buffer.from(uri, "utf8").toString("base64url");
|
|
4596
|
+
const arn = ARN_PREFIX + payload;
|
|
4597
|
+
if (!CLEF_HSM_ARN_RE.test(arn)) {
|
|
4598
|
+
throw new Error(`Synthesized ARN failed self-validation: '${arn}'.`);
|
|
4599
|
+
}
|
|
4600
|
+
return arn;
|
|
4601
|
+
}
|
|
4602
|
+
function syntheticArnToPkcs11Uri(arn) {
|
|
4603
|
+
const match = CLEF_HSM_ARN_RE.exec(arn);
|
|
4604
|
+
if (!match) return null;
|
|
4605
|
+
const [, version, payload] = match;
|
|
4606
|
+
if (version !== SUPPORTED_VERSION) return null;
|
|
4607
|
+
let decoded;
|
|
4608
|
+
try {
|
|
4609
|
+
decoded = Buffer.from(payload, "base64url").toString("utf8");
|
|
4610
|
+
} catch {
|
|
4611
|
+
return null;
|
|
4612
|
+
}
|
|
4613
|
+
if (!decoded.startsWith("pkcs11:")) return null;
|
|
4614
|
+
return decoded;
|
|
4615
|
+
}
|
|
4616
|
+
function isClefHsmArn(arn) {
|
|
4617
|
+
return CLEF_HSM_ARN_RE.test(arn);
|
|
4618
|
+
}
|
|
4619
|
+
|
|
4472
4620
|
// src/sops/client.ts
|
|
4473
4621
|
function formatFromPath(filePath) {
|
|
4474
4622
|
return filePath.endsWith(".json") ? "json" : "yaml";
|
|
@@ -4500,14 +4648,25 @@ var SopsClient = class {
|
|
|
4500
4648
|
* to the subprocess environment.
|
|
4501
4649
|
* @param sopsPath - Optional explicit path to the sops binary. When omitted,
|
|
4502
4650
|
* resolved automatically via {@link resolveSopsPath}.
|
|
4651
|
+
* @param keyserviceAddr - Optional address of an external SOPS KeyService
|
|
4652
|
+
* sidecar (e.g. `tcp://127.0.0.1:12345`). When set, every SOPS invocation
|
|
4653
|
+
* includes `--enable-local-keyservice=false --keyservice <addr>` so KMS
|
|
4654
|
+
* wrap/unwrap is routed to the sidecar (used for the HSM backend, where
|
|
4655
|
+
* the sidecar is `clef-keyservice` talking PKCS#11 to the HSM).
|
|
4656
|
+
*
|
|
4657
|
+
* The flags are inserted **after** the SOPS subcommand — placing them
|
|
4658
|
+
* before is silently ignored by SOPS (a footgun discovered the first
|
|
4659
|
+
* time we shipped this).
|
|
4503
4660
|
*/
|
|
4504
|
-
constructor(runner, ageKeyFile, ageKey, sopsPath) {
|
|
4661
|
+
constructor(runner, ageKeyFile, ageKey, sopsPath, keyserviceAddr) {
|
|
4505
4662
|
this.runner = runner;
|
|
4506
4663
|
this.ageKeyFile = ageKeyFile;
|
|
4507
4664
|
this.ageKey = ageKey;
|
|
4508
4665
|
this.sopsCommand = sopsPath ?? resolveSopsPath().path;
|
|
4666
|
+
this.keyserviceArgs = keyserviceAddr ? Object.freeze(["--enable-local-keyservice=false", "--keyservice", keyserviceAddr]) : Object.freeze([]);
|
|
4509
4667
|
}
|
|
4510
4668
|
sopsCommand;
|
|
4669
|
+
keyserviceArgs;
|
|
4511
4670
|
buildSopsEnv() {
|
|
4512
4671
|
const env = {};
|
|
4513
4672
|
if (this.ageKey) {
|
|
@@ -4532,7 +4691,7 @@ var SopsClient = class {
|
|
|
4532
4691
|
const env = this.buildSopsEnv();
|
|
4533
4692
|
const result = await this.runner.run(
|
|
4534
4693
|
this.sopsCommand,
|
|
4535
|
-
["decrypt", "--output-type", fmt, filePath],
|
|
4694
|
+
["decrypt", ...this.keyserviceArgs, "--output-type", fmt, filePath],
|
|
4536
4695
|
{
|
|
4537
4696
|
...env ? { env } : {}
|
|
4538
4697
|
}
|
|
@@ -4599,6 +4758,7 @@ var SopsClient = class {
|
|
|
4599
4758
|
"--config",
|
|
4600
4759
|
configPath,
|
|
4601
4760
|
"encrypt",
|
|
4761
|
+
...this.keyserviceArgs,
|
|
4602
4762
|
...args,
|
|
4603
4763
|
"--input-type",
|
|
4604
4764
|
fmt,
|
|
@@ -4655,7 +4815,7 @@ var SopsClient = class {
|
|
|
4655
4815
|
const env = this.buildSopsEnv();
|
|
4656
4816
|
const result = await this.runner.run(
|
|
4657
4817
|
this.sopsCommand,
|
|
4658
|
-
["rotate", "-i", "--add-age", key, filePath],
|
|
4818
|
+
["rotate", ...this.keyserviceArgs, "-i", "--add-age", key, filePath],
|
|
4659
4819
|
{
|
|
4660
4820
|
...env ? { env } : {}
|
|
4661
4821
|
}
|
|
@@ -4679,7 +4839,7 @@ var SopsClient = class {
|
|
|
4679
4839
|
const env = this.buildSopsEnv();
|
|
4680
4840
|
const result = await this.runner.run(
|
|
4681
4841
|
this.sopsCommand,
|
|
4682
|
-
["rotate", "-i", "--rm-age", key, filePath],
|
|
4842
|
+
["rotate", ...this.keyserviceArgs, "-i", "--rm-age", key, filePath],
|
|
4683
4843
|
{
|
|
4684
4844
|
...env ? { env } : {}
|
|
4685
4845
|
}
|
|
@@ -4794,7 +4954,14 @@ var SopsClient = class {
|
|
|
4794
4954
|
}
|
|
4795
4955
|
detectBackend(sops) {
|
|
4796
4956
|
if (sops.age && Array.isArray(sops.age) && sops.age.length > 0) return "age";
|
|
4797
|
-
if (sops.kms && Array.isArray(sops.kms) && sops.kms.length > 0)
|
|
4957
|
+
if (sops.kms && Array.isArray(sops.kms) && sops.kms.length > 0) {
|
|
4958
|
+
const kmsEntries = sops.kms;
|
|
4959
|
+
const firstArn = kmsEntries[0]?.arn;
|
|
4960
|
+
if (typeof firstArn === "string" && isClefHsmArn(firstArn)) {
|
|
4961
|
+
return "hsm";
|
|
4962
|
+
}
|
|
4963
|
+
return "awskms";
|
|
4964
|
+
}
|
|
4798
4965
|
if (sops.gcp_kms && Array.isArray(sops.gcp_kms) && sops.gcp_kms.length > 0)
|
|
4799
4966
|
return "gcpkms";
|
|
4800
4967
|
if (sops.azure_kv && Array.isArray(sops.azure_kv) && sops.azure_kv.length > 0)
|
|
@@ -4812,6 +4979,13 @@ var SopsClient = class {
|
|
|
4812
4979
|
const entries = sops.kms;
|
|
4813
4980
|
return entries?.map((e) => String(e.arn ?? "")) ?? [];
|
|
4814
4981
|
}
|
|
4982
|
+
case "hsm": {
|
|
4983
|
+
const entries = sops.kms;
|
|
4984
|
+
return entries?.map((e) => {
|
|
4985
|
+
const raw = String(e.arn ?? "");
|
|
4986
|
+
return syntheticArnToPkcs11Uri(raw) ?? raw;
|
|
4987
|
+
}) ?? [];
|
|
4988
|
+
}
|
|
4815
4989
|
case "gcpkms": {
|
|
4816
4990
|
const entries = sops.gcp_kms;
|
|
4817
4991
|
return entries?.map((e) => String(e.resource_id ?? "")) ?? [];
|
|
@@ -4837,7 +5011,8 @@ var SopsClient = class {
|
|
|
4837
5011
|
aws_kms_arn: manifest.sops.aws_kms_arn,
|
|
4838
5012
|
gcp_kms_resource_id: manifest.sops.gcp_kms_resource_id,
|
|
4839
5013
|
azure_kv_url: manifest.sops.azure_kv_url,
|
|
4840
|
-
pgp_fingerprint: manifest.sops.pgp_fingerprint
|
|
5014
|
+
pgp_fingerprint: manifest.sops.pgp_fingerprint,
|
|
5015
|
+
pkcs11_uri: manifest.sops.pkcs11_uri
|
|
4841
5016
|
};
|
|
4842
5017
|
switch (config.backend) {
|
|
4843
5018
|
case "age": {
|
|
@@ -4869,13 +5044,172 @@ var SopsClient = class {
|
|
|
4869
5044
|
args.push("--pgp", config.pgp_fingerprint);
|
|
4870
5045
|
}
|
|
4871
5046
|
break;
|
|
5047
|
+
case "hsm":
|
|
5048
|
+
if (config.pkcs11_uri) {
|
|
5049
|
+
args.push("--kms", pkcs11UriToSyntheticArn(config.pkcs11_uri));
|
|
5050
|
+
}
|
|
5051
|
+
break;
|
|
4872
5052
|
}
|
|
4873
5053
|
return args;
|
|
4874
5054
|
}
|
|
4875
5055
|
};
|
|
4876
5056
|
|
|
4877
|
-
// src/
|
|
5057
|
+
// src/hsm/bundled.ts
|
|
5058
|
+
import * as fs14 from "fs";
|
|
4878
5059
|
import * as path12 from "path";
|
|
5060
|
+
function tryBundledKeyservice() {
|
|
5061
|
+
const platform = process.platform;
|
|
5062
|
+
const arch = process.arch;
|
|
5063
|
+
const archName = arch === "x64" ? "x64" : arch === "arm64" ? "arm64" : null;
|
|
5064
|
+
if (!archName) return null;
|
|
5065
|
+
const platformName = platform === "darwin" ? "darwin" : platform === "linux" ? "linux" : null;
|
|
5066
|
+
if (!platformName) return null;
|
|
5067
|
+
const packageName = `@clef-sh/keyservice-${platformName}-${archName}`;
|
|
5068
|
+
const binName = "clef-keyservice";
|
|
5069
|
+
try {
|
|
5070
|
+
const packageMain = __require.resolve(`${packageName}/package.json`);
|
|
5071
|
+
const packageDir = path12.dirname(packageMain);
|
|
5072
|
+
const binPath = path12.join(packageDir, "bin", binName);
|
|
5073
|
+
return fs14.existsSync(binPath) ? binPath : null;
|
|
5074
|
+
} catch {
|
|
5075
|
+
return null;
|
|
5076
|
+
}
|
|
5077
|
+
}
|
|
5078
|
+
|
|
5079
|
+
// src/hsm/resolver.ts
|
|
5080
|
+
import * as fs15 from "fs";
|
|
5081
|
+
import * as path13 from "path";
|
|
5082
|
+
function validateKeyservicePath(candidate) {
|
|
5083
|
+
if (!path13.isAbsolute(candidate)) {
|
|
5084
|
+
throw new Error(`CLEF_KEYSERVICE_PATH must be an absolute path, got '${candidate}'.`);
|
|
5085
|
+
}
|
|
5086
|
+
const segments = candidate.split(/[/\\]/);
|
|
5087
|
+
if (segments.includes("..")) {
|
|
5088
|
+
throw new Error(
|
|
5089
|
+
`CLEF_KEYSERVICE_PATH contains '..' path segments ('${candidate}'). Use an absolute path without directory traversal.`
|
|
5090
|
+
);
|
|
5091
|
+
}
|
|
5092
|
+
}
|
|
5093
|
+
var cached2;
|
|
5094
|
+
function resolveKeyservicePath() {
|
|
5095
|
+
if (cached2) return cached2;
|
|
5096
|
+
const envPath = process.env.CLEF_KEYSERVICE_PATH?.trim();
|
|
5097
|
+
if (envPath) {
|
|
5098
|
+
validateKeyservicePath(envPath);
|
|
5099
|
+
if (!fs15.existsSync(envPath)) {
|
|
5100
|
+
throw new Error(`CLEF_KEYSERVICE_PATH points to '${envPath}' but the file does not exist.`);
|
|
5101
|
+
}
|
|
5102
|
+
cached2 = { path: envPath, source: "env" };
|
|
5103
|
+
return cached2;
|
|
5104
|
+
}
|
|
5105
|
+
const bundledPath = tryBundledKeyservice();
|
|
5106
|
+
if (bundledPath) {
|
|
5107
|
+
cached2 = { path: bundledPath, source: "bundled" };
|
|
5108
|
+
return cached2;
|
|
5109
|
+
}
|
|
5110
|
+
cached2 = { path: "clef-keyservice", source: "system" };
|
|
5111
|
+
return cached2;
|
|
5112
|
+
}
|
|
5113
|
+
function resetKeyserviceResolution() {
|
|
5114
|
+
cached2 = void 0;
|
|
5115
|
+
}
|
|
5116
|
+
|
|
5117
|
+
// src/hsm/keyservice.ts
|
|
5118
|
+
import { spawn } from "child_process";
|
|
5119
|
+
import * as readline from "readline";
|
|
5120
|
+
var PORT_REGEX = /^PORT=(\d+)$/;
|
|
5121
|
+
var STARTUP_TIMEOUT_MS = 5e3;
|
|
5122
|
+
var SHUTDOWN_TIMEOUT_MS = 3e3;
|
|
5123
|
+
async function spawnKeyservice(options) {
|
|
5124
|
+
if (!options.pin && !options.pinFile) {
|
|
5125
|
+
throw new Error(
|
|
5126
|
+
"Keyservice requires a PIN. Set CLEF_PKCS11_PIN, CLEF_PKCS11_PIN_FILE, or .clef/config.yaml pkcs11_pin_file."
|
|
5127
|
+
);
|
|
5128
|
+
}
|
|
5129
|
+
const args = ["--addr", "127.0.0.1:0", "--pkcs11-module", options.modulePath];
|
|
5130
|
+
const childEnv = {
|
|
5131
|
+
...process.env,
|
|
5132
|
+
...options.extraEnv ?? {},
|
|
5133
|
+
...options.pin ? { CLEF_PKCS11_PIN: options.pin } : {},
|
|
5134
|
+
...options.pinFile ? { CLEF_PKCS11_PIN_FILE: options.pinFile } : {}
|
|
5135
|
+
};
|
|
5136
|
+
const child = spawn(options.binaryPath, args, {
|
|
5137
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
5138
|
+
env: childEnv
|
|
5139
|
+
});
|
|
5140
|
+
const port = await readPort(child);
|
|
5141
|
+
return {
|
|
5142
|
+
addr: `tcp://127.0.0.1:${port}`,
|
|
5143
|
+
kill: () => killGracefully(child)
|
|
5144
|
+
};
|
|
5145
|
+
}
|
|
5146
|
+
function readPort(child) {
|
|
5147
|
+
return new Promise((resolve, reject) => {
|
|
5148
|
+
let settled = false;
|
|
5149
|
+
if (!child.stdout) {
|
|
5150
|
+
reject(new Error("Keyservice child has no stdout pipe."));
|
|
5151
|
+
return;
|
|
5152
|
+
}
|
|
5153
|
+
const rl = readline.createInterface({ input: child.stdout });
|
|
5154
|
+
const settle = () => {
|
|
5155
|
+
clearTimeout(timer);
|
|
5156
|
+
rl.close();
|
|
5157
|
+
};
|
|
5158
|
+
const timer = setTimeout(() => {
|
|
5159
|
+
if (!settled) {
|
|
5160
|
+
settled = true;
|
|
5161
|
+
settle();
|
|
5162
|
+
child.kill("SIGKILL");
|
|
5163
|
+
reject(
|
|
5164
|
+
new Error(
|
|
5165
|
+
`clef-keyservice did not report a port within ${STARTUP_TIMEOUT_MS}ms. Check that the PKCS#11 module path is valid and the PIN is correct.`
|
|
5166
|
+
)
|
|
5167
|
+
);
|
|
5168
|
+
}
|
|
5169
|
+
}, STARTUP_TIMEOUT_MS);
|
|
5170
|
+
rl.on("line", (line) => {
|
|
5171
|
+
const match = PORT_REGEX.exec(line);
|
|
5172
|
+
if (match && !settled) {
|
|
5173
|
+
settled = true;
|
|
5174
|
+
settle();
|
|
5175
|
+
resolve(parseInt(match[1], 10));
|
|
5176
|
+
}
|
|
5177
|
+
});
|
|
5178
|
+
child.on("error", (err) => {
|
|
5179
|
+
if (!settled) {
|
|
5180
|
+
settled = true;
|
|
5181
|
+
settle();
|
|
5182
|
+
reject(new Error(`Failed to start clef-keyservice: ${err.message}`));
|
|
5183
|
+
}
|
|
5184
|
+
});
|
|
5185
|
+
child.on("exit", (code) => {
|
|
5186
|
+
if (!settled) {
|
|
5187
|
+
settled = true;
|
|
5188
|
+
settle();
|
|
5189
|
+
reject(new Error(`clef-keyservice exited with code ${code} before reporting a port.`));
|
|
5190
|
+
}
|
|
5191
|
+
});
|
|
5192
|
+
});
|
|
5193
|
+
}
|
|
5194
|
+
function killGracefully(child) {
|
|
5195
|
+
return new Promise((resolve) => {
|
|
5196
|
+
if (child.exitCode !== null) {
|
|
5197
|
+
resolve();
|
|
5198
|
+
return;
|
|
5199
|
+
}
|
|
5200
|
+
const timer = setTimeout(() => {
|
|
5201
|
+
child.kill("SIGKILL");
|
|
5202
|
+
}, SHUTDOWN_TIMEOUT_MS);
|
|
5203
|
+
child.on("exit", () => {
|
|
5204
|
+
clearTimeout(timer);
|
|
5205
|
+
resolve();
|
|
5206
|
+
});
|
|
5207
|
+
child.kill("SIGTERM");
|
|
5208
|
+
});
|
|
5209
|
+
}
|
|
5210
|
+
|
|
5211
|
+
// src/lint/runner.ts
|
|
5212
|
+
import * as path14 from "path";
|
|
4879
5213
|
var LintRunner = class {
|
|
4880
5214
|
constructor(matrixManager, schemaValidator, sopsClient) {
|
|
4881
5215
|
this.matrixManager = matrixManager;
|
|
@@ -4975,7 +5309,7 @@ var LintRunner = class {
|
|
|
4975
5309
|
}
|
|
4976
5310
|
const ns = manifest.namespaces.find((n) => n.name === cell.namespace);
|
|
4977
5311
|
if (ns?.schema) {
|
|
4978
|
-
const schemaPath =
|
|
5312
|
+
const schemaPath = path14.join(repoRoot, ns.schema);
|
|
4979
5313
|
try {
|
|
4980
5314
|
const schema = this.schemaValidator.loadSchema(schemaPath);
|
|
4981
5315
|
const result = this.schemaValidator.validate(decrypted.values, schema);
|
|
@@ -5076,8 +5410,50 @@ var LintRunner = class {
|
|
|
5076
5410
|
);
|
|
5077
5411
|
issues.push(...siIssues);
|
|
5078
5412
|
}
|
|
5413
|
+
const metadataIssues = await this.lintMetadataConsistency(existingCells);
|
|
5414
|
+
issues.push(...metadataIssues);
|
|
5079
5415
|
return { issues, fileCount: fileCount + missingCells.length, pendingCount };
|
|
5080
5416
|
}
|
|
5417
|
+
/**
|
|
5418
|
+
* Cross-reference `.clef-meta.yaml` against the cipher's plaintext key
|
|
5419
|
+
* names for each existing cell. Reports orphan rotation records and
|
|
5420
|
+
* dual-state (pending + rotation) inconsistencies. Uses
|
|
5421
|
+
* {@link readSopsKeyNames} (plaintext YAML parse) — no decryption.
|
|
5422
|
+
*/
|
|
5423
|
+
async lintMetadataConsistency(cells) {
|
|
5424
|
+
const issues = [];
|
|
5425
|
+
for (const cell of cells) {
|
|
5426
|
+
const keysInCipher = readSopsKeyNames(cell.filePath);
|
|
5427
|
+
if (keysInCipher === null) continue;
|
|
5428
|
+
const cipherKeys = new Set(keysInCipher);
|
|
5429
|
+
const metadata = await loadMetadata(cell.filePath);
|
|
5430
|
+
for (const record of metadata.rotations) {
|
|
5431
|
+
if (!cipherKeys.has(record.key)) {
|
|
5432
|
+
issues.push({
|
|
5433
|
+
severity: "warning",
|
|
5434
|
+
category: "metadata",
|
|
5435
|
+
file: cell.filePath,
|
|
5436
|
+
key: record.key,
|
|
5437
|
+
message: `Rotation record exists for key '${record.key}' but the key is not in this cell. Remove the orphan entry from .clef-meta.yaml or re-add the key via clef set.`
|
|
5438
|
+
});
|
|
5439
|
+
}
|
|
5440
|
+
}
|
|
5441
|
+
const pendingKeys = new Set(metadata.pending.map((p) => p.key));
|
|
5442
|
+
for (const record of metadata.rotations) {
|
|
5443
|
+
if (pendingKeys.has(record.key)) {
|
|
5444
|
+
issues.push({
|
|
5445
|
+
severity: "error",
|
|
5446
|
+
category: "metadata",
|
|
5447
|
+
file: cell.filePath,
|
|
5448
|
+
key: record.key,
|
|
5449
|
+
message: `Key '${record.key}' appears in both 'pending' and 'rotations' sections of .clef-meta.yaml. One of them is stale \u2014 likely a manual edit or a failed transaction. Re-run clef set to reconcile.`,
|
|
5450
|
+
fixCommand: `clef set ${cell.namespace}/${cell.environment} ${record.key}`
|
|
5451
|
+
});
|
|
5452
|
+
}
|
|
5453
|
+
}
|
|
5454
|
+
}
|
|
5455
|
+
return issues;
|
|
5456
|
+
}
|
|
5081
5457
|
/**
|
|
5082
5458
|
* Lint service identity configurations for drift issues.
|
|
5083
5459
|
*/
|
|
@@ -5220,14 +5596,14 @@ Use 'clef exec' to inject secrets directly into a process, or 'clef export --for
|
|
|
5220
5596
|
};
|
|
5221
5597
|
|
|
5222
5598
|
// src/import/index.ts
|
|
5223
|
-
import * as
|
|
5599
|
+
import * as path16 from "path";
|
|
5224
5600
|
|
|
5225
5601
|
// src/import/parsers.ts
|
|
5226
|
-
import * as
|
|
5602
|
+
import * as path15 from "path";
|
|
5227
5603
|
import * as YAML8 from "yaml";
|
|
5228
5604
|
function detectFormat(filePath, content) {
|
|
5229
|
-
const base =
|
|
5230
|
-
const ext =
|
|
5605
|
+
const base = path15.basename(filePath);
|
|
5606
|
+
const ext = path15.extname(filePath).toLowerCase();
|
|
5231
5607
|
if (base === ".env" || base.startsWith(".env.")) {
|
|
5232
5608
|
return "dotenv";
|
|
5233
5609
|
}
|
|
@@ -5393,7 +5769,7 @@ var ImportRunner = class {
|
|
|
5393
5769
|
*/
|
|
5394
5770
|
async import(target, sourcePath, content, manifest, repoRoot, options) {
|
|
5395
5771
|
const [ns, env] = target.split("/");
|
|
5396
|
-
const filePath =
|
|
5772
|
+
const filePath = path16.join(
|
|
5397
5773
|
repoRoot,
|
|
5398
5774
|
manifest.file_pattern.replace("{namespace}", ns).replace("{environment}", env)
|
|
5399
5775
|
);
|
|
@@ -5430,22 +5806,33 @@ var ImportRunner = class {
|
|
|
5430
5806
|
}
|
|
5431
5807
|
const decrypted = await this.sopsClient.decrypt(filePath);
|
|
5432
5808
|
const newValues = { ...decrypted.values };
|
|
5809
|
+
const rotatedKeys = [];
|
|
5433
5810
|
for (const [key, value] of candidates) {
|
|
5434
|
-
|
|
5811
|
+
const existed = key in decrypted.values;
|
|
5812
|
+
if (existed && !options.overwrite) {
|
|
5435
5813
|
skipped.push(key);
|
|
5436
5814
|
continue;
|
|
5437
5815
|
}
|
|
5816
|
+
const valueChanged = !existed || decrypted.values[key] !== value;
|
|
5438
5817
|
newValues[key] = value;
|
|
5439
5818
|
imported.push(key);
|
|
5819
|
+
if (valueChanged) rotatedKeys.push(key);
|
|
5440
5820
|
}
|
|
5441
5821
|
if (imported.length === 0) {
|
|
5442
5822
|
return { imported, skipped, failed, warnings, dryRun: false };
|
|
5443
5823
|
}
|
|
5824
|
+
const relCellPath = path16.relative(repoRoot, filePath);
|
|
5825
|
+
const relMetaPath = relCellPath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml");
|
|
5444
5826
|
await this.tx.run(repoRoot, {
|
|
5445
5827
|
description: `clef import ${target}: ${imported.length} key(s)`,
|
|
5446
|
-
|
|
5828
|
+
// Include the metadata path so rotation records created in the mutate
|
|
5829
|
+
// callback are staged and rolled back atomically with the ciphertext.
|
|
5830
|
+
paths: [relCellPath, relMetaPath],
|
|
5447
5831
|
mutate: async () => {
|
|
5448
5832
|
await this.sopsClient.encrypt(filePath, newValues, manifest, env);
|
|
5833
|
+
if (options.rotatedBy && rotatedKeys.length > 0) {
|
|
5834
|
+
await recordRotation(filePath, rotatedKeys, options.rotatedBy);
|
|
5835
|
+
}
|
|
5449
5836
|
}
|
|
5450
5837
|
});
|
|
5451
5838
|
return { imported, skipped, failed, warnings, dryRun: false };
|
|
@@ -5453,7 +5840,7 @@ var ImportRunner = class {
|
|
|
5453
5840
|
};
|
|
5454
5841
|
|
|
5455
5842
|
// src/recipients/index.ts
|
|
5456
|
-
import * as
|
|
5843
|
+
import * as path17 from "path";
|
|
5457
5844
|
function parseRecipientEntry(entry) {
|
|
5458
5845
|
if (typeof entry === "string") {
|
|
5459
5846
|
return { key: entry };
|
|
@@ -5578,7 +5965,7 @@ var RecipientManager = class {
|
|
|
5578
5965
|
const reEncryptedFiles = [];
|
|
5579
5966
|
await this.tx.run(repoRoot, {
|
|
5580
5967
|
description: environment ? `clef recipients add ${keyPreview(normalizedKey)} -e ${environment}` : `clef recipients add ${keyPreview(normalizedKey)}`,
|
|
5581
|
-
paths: [...cells.map((c) =>
|
|
5968
|
+
paths: [...cells.map((c) => path17.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME],
|
|
5582
5969
|
mutate: async () => {
|
|
5583
5970
|
const doc = readManifestYaml(repoRoot);
|
|
5584
5971
|
const recipients = environment ? ensureEnvironmentRecipientsArray(doc, environment) : ensureRecipientsArray(doc);
|
|
@@ -5637,7 +6024,7 @@ var RecipientManager = class {
|
|
|
5637
6024
|
const reEncryptedFiles = [];
|
|
5638
6025
|
await this.tx.run(repoRoot, {
|
|
5639
6026
|
description: environment ? `clef recipients remove ${keyPreview(trimmedKey)} -e ${environment}` : `clef recipients remove ${keyPreview(trimmedKey)}`,
|
|
5640
|
-
paths: [...cells.map((c) =>
|
|
6027
|
+
paths: [...cells.map((c) => path17.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME],
|
|
5641
6028
|
mutate: async () => {
|
|
5642
6029
|
const doc = readManifestYaml(repoRoot);
|
|
5643
6030
|
const recipients = environment ? ensureEnvironmentRecipientsArray(doc, environment) : ensureRecipientsArray(doc);
|
|
@@ -5666,19 +6053,19 @@ var RecipientManager = class {
|
|
|
5666
6053
|
};
|
|
5667
6054
|
|
|
5668
6055
|
// src/recipients/requests.ts
|
|
5669
|
-
import * as
|
|
5670
|
-
import * as
|
|
6056
|
+
import * as fs16 from "fs";
|
|
6057
|
+
import * as path18 from "path";
|
|
5671
6058
|
import * as YAML9 from "yaml";
|
|
5672
6059
|
var REQUESTS_FILENAME = ".clef-requests.yaml";
|
|
5673
6060
|
var HEADER_COMMENT2 = "# Pending recipient access requests. Approve with: clef recipients approve <label>\n";
|
|
5674
6061
|
function requestsFilePath(repoRoot) {
|
|
5675
|
-
return
|
|
6062
|
+
return path18.join(repoRoot, REQUESTS_FILENAME);
|
|
5676
6063
|
}
|
|
5677
6064
|
function loadRequests(repoRoot) {
|
|
5678
6065
|
const filePath = requestsFilePath(repoRoot);
|
|
5679
6066
|
try {
|
|
5680
|
-
if (!
|
|
5681
|
-
const content =
|
|
6067
|
+
if (!fs16.existsSync(filePath)) return [];
|
|
6068
|
+
const content = fs16.readFileSync(filePath, "utf-8");
|
|
5682
6069
|
const parsed = YAML9.parse(content);
|
|
5683
6070
|
if (!parsed || !Array.isArray(parsed.requests)) return [];
|
|
5684
6071
|
return parsed.requests.map((r) => ({
|
|
@@ -5695,7 +6082,7 @@ function saveRequests(repoRoot, requests) {
|
|
|
5695
6082
|
const filePath = requestsFilePath(repoRoot);
|
|
5696
6083
|
if (requests.length === 0) {
|
|
5697
6084
|
try {
|
|
5698
|
-
|
|
6085
|
+
fs16.unlinkSync(filePath);
|
|
5699
6086
|
} catch {
|
|
5700
6087
|
}
|
|
5701
6088
|
return;
|
|
@@ -5711,7 +6098,7 @@ function saveRequests(repoRoot, requests) {
|
|
|
5711
6098
|
return raw;
|
|
5712
6099
|
})
|
|
5713
6100
|
};
|
|
5714
|
-
|
|
6101
|
+
fs16.writeFileSync(filePath, HEADER_COMMENT2 + YAML9.stringify(data), "utf-8");
|
|
5715
6102
|
}
|
|
5716
6103
|
function upsertRequest(repoRoot, key, label, environment) {
|
|
5717
6104
|
const requests = loadRequests(repoRoot);
|
|
@@ -5747,7 +6134,7 @@ function findInList(requests, identifier) {
|
|
|
5747
6134
|
}
|
|
5748
6135
|
|
|
5749
6136
|
// src/drift/detector.ts
|
|
5750
|
-
import * as
|
|
6137
|
+
import * as path19 from "path";
|
|
5751
6138
|
var DriftDetector = class {
|
|
5752
6139
|
parser = new ManifestParser();
|
|
5753
6140
|
matrix = new MatrixManager();
|
|
@@ -5760,8 +6147,8 @@ var DriftDetector = class {
|
|
|
5760
6147
|
* @returns Drift result with any issues found.
|
|
5761
6148
|
*/
|
|
5762
6149
|
detect(localRoot, remoteRoot, namespaceFilter) {
|
|
5763
|
-
const localManifest = this.parser.parse(
|
|
5764
|
-
const remoteManifest = this.parser.parse(
|
|
6150
|
+
const localManifest = this.parser.parse(path19.join(localRoot, CLEF_MANIFEST_FILENAME));
|
|
6151
|
+
const remoteManifest = this.parser.parse(path19.join(remoteRoot, CLEF_MANIFEST_FILENAME));
|
|
5765
6152
|
const localCells = this.matrix.resolveMatrix(localManifest, localRoot);
|
|
5766
6153
|
const remoteCells = this.matrix.resolveMatrix(remoteManifest, remoteRoot);
|
|
5767
6154
|
const localEnvNames = localManifest.environments.map((e) => e.name);
|
|
@@ -5825,7 +6212,7 @@ var DriftDetector = class {
|
|
|
5825
6212
|
};
|
|
5826
6213
|
|
|
5827
6214
|
// src/report/generator.ts
|
|
5828
|
-
import * as
|
|
6215
|
+
import * as path20 from "path";
|
|
5829
6216
|
|
|
5830
6217
|
// src/report/sanitizer.ts
|
|
5831
6218
|
var ReportSanitizer = class {
|
|
@@ -5981,7 +6368,7 @@ var ReportGenerator = class {
|
|
|
5981
6368
|
let manifest = null;
|
|
5982
6369
|
try {
|
|
5983
6370
|
const parser = new ManifestParser();
|
|
5984
|
-
manifest = parser.parse(
|
|
6371
|
+
manifest = parser.parse(path20.join(repoRoot, "clef.yaml"));
|
|
5985
6372
|
} catch {
|
|
5986
6373
|
const emptyManifest = {
|
|
5987
6374
|
manifestVersion: 0,
|
|
@@ -6458,8 +6845,118 @@ var SopsMergeDriver = class {
|
|
|
6458
6845
|
}
|
|
6459
6846
|
};
|
|
6460
6847
|
|
|
6848
|
+
// src/merge/metadata-driver.ts
|
|
6849
|
+
import * as fs17 from "fs";
|
|
6850
|
+
import * as YAML10 from "yaml";
|
|
6851
|
+
var HEADER_COMMENT3 = "# Managed by Clef. Do not edit manually.\n";
|
|
6852
|
+
function parseMetadata(content) {
|
|
6853
|
+
try {
|
|
6854
|
+
const parsed = YAML10.parse(content);
|
|
6855
|
+
if (!parsed || typeof parsed !== "object") return emptyMetadata2();
|
|
6856
|
+
const pendingRaw = Array.isArray(parsed.pending) ? parsed.pending : [];
|
|
6857
|
+
const pending = pendingRaw.filter(
|
|
6858
|
+
(p) => !!p && typeof p === "object" && typeof p.key === "string" && typeof p.since === "string" && typeof p.setBy === "string"
|
|
6859
|
+
).map((p) => ({ key: p.key, since: new Date(p.since), setBy: p.setBy }));
|
|
6860
|
+
const rotationsRaw = Array.isArray(parsed.rotations) ? parsed.rotations : [];
|
|
6861
|
+
const rotations = rotationsRaw.filter(
|
|
6862
|
+
(r) => !!r && typeof r === "object" && typeof r.key === "string" && typeof r.last_rotated_at === "string" && typeof r.rotated_by === "string" && typeof r.rotation_count === "number"
|
|
6863
|
+
).map((r) => ({
|
|
6864
|
+
key: r.key,
|
|
6865
|
+
lastRotatedAt: new Date(r.last_rotated_at),
|
|
6866
|
+
rotatedBy: r.rotated_by,
|
|
6867
|
+
rotationCount: r.rotation_count
|
|
6868
|
+
}));
|
|
6869
|
+
return { version: 1, pending, rotations };
|
|
6870
|
+
} catch {
|
|
6871
|
+
return emptyMetadata2();
|
|
6872
|
+
}
|
|
6873
|
+
}
|
|
6874
|
+
function emptyMetadata2() {
|
|
6875
|
+
return { version: 1, pending: [], rotations: [] };
|
|
6876
|
+
}
|
|
6877
|
+
function serializeMetadata(m) {
|
|
6878
|
+
const data = {
|
|
6879
|
+
version: m.version,
|
|
6880
|
+
pending: m.pending.map((p) => ({
|
|
6881
|
+
key: p.key,
|
|
6882
|
+
since: p.since.toISOString(),
|
|
6883
|
+
setBy: p.setBy
|
|
6884
|
+
})),
|
|
6885
|
+
rotations: m.rotations.map((r) => ({
|
|
6886
|
+
key: r.key,
|
|
6887
|
+
last_rotated_at: r.lastRotatedAt.toISOString(),
|
|
6888
|
+
rotated_by: r.rotatedBy,
|
|
6889
|
+
rotation_count: r.rotationCount
|
|
6890
|
+
}))
|
|
6891
|
+
};
|
|
6892
|
+
return HEADER_COMMENT3 + YAML10.stringify(data);
|
|
6893
|
+
}
|
|
6894
|
+
function mergeRotations(ours, theirs) {
|
|
6895
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
6896
|
+
const ourByKey = new Map(ours.map((r) => [r.key, r]));
|
|
6897
|
+
const theirByKey = new Map(theirs.map((r) => [r.key, r]));
|
|
6898
|
+
const allKeys = /* @__PURE__ */ new Set([...ourByKey.keys(), ...theirByKey.keys()]);
|
|
6899
|
+
for (const key of allKeys) {
|
|
6900
|
+
const o = ourByKey.get(key);
|
|
6901
|
+
const t = theirByKey.get(key);
|
|
6902
|
+
if (o && t) {
|
|
6903
|
+
const oTime = o.lastRotatedAt.getTime();
|
|
6904
|
+
const tTime = t.lastRotatedAt.getTime();
|
|
6905
|
+
const winner = tTime > oTime ? t : o;
|
|
6906
|
+
byKey.set(key, {
|
|
6907
|
+
key,
|
|
6908
|
+
lastRotatedAt: winner.lastRotatedAt,
|
|
6909
|
+
rotatedBy: winner.rotatedBy,
|
|
6910
|
+
rotationCount: Math.max(o.rotationCount, t.rotationCount) + 1
|
|
6911
|
+
});
|
|
6912
|
+
} else if (o) {
|
|
6913
|
+
byKey.set(key, o);
|
|
6914
|
+
} else if (t) {
|
|
6915
|
+
byKey.set(key, t);
|
|
6916
|
+
}
|
|
6917
|
+
}
|
|
6918
|
+
return Array.from(byKey.values());
|
|
6919
|
+
}
|
|
6920
|
+
function mergePending(oursPending, theirsPending, oursRotations, theirsRotations) {
|
|
6921
|
+
const ourByKey = new Map(oursPending.map((p) => [p.key, p]));
|
|
6922
|
+
const theirByKey = new Map(theirsPending.map((p) => [p.key, p]));
|
|
6923
|
+
const rotatedKeys = /* @__PURE__ */ new Set([
|
|
6924
|
+
...oursRotations.map((r) => r.key),
|
|
6925
|
+
...theirsRotations.map((r) => r.key)
|
|
6926
|
+
]);
|
|
6927
|
+
const allKeys = /* @__PURE__ */ new Set([...ourByKey.keys(), ...theirByKey.keys()]);
|
|
6928
|
+
const out = [];
|
|
6929
|
+
for (const key of allKeys) {
|
|
6930
|
+
if (rotatedKeys.has(key)) continue;
|
|
6931
|
+
const o = ourByKey.get(key);
|
|
6932
|
+
const t = theirByKey.get(key);
|
|
6933
|
+
if (o && t) {
|
|
6934
|
+
const winner = t.since.getTime() > o.since.getTime() ? t : o;
|
|
6935
|
+
out.push({ key, since: winner.since, setBy: winner.setBy });
|
|
6936
|
+
} else if (o) {
|
|
6937
|
+
out.push(o);
|
|
6938
|
+
} else if (t) {
|
|
6939
|
+
out.push(t);
|
|
6940
|
+
}
|
|
6941
|
+
}
|
|
6942
|
+
return out;
|
|
6943
|
+
}
|
|
6944
|
+
function mergeMetadataContents(oursContent, theirsContent) {
|
|
6945
|
+
const ours = parseMetadata(oursContent);
|
|
6946
|
+
const theirs = parseMetadata(theirsContent);
|
|
6947
|
+
const rotations = mergeRotations(ours.rotations, theirs.rotations);
|
|
6948
|
+
const pending = mergePending(ours.pending, theirs.pending, ours.rotations, theirs.rotations);
|
|
6949
|
+
return serializeMetadata({ version: 1, pending, rotations });
|
|
6950
|
+
}
|
|
6951
|
+
function mergeMetadataFiles(_basePath, oursPath, theirsPath) {
|
|
6952
|
+
const oursContent = fs17.existsSync(oursPath) ? fs17.readFileSync(oursPath, "utf-8") : "";
|
|
6953
|
+
const theirsContent = fs17.existsSync(theirsPath) ? fs17.readFileSync(theirsPath, "utf-8") : "";
|
|
6954
|
+
const merged = mergeMetadataContents(oursContent, theirsContent);
|
|
6955
|
+
fs17.writeFileSync(oursPath, merged, "utf-8");
|
|
6956
|
+
}
|
|
6957
|
+
|
|
6461
6958
|
// src/service-identity/manager.ts
|
|
6462
|
-
import * as
|
|
6959
|
+
import * as path21 from "path";
|
|
6463
6960
|
var ServiceIdentityManager = class {
|
|
6464
6961
|
constructor(encryption, matrixManager, tx) {
|
|
6465
6962
|
this.encryption = encryption;
|
|
@@ -6471,7 +6968,7 @@ var ServiceIdentityManager = class {
|
|
|
6471
6968
|
* to seed TransactionManager.run's `paths` argument.
|
|
6472
6969
|
*/
|
|
6473
6970
|
txPaths(repoRoot, cells) {
|
|
6474
|
-
return [...cells.map((c) =>
|
|
6971
|
+
return [...cells.map((c) => path21.relative(repoRoot, c.filePath)), CLEF_MANIFEST_FILENAME];
|
|
6475
6972
|
}
|
|
6476
6973
|
/**
|
|
6477
6974
|
* Create a new service identity with per-environment age key pairs or KMS envelope config.
|
|
@@ -6993,8 +7490,8 @@ var ServiceIdentityManager = class {
|
|
|
6993
7490
|
};
|
|
6994
7491
|
|
|
6995
7492
|
// src/structure/manager.ts
|
|
6996
|
-
import * as
|
|
6997
|
-
import * as
|
|
7493
|
+
import * as fs18 from "fs";
|
|
7494
|
+
import * as path22 from "path";
|
|
6998
7495
|
var StructureManager = class {
|
|
6999
7496
|
constructor(matrixManager, encryption, tx) {
|
|
7000
7497
|
this.matrixManager = matrixManager;
|
|
@@ -7015,15 +7512,15 @@ var StructureManager = class {
|
|
|
7015
7512
|
this.assertValidIdentifier("namespace", name);
|
|
7016
7513
|
const newCellPaths = manifest.environments.map((env) => ({
|
|
7017
7514
|
environment: env.name,
|
|
7018
|
-
filePath:
|
|
7515
|
+
filePath: path22.join(
|
|
7019
7516
|
repoRoot,
|
|
7020
7517
|
manifest.file_pattern.replace("{namespace}", name).replace("{environment}", env.name)
|
|
7021
7518
|
)
|
|
7022
7519
|
}));
|
|
7023
7520
|
for (const cell of newCellPaths) {
|
|
7024
|
-
if (
|
|
7521
|
+
if (fs18.existsSync(cell.filePath)) {
|
|
7025
7522
|
throw new Error(
|
|
7026
|
-
`Cannot add namespace '${name}': file '${
|
|
7523
|
+
`Cannot add namespace '${name}': file '${path22.relative(repoRoot, cell.filePath)}' already exists.`
|
|
7027
7524
|
);
|
|
7028
7525
|
}
|
|
7029
7526
|
}
|
|
@@ -7042,7 +7539,7 @@ var StructureManager = class {
|
|
|
7042
7539
|
await this.tx.run(repoRoot, {
|
|
7043
7540
|
description: `clef namespace add ${name}`,
|
|
7044
7541
|
paths: [
|
|
7045
|
-
...newCellPaths.map((c) =>
|
|
7542
|
+
...newCellPaths.map((c) => path22.relative(repoRoot, c.filePath)),
|
|
7046
7543
|
CLEF_MANIFEST_FILENAME
|
|
7047
7544
|
],
|
|
7048
7545
|
mutate: async () => {
|
|
@@ -7087,15 +7584,15 @@ var StructureManager = class {
|
|
|
7087
7584
|
this.assertValidIdentifier("environment", name);
|
|
7088
7585
|
const newCellPaths = manifest.namespaces.map((ns) => ({
|
|
7089
7586
|
namespace: ns.name,
|
|
7090
|
-
filePath:
|
|
7587
|
+
filePath: path22.join(
|
|
7091
7588
|
repoRoot,
|
|
7092
7589
|
manifest.file_pattern.replace("{namespace}", ns.name).replace("{environment}", name)
|
|
7093
7590
|
)
|
|
7094
7591
|
}));
|
|
7095
7592
|
for (const cell of newCellPaths) {
|
|
7096
|
-
if (
|
|
7593
|
+
if (fs18.existsSync(cell.filePath)) {
|
|
7097
7594
|
throw new Error(
|
|
7098
|
-
`Cannot add environment '${name}': file '${
|
|
7595
|
+
`Cannot add environment '${name}': file '${path22.relative(repoRoot, cell.filePath)}' already exists.`
|
|
7099
7596
|
);
|
|
7100
7597
|
}
|
|
7101
7598
|
}
|
|
@@ -7114,7 +7611,7 @@ var StructureManager = class {
|
|
|
7114
7611
|
await this.tx.run(repoRoot, {
|
|
7115
7612
|
description: `clef env add ${name}`,
|
|
7116
7613
|
paths: [
|
|
7117
|
-
...newCellPaths.map((c) =>
|
|
7614
|
+
...newCellPaths.map((c) => path22.relative(repoRoot, c.filePath)),
|
|
7118
7615
|
CLEF_MANIFEST_FILENAME
|
|
7119
7616
|
],
|
|
7120
7617
|
mutate: async () => {
|
|
@@ -7177,7 +7674,7 @@ var StructureManager = class {
|
|
|
7177
7674
|
paths: this.deletePaths(repoRoot, cellsToDelete),
|
|
7178
7675
|
mutate: async () => {
|
|
7179
7676
|
for (const cell of cellsToDelete) {
|
|
7180
|
-
|
|
7677
|
+
fs18.unlinkSync(cell.filePath);
|
|
7181
7678
|
this.unlinkMetaSibling(cell.filePath);
|
|
7182
7679
|
}
|
|
7183
7680
|
const doc = readManifestYaml(repoRoot);
|
|
@@ -7227,7 +7724,7 @@ var StructureManager = class {
|
|
|
7227
7724
|
paths: this.deletePaths(repoRoot, cellsToDelete),
|
|
7228
7725
|
mutate: async () => {
|
|
7229
7726
|
for (const cell of cellsToDelete) {
|
|
7230
|
-
|
|
7727
|
+
fs18.unlinkSync(cell.filePath);
|
|
7231
7728
|
this.unlinkMetaSibling(cell.filePath);
|
|
7232
7729
|
}
|
|
7233
7730
|
const doc = readManifestYaml(repoRoot);
|
|
@@ -7269,9 +7766,9 @@ var StructureManager = class {
|
|
|
7269
7766
|
const renamePairs = isRename ? this.collectRenamePairs(manifest, repoRoot, name, opts.rename, "namespace") : [];
|
|
7270
7767
|
if (isRename) {
|
|
7271
7768
|
for (const pair of renamePairs) {
|
|
7272
|
-
if (
|
|
7769
|
+
if (fs18.existsSync(pair.to)) {
|
|
7273
7770
|
throw new Error(
|
|
7274
|
-
`Rename target '${
|
|
7771
|
+
`Rename target '${path22.relative(repoRoot, pair.to)}' already exists. Move or remove it first.`
|
|
7275
7772
|
);
|
|
7276
7773
|
}
|
|
7277
7774
|
}
|
|
@@ -7312,9 +7809,9 @@ var StructureManager = class {
|
|
|
7312
7809
|
const renamePairs = isRename ? this.collectRenamePairs(manifest, repoRoot, name, opts.rename, "environment") : [];
|
|
7313
7810
|
if (isRename) {
|
|
7314
7811
|
for (const pair of renamePairs) {
|
|
7315
|
-
if (
|
|
7812
|
+
if (fs18.existsSync(pair.to)) {
|
|
7316
7813
|
throw new Error(
|
|
7317
|
-
`Rename target '${
|
|
7814
|
+
`Rename target '${path22.relative(repoRoot, pair.to)}' already exists. Move or remove it first.`
|
|
7318
7815
|
);
|
|
7319
7816
|
}
|
|
7320
7817
|
}
|
|
@@ -7349,7 +7846,7 @@ var StructureManager = class {
|
|
|
7349
7846
|
const newCellPath = this.swapAxisInCellPath(repoRoot, manifest, cell, axis, newName);
|
|
7350
7847
|
pairs.push({ from: cell.filePath, to: newCellPath });
|
|
7351
7848
|
const oldMeta = cell.filePath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml");
|
|
7352
|
-
if (
|
|
7849
|
+
if (fs18.existsSync(oldMeta)) {
|
|
7353
7850
|
const newMeta = newCellPath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml");
|
|
7354
7851
|
pairs.push({ from: oldMeta, to: newMeta });
|
|
7355
7852
|
}
|
|
@@ -7364,7 +7861,7 @@ var StructureManager = class {
|
|
|
7364
7861
|
swapAxisInCellPath(repoRoot, manifest, cell, axis, newName) {
|
|
7365
7862
|
const ns = axis === "namespace" ? newName : cell.namespace;
|
|
7366
7863
|
const env = axis === "environment" ? newName : cell.environment;
|
|
7367
|
-
return
|
|
7864
|
+
return path22.join(
|
|
7368
7865
|
repoRoot,
|
|
7369
7866
|
manifest.file_pattern.replace("{namespace}", ns).replace("{environment}", env)
|
|
7370
7867
|
);
|
|
@@ -7376,8 +7873,8 @@ var StructureManager = class {
|
|
|
7376
7873
|
txPaths(repoRoot, renamePairs) {
|
|
7377
7874
|
const paths = /* @__PURE__ */ new Set();
|
|
7378
7875
|
for (const pair of renamePairs) {
|
|
7379
|
-
paths.add(
|
|
7380
|
-
paths.add(
|
|
7876
|
+
paths.add(path22.relative(repoRoot, pair.from));
|
|
7877
|
+
paths.add(path22.relative(repoRoot, pair.to));
|
|
7381
7878
|
}
|
|
7382
7879
|
paths.add(CLEF_MANIFEST_FILENAME);
|
|
7383
7880
|
return [...paths];
|
|
@@ -7388,11 +7885,11 @@ var StructureManager = class {
|
|
|
7388
7885
|
*/
|
|
7389
7886
|
applyRenames(pairs) {
|
|
7390
7887
|
for (const pair of pairs) {
|
|
7391
|
-
const targetDir =
|
|
7392
|
-
if (!
|
|
7393
|
-
|
|
7888
|
+
const targetDir = path22.dirname(pair.to);
|
|
7889
|
+
if (!fs18.existsSync(targetDir)) {
|
|
7890
|
+
fs18.mkdirSync(targetDir, { recursive: true });
|
|
7394
7891
|
}
|
|
7395
|
-
|
|
7892
|
+
fs18.renameSync(pair.from, pair.to);
|
|
7396
7893
|
}
|
|
7397
7894
|
}
|
|
7398
7895
|
/**
|
|
@@ -7403,10 +7900,10 @@ var StructureManager = class {
|
|
|
7403
7900
|
deletePaths(repoRoot, cells) {
|
|
7404
7901
|
const paths = /* @__PURE__ */ new Set();
|
|
7405
7902
|
for (const cell of cells) {
|
|
7406
|
-
paths.add(
|
|
7903
|
+
paths.add(path22.relative(repoRoot, cell.filePath));
|
|
7407
7904
|
const meta = cell.filePath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml");
|
|
7408
|
-
if (
|
|
7409
|
-
paths.add(
|
|
7905
|
+
if (fs18.existsSync(meta)) {
|
|
7906
|
+
paths.add(path22.relative(repoRoot, meta));
|
|
7410
7907
|
}
|
|
7411
7908
|
}
|
|
7412
7909
|
paths.add(CLEF_MANIFEST_FILENAME);
|
|
@@ -7419,8 +7916,8 @@ var StructureManager = class {
|
|
|
7419
7916
|
*/
|
|
7420
7917
|
unlinkMetaSibling(cellPath) {
|
|
7421
7918
|
const meta = cellPath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml");
|
|
7422
|
-
if (
|
|
7423
|
-
|
|
7919
|
+
if (fs18.existsSync(meta)) {
|
|
7920
|
+
fs18.unlinkSync(meta);
|
|
7424
7921
|
}
|
|
7425
7922
|
}
|
|
7426
7923
|
/**
|
|
@@ -7565,20 +8062,20 @@ async function resolveIdentitySecrets(identityName, environment, manifest, repoR
|
|
|
7565
8062
|
import * as crypto3 from "crypto";
|
|
7566
8063
|
|
|
7567
8064
|
// src/artifact/output.ts
|
|
7568
|
-
import * as
|
|
7569
|
-
import * as
|
|
8065
|
+
import * as fs19 from "fs";
|
|
8066
|
+
import * as path23 from "path";
|
|
7570
8067
|
var FilePackOutput = class {
|
|
7571
8068
|
constructor(outputPath) {
|
|
7572
8069
|
this.outputPath = outputPath;
|
|
7573
8070
|
}
|
|
7574
8071
|
async write(_artifact, json) {
|
|
7575
|
-
const outputDir =
|
|
7576
|
-
if (!
|
|
7577
|
-
|
|
8072
|
+
const outputDir = path23.dirname(this.outputPath);
|
|
8073
|
+
if (!fs19.existsSync(outputDir)) {
|
|
8074
|
+
fs19.mkdirSync(outputDir, { recursive: true });
|
|
7578
8075
|
}
|
|
7579
8076
|
const tmpOutput = `${this.outputPath}.tmp.${process.pid}`;
|
|
7580
|
-
|
|
7581
|
-
|
|
8077
|
+
fs19.writeFileSync(tmpOutput, json, "utf-8");
|
|
8078
|
+
fs19.renameSync(tmpOutput, this.outputPath);
|
|
7582
8079
|
}
|
|
7583
8080
|
};
|
|
7584
8081
|
var MemoryPackOutput = class {
|
|
@@ -7785,28 +8282,187 @@ var ArtifactPacker = class {
|
|
|
7785
8282
|
const json = JSON.stringify(artifact, null, 2);
|
|
7786
8283
|
const output = config.output ?? new FilePackOutput(config.outputPath ?? "artifact.json");
|
|
7787
8284
|
await output.write(artifact, json);
|
|
8285
|
+
const keys = Object.keys(resolved.values);
|
|
7788
8286
|
return {
|
|
7789
8287
|
outputPath: config.outputPath ?? "",
|
|
7790
8288
|
namespaceCount: resolved.identity.namespaces.length,
|
|
7791
|
-
keyCount:
|
|
8289
|
+
keyCount: keys.length,
|
|
8290
|
+
keys,
|
|
7792
8291
|
artifactSize: Buffer.byteLength(json, "utf-8"),
|
|
7793
8292
|
revision: artifact.revision
|
|
7794
8293
|
};
|
|
7795
8294
|
}
|
|
7796
8295
|
};
|
|
7797
8296
|
|
|
8297
|
+
// src/artifact/guards.ts
|
|
8298
|
+
var InvalidArtifactError = class extends ClefError {
|
|
8299
|
+
constructor(message) {
|
|
8300
|
+
super(
|
|
8301
|
+
message,
|
|
8302
|
+
"Ensure the artifact was produced by a compatible clef version and was not tampered with."
|
|
8303
|
+
);
|
|
8304
|
+
this.name = "InvalidArtifactError";
|
|
8305
|
+
}
|
|
8306
|
+
};
|
|
8307
|
+
var VALID_SIGNATURE_ALGORITHMS = ["Ed25519", "ECDSA_SHA256"];
|
|
8308
|
+
function isKmsEnvelope2(x) {
|
|
8309
|
+
if (typeof x !== "object" || x === null) return false;
|
|
8310
|
+
const o = x;
|
|
8311
|
+
return typeof o.provider === "string" && typeof o.keyId === "string" && typeof o.wrappedKey === "string" && typeof o.algorithm === "string" && typeof o.iv === "string" && typeof o.authTag === "string";
|
|
8312
|
+
}
|
|
8313
|
+
function validatePackedArtifact(x) {
|
|
8314
|
+
if (typeof x !== "object" || x === null) {
|
|
8315
|
+
return { valid: false, reason: "expected object" };
|
|
8316
|
+
}
|
|
8317
|
+
const o = x;
|
|
8318
|
+
if (o.version !== 1) {
|
|
8319
|
+
return { valid: false, reason: `unsupported version: ${String(o.version)}` };
|
|
8320
|
+
}
|
|
8321
|
+
if (typeof o.identity !== "string") {
|
|
8322
|
+
return { valid: false, reason: "missing or invalid 'identity' (expected string)" };
|
|
8323
|
+
}
|
|
8324
|
+
if (typeof o.environment !== "string") {
|
|
8325
|
+
return { valid: false, reason: "missing or invalid 'environment' (expected string)" };
|
|
8326
|
+
}
|
|
8327
|
+
if (typeof o.packedAt !== "string") {
|
|
8328
|
+
return { valid: false, reason: "missing or invalid 'packedAt' (expected string)" };
|
|
8329
|
+
}
|
|
8330
|
+
if (typeof o.revision !== "string") {
|
|
8331
|
+
return { valid: false, reason: "missing or invalid 'revision' (expected string)" };
|
|
8332
|
+
}
|
|
8333
|
+
if (typeof o.ciphertextHash !== "string") {
|
|
8334
|
+
return { valid: false, reason: "missing or invalid 'ciphertextHash' (expected string)" };
|
|
8335
|
+
}
|
|
8336
|
+
if (typeof o.ciphertext !== "string") {
|
|
8337
|
+
return { valid: false, reason: "missing or invalid 'ciphertext' (expected string)" };
|
|
8338
|
+
}
|
|
8339
|
+
if (o.envelope !== void 0 && !isKmsEnvelope2(o.envelope)) {
|
|
8340
|
+
return { valid: false, reason: "invalid 'envelope' (expected KmsEnvelope shape)" };
|
|
8341
|
+
}
|
|
8342
|
+
if (o.expiresAt !== void 0 && typeof o.expiresAt !== "string") {
|
|
8343
|
+
return { valid: false, reason: "invalid 'expiresAt' (expected string)" };
|
|
8344
|
+
}
|
|
8345
|
+
if (o.revokedAt !== void 0 && typeof o.revokedAt !== "string") {
|
|
8346
|
+
return { valid: false, reason: "invalid 'revokedAt' (expected string)" };
|
|
8347
|
+
}
|
|
8348
|
+
if (o.signature !== void 0 && typeof o.signature !== "string") {
|
|
8349
|
+
return { valid: false, reason: "invalid 'signature' (expected string)" };
|
|
8350
|
+
}
|
|
8351
|
+
if (o.signatureAlgorithm !== void 0 && !VALID_SIGNATURE_ALGORITHMS.includes(o.signatureAlgorithm)) {
|
|
8352
|
+
return {
|
|
8353
|
+
valid: false,
|
|
8354
|
+
reason: `invalid 'signatureAlgorithm': expected one of ${VALID_SIGNATURE_ALGORITHMS.join(", ")}`
|
|
8355
|
+
};
|
|
8356
|
+
}
|
|
8357
|
+
return { valid: true, value: o };
|
|
8358
|
+
}
|
|
8359
|
+
function isPackedArtifact(x) {
|
|
8360
|
+
return validatePackedArtifact(x).valid;
|
|
8361
|
+
}
|
|
8362
|
+
function assertPackedArtifact(x, context) {
|
|
8363
|
+
const result = validatePackedArtifact(x);
|
|
8364
|
+
if (!result.valid) {
|
|
8365
|
+
const prefix = context ? `${context}: ` : "";
|
|
8366
|
+
throw new InvalidArtifactError(`${prefix}${result.reason}`);
|
|
8367
|
+
}
|
|
8368
|
+
}
|
|
8369
|
+
|
|
8370
|
+
// src/pack/registry.ts
|
|
8371
|
+
var PackBackendRegistry = class {
|
|
8372
|
+
factories = /* @__PURE__ */ new Map();
|
|
8373
|
+
/**
|
|
8374
|
+
* Register a backend factory under the given id. Throws if a backend
|
|
8375
|
+
* with the same id is already registered — collisions surface as a clear
|
|
8376
|
+
* error rather than a silent overwrite.
|
|
8377
|
+
*/
|
|
8378
|
+
register(id, factory) {
|
|
8379
|
+
if (this.factories.has(id)) {
|
|
8380
|
+
throw new Error(`Pack backend "${id}" is already registered.`);
|
|
8381
|
+
}
|
|
8382
|
+
this.factories.set(id, factory);
|
|
8383
|
+
}
|
|
8384
|
+
/** Whether a backend with the given id has been registered. */
|
|
8385
|
+
has(id) {
|
|
8386
|
+
return this.factories.has(id);
|
|
8387
|
+
}
|
|
8388
|
+
/** Registered backend ids, in registration order. */
|
|
8389
|
+
list() {
|
|
8390
|
+
return [...this.factories.keys()];
|
|
8391
|
+
}
|
|
8392
|
+
/**
|
|
8393
|
+
* Resolve a backend by id. Throws if unknown. Factories may be async so
|
|
8394
|
+
* a plugin package can defer construction (e.g. loading a heavy SDK only
|
|
8395
|
+
* when the backend is actually used).
|
|
8396
|
+
*/
|
|
8397
|
+
async resolve(id) {
|
|
8398
|
+
const factory = this.factories.get(id);
|
|
8399
|
+
if (!factory) {
|
|
8400
|
+
const available = this.list().join(", ") || "(none)";
|
|
8401
|
+
throw new Error(`Unknown pack backend "${id}". Available backends: ${available}`);
|
|
8402
|
+
}
|
|
8403
|
+
return await factory();
|
|
8404
|
+
}
|
|
8405
|
+
};
|
|
8406
|
+
|
|
8407
|
+
// src/pack/backends/json-envelope.ts
|
|
8408
|
+
var JsonEnvelopeBackend = class {
|
|
8409
|
+
id = "json-envelope";
|
|
8410
|
+
description = "Write the Clef JSON artifact envelope to a local file (default).";
|
|
8411
|
+
validateOptions(raw) {
|
|
8412
|
+
const opts = raw;
|
|
8413
|
+
if (opts.signingKey && opts.signingKmsKeyId) {
|
|
8414
|
+
throw new Error(
|
|
8415
|
+
"Cannot specify both signingKey (Ed25519) and signingKmsKeyId (KMS). Choose one."
|
|
8416
|
+
);
|
|
8417
|
+
}
|
|
8418
|
+
if (!opts.outputPath && !opts.output) {
|
|
8419
|
+
throw new Error("json-envelope backend requires an 'outputPath' or 'output' option.");
|
|
8420
|
+
}
|
|
8421
|
+
}
|
|
8422
|
+
async pack(req) {
|
|
8423
|
+
const opts = req.backendOptions;
|
|
8424
|
+
const packer = new ArtifactPacker(
|
|
8425
|
+
req.services.encryption,
|
|
8426
|
+
new MatrixManager(),
|
|
8427
|
+
req.services.kms
|
|
8428
|
+
);
|
|
8429
|
+
const output = opts.output ?? (opts.outputPath ? new FilePackOutput(opts.outputPath) : void 0);
|
|
8430
|
+
const result = await packer.pack(
|
|
8431
|
+
{
|
|
8432
|
+
identity: req.identity,
|
|
8433
|
+
environment: req.environment,
|
|
8434
|
+
outputPath: opts.outputPath,
|
|
8435
|
+
output,
|
|
8436
|
+
ttl: req.ttl,
|
|
8437
|
+
signingKey: opts.signingKey,
|
|
8438
|
+
signingKmsKeyId: opts.signingKmsKeyId
|
|
8439
|
+
},
|
|
8440
|
+
req.manifest,
|
|
8441
|
+
req.repoRoot
|
|
8442
|
+
);
|
|
8443
|
+
return {
|
|
8444
|
+
...result,
|
|
8445
|
+
backend: this.id,
|
|
8446
|
+
details: {
|
|
8447
|
+
outputPath: opts.outputPath ?? null
|
|
8448
|
+
}
|
|
8449
|
+
};
|
|
8450
|
+
}
|
|
8451
|
+
};
|
|
8452
|
+
|
|
7798
8453
|
// src/kms/types.ts
|
|
7799
8454
|
var VALID_KMS_PROVIDERS = ["aws", "gcp", "azure"];
|
|
7800
8455
|
|
|
7801
8456
|
// src/migration/backend.ts
|
|
7802
|
-
import * as
|
|
7803
|
-
import * as
|
|
8457
|
+
import * as path24 from "path";
|
|
8458
|
+
import * as YAML11 from "yaml";
|
|
7804
8459
|
var BACKEND_KEY_FIELDS = {
|
|
7805
8460
|
age: void 0,
|
|
7806
8461
|
awskms: "aws_kms_arn",
|
|
7807
8462
|
gcpkms: "gcp_kms_resource_id",
|
|
7808
8463
|
azurekv: "azure_kv_url",
|
|
7809
|
-
pgp: "pgp_fingerprint"
|
|
8464
|
+
pgp: "pgp_fingerprint",
|
|
8465
|
+
hsm: "pkcs11_uri"
|
|
7810
8466
|
};
|
|
7811
8467
|
var ALL_KEY_FIELDS = Object.values(BACKEND_KEY_FIELDS).filter(
|
|
7812
8468
|
(v) => v !== void 0
|
|
@@ -7916,14 +8572,14 @@ var BackendMigrator = class {
|
|
|
7916
8572
|
await this.tx.run(repoRoot, {
|
|
7917
8573
|
description: environment ? `clef migrate-backend ${target.backend}: ${environment}` : `clef migrate-backend ${target.backend}`,
|
|
7918
8574
|
paths: [
|
|
7919
|
-
...toMigrate.map((c) =>
|
|
8575
|
+
...toMigrate.map((c) => path24.relative(repoRoot, c.filePath)),
|
|
7920
8576
|
CLEF_MANIFEST_FILENAME
|
|
7921
8577
|
],
|
|
7922
8578
|
mutate: async () => {
|
|
7923
8579
|
const doc = readManifestYaml(repoRoot);
|
|
7924
8580
|
this.updateManifestDoc(doc, target, environment);
|
|
7925
8581
|
writeManifestYaml(repoRoot, doc);
|
|
7926
|
-
const updatedManifest =
|
|
8582
|
+
const updatedManifest = YAML11.parse(YAML11.stringify(doc));
|
|
7927
8583
|
for (const cell of toMigrate) {
|
|
7928
8584
|
onProgress?.({
|
|
7929
8585
|
type: "migrate",
|
|
@@ -8014,7 +8670,7 @@ var BackendMigrator = class {
|
|
|
8014
8670
|
};
|
|
8015
8671
|
|
|
8016
8672
|
// src/reset/manager.ts
|
|
8017
|
-
import * as
|
|
8673
|
+
import * as path25 from "path";
|
|
8018
8674
|
var ResetManager = class {
|
|
8019
8675
|
constructor(matrixManager, encryption, schemaValidator, tx) {
|
|
8020
8676
|
this.matrixManager = matrixManager;
|
|
@@ -8039,11 +8695,11 @@ var ResetManager = class {
|
|
|
8039
8695
|
txPaths.push(CLEF_MANIFEST_FILENAME);
|
|
8040
8696
|
}
|
|
8041
8697
|
for (const cell of targetCells) {
|
|
8042
|
-
txPaths.push(
|
|
8698
|
+
txPaths.push(path25.relative(repoRoot, cell.filePath));
|
|
8043
8699
|
const cellKeys = keyPlan.get(cell.namespace) ?? [];
|
|
8044
8700
|
if (cellKeys.length > 0) {
|
|
8045
8701
|
txPaths.push(
|
|
8046
|
-
|
|
8702
|
+
path25.relative(repoRoot, cell.filePath.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml"))
|
|
8047
8703
|
);
|
|
8048
8704
|
}
|
|
8049
8705
|
}
|
|
@@ -8131,7 +8787,7 @@ var ResetManager = class {
|
|
|
8131
8787
|
for (const namespace of namespaces) {
|
|
8132
8788
|
const nsDef = manifest.namespaces.find((n) => n.name === namespace);
|
|
8133
8789
|
if (nsDef?.schema) {
|
|
8134
|
-
const schema = this.schemaValidator.loadSchema(
|
|
8790
|
+
const schema = this.schemaValidator.loadSchema(path25.join(repoRoot, nsDef.schema));
|
|
8135
8791
|
plan.set(namespace, Object.keys(schema.keys));
|
|
8136
8792
|
continue;
|
|
8137
8793
|
}
|
|
@@ -8210,7 +8866,7 @@ function withBackendOverride(manifest, envNames, backend, key) {
|
|
|
8210
8866
|
}
|
|
8211
8867
|
|
|
8212
8868
|
// src/sync/manager.ts
|
|
8213
|
-
import * as
|
|
8869
|
+
import * as path26 from "path";
|
|
8214
8870
|
var SyncManager = class {
|
|
8215
8871
|
constructor(matrixManager, encryption, tx) {
|
|
8216
8872
|
this.matrixManager = matrixManager;
|
|
@@ -8279,7 +8935,7 @@ var SyncManager = class {
|
|
|
8279
8935
|
}
|
|
8280
8936
|
const txPaths = [];
|
|
8281
8937
|
for (const cell of syncPlan.cells) {
|
|
8282
|
-
const rel =
|
|
8938
|
+
const rel = path26.relative(repoRoot, cell.filePath);
|
|
8283
8939
|
txPaths.push(rel);
|
|
8284
8940
|
txPaths.push(rel.replace(/\.enc\.(yaml|json)$/, ".clef-meta.yaml"));
|
|
8285
8941
|
}
|
|
@@ -8318,8 +8974,8 @@ var SyncManager = class {
|
|
|
8318
8974
|
};
|
|
8319
8975
|
|
|
8320
8976
|
// src/policy/parser.ts
|
|
8321
|
-
import * as
|
|
8322
|
-
import * as
|
|
8977
|
+
import * as fs20 from "fs";
|
|
8978
|
+
import * as YAML12 from "yaml";
|
|
8323
8979
|
|
|
8324
8980
|
// src/policy/types.ts
|
|
8325
8981
|
var DEFAULT_POLICY = Object.freeze({
|
|
@@ -8340,7 +8996,7 @@ var PolicyParser = class {
|
|
|
8340
8996
|
parse(filePath) {
|
|
8341
8997
|
let raw;
|
|
8342
8998
|
try {
|
|
8343
|
-
raw =
|
|
8999
|
+
raw = fs20.readFileSync(filePath, "utf-8");
|
|
8344
9000
|
} catch {
|
|
8345
9001
|
throw new PolicyValidationError(`Could not read policy file at '${filePath}'.`);
|
|
8346
9002
|
}
|
|
@@ -8355,7 +9011,7 @@ var PolicyParser = class {
|
|
|
8355
9011
|
parseContent(content) {
|
|
8356
9012
|
let parsed;
|
|
8357
9013
|
try {
|
|
8358
|
-
parsed =
|
|
9014
|
+
parsed = YAML12.parse(content);
|
|
8359
9015
|
} catch {
|
|
8360
9016
|
throw new PolicyValidationError(
|
|
8361
9017
|
"Policy file contains invalid YAML. Check for syntax errors."
|
|
@@ -8368,7 +9024,7 @@ var PolicyParser = class {
|
|
|
8368
9024
|
* not exist. Any other read or validation error throws.
|
|
8369
9025
|
*/
|
|
8370
9026
|
load(filePath) {
|
|
8371
|
-
if (!
|
|
9027
|
+
if (!fs20.existsSync(filePath)) return DEFAULT_POLICY;
|
|
8372
9028
|
return this.parse(filePath);
|
|
8373
9029
|
}
|
|
8374
9030
|
validate(raw) {
|
|
@@ -8436,31 +9092,64 @@ var PolicyEvaluator = class {
|
|
|
8436
9092
|
this.policy = policy;
|
|
8437
9093
|
}
|
|
8438
9094
|
/**
|
|
8439
|
-
* Evaluate a single encrypted file's rotation state.
|
|
9095
|
+
* Evaluate a single encrypted file's per-key rotation state.
|
|
8440
9096
|
*
|
|
8441
9097
|
* @param filePath Repo-relative or absolute path to the encrypted file.
|
|
8442
|
-
* @param environment Environment name
|
|
8443
|
-
*
|
|
8444
|
-
*
|
|
8445
|
-
*
|
|
8446
|
-
*
|
|
9098
|
+
* @param environment Environment name; selects per-env overrides.
|
|
9099
|
+
* @param metadata SOPS metadata for the file (carries last_modified,
|
|
9100
|
+
* backend, recipients). The evaluator does not read
|
|
9101
|
+
* `last_modified` for the policy gate — it is echoed
|
|
9102
|
+
* into the output for audit consumers only.
|
|
9103
|
+
* @param keys Plaintext key names present in the cipher, enumerated
|
|
9104
|
+
* from the unencrypted YAML top-level keys (no decrypt
|
|
9105
|
+
* required since SOPS stores key names in plaintext).
|
|
9106
|
+
* @param rotations Rotation records from `.clef-meta.yaml`. Records for
|
|
9107
|
+
* keys not in `keys` are ignored (those are orphans;
|
|
9108
|
+
* lint surfaces them as a warning).
|
|
9109
|
+
* @param now Reference time. Inject for deterministic tests.
|
|
8447
9110
|
*/
|
|
8448
|
-
evaluateFile(filePath, environment, metadata, now = /* @__PURE__ */ new Date()) {
|
|
9111
|
+
evaluateFile(filePath, environment, metadata, keys, rotations, now = /* @__PURE__ */ new Date()) {
|
|
8449
9112
|
const maxAgeDays = this.resolveMaxAgeDays(environment);
|
|
8450
|
-
const
|
|
8451
|
-
const
|
|
8452
|
-
|
|
9113
|
+
const byKey = new Map(rotations.map((r) => [r.key, r]));
|
|
9114
|
+
const keyStatuses = keys.map(
|
|
9115
|
+
(key) => this.evaluateKey(key, byKey.get(key), maxAgeDays, now)
|
|
9116
|
+
);
|
|
8453
9117
|
return {
|
|
8454
9118
|
path: filePath,
|
|
8455
9119
|
environment,
|
|
8456
9120
|
backend: metadata.backend,
|
|
8457
9121
|
recipients: metadata.recipients,
|
|
8458
9122
|
last_modified: metadata.lastModified.toISOString(),
|
|
8459
|
-
// Treat a missing `lastModifiedPresent` as `true` — the field is
|
|
8460
|
-
// optional on SopsMetadata and only `parseMetadataFromFile` knows
|
|
8461
|
-
// authoritatively whether the underlying file carried `sops.lastmodified`.
|
|
8462
|
-
// Hand-constructed metadata is assumed trustworthy.
|
|
8463
9123
|
last_modified_known: metadata.lastModifiedPresent !== false,
|
|
9124
|
+
keys: keyStatuses,
|
|
9125
|
+
// Cell-level compliance is the AND of per-key verdicts. An empty
|
|
9126
|
+
// `keys` array (cell with no secrets) is vacuously compliant.
|
|
9127
|
+
compliant: keyStatuses.every((k) => k.compliant)
|
|
9128
|
+
};
|
|
9129
|
+
}
|
|
9130
|
+
evaluateKey(key, record, maxAgeDays, now) {
|
|
9131
|
+
if (!record) {
|
|
9132
|
+
return {
|
|
9133
|
+
key,
|
|
9134
|
+
last_rotated_at: null,
|
|
9135
|
+
last_rotated_known: false,
|
|
9136
|
+
rotated_by: null,
|
|
9137
|
+
rotation_count: 0,
|
|
9138
|
+
rotation_due: null,
|
|
9139
|
+
rotation_overdue: false,
|
|
9140
|
+
days_overdue: 0,
|
|
9141
|
+
compliant: false
|
|
9142
|
+
};
|
|
9143
|
+
}
|
|
9144
|
+
const rotationDue = new Date(record.lastRotatedAt.getTime() + maxAgeDays * MS_PER_DAY);
|
|
9145
|
+
const rotationOverdue = now.getTime() > rotationDue.getTime();
|
|
9146
|
+
const daysOverdue = rotationOverdue ? Math.floor((now.getTime() - rotationDue.getTime()) / MS_PER_DAY) : 0;
|
|
9147
|
+
return {
|
|
9148
|
+
key,
|
|
9149
|
+
last_rotated_at: record.lastRotatedAt.toISOString(),
|
|
9150
|
+
last_rotated_known: true,
|
|
9151
|
+
rotated_by: record.rotatedBy,
|
|
9152
|
+
rotation_count: record.rotationCount,
|
|
8464
9153
|
rotation_due: rotationDue.toISOString(),
|
|
8465
9154
|
rotation_overdue: rotationOverdue,
|
|
8466
9155
|
days_overdue: daysOverdue,
|
|
@@ -8516,10 +9205,11 @@ var ComplianceGenerator = class {
|
|
|
8516
9205
|
return `sha256:${createHash3("sha256").update(canonicalJson(policy)).digest("hex")}`;
|
|
8517
9206
|
}
|
|
8518
9207
|
buildSummary(scan, lint, files) {
|
|
9208
|
+
const rotationOverdue = files.filter((f) => !f.compliant).length;
|
|
8519
9209
|
return {
|
|
8520
9210
|
total_files: files.length,
|
|
8521
9211
|
compliant: files.filter((f) => f.compliant).length,
|
|
8522
|
-
rotation_overdue:
|
|
9212
|
+
rotation_overdue: rotationOverdue,
|
|
8523
9213
|
scan_violations: scan.matches.length,
|
|
8524
9214
|
lint_errors: lint.issues.filter((i) => i.severity === "error").length
|
|
8525
9215
|
};
|
|
@@ -8527,13 +9217,13 @@ var ComplianceGenerator = class {
|
|
|
8527
9217
|
};
|
|
8528
9218
|
|
|
8529
9219
|
// src/compliance/run.ts
|
|
8530
|
-
import * as
|
|
9220
|
+
import * as path27 from "path";
|
|
8531
9221
|
var UNKNOWN = "unknown";
|
|
8532
9222
|
async function runCompliance(opts) {
|
|
8533
9223
|
const start = Date.now();
|
|
8534
9224
|
const repoRoot = opts.repoRoot ?? process.cwd();
|
|
8535
|
-
const manifestPath = opts.manifestPath ??
|
|
8536
|
-
const policyPath = opts.policyPath ??
|
|
9225
|
+
const manifestPath = opts.manifestPath ?? path27.join(repoRoot, "clef.yaml");
|
|
9226
|
+
const policyPath = opts.policyPath ?? path27.join(repoRoot, CLEF_POLICY_FILENAME);
|
|
8537
9227
|
const include = {
|
|
8538
9228
|
scan: opts.include?.scan ?? true,
|
|
8539
9229
|
lint: opts.include?.lint ?? true,
|
|
@@ -8542,7 +9232,7 @@ async function runCompliance(opts) {
|
|
|
8542
9232
|
const now = opts.now ?? /* @__PURE__ */ new Date();
|
|
8543
9233
|
const manifest = new ManifestParser().parse(manifestPath);
|
|
8544
9234
|
const policy = opts.policy ?? new PolicyParser().load(policyPath);
|
|
8545
|
-
const sopsClient = new SopsClient(opts.runner);
|
|
9235
|
+
const sopsClient = new SopsClient(opts.runner, opts.ageKeyFile, opts.ageKey, opts.sopsPath);
|
|
8546
9236
|
const matrixManager = new MatrixManager();
|
|
8547
9237
|
const schemaValidator = new SchemaValidator();
|
|
8548
9238
|
const [sha, repo, files, scanResult, lintResult] = await Promise.all([
|
|
@@ -8560,12 +9250,13 @@ async function runCompliance(opts) {
|
|
|
8560
9250
|
include.scan ? new ScanRunner(opts.runner).scan(repoRoot, manifest) : Promise.resolve(emptyScan()),
|
|
8561
9251
|
include.lint ? new LintRunner(matrixManager, schemaValidator, sopsClient).run(manifest, repoRoot) : Promise.resolve(emptyLint())
|
|
8562
9252
|
]);
|
|
9253
|
+
const adjustedLint = downgradeDecryptIssues(lintResult);
|
|
8563
9254
|
const document = new ComplianceGenerator().generate({
|
|
8564
9255
|
sha,
|
|
8565
9256
|
repo,
|
|
8566
9257
|
policy,
|
|
8567
9258
|
scanResult,
|
|
8568
|
-
lintResult,
|
|
9259
|
+
lintResult: adjustedLint,
|
|
8569
9260
|
files,
|
|
8570
9261
|
now
|
|
8571
9262
|
});
|
|
@@ -8578,8 +9269,10 @@ async function evaluateMatrix(args) {
|
|
|
8578
9269
|
return Promise.all(
|
|
8579
9270
|
cells.map(async (cell) => {
|
|
8580
9271
|
const metadata = await args.sopsClient.getMetadata(cell.filePath);
|
|
8581
|
-
const relPath =
|
|
8582
|
-
|
|
9272
|
+
const relPath = path27.relative(args.repoRoot, cell.filePath).replace(/\\/g, "/");
|
|
9273
|
+
const keys = readSopsKeyNames(cell.filePath) ?? [];
|
|
9274
|
+
const rotations = await getRotations(cell.filePath);
|
|
9275
|
+
return evaluator.evaluateFile(relPath, cell.environment, metadata, keys, rotations, args.now);
|
|
8583
9276
|
})
|
|
8584
9277
|
);
|
|
8585
9278
|
}
|
|
@@ -8600,6 +9293,21 @@ function emptyScan() {
|
|
|
8600
9293
|
function emptyLint() {
|
|
8601
9294
|
return { issues: [], fileCount: 0, pendingCount: 0 };
|
|
8602
9295
|
}
|
|
9296
|
+
function downgradeDecryptIssues(result) {
|
|
9297
|
+
return {
|
|
9298
|
+
...result,
|
|
9299
|
+
issues: result.issues.map((issue) => {
|
|
9300
|
+
if (issue.category === "sops" && issue.message.startsWith("Failed to decrypt")) {
|
|
9301
|
+
return {
|
|
9302
|
+
...issue,
|
|
9303
|
+
severity: "info",
|
|
9304
|
+
message: `File not decryptable in this environment (compliance runs without keys). Original check: ${issue.message}`
|
|
9305
|
+
};
|
|
9306
|
+
}
|
|
9307
|
+
return issue;
|
|
9308
|
+
})
|
|
9309
|
+
};
|
|
9310
|
+
}
|
|
8603
9311
|
async function detectSha(runner, repoRoot) {
|
|
8604
9312
|
const env = process.env;
|
|
8605
9313
|
const fromEnv = env.GITHUB_SHA ?? env.CI_COMMIT_SHA ?? env.BITBUCKET_COMMIT ?? env.CIRCLE_SHA1 ?? env.BUILD_VCS_NUMBER;
|
|
@@ -8639,11 +9347,14 @@ export {
|
|
|
8639
9347
|
GitIntegration,
|
|
8640
9348
|
GitOperationError,
|
|
8641
9349
|
ImportRunner,
|
|
9350
|
+
InvalidArtifactError,
|
|
9351
|
+
JsonEnvelopeBackend,
|
|
8642
9352
|
LintRunner,
|
|
8643
9353
|
ManifestParser,
|
|
8644
9354
|
ManifestValidationError,
|
|
8645
9355
|
MatrixManager,
|
|
8646
9356
|
MemoryPackOutput,
|
|
9357
|
+
PackBackendRegistry,
|
|
8647
9358
|
PolicyEvaluator,
|
|
8648
9359
|
PolicyParser,
|
|
8649
9360
|
PolicyValidationError,
|
|
@@ -8672,6 +9383,7 @@ export {
|
|
|
8672
9383
|
TransactionPreflightError,
|
|
8673
9384
|
TransactionRollbackError,
|
|
8674
9385
|
VALID_KMS_PROVIDERS,
|
|
9386
|
+
assertPackedArtifact,
|
|
8675
9387
|
assertSops,
|
|
8676
9388
|
buildSigningPayload,
|
|
8677
9389
|
checkAll,
|
|
@@ -8687,8 +9399,11 @@ export {
|
|
|
8687
9399
|
generateRandomValue,
|
|
8688
9400
|
generateSigningKeyPair,
|
|
8689
9401
|
getPendingKeys,
|
|
9402
|
+
getRotations,
|
|
9403
|
+
isClefHsmArn,
|
|
8690
9404
|
isHighEntropy,
|
|
8691
9405
|
isKmsEnvelope,
|
|
9406
|
+
isPackedArtifact,
|
|
8692
9407
|
isPending,
|
|
8693
9408
|
keyPreview,
|
|
8694
9409
|
loadIgnoreRules,
|
|
@@ -8698,19 +9413,26 @@ export {
|
|
|
8698
9413
|
markPendingWithRetry,
|
|
8699
9414
|
markResolved,
|
|
8700
9415
|
matchPatterns,
|
|
9416
|
+
mergeMetadataContents,
|
|
9417
|
+
mergeMetadataFiles,
|
|
8701
9418
|
metadataPath,
|
|
8702
9419
|
parse9 as parse,
|
|
8703
9420
|
parseDotenv,
|
|
8704
9421
|
parseIgnoreContent,
|
|
8705
9422
|
parseJson,
|
|
8706
9423
|
parseYaml,
|
|
9424
|
+
pkcs11UriToSyntheticArn,
|
|
8707
9425
|
readManifestYaml,
|
|
9426
|
+
recordRotation,
|
|
8708
9427
|
redactValue,
|
|
8709
9428
|
removeRequest as removeAccessRequest,
|
|
9429
|
+
removeRotation,
|
|
8710
9430
|
requestsFilePath,
|
|
9431
|
+
resetKeyserviceResolution,
|
|
8711
9432
|
resetSopsResolution,
|
|
8712
9433
|
resolveBackendConfig,
|
|
8713
9434
|
resolveIdentitySecrets,
|
|
9435
|
+
resolveKeyservicePath,
|
|
8714
9436
|
resolveRecipientsForEnvironment,
|
|
8715
9437
|
resolveSopsPath,
|
|
8716
9438
|
runCompliance,
|
|
@@ -8721,8 +9443,12 @@ export {
|
|
|
8721
9443
|
shouldIgnoreMatch,
|
|
8722
9444
|
signEd25519,
|
|
8723
9445
|
signKms,
|
|
9446
|
+
spawnKeyservice,
|
|
9447
|
+
syntheticArnToPkcs11Uri,
|
|
9448
|
+
tryBundledKeyservice,
|
|
8724
9449
|
upsertRequest,
|
|
8725
9450
|
validateAgePublicKey,
|
|
9451
|
+
validatePackedArtifact,
|
|
8726
9452
|
validateResetScope,
|
|
8727
9453
|
verifySignature,
|
|
8728
9454
|
writeManifestYaml,
|