@clef-sh/cli 0.1.8-beta.52 → 0.1.9-beta.57

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/index.mjs CHANGED
@@ -977,7 +977,7 @@ var require_command = __commonJS({
977
977
  var EventEmitter = __require("node:events").EventEmitter;
978
978
  var childProcess = __require("node:child_process");
979
979
  var path44 = __require("node:path");
980
- var fs27 = __require("node:fs");
980
+ var fs26 = __require("node:fs");
981
981
  var process2 = __require("node:process");
982
982
  var { Argument: Argument2, humanReadableArgName } = require_argument();
983
983
  var { CommanderError: CommanderError2 } = require_error();
@@ -1910,10 +1910,10 @@ Expecting one of '${allowedValues.join("', '")}'`);
1910
1910
  const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
1911
1911
  function findFile(baseDir, baseName) {
1912
1912
  const localBin = path44.resolve(baseDir, baseName);
1913
- if (fs27.existsSync(localBin)) return localBin;
1913
+ if (fs26.existsSync(localBin)) return localBin;
1914
1914
  if (sourceExt.includes(path44.extname(baseName))) return void 0;
1915
1915
  const foundExt = sourceExt.find(
1916
- (ext) => fs27.existsSync(`${localBin}${ext}`)
1916
+ (ext) => fs26.existsSync(`${localBin}${ext}`)
1917
1917
  );
1918
1918
  if (foundExt) return `${localBin}${foundExt}`;
1919
1919
  return void 0;
@@ -1925,7 +1925,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
1925
1925
  if (this._scriptPath) {
1926
1926
  let resolvedScriptPath;
1927
1927
  try {
1928
- resolvedScriptPath = fs27.realpathSync(this._scriptPath);
1928
+ resolvedScriptPath = fs26.realpathSync(this._scriptPath);
1929
1929
  } catch (err) {
1930
1930
  resolvedScriptPath = this._scriptPath;
1931
1931
  }
@@ -9876,14 +9876,14 @@ var require_parser = __commonJS({
9876
9876
  case "scalar":
9877
9877
  case "single-quoted-scalar":
9878
9878
  case "double-quoted-scalar": {
9879
- const fs27 = this.flowScalar(this.type);
9879
+ const fs26 = this.flowScalar(this.type);
9880
9880
  if (atNextItem || it.value) {
9881
- map.items.push({ start, key: fs27, sep: [] });
9881
+ map.items.push({ start, key: fs26, sep: [] });
9882
9882
  this.onKeyLine = true;
9883
9883
  } else if (it.sep) {
9884
- this.stack.push(fs27);
9884
+ this.stack.push(fs26);
9885
9885
  } else {
9886
- Object.assign(it, { key: fs27, sep: [] });
9886
+ Object.assign(it, { key: fs26, sep: [] });
9887
9887
  this.onKeyLine = true;
9888
9888
  }
9889
9889
  return;
@@ -10011,13 +10011,13 @@ var require_parser = __commonJS({
10011
10011
  case "scalar":
10012
10012
  case "single-quoted-scalar":
10013
10013
  case "double-quoted-scalar": {
10014
- const fs27 = this.flowScalar(this.type);
10014
+ const fs26 = this.flowScalar(this.type);
10015
10015
  if (!it || it.value)
10016
- fc.items.push({ start: [], key: fs27, sep: [] });
10016
+ fc.items.push({ start: [], key: fs26, sep: [] });
10017
10017
  else if (it.sep)
10018
- this.stack.push(fs27);
10018
+ this.stack.push(fs26);
10019
10019
  else
10020
- Object.assign(it, { key: fs27, sep: [] });
10020
+ Object.assign(it, { key: fs26, sep: [] });
10021
10021
  return;
10022
10022
  }
10023
10023
  case "flow-map-end":
@@ -10225,7 +10225,7 @@ var require_public_api = __commonJS({
10225
10225
  }
10226
10226
  return doc;
10227
10227
  }
10228
- function parse16(src, reviver, options) {
10228
+ function parse15(src, reviver, options) {
10229
10229
  let _reviver = void 0;
10230
10230
  if (typeof reviver === "function") {
10231
10231
  _reviver = reviver;
@@ -10266,7 +10266,7 @@ var require_public_api = __commonJS({
10266
10266
  return value.toString(options);
10267
10267
  return new Document.Document(value, _replacer, options).toString(options);
10268
10268
  }
10269
- exports.parse = parse16;
10269
+ exports.parse = parse15;
10270
10270
  exports.parseAllDocuments = parseAllDocuments;
10271
10271
  exports.parseDocument = parseDocument;
10272
10272
  exports.stringify = stringify7;
@@ -10747,6 +10747,12 @@ var init_parser = __esm({
10747
10747
  "namespaces"
10748
10748
  );
10749
10749
  }
10750
+ if (!ENV_NAME_PATTERN.test(nsObj.name)) {
10751
+ throw new ManifestValidationError(
10752
+ `Namespace name '${nsObj.name}' is invalid. Names must start with a lowercase letter and contain only lowercase letters, digits, hyphens, and underscores.`,
10753
+ "namespaces"
10754
+ );
10755
+ }
10750
10756
  if (!nsObj.description || typeof nsObj.description !== "string") {
10751
10757
  throw new ManifestValidationError(
10752
10758
  `Namespace '${nsObj.name}' is missing a 'description' string.`,
@@ -10847,9 +10853,9 @@ var init_parser = __esm({
10847
10853
  );
10848
10854
  }
10849
10855
  const siName = siObj.name;
10850
- if (!siObj.description || typeof siObj.description !== "string") {
10856
+ if (siObj.description != null && typeof siObj.description !== "string") {
10851
10857
  throw new ManifestValidationError(
10852
- `Service identity '${siName}' is missing a 'description' string.`,
10858
+ `Service identity '${siName}' has a non-string 'description'.`,
10853
10859
  "service_identities"
10854
10860
  );
10855
10861
  }
@@ -10964,7 +10970,7 @@ var init_parser = __esm({
10964
10970
  }
10965
10971
  return {
10966
10972
  name: siName,
10967
- description: siObj.description,
10973
+ description: siObj.description ?? "",
10968
10974
  namespaces: siObj.namespaces,
10969
10975
  environments: parsedEnvs
10970
10976
  };
@@ -11164,7 +11170,11 @@ var init_scanner = __esm({
11164
11170
  init_patterns();
11165
11171
  init_ignore();
11166
11172
  ALWAYS_SKIP_EXTENSIONS = [".enc.yaml", ".enc.json"];
11167
- ALWAYS_SKIP_NAMES = [".clef-meta.yaml"];
11173
+ ALWAYS_SKIP_NAMES = [
11174
+ ".clef-meta.yaml",
11175
+ ".sops.yaml"
11176
+ // contains age public keys and KMS ARNs — configuration, not secrets
11177
+ ];
11168
11178
  ALWAYS_SKIP_DIRS = ["node_modules", ".git"];
11169
11179
  MAX_FILE_SIZE = 1024 * 1024;
11170
11180
  ScanRunner = class {
@@ -11460,15 +11470,36 @@ var init_metadata = __esm({
11460
11470
  }
11461
11471
  });
11462
11472
 
11463
- // ../core/src/matrix/manager.ts
11473
+ // ../core/src/sops/keys.ts
11464
11474
  import * as fs5 from "fs";
11475
+ function readSopsKeyNames(filePath) {
11476
+ try {
11477
+ const raw = fs5.readFileSync(filePath, "utf-8");
11478
+ const parsed = YAML3.parse(raw);
11479
+ if (parsed === null || parsed === void 0 || typeof parsed !== "object") return null;
11480
+ return Object.keys(parsed).filter((k) => k !== "sops");
11481
+ } catch {
11482
+ return null;
11483
+ }
11484
+ }
11485
+ var YAML3;
11486
+ var init_keys = __esm({
11487
+ "../core/src/sops/keys.ts"() {
11488
+ "use strict";
11489
+ YAML3 = __toESM(require_dist());
11490
+ }
11491
+ });
11492
+
11493
+ // ../core/src/matrix/manager.ts
11494
+ import * as fs6 from "fs";
11465
11495
  import * as path4 from "path";
11466
- var YAML3, MatrixManager;
11496
+ var YAML4, MatrixManager;
11467
11497
  var init_manager = __esm({
11468
11498
  "../core/src/matrix/manager.ts"() {
11469
11499
  "use strict";
11470
- YAML3 = __toESM(require_dist());
11500
+ YAML4 = __toESM(require_dist());
11471
11501
  init_metadata();
11502
+ init_keys();
11472
11503
  MatrixManager = class {
11473
11504
  /**
11474
11505
  * Build the full grid of {@link MatrixCell} objects from the manifest.
@@ -11487,7 +11518,7 @@ var init_manager = __esm({
11487
11518
  namespace: ns.name,
11488
11519
  environment: env.name,
11489
11520
  filePath,
11490
- exists: fs5.existsSync(filePath)
11521
+ exists: fs6.existsSync(filePath)
11491
11522
  });
11492
11523
  }
11493
11524
  }
@@ -11511,8 +11542,8 @@ var init_manager = __esm({
11511
11542
  */
11512
11543
  async scaffoldCell(cell, sopsClient, manifest) {
11513
11544
  const dir = path4.dirname(cell.filePath);
11514
- if (!fs5.existsSync(dir)) {
11515
- fs5.mkdirSync(dir, { recursive: true });
11545
+ if (!fs6.existsSync(dir)) {
11546
+ fs6.mkdirSync(dir, { recursive: true });
11516
11547
  }
11517
11548
  await sopsClient.encrypt(cell.filePath, {}, manifest, cell.environment);
11518
11549
  }
@@ -11581,22 +11612,15 @@ var init_manager = __esm({
11581
11612
  * SOPS stores key names in plaintext — only values are encrypted.
11582
11613
  */
11583
11614
  readKeyNames(filePath) {
11584
- try {
11585
- const raw = fs5.readFileSync(filePath, "utf-8");
11586
- const parsed = YAML3.parse(raw);
11587
- if (!parsed || typeof parsed !== "object") return [];
11588
- return Object.keys(parsed).filter((k) => k !== "sops");
11589
- } catch {
11590
- return [];
11591
- }
11615
+ return readSopsKeyNames(filePath) ?? [];
11592
11616
  }
11593
11617
  /**
11594
11618
  * Read the lastModified timestamp from SOPS metadata without decryption.
11595
11619
  */
11596
11620
  readLastModified(filePath) {
11597
11621
  try {
11598
- const raw = fs5.readFileSync(filePath, "utf-8");
11599
- const parsed = YAML3.parse(raw);
11622
+ const raw = fs6.readFileSync(filePath, "utf-8");
11623
+ const parsed = YAML4.parse(raw);
11600
11624
  const sops = parsed?.sops;
11601
11625
  if (sops?.lastmodified) return new Date(String(sops.lastmodified));
11602
11626
  return null;
@@ -11619,12 +11643,12 @@ var init_manager = __esm({
11619
11643
  });
11620
11644
 
11621
11645
  // ../core/src/schema/validator.ts
11622
- import * as fs6 from "fs";
11623
- var YAML4, SchemaValidator;
11646
+ import * as fs7 from "fs";
11647
+ var YAML5, SchemaValidator;
11624
11648
  var init_validator2 = __esm({
11625
11649
  "../core/src/schema/validator.ts"() {
11626
11650
  "use strict";
11627
- YAML4 = __toESM(require_dist());
11651
+ YAML5 = __toESM(require_dist());
11628
11652
  init_types();
11629
11653
  SchemaValidator = class {
11630
11654
  /**
@@ -11637,13 +11661,13 @@ var init_validator2 = __esm({
11637
11661
  loadSchema(filePath) {
11638
11662
  let raw;
11639
11663
  try {
11640
- raw = fs6.readFileSync(filePath, "utf-8");
11664
+ raw = fs7.readFileSync(filePath, "utf-8");
11641
11665
  } catch {
11642
11666
  throw new SchemaLoadError(`Could not read schema file at '${filePath}'.`, filePath);
11643
11667
  }
11644
11668
  let parsed;
11645
11669
  try {
11646
- parsed = YAML4.parse(raw);
11670
+ parsed = YAML5.parse(raw);
11647
11671
  } catch {
11648
11672
  throw new SchemaLoadError(`Schema file '${filePath}' contains invalid YAML.`, filePath);
11649
11673
  }
@@ -11958,7 +11982,7 @@ ${details}`
11958
11982
  });
11959
11983
 
11960
11984
  // ../core/src/git/integration.ts
11961
- import * as fs7 from "fs";
11985
+ import * as fs8 from "fs";
11962
11986
  import * as path7 from "path";
11963
11987
  var PRE_COMMIT_HOOK, GitIntegration;
11964
11988
  var init_integration = __esm({
@@ -12172,14 +12196,14 @@ exit $EXIT_CODE
12172
12196
  });
12173
12197
  const gitConfig = configResult.exitCode === 0 && configResult.stdout.trim().length > 0;
12174
12198
  const attrFilePath = path7.join(repoRoot, ".gitattributes");
12175
- const attrContent = fs7.existsSync(attrFilePath) ? fs7.readFileSync(attrFilePath, "utf-8") : "";
12199
+ const attrContent = fs8.existsSync(attrFilePath) ? fs8.readFileSync(attrFilePath, "utf-8") : "";
12176
12200
  const gitattributes = attrContent.includes("merge=sops");
12177
12201
  return { gitConfig, gitattributes };
12178
12202
  }
12179
12203
  async ensureGitattributes(repoRoot) {
12180
12204
  const attrPath = path7.join(repoRoot, ".gitattributes");
12181
12205
  const mergeRule = "*.enc.yaml merge=sops\n*.enc.json merge=sops";
12182
- const existing = fs7.existsSync(attrPath) ? fs7.readFileSync(attrPath, "utf-8") : "";
12206
+ const existing = fs8.existsSync(attrPath) ? fs8.readFileSync(attrPath, "utf-8") : "";
12183
12207
  if (existing.includes("merge=sops")) {
12184
12208
  return;
12185
12209
  }
@@ -12229,7 +12253,7 @@ ${mergeRule}
12229
12253
  });
12230
12254
 
12231
12255
  // ../core/src/sops/bundled.ts
12232
- import * as fs8 from "fs";
12256
+ import * as fs9 from "fs";
12233
12257
  import * as path8 from "path";
12234
12258
  function tryBundled() {
12235
12259
  const platform = process.platform;
@@ -12244,7 +12268,7 @@ function tryBundled() {
12244
12268
  const packageMain = __require.resolve(`${packageName}/package.json`);
12245
12269
  const packageDir = path8.dirname(packageMain);
12246
12270
  const binPath = path8.join(packageDir, "bin", binName);
12247
- return fs8.existsSync(binPath) ? binPath : null;
12271
+ return fs9.existsSync(binPath) ? binPath : null;
12248
12272
  } catch {
12249
12273
  return null;
12250
12274
  }
@@ -12256,7 +12280,7 @@ var init_bundled = __esm({
12256
12280
  });
12257
12281
 
12258
12282
  // ../core/src/sops/resolver.ts
12259
- import * as fs9 from "fs";
12283
+ import * as fs10 from "fs";
12260
12284
  import * as path9 from "path";
12261
12285
  function validateSopsPath(candidate) {
12262
12286
  if (!path9.isAbsolute(candidate)) {
@@ -12274,7 +12298,7 @@ function resolveSopsPath() {
12274
12298
  const envPath = process.env.CLEF_SOPS_PATH?.trim();
12275
12299
  if (envPath) {
12276
12300
  validateSopsPath(envPath);
12277
- if (!fs9.existsSync(envPath)) {
12301
+ if (!fs10.existsSync(envPath)) {
12278
12302
  throw new Error(`CLEF_SOPS_PATH points to '${envPath}' but the file does not exist.`);
12279
12303
  }
12280
12304
  cached = { path: envPath, source: "env" };
@@ -19693,7 +19717,7 @@ var init_keygen = __esm({
19693
19717
  });
19694
19718
 
19695
19719
  // ../core/src/sops/client.ts
19696
- import * as fs10 from "fs";
19720
+ import * as fs11 from "fs";
19697
19721
  import * as net from "net";
19698
19722
  import { randomBytes as randomBytes7 } from "crypto";
19699
19723
  function formatFromPath(filePath) {
@@ -19717,11 +19741,11 @@ function openWindowsInputPipe(content) {
19717
19741
  });
19718
19742
  });
19719
19743
  }
19720
- var YAML5, SopsClient;
19744
+ var YAML6, SopsClient;
19721
19745
  var init_client = __esm({
19722
19746
  "../core/src/sops/client.ts"() {
19723
19747
  "use strict";
19724
- YAML5 = __toESM(require_dist());
19748
+ YAML6 = __toESM(require_dist());
19725
19749
  init_types();
19726
19750
  init_checker();
19727
19751
  init_keygen();
@@ -19786,7 +19810,7 @@ var init_client = __esm({
19786
19810
  }
19787
19811
  let parsed;
19788
19812
  try {
19789
- parsed = YAML5.parse(result.stdout) ?? {};
19813
+ parsed = YAML6.parse(result.stdout) ?? {};
19790
19814
  } catch {
19791
19815
  throw new SopsDecryptionError(
19792
19816
  `Decrypted content of '${filePath}' is not valid YAML.`,
@@ -19813,7 +19837,7 @@ var init_client = __esm({
19813
19837
  async encrypt(filePath, values, manifest, environment) {
19814
19838
  await assertSops(this.runner, this.sopsCommand);
19815
19839
  const fmt = formatFromPath(filePath);
19816
- const content = fmt === "json" ? JSON.stringify(values, null, 2) : YAML5.stringify(values);
19840
+ const content = fmt === "json" ? JSON.stringify(values, null, 2) : YAML6.stringify(values);
19817
19841
  const args = this.buildEncryptArgs(filePath, manifest, environment);
19818
19842
  const env = this.buildSopsEnv();
19819
19843
  let inputArg;
@@ -19857,7 +19881,7 @@ var init_client = __esm({
19857
19881
  );
19858
19882
  }
19859
19883
  try {
19860
- fs10.writeFileSync(filePath, result.stdout);
19884
+ fs11.writeFileSync(filePath, result.stdout);
19861
19885
  } catch {
19862
19886
  throw new SopsEncryptionError(`Failed to write encrypted data to '${filePath}'.`, filePath);
19863
19887
  }
@@ -19870,21 +19894,7 @@ var init_client = __esm({
19870
19894
  * @throws {@link SopsEncryptionError} On failure.
19871
19895
  */
19872
19896
  async reEncrypt(filePath, newKey) {
19873
- await assertSops(this.runner, this.sopsCommand);
19874
- const env = this.buildSopsEnv();
19875
- const result = await this.runner.run(
19876
- this.sopsCommand,
19877
- ["rotate", "-i", "--add-age", newKey, filePath],
19878
- {
19879
- ...env ? { env } : {}
19880
- }
19881
- );
19882
- if (result.exitCode !== 0) {
19883
- throw new SopsEncryptionError(
19884
- `Failed to re-encrypt '${filePath}': ${result.stderr.trim()}`,
19885
- filePath
19886
- );
19887
- }
19897
+ await this.addRecipient(filePath, newKey);
19888
19898
  }
19889
19899
  /**
19890
19900
  * Add an age recipient to an existing SOPS file.
@@ -19987,7 +19997,7 @@ var init_client = __esm({
19987
19997
  if (!this.ageKey && !this.ageKeyFile) return "key-not-found";
19988
19998
  let keyContent;
19989
19999
  try {
19990
- keyContent = this.ageKey ?? fs10.readFileSync(this.ageKeyFile, "utf-8");
20000
+ keyContent = this.ageKey ?? fs11.readFileSync(this.ageKeyFile, "utf-8");
19991
20001
  } catch {
19992
20002
  return "key-not-found";
19993
20003
  }
@@ -20004,7 +20014,7 @@ var init_client = __esm({
20004
20014
  parseMetadataFromFile(filePath) {
20005
20015
  let content;
20006
20016
  try {
20007
- content = fs10.readFileSync(filePath, "utf-8");
20017
+ content = fs11.readFileSync(filePath, "utf-8");
20008
20018
  } catch {
20009
20019
  throw new SopsDecryptionError(
20010
20020
  `Could not read file '${filePath}' to extract SOPS metadata.`,
@@ -20013,7 +20023,7 @@ var init_client = __esm({
20013
20023
  }
20014
20024
  let parsed;
20015
20025
  try {
20016
- parsed = YAML5.parse(content);
20026
+ parsed = YAML6.parse(content);
20017
20027
  } catch {
20018
20028
  throw new SopsDecryptionError(
20019
20029
  `File '${filePath}' is not valid YAML. Cannot extract SOPS metadata.`,
@@ -20481,7 +20491,7 @@ function detectFormat(filePath, content) {
20481
20491
  } catch {
20482
20492
  }
20483
20493
  try {
20484
- const parsed = YAML6.parse(content);
20494
+ const parsed = YAML7.parse(content);
20485
20495
  if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
20486
20496
  return "yaml";
20487
20497
  }
@@ -20562,7 +20572,7 @@ function parseJson(content) {
20562
20572
  function parseYaml(content) {
20563
20573
  let parsed;
20564
20574
  try {
20565
- parsed = YAML6.parse(content);
20575
+ parsed = YAML7.parse(content);
20566
20576
  } catch (err) {
20567
20577
  throw new Error(`Invalid YAML: ${err.message}`);
20568
20578
  }
@@ -20596,7 +20606,7 @@ function parseYaml(content) {
20596
20606
  }
20597
20607
  return { pairs, format: "yaml", skipped, warnings };
20598
20608
  }
20599
- function parse7(content, format, filePath) {
20609
+ function parse8(content, format, filePath) {
20600
20610
  const resolved = format === "auto" ? detectFormat(filePath ?? "", content) : format;
20601
20611
  switch (resolved) {
20602
20612
  case "dotenv":
@@ -20607,11 +20617,11 @@ function parse7(content, format, filePath) {
20607
20617
  return parseYaml(content);
20608
20618
  }
20609
20619
  }
20610
- var YAML6;
20620
+ var YAML7;
20611
20621
  var init_parsers = __esm({
20612
20622
  "../core/src/import/parsers.ts"() {
20613
20623
  "use strict";
20614
- YAML6 = __toESM(require_dist());
20624
+ YAML7 = __toESM(require_dist());
20615
20625
  }
20616
20626
  });
20617
20627
 
@@ -20642,7 +20652,7 @@ var init_import = __esm({
20642
20652
  repoRoot,
20643
20653
  manifest.file_pattern.replace("{namespace}", ns).replace("{environment}", env)
20644
20654
  );
20645
- const parsed = parse7(content, options.format ?? "auto", sourcePath ?? "");
20655
+ const parsed = parse8(content, options.format ?? "auto", sourcePath ?? "");
20646
20656
  let candidates = Object.entries(parsed.pairs);
20647
20657
  if (options.prefix) {
20648
20658
  const prefix2 = options.prefix;
@@ -20698,7 +20708,7 @@ var init_import = __esm({
20698
20708
  });
20699
20709
 
20700
20710
  // ../core/src/recipients/index.ts
20701
- import * as fs11 from "fs";
20711
+ import * as fs12 from "fs";
20702
20712
  import * as path13 from "path";
20703
20713
  function parseRecipientEntry(entry) {
20704
20714
  if (typeof entry === "string") {
@@ -20722,12 +20732,12 @@ function toRecipient(entry) {
20722
20732
  }
20723
20733
  function readManifestYaml(repoRoot) {
20724
20734
  const manifestPath = path13.join(repoRoot, CLEF_MANIFEST_FILENAME);
20725
- const raw = fs11.readFileSync(manifestPath, "utf-8");
20726
- return YAML7.parse(raw);
20735
+ const raw = fs12.readFileSync(manifestPath, "utf-8");
20736
+ return YAML8.parse(raw);
20727
20737
  }
20728
20738
  function writeManifestYaml(repoRoot, doc) {
20729
20739
  const manifestPath = path13.join(repoRoot, CLEF_MANIFEST_FILENAME);
20730
- fs11.writeFileSync(manifestPath, YAML7.stringify(doc), "utf-8");
20740
+ fs12.writeFileSync(manifestPath, YAML8.stringify(doc), "utf-8");
20731
20741
  }
20732
20742
  function getRecipientsArray(doc) {
20733
20743
  const sops = doc.sops;
@@ -20775,11 +20785,11 @@ function ensureEnvironmentRecipientsArray(doc, envName) {
20775
20785
  }
20776
20786
  return env.recipients;
20777
20787
  }
20778
- var YAML7, RecipientManager;
20788
+ var YAML8, RecipientManager;
20779
20789
  var init_recipients2 = __esm({
20780
20790
  "../core/src/recipients/index.ts"() {
20781
20791
  "use strict";
20782
- YAML7 = __toESM(require_dist());
20792
+ YAML8 = __toESM(require_dist());
20783
20793
  init_validator();
20784
20794
  init_parser();
20785
20795
  RecipientManager = class {
@@ -20835,7 +20845,7 @@ var init_recipients2 = __esm({
20835
20845
  throw new Error(`Recipient '${keyPreview(normalizedKey)}' is already present.`);
20836
20846
  }
20837
20847
  const manifestPath = path13.join(repoRoot, CLEF_MANIFEST_FILENAME);
20838
- const manifestBackup = fs11.readFileSync(manifestPath, "utf-8");
20848
+ const manifestBackup = fs12.readFileSync(manifestPath, "utf-8");
20839
20849
  const recipients = environment ? ensureEnvironmentRecipientsArray(doc, environment) : ensureRecipientsArray(doc);
20840
20850
  if (label2) {
20841
20851
  recipients.push({ key: normalizedKey, label: label2 });
@@ -20850,16 +20860,16 @@ var init_recipients2 = __esm({
20850
20860
  const fileBackups = /* @__PURE__ */ new Map();
20851
20861
  for (const cell of cells) {
20852
20862
  try {
20853
- fileBackups.set(cell.filePath, fs11.readFileSync(cell.filePath, "utf-8"));
20863
+ fileBackups.set(cell.filePath, fs12.readFileSync(cell.filePath, "utf-8"));
20854
20864
  await this.encryption.addRecipient(cell.filePath, normalizedKey);
20855
20865
  reEncryptedFiles.push(cell.filePath);
20856
20866
  } catch {
20857
20867
  failedFiles.push(cell.filePath);
20858
- fs11.writeFileSync(manifestPath, manifestBackup, "utf-8");
20868
+ fs12.writeFileSync(manifestPath, manifestBackup, "utf-8");
20859
20869
  for (const reEncryptedFile of reEncryptedFiles) {
20860
20870
  const backup = fileBackups.get(reEncryptedFile);
20861
20871
  if (backup) {
20862
- fs11.writeFileSync(reEncryptedFile, backup, "utf-8");
20872
+ fs12.writeFileSync(reEncryptedFile, backup, "utf-8");
20863
20873
  }
20864
20874
  }
20865
20875
  const restoredDoc = readManifestYaml(repoRoot);
@@ -20913,7 +20923,7 @@ var init_recipients2 = __esm({
20913
20923
  }
20914
20924
  const removedEntry = parsed[matchIndex];
20915
20925
  const manifestPath = path13.join(repoRoot, CLEF_MANIFEST_FILENAME);
20916
- const manifestBackup = fs11.readFileSync(manifestPath, "utf-8");
20926
+ const manifestBackup = fs12.readFileSync(manifestPath, "utf-8");
20917
20927
  const recipients = environment ? ensureEnvironmentRecipientsArray(doc, environment) : ensureRecipientsArray(doc);
20918
20928
  recipients.splice(matchIndex, 1);
20919
20929
  writeManifestYaml(repoRoot, doc);
@@ -20924,16 +20934,16 @@ var init_recipients2 = __esm({
20924
20934
  const fileBackups = /* @__PURE__ */ new Map();
20925
20935
  for (const cell of cells) {
20926
20936
  try {
20927
- fileBackups.set(cell.filePath, fs11.readFileSync(cell.filePath, "utf-8"));
20937
+ fileBackups.set(cell.filePath, fs12.readFileSync(cell.filePath, "utf-8"));
20928
20938
  await this.encryption.removeRecipient(cell.filePath, trimmedKey);
20929
20939
  reEncryptedFiles.push(cell.filePath);
20930
20940
  } catch {
20931
20941
  failedFiles.push(cell.filePath);
20932
- fs11.writeFileSync(manifestPath, manifestBackup, "utf-8");
20942
+ fs12.writeFileSync(manifestPath, manifestBackup, "utf-8");
20933
20943
  for (const reEncryptedFile of reEncryptedFiles) {
20934
20944
  const backup = fileBackups.get(reEncryptedFile);
20935
20945
  if (backup) {
20936
- fs11.writeFileSync(reEncryptedFile, backup, "utf-8");
20946
+ fs12.writeFileSync(reEncryptedFile, backup, "utf-8");
20937
20947
  }
20938
20948
  }
20939
20949
  const restoredDoc = readManifestYaml(repoRoot);
@@ -20969,7 +20979,7 @@ var init_recipients2 = __esm({
20969
20979
  });
20970
20980
 
20971
20981
  // ../core/src/recipients/requests.ts
20972
- import * as fs12 from "fs";
20982
+ import * as fs13 from "fs";
20973
20983
  import * as path14 from "path";
20974
20984
  function requestsFilePath(repoRoot) {
20975
20985
  return path14.join(repoRoot, REQUESTS_FILENAME);
@@ -20977,9 +20987,9 @@ function requestsFilePath(repoRoot) {
20977
20987
  function loadRequests(repoRoot) {
20978
20988
  const filePath = requestsFilePath(repoRoot);
20979
20989
  try {
20980
- if (!fs12.existsSync(filePath)) return [];
20981
- const content = fs12.readFileSync(filePath, "utf-8");
20982
- const parsed = YAML8.parse(content);
20990
+ if (!fs13.existsSync(filePath)) return [];
20991
+ const content = fs13.readFileSync(filePath, "utf-8");
20992
+ const parsed = YAML9.parse(content);
20983
20993
  if (!parsed || !Array.isArray(parsed.requests)) return [];
20984
20994
  return parsed.requests.map((r) => ({
20985
20995
  key: r.key,
@@ -20995,7 +21005,7 @@ function saveRequests(repoRoot, requests) {
20995
21005
  const filePath = requestsFilePath(repoRoot);
20996
21006
  if (requests.length === 0) {
20997
21007
  try {
20998
- fs12.unlinkSync(filePath);
21008
+ fs13.unlinkSync(filePath);
20999
21009
  } catch {
21000
21010
  }
21001
21011
  return;
@@ -21011,7 +21021,7 @@ function saveRequests(repoRoot, requests) {
21011
21021
  return raw;
21012
21022
  })
21013
21023
  };
21014
- fs12.writeFileSync(filePath, HEADER_COMMENT2 + YAML8.stringify(data), "utf-8");
21024
+ fs13.writeFileSync(filePath, HEADER_COMMENT2 + YAML9.stringify(data), "utf-8");
21015
21025
  }
21016
21026
  function upsertRequest(repoRoot, key, label2, environment) {
21017
21027
  const requests = loadRequests(repoRoot);
@@ -21045,26 +21055,25 @@ function findInList(requests, identifier) {
21045
21055
  const byKey = requests.find((r) => r.key === identifier);
21046
21056
  return byKey ?? null;
21047
21057
  }
21048
- var YAML8, REQUESTS_FILENAME, HEADER_COMMENT2;
21058
+ var YAML9, REQUESTS_FILENAME, HEADER_COMMENT2;
21049
21059
  var init_requests = __esm({
21050
21060
  "../core/src/recipients/requests.ts"() {
21051
21061
  "use strict";
21052
- YAML8 = __toESM(require_dist());
21062
+ YAML9 = __toESM(require_dist());
21053
21063
  REQUESTS_FILENAME = ".clef-requests.yaml";
21054
21064
  HEADER_COMMENT2 = "# Pending recipient access requests. Approve with: clef recipients approve <label>\n";
21055
21065
  }
21056
21066
  });
21057
21067
 
21058
21068
  // ../core/src/drift/detector.ts
21059
- import * as fs13 from "fs";
21060
21069
  import * as path15 from "path";
21061
- var YAML9, DriftDetector;
21070
+ var DriftDetector;
21062
21071
  var init_detector = __esm({
21063
21072
  "../core/src/drift/detector.ts"() {
21064
21073
  "use strict";
21065
- YAML9 = __toESM(require_dist());
21066
21074
  init_parser();
21067
21075
  init_manager();
21076
+ init_keys();
21068
21077
  DriftDetector = class {
21069
21078
  parser = new ManifestParser();
21070
21079
  matrix = new MatrixManager();
@@ -21092,45 +21101,30 @@ var init_detector = __esm({
21092
21101
  }
21093
21102
  const issues = [];
21094
21103
  let namespacesClean = 0;
21104
+ const remoteEnvSet = new Set(remoteEnvNames);
21105
+ const sharedEnvSet = new Set(localEnvNames.filter((e) => remoteEnvSet.has(e)));
21095
21106
  for (const ns of sharedNamespaces) {
21096
- const keyEnvs = /* @__PURE__ */ new Map();
21097
- const allEnvs = /* @__PURE__ */ new Set();
21098
- const localNsCells = localCells.filter((c) => c.namespace === ns);
21099
- for (const cell of localNsCells) {
21100
- const keys = this.readKeysFromFile(cell.filePath);
21101
- if (keys === null) continue;
21102
- allEnvs.add(cell.environment);
21103
- for (const key of keys) {
21104
- if (!keyEnvs.has(key)) keyEnvs.set(key, /* @__PURE__ */ new Set());
21105
- keyEnvs.get(key).add(cell.environment);
21106
- }
21107
- }
21108
- const remoteNsCells = remoteCells.filter((c) => c.namespace === ns);
21109
- for (const cell of remoteNsCells) {
21110
- const keys = this.readKeysFromFile(cell.filePath);
21111
- if (keys === null) continue;
21112
- allEnvs.add(cell.environment);
21113
- for (const key of keys) {
21114
- if (!keyEnvs.has(key)) keyEnvs.set(key, /* @__PURE__ */ new Set());
21115
- keyEnvs.get(key).add(cell.environment);
21116
- }
21117
- }
21118
- const envList = [...allEnvs];
21107
+ const localKeyEnvs = this.collectKeyEnvs(localCells, ns, sharedEnvSet);
21108
+ const remoteKeyEnvs = this.collectKeyEnvs(remoteCells, ns, sharedEnvSet);
21119
21109
  let nsClean = true;
21120
- for (const [key, envSet] of keyEnvs) {
21121
- const missingFrom = envList.filter((e) => !envSet.has(e));
21122
- if (missingFrom.length > 0) {
21123
- nsClean = false;
21124
- const presentIn = [...envSet].sort();
21125
- issues.push({
21126
- namespace: ns,
21127
- key,
21128
- presentIn,
21129
- missingFrom: missingFrom.sort(),
21130
- message: `Key '${key}' in namespace '${ns}' exists in [${presentIn.join(", ")}] but is missing from [${missingFrom.sort().join(", ")}]`
21131
- });
21110
+ const reportDrift = (sourceMap, targetMap, direction) => {
21111
+ for (const [key, sourceEnvs] of sourceMap) {
21112
+ const targetEnvs = targetMap.get(key);
21113
+ const missingFrom = [...sourceEnvs].filter((e) => !targetEnvs?.has(e)).sort();
21114
+ if (missingFrom.length > 0) {
21115
+ nsClean = false;
21116
+ issues.push({
21117
+ namespace: ns,
21118
+ key,
21119
+ presentIn: [...sourceEnvs].sort(),
21120
+ missingFrom,
21121
+ message: `Key '${key}' in namespace '${ns}' exists in ${direction} [${[...sourceEnvs].sort().join(", ")}] but is missing from [${missingFrom.join(", ")}]`
21122
+ });
21123
+ }
21132
21124
  }
21133
- }
21125
+ };
21126
+ reportDrift(remoteKeyEnvs, localKeyEnvs, "remote");
21127
+ reportDrift(localKeyEnvs, remoteKeyEnvs, "local");
21134
21128
  if (nsClean) namespacesClean++;
21135
21129
  }
21136
21130
  return {
@@ -21141,22 +21135,18 @@ var init_detector = __esm({
21141
21135
  remoteEnvironments: remoteEnvNames
21142
21136
  };
21143
21137
  }
21144
- /**
21145
- * Read top-level key names from an encrypted SOPS YAML file,
21146
- * filtering out the `sops` metadata key.
21147
- *
21148
- * @returns Array of key names, or `null` if the file cannot be read.
21149
- */
21150
- readKeysFromFile(filePath) {
21151
- try {
21152
- if (!fs13.existsSync(filePath)) return null;
21153
- const raw = fs13.readFileSync(filePath, "utf-8");
21154
- const parsed = YAML9.parse(raw);
21155
- if (parsed === null || parsed === void 0 || typeof parsed !== "object") return null;
21156
- return Object.keys(parsed).filter((k) => k !== "sops");
21157
- } catch {
21158
- return null;
21138
+ collectKeyEnvs(cells, ns, sharedEnvSet) {
21139
+ const keyEnvs = /* @__PURE__ */ new Map();
21140
+ for (const cell of cells) {
21141
+ if (cell.namespace !== ns || !sharedEnvSet.has(cell.environment)) continue;
21142
+ const keys = readSopsKeyNames(cell.filePath);
21143
+ if (keys === null) continue;
21144
+ for (const key of keys) {
21145
+ if (!keyEnvs.has(key)) keyEnvs.set(key, /* @__PURE__ */ new Set());
21146
+ keyEnvs.get(key).add(cell.environment);
21147
+ }
21159
21148
  }
21149
+ return keyEnvs;
21160
21150
  }
21161
21151
  };
21162
21152
  }
@@ -21302,19 +21292,18 @@ var init_sanitizer = __esm({
21302
21292
  });
21303
21293
 
21304
21294
  // ../core/src/report/generator.ts
21305
- import * as fs14 from "fs";
21306
21295
  import * as path16 from "path";
21307
- var YAML10, ReportGenerator;
21296
+ var ReportGenerator;
21308
21297
  var init_generator = __esm({
21309
21298
  "../core/src/report/generator.ts"() {
21310
21299
  "use strict";
21311
- YAML10 = __toESM(require_dist());
21312
21300
  init_types();
21313
21301
  init_parser();
21314
21302
  init_runner();
21315
21303
  init_metadata();
21316
21304
  init_checker();
21317
21305
  init_sanitizer();
21306
+ init_keys();
21318
21307
  ReportGenerator = class {
21319
21308
  constructor(runner2, sopsClient, matrixManager, schemaValidator) {
21320
21309
  this.runner = runner2;
@@ -21484,15 +21473,7 @@ var init_generator = __esm({
21484
21473
  };
21485
21474
  }
21486
21475
  readKeyCount(filePath) {
21487
- try {
21488
- if (!fs14.existsSync(filePath)) return 0;
21489
- const raw = fs14.readFileSync(filePath, "utf-8");
21490
- const parsed = YAML10.parse(raw);
21491
- if (parsed === null || parsed === void 0 || typeof parsed !== "object") return 0;
21492
- return Object.keys(parsed).filter((k) => k !== "sops").length;
21493
- } catch {
21494
- return 0;
21495
- }
21476
+ return readSopsKeyNames(filePath)?.length ?? 0;
21496
21477
  }
21497
21478
  async buildPolicy(manifest, repoRoot) {
21498
21479
  try {
@@ -21859,14 +21840,14 @@ var init_driver = __esm({
21859
21840
  });
21860
21841
 
21861
21842
  // ../core/src/service-identity/manager.ts
21862
- import * as fs15 from "fs";
21843
+ import * as fs14 from "fs";
21863
21844
  import * as os from "os";
21864
21845
  import * as path17 from "path";
21865
- var YAML11, PartialRotationError, ServiceIdentityManager;
21846
+ var YAML10, PartialRotationError, ServiceIdentityManager;
21866
21847
  var init_manager2 = __esm({
21867
21848
  "../core/src/service-identity/manager.ts"() {
21868
21849
  "use strict";
21869
- YAML11 = __toESM(require_dist());
21850
+ YAML10 = __toESM(require_dist());
21870
21851
  init_types();
21871
21852
  init_keygen();
21872
21853
  init_parser();
@@ -21921,8 +21902,8 @@ var init_manager2 = __esm({
21921
21902
  };
21922
21903
  await this.registerRecipients(definition, manifest, repoRoot);
21923
21904
  const manifestPath = path17.join(repoRoot, CLEF_MANIFEST_FILENAME);
21924
- const raw = fs15.readFileSync(manifestPath, "utf-8");
21925
- const doc = YAML11.parse(raw);
21905
+ const raw = fs14.readFileSync(manifestPath, "utf-8");
21906
+ const doc = YAML10.parse(raw);
21926
21907
  if (!Array.isArray(doc.service_identities)) {
21927
21908
  doc.service_identities = [];
21928
21909
  }
@@ -21934,11 +21915,11 @@ var init_manager2 = __esm({
21934
21915
  });
21935
21916
  const tmpCreate = path17.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
21936
21917
  try {
21937
- fs15.writeFileSync(tmpCreate, YAML11.stringify(doc), "utf-8");
21938
- fs15.renameSync(tmpCreate, manifestPath);
21918
+ fs14.writeFileSync(tmpCreate, YAML10.stringify(doc), "utf-8");
21919
+ fs14.renameSync(tmpCreate, manifestPath);
21939
21920
  } finally {
21940
21921
  try {
21941
- fs15.unlinkSync(tmpCreate);
21922
+ fs14.unlinkSync(tmpCreate);
21942
21923
  } catch {
21943
21924
  }
21944
21925
  }
@@ -21977,8 +21958,8 @@ var init_manager2 = __esm({
21977
21958
  }
21978
21959
  }
21979
21960
  const manifestPath = path17.join(repoRoot, CLEF_MANIFEST_FILENAME);
21980
- const raw = fs15.readFileSync(manifestPath, "utf-8");
21981
- const doc = YAML11.parse(raw);
21961
+ const raw = fs14.readFileSync(manifestPath, "utf-8");
21962
+ const doc = YAML10.parse(raw);
21982
21963
  const identities = doc.service_identities;
21983
21964
  if (Array.isArray(identities)) {
21984
21965
  doc.service_identities = identities.filter(
@@ -21987,11 +21968,11 @@ var init_manager2 = __esm({
21987
21968
  }
21988
21969
  const tmp = path17.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
21989
21970
  try {
21990
- fs15.writeFileSync(tmp, YAML11.stringify(doc), "utf-8");
21991
- fs15.renameSync(tmp, manifestPath);
21971
+ fs14.writeFileSync(tmp, YAML10.stringify(doc), "utf-8");
21972
+ fs14.renameSync(tmp, manifestPath);
21992
21973
  } finally {
21993
21974
  try {
21994
- fs15.unlinkSync(tmp);
21975
+ fs14.unlinkSync(tmp);
21995
21976
  } catch {
21996
21977
  }
21997
21978
  }
@@ -22007,8 +21988,8 @@ var init_manager2 = __esm({
22007
21988
  throw new Error(`Service identity '${name}' not found.`);
22008
21989
  }
22009
21990
  const manifestPath = path17.join(repoRoot, CLEF_MANIFEST_FILENAME);
22010
- const raw = fs15.readFileSync(manifestPath, "utf-8");
22011
- const doc = YAML11.parse(raw);
21991
+ const raw = fs14.readFileSync(manifestPath, "utf-8");
21992
+ const doc = YAML10.parse(raw);
22012
21993
  const identities = doc.service_identities;
22013
21994
  const siDoc = identities.find((si) => si.name === name);
22014
21995
  const envs = siDoc.environments;
@@ -22035,11 +22016,11 @@ var init_manager2 = __esm({
22035
22016
  }
22036
22017
  const tmp = path17.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
22037
22018
  try {
22038
- fs15.writeFileSync(tmp, YAML11.stringify(doc), "utf-8");
22039
- fs15.renameSync(tmp, manifestPath);
22019
+ fs14.writeFileSync(tmp, YAML10.stringify(doc), "utf-8");
22020
+ fs14.renameSync(tmp, manifestPath);
22040
22021
  } finally {
22041
22022
  try {
22042
- fs15.unlinkSync(tmp);
22023
+ fs14.unlinkSync(tmp);
22043
22024
  } catch {
22044
22025
  }
22045
22026
  }
@@ -22076,8 +22057,8 @@ var init_manager2 = __esm({
22076
22057
  throw new Error(`Service identity '${name}' not found.`);
22077
22058
  }
22078
22059
  const manifestPath = path17.join(repoRoot, CLEF_MANIFEST_FILENAME);
22079
- const raw = fs15.readFileSync(manifestPath, "utf-8");
22080
- const doc = YAML11.parse(raw);
22060
+ const raw = fs14.readFileSync(manifestPath, "utf-8");
22061
+ const doc = YAML10.parse(raw);
22081
22062
  const identities = doc.service_identities;
22082
22063
  const siDoc = identities.find((si) => si.name === name);
22083
22064
  const envs = siDoc.environments;
@@ -22132,11 +22113,11 @@ var init_manager2 = __esm({
22132
22113
  }
22133
22114
  const tmpRotate = path17.join(os.tmpdir(), `clef-manifest-${process.pid}-${Date.now()}.tmp`);
22134
22115
  try {
22135
- fs15.writeFileSync(tmpRotate, YAML11.stringify(doc), "utf-8");
22136
- fs15.renameSync(tmpRotate, manifestPath);
22116
+ fs14.writeFileSync(tmpRotate, YAML10.stringify(doc), "utf-8");
22117
+ fs14.renameSync(tmpRotate, manifestPath);
22137
22118
  } finally {
22138
22119
  try {
22139
- fs15.unlinkSync(tmpRotate);
22120
+ fs14.unlinkSync(tmpRotate);
22140
22121
  } catch {
22141
22122
  }
22142
22123
  }
@@ -22267,7 +22248,7 @@ var init_resolve = __esm({
22267
22248
  import * as crypto3 from "crypto";
22268
22249
  function buildSigningPayload(artifact) {
22269
22250
  const fields = [
22270
- "clef-sig-v1",
22251
+ "clef-sig-v2",
22271
22252
  String(artifact.version),
22272
22253
  artifact.identity,
22273
22254
  artifact.environment,
@@ -22279,7 +22260,9 @@ function buildSigningPayload(artifact) {
22279
22260
  artifact.envelope?.provider ?? "",
22280
22261
  artifact.envelope?.keyId ?? "",
22281
22262
  artifact.envelope?.wrappedKey ?? "",
22282
- artifact.envelope?.algorithm ?? ""
22263
+ artifact.envelope?.algorithm ?? "",
22264
+ artifact.envelope?.iv ?? "",
22265
+ artifact.envelope?.authTag ?? ""
22283
22266
  ];
22284
22267
  return Buffer.from(fields.join("\n"), "utf-8");
22285
22268
  }
@@ -22347,7 +22330,7 @@ var init_signer = __esm({
22347
22330
  });
22348
22331
 
22349
22332
  // ../core/src/artifact/packer.ts
22350
- import * as fs16 from "fs";
22333
+ import * as fs15 from "fs";
22351
22334
  import * as path18 from "path";
22352
22335
  import * as crypto4 from "crypto";
22353
22336
  var ArtifactPacker;
@@ -22388,37 +22371,41 @@ var init_packer = __esm({
22388
22371
  if (!this.kms) {
22389
22372
  throw new Error("KMS provider required for envelope encryption but none was provided.");
22390
22373
  }
22391
- const { generateIdentity: generateIdentity2, identityToRecipient: identityToRecipient2, Encrypter: Encrypter2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
22392
- const ephemeralPrivateKey = await generateIdentity2();
22393
- const ephemeralPublicKey = await identityToRecipient2(ephemeralPrivateKey);
22374
+ const dek = crypto4.randomBytes(32);
22375
+ const iv = crypto4.randomBytes(12);
22394
22376
  try {
22395
- const e = new Encrypter2();
22396
- e.addRecipient(ephemeralPublicKey);
22397
- const encrypted = await e.encrypt(plaintext);
22398
- ciphertext = Buffer.from(encrypted).toString("base64");
22399
- } catch {
22400
- throw new Error("Failed to age-encrypt artifact with ephemeral key.");
22377
+ const cipher = crypto4.createCipheriv("aes-256-gcm", dek, iv);
22378
+ const ciphertextBuf = Buffer.concat([
22379
+ cipher.update(Buffer.from(plaintext, "utf-8")),
22380
+ cipher.final()
22381
+ ]);
22382
+ const authTag = cipher.getAuthTag();
22383
+ ciphertext = ciphertextBuf.toString("base64");
22384
+ const kmsConfig = resolved.envConfig.kms;
22385
+ const wrapped = await this.kms.wrap(kmsConfig.keyId, dek);
22386
+ const revision = `${Date.now()}-${crypto4.randomBytes(4).toString("hex")}`;
22387
+ const ciphertextHash = crypto4.createHash("sha256").update(ciphertext).digest("hex");
22388
+ artifact = {
22389
+ version: 1,
22390
+ identity: config.identity,
22391
+ environment: config.environment,
22392
+ packedAt: (/* @__PURE__ */ new Date()).toISOString(),
22393
+ revision,
22394
+ ciphertextHash,
22395
+ ciphertext,
22396
+ keys: Object.keys(resolved.values),
22397
+ envelope: {
22398
+ provider: kmsConfig.provider,
22399
+ keyId: kmsConfig.keyId,
22400
+ wrappedKey: wrapped.wrappedKey.toString("base64"),
22401
+ algorithm: wrapped.algorithm,
22402
+ iv: iv.toString("base64"),
22403
+ authTag: authTag.toString("base64")
22404
+ }
22405
+ };
22406
+ } finally {
22407
+ dek.fill(0);
22401
22408
  }
22402
- const kmsConfig = resolved.envConfig.kms;
22403
- const wrapped = await this.kms.wrap(kmsConfig.keyId, Buffer.from(ephemeralPrivateKey));
22404
- const revision = `${Date.now()}-${crypto4.randomBytes(4).toString("hex")}`;
22405
- const ciphertextHash = crypto4.createHash("sha256").update(ciphertext).digest("hex");
22406
- artifact = {
22407
- version: 1,
22408
- identity: config.identity,
22409
- environment: config.environment,
22410
- packedAt: (/* @__PURE__ */ new Date()).toISOString(),
22411
- revision,
22412
- ciphertextHash,
22413
- ciphertext,
22414
- keys: Object.keys(resolved.values),
22415
- envelope: {
22416
- provider: kmsConfig.provider,
22417
- keyId: kmsConfig.keyId,
22418
- wrappedKey: wrapped.wrappedKey.toString("base64"),
22419
- algorithm: wrapped.algorithm
22420
- }
22421
- };
22422
22409
  } else {
22423
22410
  try {
22424
22411
  const { Encrypter: Encrypter2 } = await Promise.resolve().then(() => (init_dist(), dist_exports));
@@ -22426,8 +22413,10 @@ var init_packer = __esm({
22426
22413
  e.addRecipient(resolved.recipient);
22427
22414
  const encrypted = await e.encrypt(plaintext);
22428
22415
  ciphertext = Buffer.from(encrypted).toString("base64");
22429
- } catch {
22430
- throw new Error("Failed to age-encrypt artifact. Check recipient key.");
22416
+ } catch (err) {
22417
+ throw new Error(
22418
+ `Failed to age-encrypt artifact: ${err instanceof Error ? err.message : String(err)}`
22419
+ );
22431
22420
  }
22432
22421
  const revision = `${Date.now()}-${crypto4.randomBytes(4).toString("hex")}`;
22433
22422
  const ciphertextHash = crypto4.createHash("sha256").update(ciphertext).digest("hex");
@@ -22443,8 +22432,8 @@ var init_packer = __esm({
22443
22432
  };
22444
22433
  }
22445
22434
  const outputDir = path18.dirname(config.outputPath);
22446
- if (!fs16.existsSync(outputDir)) {
22447
- fs16.mkdirSync(outputDir, { recursive: true });
22435
+ if (!fs15.existsSync(outputDir)) {
22436
+ fs15.mkdirSync(outputDir, { recursive: true });
22448
22437
  }
22449
22438
  if (config.ttl && config.ttl > 0) {
22450
22439
  artifact.expiresAt = new Date(Date.now() + config.ttl * 1e3).toISOString();
@@ -22463,8 +22452,8 @@ var init_packer = __esm({
22463
22452
  }
22464
22453
  const json = JSON.stringify(artifact, null, 2);
22465
22454
  const tmpOutput = `${config.outputPath}.tmp.${process.pid}`;
22466
- fs16.writeFileSync(tmpOutput, json, "utf-8");
22467
- fs16.renameSync(tmpOutput, config.outputPath);
22455
+ fs15.writeFileSync(tmpOutput, json, "utf-8");
22456
+ fs15.renameSync(tmpOutput, config.outputPath);
22468
22457
  return {
22469
22458
  outputPath: config.outputPath,
22470
22459
  namespaceCount: resolved.identity.namespaces.length,
@@ -22477,6 +22466,23 @@ var init_packer = __esm({
22477
22466
  }
22478
22467
  });
22479
22468
 
22469
+ // ../core/src/kms/types.ts
22470
+ var VALID_KMS_PROVIDERS;
22471
+ var init_types2 = __esm({
22472
+ "../core/src/kms/types.ts"() {
22473
+ "use strict";
22474
+ VALID_KMS_PROVIDERS = ["aws", "gcp", "azure"];
22475
+ }
22476
+ });
22477
+
22478
+ // ../core/src/kms/index.ts
22479
+ var init_kms = __esm({
22480
+ "../core/src/kms/index.ts"() {
22481
+ "use strict";
22482
+ init_types2();
22483
+ }
22484
+ });
22485
+
22480
22486
  // ../core/src/index.ts
22481
22487
  var src_exports = {};
22482
22488
  __export(src_exports, {
@@ -22516,6 +22522,7 @@ __export(src_exports, {
22516
22522
  SopsMergeDriver: () => SopsMergeDriver,
22517
22523
  SopsMissingError: () => SopsMissingError,
22518
22524
  SopsVersionError: () => SopsVersionError,
22525
+ VALID_KMS_PROVIDERS: () => VALID_KMS_PROVIDERS,
22519
22526
  assertSops: () => assertSops,
22520
22527
  buildSigningPayload: () => buildSigningPayload,
22521
22528
  checkAll: () => checkAll,
@@ -22542,7 +22549,7 @@ __export(src_exports, {
22542
22549
  markResolved: () => markResolved,
22543
22550
  matchPatterns: () => matchPatterns,
22544
22551
  metadataPath: () => metadataPath,
22545
- parse: () => parse7,
22552
+ parse: () => parse8,
22546
22553
  parseDotenv: () => parseDotenv,
22547
22554
  parseIgnoreContent: () => parseIgnoreContent,
22548
22555
  parseJson: () => parseJson,
@@ -22596,6 +22603,7 @@ var init_src = __esm({
22596
22603
  init_resolve();
22597
22604
  init_packer();
22598
22605
  init_signer();
22606
+ init_kms();
22599
22607
  }
22600
22608
  });
22601
22609
 
@@ -22684,7 +22692,7 @@ var require_ms = __commonJS({
22684
22692
  options = options || {};
22685
22693
  var type = typeof val;
22686
22694
  if (type === "string" && val.length > 0) {
22687
- return parse16(val);
22695
+ return parse15(val);
22688
22696
  } else if (type === "number" && isFinite(val)) {
22689
22697
  return options.long ? fmtLong(val) : fmtShort(val);
22690
22698
  }
@@ -22692,7 +22700,7 @@ var require_ms = __commonJS({
22692
22700
  "val is not a non-empty string or a valid number. val=" + JSON.stringify(val)
22693
22701
  );
22694
22702
  };
22695
- function parse16(str2) {
22703
+ function parse15(str2) {
22696
22704
  str2 = String(str2);
22697
22705
  if (str2.length > 100) {
22698
22706
  return;
@@ -23151,7 +23159,7 @@ var require_has_flag = __commonJS({
23151
23159
  var require_supports_color = __commonJS({
23152
23160
  "../../node_modules/supports-color/index.js"(exports, module) {
23153
23161
  "use strict";
23154
- var os3 = __require("os");
23162
+ var os4 = __require("os");
23155
23163
  var tty = __require("tty");
23156
23164
  var hasFlag = require_has_flag();
23157
23165
  var { env } = process;
@@ -23199,7 +23207,7 @@ var require_supports_color = __commonJS({
23199
23207
  return min;
23200
23208
  }
23201
23209
  if (process.platform === "win32") {
23202
- const osRelease = os3.release().split(".");
23210
+ const osRelease = os4.release().split(".");
23203
23211
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
23204
23212
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
23205
23213
  }
@@ -24131,7 +24139,7 @@ var require_bytes = __commonJS({
24131
24139
  "use strict";
24132
24140
  module.exports = bytes;
24133
24141
  module.exports.format = format;
24134
- module.exports.parse = parse16;
24142
+ module.exports.parse = parse15;
24135
24143
  var formatThousandsRegExp = /\B(?=(\d{3})+(?!\d))/g;
24136
24144
  var formatDecimalsRegExp = /(?:\.0*|(\.[^0]+)0+)$/;
24137
24145
  var map = {
@@ -24145,7 +24153,7 @@ var require_bytes = __commonJS({
24145
24153
  var parseRegExp = /^((-|\+)?(\d+(?:\.\d+)?)) *(kb|mb|gb|tb|pb)$/i;
24146
24154
  function bytes(value, options) {
24147
24155
  if (typeof value === "string") {
24148
- return parse16(value);
24156
+ return parse15(value);
24149
24157
  }
24150
24158
  if (typeof value === "number") {
24151
24159
  return format(value, options);
@@ -24189,7 +24197,7 @@ var require_bytes = __commonJS({
24189
24197
  }
24190
24198
  return str2 + unitSeparator + unit;
24191
24199
  }
24192
- function parse16(val) {
24200
+ function parse15(val) {
24193
24201
  if (typeof val === "number" && !isNaN(val)) {
24194
24202
  return val;
24195
24203
  }
@@ -28394,7 +28402,7 @@ var require_content_type = __commonJS({
28394
28402
  var QUOTE_REGEXP = /([\\"])/g;
28395
28403
  var TYPE_REGEXP = /^[!#$%&'*+.^_`|~0-9A-Za-z-]+\/[!#$%&'*+.^_`|~0-9A-Za-z-]+$/;
28396
28404
  exports.format = format;
28397
- exports.parse = parse16;
28405
+ exports.parse = parse15;
28398
28406
  function format(obj) {
28399
28407
  if (!obj || typeof obj !== "object") {
28400
28408
  throw new TypeError("argument obj is required");
@@ -28418,7 +28426,7 @@ var require_content_type = __commonJS({
28418
28426
  }
28419
28427
  return string;
28420
28428
  }
28421
- function parse16(string) {
28429
+ function parse15(string) {
28422
28430
  if (!string) {
28423
28431
  throw new TypeError("argument string is required");
28424
28432
  }
@@ -38000,7 +38008,7 @@ var require_media_typer = __commonJS({
38000
38008
  var TYPE_NAME_REGEXP = /^[A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126}$/;
38001
38009
  var TYPE_REGEXP = /^ *([A-Za-z0-9][A-Za-z0-9!#$&^_-]{0,126})\/([A-Za-z0-9][A-Za-z0-9!#$&^_.+-]{0,126}) *$/;
38002
38010
  exports.format = format;
38003
- exports.parse = parse16;
38011
+ exports.parse = parse15;
38004
38012
  exports.test = test;
38005
38013
  function format(obj) {
38006
38014
  if (!obj || typeof obj !== "object") {
@@ -38033,7 +38041,7 @@ var require_media_typer = __commonJS({
38033
38041
  }
38034
38042
  return TYPE_REGEXP.test(string.toLowerCase());
38035
38043
  }
38036
- function parse16(string) {
38044
+ function parse15(string) {
38037
38045
  if (!string) {
38038
38046
  throw new TypeError("argument string is required");
38039
38047
  }
@@ -38219,7 +38227,7 @@ var require_read = __commonJS({
38219
38227
  var hasBody = require_type_is().hasBody;
38220
38228
  var { getCharset } = require_utils();
38221
38229
  module.exports = read2;
38222
- function read2(req, res, next, parse16, debug, options) {
38230
+ function read2(req, res, next, parse15, debug, options) {
38223
38231
  if (onFinished.isFinished(req)) {
38224
38232
  debug("body already parsed");
38225
38233
  next();
@@ -38307,7 +38315,7 @@ var require_read = __commonJS({
38307
38315
  try {
38308
38316
  debug("parse body");
38309
38317
  str2 = typeof body !== "string" && encoding !== null ? iconv.decode(body, encoding) : body;
38310
- req.body = parse16(str2, encoding);
38318
+ req.body = parse15(str2, encoding);
38311
38319
  } catch (err) {
38312
38320
  next(createError(400, err, {
38313
38321
  body: str2,
@@ -38380,7 +38388,7 @@ var require_json = __commonJS({
38380
38388
  const normalizedOptions = normalizeOptions(options, "application/json");
38381
38389
  var reviver = options?.reviver;
38382
38390
  var strict = options?.strict !== false;
38383
- function parse16(body) {
38391
+ function parse15(body) {
38384
38392
  if (body.length === 0) {
38385
38393
  return {};
38386
38394
  }
@@ -38407,7 +38415,7 @@ var require_json = __commonJS({
38407
38415
  isValidCharset: (charset) => charset.slice(0, 4) === "utf-"
38408
38416
  };
38409
38417
  return function jsonParser(req, res, next) {
38410
- read2(req, res, next, parse16, debug, readOptions);
38418
+ read2(req, res, next, parse15, debug, readOptions);
38411
38419
  };
38412
38420
  }
38413
38421
  function createStrictSyntaxError(str2, char) {
@@ -40985,11 +40993,11 @@ var require_lib2 = __commonJS({
40985
40993
  "../../node_modules/qs/lib/index.js"(exports, module) {
40986
40994
  "use strict";
40987
40995
  var stringify7 = require_stringify2();
40988
- var parse16 = require_parse();
40996
+ var parse15 = require_parse();
40989
40997
  var formats = require_formats();
40990
40998
  module.exports = {
40991
40999
  formats,
40992
- parse: parse16,
41000
+ parse: parse15,
40993
41001
  stringify: stringify7
40994
41002
  };
40995
41003
  }
@@ -41011,7 +41019,7 @@ var require_urlencoded = __commonJS({
41011
41019
  throw new TypeError("option defaultCharset must be either utf-8 or iso-8859-1");
41012
41020
  }
41013
41021
  var queryparse = createQueryParser(options);
41014
- function parse16(body, encoding) {
41022
+ function parse15(body, encoding) {
41015
41023
  return body.length ? queryparse(body, encoding) : {};
41016
41024
  }
41017
41025
  const readOptions = {
@@ -41020,7 +41028,7 @@ var require_urlencoded = __commonJS({
41020
41028
  isValidCharset: (charset) => charset === "utf-8" || charset === "iso-8859-1"
41021
41029
  };
41022
41030
  return function urlencodedParser(req, res, next) {
41023
- read2(req, res, next, parse16, debug, readOptions);
41031
+ read2(req, res, next, parse15, debug, readOptions);
41024
41032
  };
41025
41033
  }
41026
41034
  function createQueryParser(options) {
@@ -41204,7 +41212,7 @@ var require_parseurl = __commonJS({
41204
41212
  "../../node_modules/parseurl/index.js"(exports, module) {
41205
41213
  "use strict";
41206
41214
  var url = __require("url");
41207
- var parse16 = url.parse;
41215
+ var parse15 = url.parse;
41208
41216
  var Url = url.Url;
41209
41217
  module.exports = parseurl;
41210
41218
  module.exports.original = originalurl;
@@ -41236,7 +41244,7 @@ var require_parseurl = __commonJS({
41236
41244
  }
41237
41245
  function fastparse(str2) {
41238
41246
  if (typeof str2 !== "string" || str2.charCodeAt(0) !== 47) {
41239
- return parse16(str2);
41247
+ return parse15(str2);
41240
41248
  }
41241
41249
  var pathname = str2;
41242
41250
  var query = null;
@@ -41264,7 +41272,7 @@ var require_parseurl = __commonJS({
41264
41272
  /* # */
41265
41273
  case 160:
41266
41274
  case 65279:
41267
- return parse16(str2);
41275
+ return parse15(str2);
41268
41276
  }
41269
41277
  }
41270
41278
  var url2 = Url !== void 0 ? new Url() : {};
@@ -41416,7 +41424,7 @@ var require_view = __commonJS({
41416
41424
  "use strict";
41417
41425
  var debug = require_src()("express:view");
41418
41426
  var path44 = __require("node:path");
41419
- var fs27 = __require("node:fs");
41427
+ var fs26 = __require("node:fs");
41420
41428
  var dirname7 = path44.dirname;
41421
41429
  var basename5 = path44.basename;
41422
41430
  var extname2 = path44.extname;
@@ -41496,7 +41504,7 @@ var require_view = __commonJS({
41496
41504
  function tryStat(path45) {
41497
41505
  debug('stat "%s"', path45);
41498
41506
  try {
41499
- return fs27.statSync(path45);
41507
+ return fs26.statSync(path45);
41500
41508
  } catch (e) {
41501
41509
  return void 0;
41502
41510
  }
@@ -51060,7 +51068,7 @@ var require_forwarded = __commonJS({
51060
51068
  if (!req) {
51061
51069
  throw new TypeError("argument req is required");
51062
51070
  }
51063
- var proxyAddrs = parse16(req.headers["x-forwarded-for"] || "");
51071
+ var proxyAddrs = parse15(req.headers["x-forwarded-for"] || "");
51064
51072
  var socketAddr = getSocketAddr(req);
51065
51073
  var addrs = [socketAddr].concat(proxyAddrs);
51066
51074
  return addrs;
@@ -51068,7 +51076,7 @@ var require_forwarded = __commonJS({
51068
51076
  function getSocketAddr(req) {
51069
51077
  return req.socket ? req.socket.remoteAddress : req.connection.remoteAddress;
51070
51078
  }
51071
- function parse16(header) {
51079
+ function parse15(header) {
51072
51080
  var end = header.length;
51073
51081
  var list = [];
51074
51082
  var start = header.length;
@@ -52097,7 +52105,7 @@ var require_dist2 = __commonJS({
52097
52105
  "use strict";
52098
52106
  Object.defineProperty(exports, "__esModule", { value: true });
52099
52107
  exports.PathError = exports.TokenData = void 0;
52100
- exports.parse = parse16;
52108
+ exports.parse = parse15;
52101
52109
  exports.compile = compile;
52102
52110
  exports.match = match;
52103
52111
  exports.pathToRegexp = pathToRegexp;
@@ -52143,7 +52151,7 @@ var require_dist2 = __commonJS({
52143
52151
  }
52144
52152
  };
52145
52153
  exports.PathError = PathError;
52146
- function parse16(str2, options = {}) {
52154
+ function parse15(str2, options = {}) {
52147
52155
  const { encodePath = NOOP_VALUE } = options;
52148
52156
  const chars = [...str2];
52149
52157
  const tokens = [];
@@ -52233,7 +52241,7 @@ var require_dist2 = __commonJS({
52233
52241
  }
52234
52242
  function compile(path44, options = {}) {
52235
52243
  const { encode: encode2 = encodeURIComponent, delimiter = DEFAULT_DELIMITER } = options;
52236
- const data = typeof path44 === "object" ? path44 : parse16(path44, options);
52244
+ const data = typeof path44 === "object" ? path44 : parse15(path44, options);
52237
52245
  const fn = tokensToFunction(data.tokens, delimiter, encode2);
52238
52246
  return function path45(params = {}) {
52239
52247
  const [path46, ...missing] = fn(params);
@@ -52328,7 +52336,7 @@ var require_dist2 = __commonJS({
52328
52336
  const flags = sensitive ? "" : "i";
52329
52337
  const sources = [];
52330
52338
  for (const input of pathsToArray(path44, [])) {
52331
- const data = typeof input === "object" ? input : parse16(input, options);
52339
+ const data = typeof input === "object" ? input : parse15(input, options);
52332
52340
  for (const tokens of flatten2(data.tokens, 0, [])) {
52333
52341
  sources.push(toRegExpSource(tokens, delimiter, keys, data.originalPath));
52334
52342
  }
@@ -63637,7 +63645,7 @@ var require_request = __commonJS({
63637
63645
  var http = __require("node:http");
63638
63646
  var fresh = require_fresh();
63639
63647
  var parseRange = require_range_parser();
63640
- var parse16 = require_parseurl();
63648
+ var parse15 = require_parseurl();
63641
63649
  var proxyaddr = require_proxy_addr();
63642
63650
  var req = Object.create(http.IncomingMessage.prototype);
63643
63651
  module.exports = req;
@@ -63682,7 +63690,7 @@ var require_request = __commonJS({
63682
63690
  if (!queryparse) {
63683
63691
  return /* @__PURE__ */ Object.create(null);
63684
63692
  }
63685
- var querystring = parse16(this).query;
63693
+ var querystring = parse15(this).query;
63686
63694
  return queryparse(querystring);
63687
63695
  });
63688
63696
  req.is = function is(types) {
@@ -63726,7 +63734,7 @@ var require_request = __commonJS({
63726
63734
  return subdomains2.slice(offset);
63727
63735
  });
63728
63736
  defineGetter(req, "path", function path44() {
63729
- return parse16(this).pathname;
63737
+ return parse15(this).pathname;
63730
63738
  });
63731
63739
  defineGetter(req, "host", function host() {
63732
63740
  var trust = this.app.get("trust proxy fn");
@@ -63780,7 +63788,7 @@ var require_content_disposition = __commonJS({
63780
63788
  "../../node_modules/content-disposition/index.js"(exports, module) {
63781
63789
  "use strict";
63782
63790
  module.exports = contentDisposition;
63783
- module.exports.parse = parse16;
63791
+ module.exports.parse = parse15;
63784
63792
  var basename5 = __require("path").basename;
63785
63793
  var ENCODE_URL_ATTR_CHAR_REGEXP = /[\x00-\x20"'()*,/:;<=>?@[\\\]{}\x7f]/g;
63786
63794
  var HEX_ESCAPE_REGEXP = /%[0-9A-Fa-f]{2}/;
@@ -63871,7 +63879,7 @@ var require_content_disposition = __commonJS({
63871
63879
  function getlatin1(val) {
63872
63880
  return String(val).replace(NON_LATIN1_REGEXP, "?");
63873
63881
  }
63874
- function parse16(string) {
63882
+ function parse15(string) {
63875
63883
  if (!string || typeof string !== "string") {
63876
63884
  throw new TypeError("argument string is required");
63877
63885
  }
@@ -63960,7 +63968,7 @@ var require_cookie_signature = __commonJS({
63960
63968
  var require_cookie = __commonJS({
63961
63969
  "../../node_modules/cookie/index.js"(exports) {
63962
63970
  "use strict";
63963
- exports.parse = parse16;
63971
+ exports.parse = parse15;
63964
63972
  exports.serialize = serialize;
63965
63973
  var __toString = Object.prototype.toString;
63966
63974
  var __hasOwnProperty = Object.prototype.hasOwnProperty;
@@ -63968,7 +63976,7 @@ var require_cookie = __commonJS({
63968
63976
  var cookieValueRegExp = /^("?)[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]*\1$/;
63969
63977
  var domainValueRegExp = /^([.]?[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)([.][a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?)*$/i;
63970
63978
  var pathValueRegExp = /^[\u0020-\u003A\u003D-\u007E]*$/;
63971
- function parse16(str2, opt) {
63979
+ function parse15(str2, opt) {
63972
63980
  if (typeof str2 !== "string") {
63973
63981
  throw new TypeError("argument str must be a string");
63974
63982
  }
@@ -73637,7 +73645,7 @@ var require_send = __commonJS({
73637
73645
  var escapeHtml = require_escape_html();
73638
73646
  var etag = require_etag();
73639
73647
  var fresh = require_fresh();
73640
- var fs27 = __require("fs");
73648
+ var fs26 = __require("fs");
73641
73649
  var mime = require_mime_types4();
73642
73650
  var ms = require_ms();
73643
73651
  var onFinished = require_on_finished();
@@ -73919,7 +73927,7 @@ var require_send = __commonJS({
73919
73927
  var i = 0;
73920
73928
  var self = this;
73921
73929
  debug('stat "%s"', path45);
73922
- fs27.stat(path45, function onstat(err, stat) {
73930
+ fs26.stat(path45, function onstat(err, stat) {
73923
73931
  var pathEndsWithSep = path45[path45.length - 1] === sep;
73924
73932
  if (err && err.code === "ENOENT" && !extname2(path45) && !pathEndsWithSep) {
73925
73933
  return next(err);
@@ -73936,7 +73944,7 @@ var require_send = __commonJS({
73936
73944
  }
73937
73945
  var p = path45 + "." + self._extensions[i++];
73938
73946
  debug('stat "%s"', p);
73939
- fs27.stat(p, function(err2, stat) {
73947
+ fs26.stat(p, function(err2, stat) {
73940
73948
  if (err2) return next(err2);
73941
73949
  if (stat.isDirectory()) return next();
73942
73950
  self.emit("file", p, stat);
@@ -73954,7 +73962,7 @@ var require_send = __commonJS({
73954
73962
  }
73955
73963
  var p = join40(path45, self._index[i]);
73956
73964
  debug('stat "%s"', p);
73957
- fs27.stat(p, function(err2, stat) {
73965
+ fs26.stat(p, function(err2, stat) {
73958
73966
  if (err2) return next(err2);
73959
73967
  if (stat.isDirectory()) return next();
73960
73968
  self.emit("file", p, stat);
@@ -73966,7 +73974,7 @@ var require_send = __commonJS({
73966
73974
  SendStream.prototype.stream = function stream2(path45, options) {
73967
73975
  var self = this;
73968
73976
  var res = this.res;
73969
- var stream3 = fs27.createReadStream(path45, options);
73977
+ var stream3 = fs26.createReadStream(path45, options);
73970
73978
  this.emit("stream", stream3);
73971
73979
  stream3.pipe(res);
73972
73980
  function cleanup() {
@@ -74124,7 +74132,7 @@ var require_vary = __commonJS({
74124
74132
  if (!field) {
74125
74133
  throw new TypeError("field argument is required");
74126
74134
  }
74127
- var fields = !Array.isArray(field) ? parse16(String(field)) : field;
74135
+ var fields = !Array.isArray(field) ? parse15(String(field)) : field;
74128
74136
  for (var j = 0; j < fields.length; j++) {
74129
74137
  if (!FIELD_NAME_REGEXP.test(fields[j])) {
74130
74138
  throw new TypeError("field argument contains an invalid header name");
@@ -74134,7 +74142,7 @@ var require_vary = __commonJS({
74134
74142
  return header;
74135
74143
  }
74136
74144
  var val = header;
74137
- var vals = parse16(header.toLowerCase());
74145
+ var vals = parse15(header.toLowerCase());
74138
74146
  if (fields.indexOf("*") !== -1 || vals.indexOf("*") !== -1) {
74139
74147
  return "*";
74140
74148
  }
@@ -74147,7 +74155,7 @@ var require_vary = __commonJS({
74147
74155
  }
74148
74156
  return val;
74149
74157
  }
74150
- function parse16(header) {
74158
+ function parse15(header) {
74151
74159
  var end = 0;
74152
74160
  var list = [];
74153
74161
  var start = 0;
@@ -75652,7 +75660,7 @@ var require_api = __commonJS({
75652
75660
  Object.defineProperty(exports, "__esModule", { value: true });
75653
75661
  exports.createApiRouter = createApiRouter;
75654
75662
  var path44 = __importStar(__require("path"));
75655
- var os3 = __importStar(__require("os"));
75663
+ var os4 = __importStar(__require("os"));
75656
75664
  var child_process_1 = __require("child_process");
75657
75665
  var express_1 = require_express2();
75658
75666
  var _useStdinFifo = process.platform === "linux" && !process.env.JEST_WORKER_ID;
@@ -75672,7 +75680,7 @@ var require_api = __commonJS({
75672
75680
  env: { SOPS_CONFIG: path44.join(deps2.repoRoot, ".sops.yaml"), ...opts2?.env }
75673
75681
  });
75674
75682
  }
75675
- const fifoDir = (0, child_process_1.execFileSync)("mktemp", ["-d", path44.join(os3.tmpdir(), "clef-fifo-XXXXXX")]).toString().trim();
75683
+ const fifoDir = (0, child_process_1.execFileSync)("mktemp", ["-d", path44.join(os4.tmpdir(), "clef-fifo-XXXXXX")]).toString().trim();
75676
75684
  const fifoPath = path44.join(fifoDir, "input");
75677
75685
  (0, child_process_1.execFileSync)("mkfifo", [fifoPath]);
75678
75686
  const writer = (0, child_process_1.spawn)("dd", [`of=${fifoPath}`, "status=none"], {
@@ -75706,6 +75714,7 @@ var require_api = __commonJS({
75706
75714
  const git = new core_1.GitIntegration(deps2.runner);
75707
75715
  const scanRunner = new core_1.ScanRunner(deps2.runner);
75708
75716
  const recipientManager = new core_1.RecipientManager(sops, matrix);
75717
+ const serviceIdManager = new core_1.ServiceIdentityManager(sops, matrix);
75709
75718
  const bulkOps = new core_1.BulkOps();
75710
75719
  let lastScanResult = null;
75711
75720
  let lastScanAt = null;
@@ -75713,6 +75722,10 @@ var require_api = __commonJS({
75713
75722
  const manifestPath = `${deps2.repoRoot}/clef.yaml`;
75714
75723
  return parser.parse(manifestPath);
75715
75724
  }
75725
+ function zeroStringRecord(record) {
75726
+ for (const k of Object.keys(record))
75727
+ record[k] = "";
75728
+ }
75716
75729
  function setNoCacheHeaders(res) {
75717
75730
  res.set({
75718
75731
  "Cache-Control": "no-store, no-cache, must-revalidate",
@@ -75954,6 +75967,14 @@ var require_api = __commonJS({
75954
75967
  return;
75955
75968
  }
75956
75969
  const result = await diffEngine.diffFiles(ns, envA, envB, manifest, sops, deps2.repoRoot);
75970
+ if (req.query.showValues !== "true") {
75971
+ for (const row of result.rows) {
75972
+ if (row.valueA !== null)
75973
+ row.valueA = "\u25CF\u25CF\u25CF\u25CF\u25CF\u25CF\u25CF\u25CF";
75974
+ if (row.valueB !== null)
75975
+ row.valueB = "\u25CF\u25CF\u25CF\u25CF\u25CF\u25CF\u25CF\u25CF";
75976
+ }
75977
+ }
75957
75978
  res.json(result);
75958
75979
  } catch {
75959
75980
  res.status(500).json({ error: "Failed to compute diff", code: "DIFF_ERROR" });
@@ -76282,6 +76303,100 @@ var require_api = __commonJS({
76282
76303
  res.status(500).json({ error: message, code: "SERVICE_IDENTITY_ERROR" });
76283
76304
  }
76284
76305
  });
76306
+ router.post("/service-identities", async (req, res) => {
76307
+ try {
76308
+ const manifest = loadManifest();
76309
+ const { name, description, namespaces, kmsEnvConfigs } = req.body;
76310
+ if (!name || typeof name !== "string") {
76311
+ res.status(400).json({ error: "name is required.", code: "BAD_REQUEST" });
76312
+ return;
76313
+ }
76314
+ if (!Array.isArray(namespaces) || namespaces.length === 0) {
76315
+ res.status(400).json({ error: "namespaces must be a non-empty array.", code: "BAD_REQUEST" });
76316
+ return;
76317
+ }
76318
+ let typedKmsConfigs;
76319
+ if (kmsEnvConfigs && Object.keys(kmsEnvConfigs).length > 0) {
76320
+ typedKmsConfigs = {};
76321
+ for (const [envName, cfg] of Object.entries(kmsEnvConfigs)) {
76322
+ if (!core_1.VALID_KMS_PROVIDERS.includes(cfg.provider)) {
76323
+ res.status(400).json({
76324
+ error: `Invalid KMS provider '${cfg.provider}' for environment '${envName}'. Must be aws, gcp, or azure.`,
76325
+ code: "BAD_REQUEST"
76326
+ });
76327
+ return;
76328
+ }
76329
+ typedKmsConfigs[envName] = {
76330
+ provider: cfg.provider,
76331
+ keyId: cfg.keyId
76332
+ };
76333
+ }
76334
+ }
76335
+ const result = await serviceIdManager.create(name, namespaces, description ?? "", manifest, deps2.repoRoot, typedKmsConfigs);
76336
+ setNoCacheHeaders(res);
76337
+ res.json({ identity: result.identity, privateKeys: result.privateKeys });
76338
+ zeroStringRecord(result.privateKeys);
76339
+ } catch (err) {
76340
+ const message = err instanceof Error ? err.message : "Failed to create service identity";
76341
+ res.status(500).json({ error: message, code: "SERVICE_IDENTITY_ERROR" });
76342
+ }
76343
+ });
76344
+ router.delete("/service-identities/:name", async (req, res) => {
76345
+ try {
76346
+ const name = req.params.name;
76347
+ const manifest = loadManifest();
76348
+ if (!manifest.service_identities?.find((si) => si.name === name)) {
76349
+ res.status(404).json({ error: `Service identity '${name}' not found.`, code: "NOT_FOUND" });
76350
+ return;
76351
+ }
76352
+ await serviceIdManager.delete(name, manifest, deps2.repoRoot);
76353
+ res.json({ ok: true });
76354
+ } catch (err) {
76355
+ const message = err instanceof Error ? err.message : "Failed to delete service identity";
76356
+ res.status(500).json({ error: message, code: "SERVICE_IDENTITY_ERROR" });
76357
+ }
76358
+ });
76359
+ router.patch("/service-identities/:name", async (req, res) => {
76360
+ try {
76361
+ const name = req.params.name;
76362
+ const { kmsEnvConfigs } = req.body;
76363
+ if (!kmsEnvConfigs || Object.keys(kmsEnvConfigs).length === 0) {
76364
+ res.status(400).json({ error: "kmsEnvConfigs must be a non-empty object.", code: "BAD_REQUEST" });
76365
+ return;
76366
+ }
76367
+ const manifest = loadManifest();
76368
+ const typedKmsConfigs = {};
76369
+ for (const [envName, cfg] of Object.entries(kmsEnvConfigs)) {
76370
+ if (cfg.provider !== "aws" && cfg.provider !== "gcp" && cfg.provider !== "azure") {
76371
+ res.status(400).json({
76372
+ error: `Invalid KMS provider '${cfg.provider}' for environment '${envName}'. Must be aws, gcp, or azure.`,
76373
+ code: "BAD_REQUEST"
76374
+ });
76375
+ return;
76376
+ }
76377
+ typedKmsConfigs[envName] = { provider: cfg.provider, keyId: cfg.keyId };
76378
+ }
76379
+ await serviceIdManager.updateEnvironments(name, typedKmsConfigs, manifest, deps2.repoRoot);
76380
+ res.json({ ok: true });
76381
+ } catch (err) {
76382
+ const message = err instanceof Error ? err.message : "Failed to update service identity";
76383
+ res.status(500).json({ error: message, code: "SERVICE_IDENTITY_ERROR" });
76384
+ }
76385
+ });
76386
+ router.post("/service-identities/:name/rotate", async (req, res) => {
76387
+ try {
76388
+ const name = req.params.name;
76389
+ const { environment } = req.body;
76390
+ const manifest = loadManifest();
76391
+ const privateKeys = await serviceIdManager.rotateKey(name, manifest, deps2.repoRoot, environment);
76392
+ setNoCacheHeaders(res);
76393
+ res.json({ privateKeys });
76394
+ zeroStringRecord(privateKeys);
76395
+ } catch (err) {
76396
+ const message = err instanceof Error ? err.message : "Failed to rotate service identity key";
76397
+ res.status(500).json({ error: message, code: "SERVICE_IDENTITY_ERROR" });
76398
+ }
76399
+ });
76285
76400
  function dispose() {
76286
76401
  lastScanResult = null;
76287
76402
  lastScanAt = null;
@@ -76437,7 +76552,7 @@ var require_server = __commonJS({
76437
76552
  const resolvedClientDir = clientDir ?? path44.resolve(__dirname, "../client");
76438
76553
  app.use(staticLimiter, express_1.default.static(resolvedClientDir));
76439
76554
  app.get("/{*splat}", staticLimiter, (_req, res) => {
76440
- res.sendFile(path44.join(resolvedClientDir, "index.html"));
76555
+ res.sendFile("index.html", { root: resolvedClientDir });
76441
76556
  });
76442
76557
  }
76443
76558
  const url = `http://127.0.0.1:${port}`;
@@ -76491,6 +76606,11 @@ var require_secrets_cache = __commonJS({
76491
76606
  snapshot = null;
76492
76607
  /** Replace the cached secrets in a single reference assignment. */
76493
76608
  swap(values, keys, revision) {
76609
+ if (this.snapshot) {
76610
+ for (const k of Object.keys(this.snapshot.values)) {
76611
+ this.snapshot.values[k] = "";
76612
+ }
76613
+ }
76494
76614
  this.snapshot = { values: { ...values }, keys: [...keys], revision, swappedAt: Date.now() };
76495
76615
  }
76496
76616
  /** Whether the cache has exceeded the given TTL (seconds). */
@@ -76499,8 +76619,13 @@ var require_secrets_cache = __commonJS({
76499
76619
  return false;
76500
76620
  return (Date.now() - this.snapshot.swappedAt) / 1e3 > ttlSeconds;
76501
76621
  }
76502
- /** Clear the cached snapshot. */
76622
+ /** Clear the cached snapshot, zeroing values first (best-effort). */
76503
76623
  wipe() {
76624
+ if (this.snapshot) {
76625
+ for (const k of Object.keys(this.snapshot.values)) {
76626
+ this.snapshot.values[k] = "";
76627
+ }
76628
+ }
76504
76629
  this.snapshot = null;
76505
76630
  }
76506
76631
  /** Epoch ms when the cache was last swapped, or null if never loaded. */
@@ -76579,7 +76704,7 @@ var require_disk_cache = __commonJS({
76579
76704
  })();
76580
76705
  Object.defineProperty(exports, "__esModule", { value: true });
76581
76706
  exports.DiskCache = void 0;
76582
- var fs27 = __importStar(__require("fs"));
76707
+ var fs26 = __importStar(__require("fs"));
76583
76708
  var path44 = __importStar(__require("path"));
76584
76709
  var DiskCache = class {
76585
76710
  artifactPath;
@@ -76592,39 +76717,35 @@ var require_disk_cache = __commonJS({
76592
76717
  /** Write an artifact and optional metadata to disk (atomic via tmp+rename). */
76593
76718
  write(raw, sha) {
76594
76719
  const dir = path44.dirname(this.artifactPath);
76595
- fs27.mkdirSync(dir, { recursive: true });
76720
+ fs26.mkdirSync(dir, { recursive: true });
76596
76721
  const tmpArtifact = `${this.artifactPath}.tmp.${process.pid}`;
76597
- fs27.writeFileSync(tmpArtifact, raw, "utf-8");
76598
- fs27.renameSync(tmpArtifact, this.artifactPath);
76722
+ fs26.writeFileSync(tmpArtifact, raw, "utf-8");
76723
+ fs26.renameSync(tmpArtifact, this.artifactPath);
76599
76724
  const meta = { sha, fetchedAt: (/* @__PURE__ */ new Date()).toISOString() };
76600
76725
  const tmpMeta = `${this.metaPath}.tmp.${process.pid}`;
76601
- fs27.writeFileSync(tmpMeta, JSON.stringify(meta), "utf-8");
76602
- fs27.renameSync(tmpMeta, this.metaPath);
76726
+ fs26.writeFileSync(tmpMeta, JSON.stringify(meta), "utf-8");
76727
+ fs26.renameSync(tmpMeta, this.metaPath);
76603
76728
  }
76604
76729
  /** Read the cached artifact. Returns null if no cache file exists. */
76605
76730
  read() {
76606
76731
  try {
76607
- return fs27.readFileSync(this.artifactPath, "utf-8");
76732
+ return fs26.readFileSync(this.artifactPath, "utf-8");
76608
76733
  } catch {
76609
76734
  return null;
76610
76735
  }
76611
76736
  }
76612
76737
  /** Get the SHA from the cached metadata, if available. */
76613
76738
  getCachedSha() {
76614
- try {
76615
- const raw = fs27.readFileSync(this.metaPath, "utf-8");
76616
- const meta = JSON.parse(raw);
76617
- return meta.sha;
76618
- } catch {
76619
- return void 0;
76620
- }
76739
+ return this.readMeta()?.sha;
76621
76740
  }
76622
76741
  /** Get the fetchedAt timestamp from metadata, if available. */
76623
76742
  getFetchedAt() {
76743
+ return this.readMeta()?.fetchedAt;
76744
+ }
76745
+ readMeta() {
76624
76746
  try {
76625
- const raw = fs27.readFileSync(this.metaPath, "utf-8");
76626
- const meta = JSON.parse(raw);
76627
- return meta.fetchedAt;
76747
+ const raw = fs26.readFileSync(this.metaPath, "utf-8");
76748
+ return JSON.parse(raw);
76628
76749
  } catch {
76629
76750
  return void 0;
76630
76751
  }
@@ -76632,11 +76753,11 @@ var require_disk_cache = __commonJS({
76632
76753
  /** Remove cached artifact and metadata files. */
76633
76754
  purge() {
76634
76755
  try {
76635
- fs27.unlinkSync(this.artifactPath);
76756
+ fs26.unlinkSync(this.artifactPath);
76636
76757
  } catch {
76637
76758
  }
76638
76759
  try {
76639
- fs27.unlinkSync(this.metaPath);
76760
+ fs26.unlinkSync(this.metaPath);
76640
76761
  } catch {
76641
76762
  }
76642
76763
  }
@@ -76688,7 +76809,7 @@ var require_decrypt = __commonJS({
76688
76809
  })();
76689
76810
  Object.defineProperty(exports, "__esModule", { value: true });
76690
76811
  exports.AgeDecryptor = void 0;
76691
- var fs27 = __importStar(__require("fs"));
76812
+ var fs26 = __importStar(__require("fs"));
76692
76813
  var AgeDecryptor = class {
76693
76814
  /**
76694
76815
  * Decrypt an age-encrypted PEM-armored ciphertext string.
@@ -76714,7 +76835,7 @@ var require_decrypt = __commonJS({
76714
76835
  if (ageKey)
76715
76836
  return ageKey.trim();
76716
76837
  if (ageKeyFile) {
76717
- const content = fs27.readFileSync(ageKeyFile, "utf-8").trim();
76838
+ const content = fs26.readFileSync(ageKeyFile, "utf-8").trim();
76718
76839
  const lines = content.split("\n").filter((l) => l.startsWith("AGE-SECRET-KEY-"));
76719
76840
  if (lines.length === 0) {
76720
76841
  throw new Error(`No age secret key found in file: ${ageKeyFile}`);
@@ -77046,6 +77167,147 @@ var require_kms = __commonJS({
77046
77167
  }
77047
77168
  });
77048
77169
 
77170
+ // ../runtime/dist/artifact-decryptor.js
77171
+ var require_artifact_decryptor = __commonJS({
77172
+ "../runtime/dist/artifact-decryptor.js"(exports) {
77173
+ "use strict";
77174
+ var __createBinding = exports && exports.__createBinding || (Object.create ? (function(o, m, k, k2) {
77175
+ if (k2 === void 0) k2 = k;
77176
+ var desc = Object.getOwnPropertyDescriptor(m, k);
77177
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
77178
+ desc = { enumerable: true, get: function() {
77179
+ return m[k];
77180
+ } };
77181
+ }
77182
+ Object.defineProperty(o, k2, desc);
77183
+ }) : (function(o, m, k, k2) {
77184
+ if (k2 === void 0) k2 = k;
77185
+ o[k2] = m[k];
77186
+ }));
77187
+ var __setModuleDefault = exports && exports.__setModuleDefault || (Object.create ? (function(o, v) {
77188
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
77189
+ }) : function(o, v) {
77190
+ o["default"] = v;
77191
+ });
77192
+ var __importStar = exports && exports.__importStar || /* @__PURE__ */ (function() {
77193
+ var ownKeys = function(o) {
77194
+ ownKeys = Object.getOwnPropertyNames || function(o2) {
77195
+ var ar = [];
77196
+ for (var k in o2) if (Object.prototype.hasOwnProperty.call(o2, k)) ar[ar.length] = k;
77197
+ return ar;
77198
+ };
77199
+ return ownKeys(o);
77200
+ };
77201
+ return function(mod3) {
77202
+ if (mod3 && mod3.__esModule) return mod3;
77203
+ var result = {};
77204
+ if (mod3 != null) {
77205
+ for (var k = ownKeys(mod3), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod3, k[i]);
77206
+ }
77207
+ __setModuleDefault(result, mod3);
77208
+ return result;
77209
+ };
77210
+ })();
77211
+ Object.defineProperty(exports, "__esModule", { value: true });
77212
+ exports.ArtifactDecryptor = void 0;
77213
+ var crypto6 = __importStar(__require("crypto"));
77214
+ var decrypt_1 = require_decrypt();
77215
+ var kms_1 = require_kms();
77216
+ var ArtifactDecryptor = class {
77217
+ ageDecryptor = new decrypt_1.AgeDecryptor();
77218
+ privateKey;
77219
+ telemetryOverride;
77220
+ initialTelemetry;
77221
+ constructor(options) {
77222
+ this.privateKey = options.privateKey;
77223
+ this.initialTelemetry = options.telemetry;
77224
+ }
77225
+ /** Set or replace the telemetry emitter. */
77226
+ setTelemetry(emitter) {
77227
+ this.telemetryOverride = emitter;
77228
+ }
77229
+ get telemetry() {
77230
+ return this.telemetryOverride ?? this.initialTelemetry;
77231
+ }
77232
+ /**
77233
+ * Decrypt an artifact envelope into plaintext key-value pairs.
77234
+ *
77235
+ * @throws On KMS unwrap failure, AES-GCM auth failure, age decrypt failure,
77236
+ * missing private key (config error), or malformed plaintext JSON.
77237
+ */
77238
+ async decrypt(artifact) {
77239
+ let plaintext;
77240
+ if (artifact.envelope) {
77241
+ plaintext = await this.decryptKmsEnvelope(artifact);
77242
+ } else {
77243
+ plaintext = await this.decryptAge(artifact);
77244
+ }
77245
+ let values;
77246
+ try {
77247
+ values = JSON.parse(plaintext);
77248
+ } catch (err) {
77249
+ this.telemetry?.artifactInvalid({
77250
+ reason: "payload_parse",
77251
+ error: err instanceof Error ? err.message : String(err)
77252
+ });
77253
+ throw err;
77254
+ } finally {
77255
+ plaintext = "";
77256
+ }
77257
+ return { values, keys: artifact.keys, revision: artifact.revision };
77258
+ }
77259
+ /** KMS envelope: unwrap DEK via KMS, then AES-256-GCM decrypt. */
77260
+ async decryptKmsEnvelope(artifact) {
77261
+ const envelope = artifact.envelope;
77262
+ let dek;
77263
+ try {
77264
+ const kms = (0, kms_1.createKmsProvider)(envelope.provider);
77265
+ const wrappedKey = Buffer.from(envelope.wrappedKey, "base64");
77266
+ dek = await kms.unwrap(envelope.keyId, wrappedKey, envelope.algorithm);
77267
+ } catch (err) {
77268
+ this.telemetry?.artifactInvalid({
77269
+ reason: "kms_unwrap",
77270
+ error: err instanceof Error ? err.message : String(err)
77271
+ });
77272
+ throw err;
77273
+ }
77274
+ try {
77275
+ const iv = Buffer.from(envelope.iv, "base64");
77276
+ const authTag = Buffer.from(envelope.authTag, "base64");
77277
+ const ciphertextBuf = Buffer.from(artifact.ciphertext, "base64");
77278
+ const decipher = crypto6.createDecipheriv("aes-256-gcm", dek, iv);
77279
+ decipher.setAuthTag(authTag);
77280
+ return Buffer.concat([decipher.update(ciphertextBuf), decipher.final()]).toString("utf-8");
77281
+ } catch (err) {
77282
+ this.telemetry?.artifactInvalid({
77283
+ reason: "decrypt",
77284
+ error: err instanceof Error ? err.message : String(err)
77285
+ });
77286
+ throw err;
77287
+ } finally {
77288
+ dek.fill(0);
77289
+ }
77290
+ }
77291
+ /** Age-only: decrypt with the static private key. */
77292
+ async decryptAge(artifact) {
77293
+ if (!this.privateKey) {
77294
+ throw new Error("Artifact requires an age private key. Set CLEF_AGENT_AGE_KEY or use KMS envelope encryption.");
77295
+ }
77296
+ try {
77297
+ return await this.ageDecryptor.decrypt(artifact.ciphertext, this.privateKey);
77298
+ } catch (err) {
77299
+ this.telemetry?.artifactInvalid({
77300
+ reason: err instanceof SyntaxError ? "payload_parse" : "decrypt",
77301
+ error: err instanceof Error ? err.message : String(err)
77302
+ });
77303
+ throw err;
77304
+ }
77305
+ }
77306
+ };
77307
+ exports.ArtifactDecryptor = ArtifactDecryptor;
77308
+ }
77309
+ });
77310
+
77049
77311
  // ../runtime/dist/signature.js
77050
77312
  var require_signature = __commonJS({
77051
77313
  "../runtime/dist/signature.js"(exports) {
@@ -77093,7 +77355,7 @@ var require_signature = __commonJS({
77093
77355
  var crypto6 = __importStar(__require("crypto"));
77094
77356
  function buildSigningPayload2(artifact) {
77095
77357
  const fields = [
77096
- "clef-sig-v1",
77358
+ "clef-sig-v2",
77097
77359
  String(artifact.version),
77098
77360
  artifact.identity,
77099
77361
  artifact.environment,
@@ -77105,7 +77367,9 @@ var require_signature = __commonJS({
77105
77367
  artifact.envelope?.provider ?? "",
77106
77368
  artifact.envelope?.keyId ?? "",
77107
77369
  artifact.envelope?.wrappedKey ?? "",
77108
- artifact.envelope?.algorithm ?? ""
77370
+ artifact.envelope?.algorithm ?? "",
77371
+ artifact.envelope?.iv ?? "",
77372
+ artifact.envelope?.authTag ?? ""
77109
77373
  ];
77110
77374
  return Buffer.from(fields.join("\n"), "utf-8");
77111
77375
  }
@@ -77172,8 +77436,7 @@ var require_poller = __commonJS({
77172
77436
  Object.defineProperty(exports, "__esModule", { value: true });
77173
77437
  exports.ArtifactPoller = void 0;
77174
77438
  var crypto6 = __importStar(__require("crypto"));
77175
- var decrypt_1 = require_decrypt();
77176
- var kms_1 = require_kms();
77439
+ var artifact_decryptor_1 = require_artifact_decryptor();
77177
77440
  var signature_1 = require_signature();
77178
77441
  var MIN_POLL_MS = 5e3;
77179
77442
  var ArtifactPoller = class {
@@ -77181,21 +77444,68 @@ var require_poller = __commonJS({
77181
77444
  lastContentHash = null;
77182
77445
  lastRevision = null;
77183
77446
  lastExpiresAt = null;
77184
- decryptor = new decrypt_1.AgeDecryptor();
77447
+ decryptor;
77185
77448
  options;
77449
+ jitMode;
77186
77450
  telemetryOverride;
77187
77451
  constructor(options) {
77188
77452
  this.options = options;
77453
+ this.jitMode = !!options.encryptedStore;
77454
+ this.decryptor = new artifact_decryptor_1.ArtifactDecryptor({
77455
+ privateKey: options.privateKey,
77456
+ telemetry: options.telemetry
77457
+ });
77458
+ }
77459
+ /** Get the decryptor instance (for JIT mode server wiring). */
77460
+ getDecryptor() {
77461
+ return this.decryptor;
77189
77462
  }
77190
77463
  /** Set or replace the telemetry emitter (e.g. after resolving token from secrets). */
77191
77464
  setTelemetry(emitter) {
77192
77465
  this.telemetryOverride = emitter;
77466
+ this.decryptor.setTelemetry(emitter);
77193
77467
  }
77194
77468
  get telemetry() {
77195
77469
  return this.telemetryOverride ?? this.options.telemetry;
77196
77470
  }
77197
- /** Fetch, validate, decrypt, and cache the artifact. */
77471
+ /**
77472
+ * Fetch, validate, decrypt, and cache the artifact.
77473
+ * Used in cached mode (cacheTtl > 0).
77474
+ */
77198
77475
  async fetchAndDecrypt() {
77476
+ const result = await this.fetchRaw();
77477
+ if (!result)
77478
+ return;
77479
+ await this.validateDecryptAndCache(result.artifact, result.contentHash);
77480
+ }
77481
+ /**
77482
+ * Fetch and validate the artifact without decrypting.
77483
+ * Stores the validated envelope in the encryptedStore for on-demand decryption.
77484
+ * Used in JIT mode (cacheTtl = 0).
77485
+ */
77486
+ async fetchAndValidate() {
77487
+ const result = await this.fetchRaw();
77488
+ if (!result)
77489
+ return;
77490
+ const artifact = this.validateArtifact(result.artifact);
77491
+ this.options.encryptedStore.swap(artifact);
77492
+ this.lastRevision = artifact.revision;
77493
+ this.lastContentHash = result.contentHash ?? null;
77494
+ this.lastExpiresAt = artifact.expiresAt ?? null;
77495
+ this.options.onRefresh?.(artifact.revision);
77496
+ this.telemetry?.artifactRefreshed({
77497
+ revision: artifact.revision,
77498
+ keyCount: artifact.keys.length,
77499
+ kmsEnvelope: !!artifact.envelope
77500
+ });
77501
+ }
77502
+ /**
77503
+ * Fetch the raw artifact from the source (with disk cache fallback),
77504
+ * parse JSON, and check for revocation.
77505
+ *
77506
+ * Returns null when the content hash is unchanged (short-circuit).
77507
+ */
77508
+ async fetchRaw() {
77199
77509
  let raw;
77200
77510
  let contentHash;
77201
77511
  try {
@@ -77203,7 +77513,7 @@ var require_poller = __commonJS({
77203
77513
  raw = result.raw;
77204
77514
  contentHash = result.contentHash;
77205
77515
  if (contentHash && contentHash === this.lastContentHash)
77206
- return;
77516
+ return null;
77207
77517
  this.options.diskCache?.write(raw, contentHash);
77208
77518
  } catch (err) {
77209
77519
  this.telemetry?.fetchFailed({
@@ -77214,7 +77524,7 @@ var require_poller = __commonJS({
77214
77524
  if (this.options.diskCache) {
77215
77525
  const cached2 = this.options.diskCache.read();
77216
77526
  if (cached2) {
77217
- if (ttl !== void 0) {
77527
+ if (ttl !== void 0 && ttl > 0) {
77218
77528
  const fetchedAt = this.options.diskCache.getFetchedAt();
77219
77529
  if (fetchedAt && (Date.now() - new Date(fetchedAt).getTime()) / 1e3 > ttl) {
77220
77530
  this.options.cache.wipe();
@@ -77229,9 +77539,9 @@ var require_poller = __commonJS({
77229
77539
  raw = cached2;
77230
77540
  contentHash = this.options.diskCache.getCachedSha();
77231
77541
  if (contentHash && contentHash === this.lastContentHash)
77232
- return;
77542
+ return null;
77233
77543
  } else {
77234
- if (ttl !== void 0 && this.options.cache.isExpired(ttl)) {
77544
+ if (ttl !== void 0 && ttl > 0 && this.options.cache.isExpired(ttl)) {
77235
77545
  this.options.cache.wipe();
77236
77546
  this.telemetry?.cacheExpired({
77237
77547
  cacheTtlSeconds: ttl,
@@ -77242,7 +77552,7 @@ var require_poller = __commonJS({
77242
77552
  throw err;
77243
77553
  }
77244
77554
  } else {
77245
- if (ttl !== void 0 && this.options.cache.isExpired(ttl)) {
77555
+ if (ttl !== void 0 && ttl > 0 && this.options.cache.isExpired(ttl)) {
77246
77556
  this.options.cache.wipe();
77247
77557
  this.telemetry?.cacheExpired({
77248
77558
  cacheTtlSeconds: ttl,
@@ -77256,6 +77566,7 @@ var require_poller = __commonJS({
77256
77566
  const parsed = JSON.parse(raw);
77257
77567
  if (parsed.revokedAt) {
77258
77568
  this.options.cache.wipe();
77569
+ this.options.encryptedStore?.wipe();
77259
77570
  this.options.diskCache?.purge();
77260
77571
  this.lastRevision = null;
77261
77572
  this.lastContentHash = null;
@@ -77264,17 +77575,18 @@ var require_poller = __commonJS({
77264
77575
  });
77265
77576
  throw new Error(`Artifact revoked: ${parsed.identity}/${parsed.environment} at ${parsed.revokedAt}`);
77266
77577
  }
77267
- await this.validateDecryptAndCache(raw, contentHash);
77578
+ return { artifact: parsed, contentHash };
77268
77579
  }
77269
77580
  /**
77270
- * Validate the artifact, decrypt it, and swap the cache.
77271
- * Emits `artifact.invalid` on any validation or decryption failure,
77272
- * and `artifact.expired` / `artifact.refreshed` on their respective paths.
77581
+ * Validate the artifact envelope: version, required fields, expiry,
77582
+ * revision dedup, integrity hash, and signature.
77583
+ * Emits `artifact.invalid` / `artifact.expired` telemetry on failure.
77584
+ * Returns the validated artifact, or throws.
77273
77585
  */
77274
- async validateDecryptAndCache(raw, contentHash) {
77586
+ validateArtifact(parsed) {
77275
77587
  let artifact;
77276
77588
  try {
77277
- artifact = this.parseAndValidate(raw);
77589
+ artifact = this.validateEnvelope(parsed);
77278
77590
  } catch (err) {
77279
77591
  this.telemetry?.artifactInvalid({
77280
77592
  reason: classifyValidationError(err),
@@ -77284,12 +77596,13 @@ var require_poller = __commonJS({
77284
77596
  }
77285
77597
  if (artifact.expiresAt && Date.now() > new Date(artifact.expiresAt).getTime()) {
77286
77598
  this.options.cache.wipe();
77599
+ this.options.encryptedStore?.wipe();
77287
77600
  this.options.diskCache?.purge();
77288
77601
  this.telemetry?.artifactExpired({ expiresAt: artifact.expiresAt });
77289
77602
  throw new Error(`Artifact expired at ${artifact.expiresAt}`);
77290
77603
  }
77291
77604
  if (artifact.revision === this.lastRevision)
77292
- return;
77605
+ return artifact;
77293
77606
  const hash = crypto6.createHash("sha256").update(artifact.ciphertext).digest("hex");
77294
77607
  if (hash !== artifact.ciphertextHash) {
77295
77608
  const err = new Error(`Artifact integrity check failed: expected hash ${artifact.ciphertextHash}, got ${hash}`);
@@ -77329,53 +77642,34 @@ var require_poller = __commonJS({
77329
77642
  throw err;
77330
77643
  }
77331
77644
  }
77332
- let agePrivateKey;
77333
- if (artifact.envelope) {
77334
- try {
77335
- const kms = (0, kms_1.createKmsProvider)(artifact.envelope.provider);
77336
- const wrappedKey = Buffer.from(artifact.envelope.wrappedKey, "base64");
77337
- const unwrapped = await kms.unwrap(artifact.envelope.keyId, wrappedKey, artifact.envelope.algorithm);
77338
- agePrivateKey = unwrapped.toString("utf-8");
77339
- unwrapped.fill(0);
77340
- } catch (err) {
77341
- this.telemetry?.artifactInvalid({
77342
- reason: "kms_unwrap",
77343
- error: err instanceof Error ? err.message : String(err)
77344
- });
77345
- throw err;
77346
- }
77347
- } else {
77348
- if (!this.options.privateKey) {
77349
- throw new Error("Artifact requires an age private key. Set CLEF_AGENT_AGE_KEY or use KMS envelope encryption.");
77350
- }
77351
- agePrivateKey = this.options.privateKey;
77352
- }
77353
- try {
77354
- const plaintext = await this.decryptor.decrypt(artifact.ciphertext, agePrivateKey);
77355
- const values = JSON.parse(plaintext);
77356
- this.options.cache.swap(values, artifact.keys, artifact.revision);
77357
- this.lastRevision = artifact.revision;
77358
- this.lastContentHash = contentHash ?? null;
77359
- this.lastExpiresAt = artifact.expiresAt ?? null;
77360
- this.options.onRefresh?.(artifact.revision);
77361
- this.telemetry?.artifactRefreshed({
77362
- revision: artifact.revision,
77363
- keyCount: artifact.keys.length,
77364
- kmsEnvelope: !!artifact.envelope
77365
- });
77366
- } catch (err) {
77367
- if (err instanceof Error && !err.message.includes("integrity check failed")) {
77368
- this.telemetry?.artifactInvalid({
77369
- reason: err instanceof SyntaxError ? "payload_parse" : "decrypt",
77370
- error: err.message
77371
- });
77372
- }
77373
- throw err;
77374
- }
77645
+ return artifact;
77646
+ }
77647
+ /**
77648
+ * Validate then decrypt and cache. Used by fetchAndDecrypt (cached mode).
77649
+ */
77650
+ async validateDecryptAndCache(parsed, contentHash) {
77651
+ const artifact = this.validateArtifact(parsed);
77652
+ if (artifact.revision === this.lastRevision)
77653
+ return;
77654
+ const { values } = await this.decryptor.decrypt(artifact);
77655
+ this.options.cache.swap(values, artifact.keys, artifact.revision);
77656
+ this.lastRevision = artifact.revision;
77657
+ this.lastContentHash = contentHash ?? null;
77658
+ this.lastExpiresAt = artifact.expiresAt ?? null;
77659
+ this.options.onRefresh?.(artifact.revision);
77660
+ this.telemetry?.artifactRefreshed({
77661
+ revision: artifact.revision,
77662
+ keyCount: artifact.keys.length,
77663
+ kmsEnvelope: !!artifact.envelope
77664
+ });
77375
77665
  }
77376
77666
  /** Start the polling loop. Performs an initial fetch immediately. */
77377
77667
  async start() {
77378
- await this.fetchAndDecrypt();
77668
+ if (this.jitMode) {
77669
+ await this.fetchAndValidate();
77670
+ } else {
77671
+ await this.fetchAndDecrypt();
77672
+ }
77379
77673
  this.scheduleNext();
77380
77674
  }
77381
77675
  /** Start only the polling schedule (no initial fetch). */
@@ -77401,7 +77695,11 @@ var require_poller = __commonJS({
77401
77695
  this.timer = setTimeout(async () => {
77402
77696
  this.timer = null;
77403
77697
  try {
77404
- await this.fetchAndDecrypt();
77698
+ if (this.jitMode) {
77699
+ await this.fetchAndValidate();
77700
+ } else {
77701
+ await this.fetchAndDecrypt();
77702
+ }
77405
77703
  } catch (err) {
77406
77704
  this.options.onError?.(err instanceof Error ? err : new Error(String(err)));
77407
77705
  }
@@ -77417,14 +77715,15 @@ var require_poller = __commonJS({
77417
77715
  }
77418
77716
  return MIN_POLL_MS;
77419
77717
  }
77718
+ if (this.jitMode)
77719
+ return MIN_POLL_MS;
77420
77720
  const ttl = this.options.cacheTtl;
77421
77721
  if (ttl !== void 0) {
77422
77722
  return Math.max(ttl / 10 * 1e3, MIN_POLL_MS);
77423
77723
  }
77424
77724
  return 3e4;
77425
77725
  }
77426
- parseAndValidate(raw) {
77427
- const artifact = JSON.parse(raw);
77726
+ validateEnvelope(artifact) {
77428
77727
  if (artifact.version !== 1) {
77429
77728
  throw new Error(`Unsupported artifact version: ${artifact.version}`);
77430
77729
  }
@@ -77432,7 +77731,7 @@ var require_poller = __commonJS({
77432
77731
  throw new Error("Invalid artifact: missing required fields.");
77433
77732
  }
77434
77733
  if (artifact.envelope) {
77435
- if (!artifact.envelope.provider || !artifact.envelope.keyId || !artifact.envelope.wrappedKey || !artifact.envelope.algorithm) {
77734
+ if (!artifact.envelope.provider || !artifact.envelope.keyId || !artifact.envelope.wrappedKey || !artifact.envelope.algorithm || !artifact.envelope.iv || !artifact.envelope.authTag) {
77436
77735
  throw new Error("Invalid artifact: incomplete envelope fields.");
77437
77736
  }
77438
77737
  }
@@ -77457,6 +77756,50 @@ var require_poller = __commonJS({
77457
77756
  }
77458
77757
  });
77459
77758
 
77759
+ // ../runtime/dist/encrypted-artifact-store.js
77760
+ var require_encrypted_artifact_store = __commonJS({
77761
+ "../runtime/dist/encrypted-artifact-store.js"(exports) {
77762
+ "use strict";
77763
+ Object.defineProperty(exports, "__esModule", { value: true });
77764
+ exports.EncryptedArtifactStore = void 0;
77765
+ var EncryptedArtifactStore = class {
77766
+ artifact = null;
77767
+ _storedAt = null;
77768
+ /** Atomically replace the stored artifact. */
77769
+ swap(artifact) {
77770
+ this.artifact = artifact;
77771
+ this._storedAt = Date.now();
77772
+ }
77773
+ /** Get the current encrypted artifact. Returns null if not yet loaded. */
77774
+ get() {
77775
+ return this.artifact;
77776
+ }
77777
+ /** Whether an artifact has been stored. */
77778
+ isReady() {
77779
+ return this.artifact !== null;
77780
+ }
77781
+ /** Epoch ms of last store, or null. */
77782
+ getStoredAt() {
77783
+ return this._storedAt;
77784
+ }
77785
+ /** Get key names from the stored artifact metadata (no decryption needed). */
77786
+ getKeys() {
77787
+ return this.artifact ? [...this.artifact.keys] : [];
77788
+ }
77789
+ /** Get the revision from the stored artifact. */
77790
+ getRevision() {
77791
+ return this.artifact?.revision ?? null;
77792
+ }
77793
+ /** Clear the stored artifact (on revocation/expiry). */
77794
+ wipe() {
77795
+ this.artifact = null;
77796
+ this._storedAt = null;
77797
+ }
77798
+ };
77799
+ exports.EncryptedArtifactStore = EncryptedArtifactStore;
77800
+ }
77801
+ });
77802
+
77460
77803
  // ../runtime/dist/telemetry.js
77461
77804
  var require_telemetry = __commonJS({
77462
77805
  "../runtime/dist/telemetry.js"(exports) {
@@ -77811,14 +78154,23 @@ var require_http = __commonJS({
77811
78154
  async fetch() {
77812
78155
  const res = await fetch(this.url);
77813
78156
  if (!res.ok) {
77814
- throw new Error(`Failed to fetch artifact from ${this.url}: ${res.status}`);
78157
+ throw new Error(`Failed to fetch artifact from ${this.describe()}: ${res.status}`);
77815
78158
  }
77816
78159
  const raw = await res.text();
77817
78160
  const etag = res.headers.get("etag") ?? void 0;
77818
78161
  return { raw, contentHash: etag };
77819
78162
  }
77820
78163
  describe() {
77821
- return `HTTP ${this.url}`;
78164
+ try {
78165
+ const parsed = new URL(this.url);
78166
+ if (parsed.username || parsed.password) {
78167
+ parsed.username = "***";
78168
+ parsed.password = "";
78169
+ }
78170
+ return `HTTP ${parsed.href}`;
78171
+ } catch {
78172
+ return "HTTP <invalid-url>";
78173
+ }
77822
78174
  }
77823
78175
  };
77824
78176
  exports.HttpArtifactSource = HttpArtifactSource;
@@ -77868,14 +78220,14 @@ var require_file = __commonJS({
77868
78220
  })();
77869
78221
  Object.defineProperty(exports, "__esModule", { value: true });
77870
78222
  exports.FileArtifactSource = void 0;
77871
- var fs27 = __importStar(__require("fs"));
78223
+ var fs26 = __importStar(__require("fs"));
77872
78224
  var FileArtifactSource = class {
77873
78225
  path;
77874
78226
  constructor(filePath) {
77875
78227
  this.path = filePath;
77876
78228
  }
77877
78229
  async fetch() {
77878
- const raw = fs27.readFileSync(this.path, "utf-8");
78230
+ const raw = fs26.readFileSync(this.path, "utf-8");
77879
78231
  return { raw };
77880
78232
  }
77881
78233
  describe() {
@@ -77920,7 +78272,7 @@ var require_dist4 = __commonJS({
77920
78272
  "../runtime/dist/index.js"(exports) {
77921
78273
  "use strict";
77922
78274
  Object.defineProperty(exports, "__esModule", { value: true });
77923
- exports.ClefRuntime = exports.verifySignature = exports.buildSigningPayload = exports.VcsArtifactSource = exports.FileArtifactSource = exports.HttpArtifactSource = exports.createKmsProvider = exports.AwsKmsProvider = exports.createVcsProvider = exports.BitbucketProvider = exports.GitLabProvider = exports.GitHubProvider = exports.TelemetryEmitter = exports.ArtifactPoller = exports.AgeDecryptor = exports.DiskCache = exports.SecretsCache = void 0;
78275
+ exports.ClefRuntime = exports.verifySignature = exports.buildSigningPayload = exports.VcsArtifactSource = exports.FileArtifactSource = exports.HttpArtifactSource = exports.createKmsProvider = exports.AwsKmsProvider = exports.createVcsProvider = exports.BitbucketProvider = exports.GitLabProvider = exports.GitHubProvider = exports.TelemetryEmitter = exports.EncryptedArtifactStore = exports.ArtifactDecryptor = exports.ArtifactPoller = exports.AgeDecryptor = exports.DiskCache = exports.SecretsCache = void 0;
77924
78276
  exports.init = init;
77925
78277
  var secrets_cache_1 = require_secrets_cache();
77926
78278
  Object.defineProperty(exports, "SecretsCache", { enumerable: true, get: function() {
@@ -77938,6 +78290,14 @@ var require_dist4 = __commonJS({
77938
78290
  Object.defineProperty(exports, "ArtifactPoller", { enumerable: true, get: function() {
77939
78291
  return poller_1.ArtifactPoller;
77940
78292
  } });
78293
+ var artifact_decryptor_1 = require_artifact_decryptor();
78294
+ Object.defineProperty(exports, "ArtifactDecryptor", { enumerable: true, get: function() {
78295
+ return artifact_decryptor_1.ArtifactDecryptor;
78296
+ } });
78297
+ var encrypted_artifact_store_1 = require_encrypted_artifact_store();
78298
+ Object.defineProperty(exports, "EncryptedArtifactStore", { enumerable: true, get: function() {
78299
+ return encrypted_artifact_store_1.EncryptedArtifactStore;
78300
+ } });
77941
78301
  var telemetry_1 = require_telemetry();
77942
78302
  Object.defineProperty(exports, "TelemetryEmitter", { enumerable: true, get: function() {
77943
78303
  return telemetry_1.TelemetryEmitter;
@@ -78150,12 +78510,15 @@ var NodeSubprocessRunner = class {
78150
78510
  };
78151
78511
 
78152
78512
  // src/commands/init.ts
78153
- var YAML12 = __toESM(require_dist());
78513
+ var YAML11 = __toESM(require_dist());
78154
78514
  init_src();
78155
- import * as fs17 from "fs";
78515
+ import * as fs16 from "fs";
78156
78516
  import * as path19 from "path";
78157
78517
  import * as readline2 from "readline";
78158
78518
 
78519
+ // src/handle-error.ts
78520
+ init_src();
78521
+
78159
78522
  // src/output/formatter.ts
78160
78523
  var import_picocolors = __toESM(require_picocolors());
78161
78524
  init_src();
@@ -78365,6 +78728,16 @@ function pad(str2, width) {
78365
78728
  return diff > 0 ? str2 + " ".repeat(diff) : str2;
78366
78729
  }
78367
78730
 
78731
+ // src/handle-error.ts
78732
+ function handleCommandError(err) {
78733
+ if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
78734
+ formatter.formatDependencyError(err);
78735
+ } else {
78736
+ formatter.error(err.message);
78737
+ }
78738
+ process.exit(1);
78739
+ }
78740
+
78368
78741
  // src/keychain.ts
78369
78742
  var SERVICE = "clef";
78370
78743
  var CRED_HELPER_CS = `
@@ -78815,8 +79188,8 @@ function registerInitCommand(program3, deps2) {
78815
79188
  }
78816
79189
  const manifestPath = path19.join(repoRoot, "clef.yaml");
78817
79190
  const clefConfigPath = path19.join(repoRoot, CLEF_DIR, CLEF_CONFIG_FILENAME);
78818
- const manifestExists = fs17.existsSync(manifestPath);
78819
- const localConfigExists = fs17.existsSync(clefConfigPath);
79191
+ const manifestExists = fs16.existsSync(manifestPath);
79192
+ const localConfigExists = fs16.existsSync(clefConfigPath);
78820
79193
  if (manifestExists && localConfigExists) {
78821
79194
  formatter.print("Already initialised. Run 'clef update' to scaffold new environments.");
78822
79195
  process.exit(0);
@@ -78838,8 +79211,7 @@ function registerInitCommand(program3, deps2) {
78838
79211
  }
78839
79212
  await handleFullSetup(repoRoot, manifestPath, clefConfigPath, deps2, options);
78840
79213
  } catch (err) {
78841
- formatter.error(err.message);
78842
- process.exit(1);
79214
+ handleCommandError(err);
78843
79215
  }
78844
79216
  });
78845
79217
  }
@@ -78871,22 +79243,22 @@ async function handleSecondDevOnboarding(repoRoot, clefConfigPath, deps2, option
78871
79243
  const publicKey = identity.publicKey;
78872
79244
  const keyContent = formatAgeKeyFile(privateKey, publicKey);
78873
79245
  const keyDir = path19.dirname(keyPath);
78874
- if (!fs17.existsSync(keyDir)) {
78875
- fs17.mkdirSync(keyDir, { recursive: true });
79246
+ if (!fs16.existsSync(keyDir)) {
79247
+ fs16.mkdirSync(keyDir, { recursive: true });
78876
79248
  }
78877
- fs17.writeFileSync(keyPath, keyContent, { encoding: "utf-8", mode: 384 });
79249
+ fs16.writeFileSync(keyPath, keyContent, { encoding: "utf-8", mode: 384 });
78878
79250
  formatter.success(`Generated age key at ${keyPath}`);
78879
79251
  config = { age_key_file: keyPath, age_key_storage: "file", age_keychain_label: label2 };
78880
79252
  }
78881
79253
  const clefDir = path19.dirname(clefConfigPath);
78882
- if (!fs17.existsSync(clefDir)) {
78883
- fs17.mkdirSync(clefDir, { recursive: true });
79254
+ if (!fs16.existsSync(clefDir)) {
79255
+ fs16.mkdirSync(clefDir, { recursive: true });
78884
79256
  }
78885
- fs17.writeFileSync(clefConfigPath, YAML12.stringify(config), "utf-8");
79257
+ fs16.writeFileSync(clefConfigPath, YAML11.stringify(config), "utf-8");
78886
79258
  formatter.success("Created .clef/config.yaml");
78887
79259
  const gitignorePath = path19.join(clefDir, ".gitignore");
78888
- if (!fs17.existsSync(gitignorePath)) {
78889
- fs17.writeFileSync(gitignorePath, "*\n", "utf-8");
79260
+ if (!fs16.existsSync(gitignorePath)) {
79261
+ fs16.writeFileSync(gitignorePath, "*\n", "utf-8");
78890
79262
  formatter.success("Created .clef/.gitignore");
78891
79263
  }
78892
79264
  formatter.success(`Key label: ${label2}`);
@@ -78978,38 +79350,38 @@ async function handleFullSetup(repoRoot, manifestPath, clefConfigPath, deps2, op
78978
79350
  }
78979
79351
  const keyContent = formatAgeKeyFile(privateKey, publicKey);
78980
79352
  const keyDir = path19.dirname(keyPath);
78981
- if (!fs17.existsSync(keyDir)) {
78982
- fs17.mkdirSync(keyDir, { recursive: true });
79353
+ if (!fs16.existsSync(keyDir)) {
79354
+ fs16.mkdirSync(keyDir, { recursive: true });
78983
79355
  }
78984
- fs17.writeFileSync(keyPath, keyContent, { encoding: "utf-8", mode: 384 });
79356
+ fs16.writeFileSync(keyPath, keyContent, { encoding: "utf-8", mode: 384 });
78985
79357
  formatter.success(`Generated age key at ${keyPath}`);
78986
79358
  ageKeyFile = keyPath;
78987
79359
  }
78988
79360
  const clefDir = path19.dirname(clefConfigPath);
78989
- if (!fs17.existsSync(clefDir)) {
78990
- fs17.mkdirSync(clefDir, { recursive: true });
79361
+ if (!fs16.existsSync(clefDir)) {
79362
+ fs16.mkdirSync(clefDir, { recursive: true });
78991
79363
  }
78992
79364
  const config = ageKeyFile ? { age_key_file: ageKeyFile, age_key_storage: "file", age_keychain_label: label2 } : { age_key_storage: "keychain", age_keychain_label: label2 };
78993
- fs17.writeFileSync(clefConfigPath, YAML12.stringify(config), "utf-8");
79365
+ fs16.writeFileSync(clefConfigPath, YAML11.stringify(config), "utf-8");
78994
79366
  formatter.success("Created .clef/config.yaml");
78995
79367
  const gitignorePath = path19.join(clefDir, ".gitignore");
78996
- if (!fs17.existsSync(gitignorePath)) {
78997
- fs17.writeFileSync(gitignorePath, "*\n", "utf-8");
79368
+ if (!fs16.existsSync(gitignorePath)) {
79369
+ fs16.writeFileSync(gitignorePath, "*\n", "utf-8");
78998
79370
  formatter.success("Created .clef/.gitignore");
78999
79371
  }
79000
79372
  formatter.success(`Key label: ${label2}`);
79001
79373
  }
79002
- const manifestDoc = YAML12.parse(YAML12.stringify(manifest));
79374
+ const manifestDoc = YAML11.parse(YAML11.stringify(manifest));
79003
79375
  if (backend === "age" && publicKey) {
79004
79376
  const sopsDoc = manifestDoc.sops;
79005
79377
  sopsDoc.age = { recipients: [publicKey] };
79006
79378
  }
79007
- fs17.writeFileSync(manifestPath, YAML12.stringify(manifestDoc), "utf-8");
79379
+ fs16.writeFileSync(manifestPath, YAML11.stringify(manifestDoc), "utf-8");
79008
79380
  formatter.success("Created clef.yaml");
79009
79381
  {
79010
79382
  const sopsYamlPath = path19.join(repoRoot, ".sops.yaml");
79011
79383
  const sopsConfig = buildSopsYaml(manifest, repoRoot, publicKey);
79012
- fs17.writeFileSync(sopsYamlPath, YAML12.stringify(sopsConfig), "utf-8");
79384
+ fs16.writeFileSync(sopsYamlPath, YAML11.stringify(sopsConfig), "utf-8");
79013
79385
  formatter.success("Created .sops.yaml");
79014
79386
  }
79015
79387
  const sopsClient = new SopsClient(deps2.runner, ageKeyFile, ageKey);
@@ -79066,8 +79438,8 @@ async function handleFullSetup(repoRoot, manifestPath, clefConfigPath, deps2, op
79066
79438
  }
79067
79439
  }
79068
79440
  const clefignorePath = path19.join(repoRoot, ".clefignore");
79069
- if (!fs17.existsSync(clefignorePath)) {
79070
- fs17.writeFileSync(clefignorePath, DEFAULT_CLEFIGNORE, "utf-8");
79441
+ if (!fs16.existsSync(clefignorePath)) {
79442
+ fs16.writeFileSync(clefignorePath, DEFAULT_CLEFIGNORE, "utf-8");
79071
79443
  formatter.success("Created .clefignore");
79072
79444
  } else {
79073
79445
  formatter.print(" .clefignore already exists \u2014 skipping");
@@ -79099,7 +79471,7 @@ function scaffoldSopsConfig(repoRoot) {
79099
79471
  agePublicKey = resolveAgePublicKeyFromEnvOrFile(repoRoot);
79100
79472
  }
79101
79473
  const sopsConfig = buildSopsYaml(manifest, repoRoot, agePublicKey);
79102
- fs17.writeFileSync(sopsYamlPath, YAML12.stringify(sopsConfig), "utf-8");
79474
+ fs16.writeFileSync(sopsYamlPath, YAML11.stringify(sopsConfig), "utf-8");
79103
79475
  }
79104
79476
  function buildSopsYaml(manifest, _repoRoot, agePublicKey) {
79105
79477
  const creationRules = [];
@@ -79163,9 +79535,9 @@ function resolveAgePublicKeyFromEnvOrFile(repoRoot) {
79163
79535
  if (match) return match[1];
79164
79536
  }
79165
79537
  const clefConfigPath = path19.join(repoRoot, CLEF_DIR, CLEF_CONFIG_FILENAME);
79166
- if (fs17.existsSync(clefConfigPath)) {
79538
+ if (fs16.existsSync(clefConfigPath)) {
79167
79539
  try {
79168
- const config = YAML12.parse(fs17.readFileSync(clefConfigPath, "utf-8"));
79540
+ const config = YAML11.parse(fs16.readFileSync(clefConfigPath, "utf-8"));
79169
79541
  if (config?.age_key_file) {
79170
79542
  const pubKey = extractAgePublicKey(config.age_key_file);
79171
79543
  if (pubKey) return pubKey;
@@ -79177,8 +79549,8 @@ function resolveAgePublicKeyFromEnvOrFile(repoRoot) {
79177
79549
  }
79178
79550
  function extractAgePublicKey(keyFilePath) {
79179
79551
  try {
79180
- if (!fs17.existsSync(keyFilePath)) return void 0;
79181
- const content = fs17.readFileSync(keyFilePath, "utf-8");
79552
+ if (!fs16.existsSync(keyFilePath)) return void 0;
79553
+ const content = fs16.readFileSync(keyFilePath, "utf-8");
79182
79554
  const match = content.match(/# public key: (age1[a-z0-9]+)/);
79183
79555
  return match ? match[1] : void 0;
79184
79556
  } catch {
@@ -79245,9 +79617,9 @@ init_src();
79245
79617
  import * as path21 from "path";
79246
79618
 
79247
79619
  // src/age-credential.ts
79248
- var YAML13 = __toESM(require_dist());
79620
+ var YAML12 = __toESM(require_dist());
79249
79621
  init_src();
79250
- import * as fs18 from "fs";
79622
+ import * as fs17 from "fs";
79251
79623
  import * as path20 from "path";
79252
79624
  var CLEF_DIR2 = ".clef";
79253
79625
  var CLEF_CONFIG_FILENAME2 = "config.yaml";
@@ -79312,7 +79684,7 @@ async function resolveAgePrivateKey(repoRoot, runner2) {
79312
79684
  const filePath = process.env.CLEF_AGE_KEY_FILE;
79313
79685
  if (!filePath) return null;
79314
79686
  try {
79315
- const content = fs18.readFileSync(filePath, "utf-8");
79687
+ const content = fs17.readFileSync(filePath, "utf-8");
79316
79688
  const match = content.match(AGE_SECRET_KEY_RE);
79317
79689
  return match ? match[1] : null;
79318
79690
  } catch (err) {
@@ -79324,7 +79696,7 @@ async function resolveAgePrivateKey(repoRoot, runner2) {
79324
79696
  }
79325
79697
  case "config-file": {
79326
79698
  try {
79327
- const content = fs18.readFileSync(credential.path, "utf-8");
79699
+ const content = fs17.readFileSync(credential.path, "utf-8");
79328
79700
  const match = content.match(AGE_SECRET_KEY_RE);
79329
79701
  return match ? match[1] : null;
79330
79702
  } catch (err) {
@@ -79339,8 +79711,8 @@ async function resolveAgePrivateKey(repoRoot, runner2) {
79339
79711
  function readLocalConfig(repoRoot) {
79340
79712
  const clefConfigPath = path20.join(repoRoot, CLEF_DIR2, CLEF_CONFIG_FILENAME2);
79341
79713
  try {
79342
- if (!fs18.existsSync(clefConfigPath)) return null;
79343
- return YAML13.parse(fs18.readFileSync(clefConfigPath, "utf-8"));
79714
+ if (!fs17.existsSync(clefConfigPath)) return null;
79715
+ return YAML12.parse(fs17.readFileSync(clefConfigPath, "utf-8"));
79344
79716
  } catch (err) {
79345
79717
  formatter.warn(
79346
79718
  `Failed to parse ${clefConfigPath}: ${err instanceof Error ? err.message : String(err)}
@@ -79382,6 +79754,15 @@ function maskedPlaceholder() {
79382
79754
  return "\u2022\u2022\u2022\u2022\u2022\u2022\u2022\u2022";
79383
79755
  }
79384
79756
 
79757
+ // src/parse-target.ts
79758
+ function parseTarget(target) {
79759
+ const parts = target.split("/");
79760
+ if (parts.length !== 2 || !parts[0] || !parts[1]) {
79761
+ throw new Error(`Invalid target "${target}". Expected format: namespace/environment`);
79762
+ }
79763
+ return [parts[0], parts[1]];
79764
+ }
79765
+
79385
79766
  // src/commands/get.ts
79386
79767
  function registerGetCommand(program3, deps2) {
79387
79768
  program3.command("get <target> <key>").description(
@@ -79417,23 +79798,10 @@ function registerGetCommand(program3, deps2) {
79417
79798
  }
79418
79799
  }
79419
79800
  } catch (err) {
79420
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
79421
- formatter.formatDependencyError(err);
79422
- process.exit(1);
79423
- return;
79424
- }
79425
- formatter.error(err.message);
79426
- process.exit(1);
79801
+ handleCommandError(err);
79427
79802
  }
79428
79803
  });
79429
79804
  }
79430
- function parseTarget(target) {
79431
- const parts = target.split("/");
79432
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
79433
- throw new Error(`Invalid target "${target}". Expected format: namespace/environment`);
79434
- }
79435
- return [parts[0], parts[1]];
79436
- }
79437
79805
 
79438
79806
  // src/commands/set.ts
79439
79807
  init_src();
@@ -79548,7 +79916,7 @@ function registerSetCommand(program3, deps2) {
79548
79916
  Consider using the interactive prompt instead: clef set ${target} ${key}`
79549
79917
  );
79550
79918
  }
79551
- const [namespace, environment] = parseTarget2(target);
79919
+ const [namespace, environment] = parseTarget(target);
79552
79920
  const matrixManager = new MatrixManager();
79553
79921
  if (matrixManager.isProtectedEnvironment(manifest, environment)) {
79554
79922
  const confirmed = await formatter.confirm(
@@ -79580,11 +79948,22 @@ function registerSetCommand(program3, deps2) {
79580
79948
  try {
79581
79949
  await markPendingWithRetry(filePath, [key], "clef set --random");
79582
79950
  } catch {
79583
- formatter.error(
79584
- `${key} was encrypted but pending state could not be recorded.
79585
- The encrypted file contains a random placeholder value with no tracking metadata.
79951
+ try {
79952
+ delete decrypted.values[key];
79953
+ await sopsClient.encrypt(filePath, decrypted.values, manifest, environment);
79954
+ } catch {
79955
+ formatter.error(
79956
+ `${key} was encrypted but pending state could not be recorded, and rollback failed.
79957
+ The encrypted file may contain an untracked random placeholder.
79586
79958
  This key MUST be set to a real value before deploying.
79587
79959
  Run: clef set ${namespace}/${environment} ${key}`
79960
+ );
79961
+ process.exit(1);
79962
+ return;
79963
+ }
79964
+ formatter.error(
79965
+ `${key}: pending state could not be recorded. The value was rolled back.
79966
+ Retry: clef set --random ${namespace}/${environment} ${key}`
79588
79967
  );
79589
79968
  process.exit(1);
79590
79969
  return;
@@ -79609,24 +79988,11 @@ function registerSetCommand(program3, deps2) {
79609
79988
  );
79610
79989
  }
79611
79990
  } catch (err) {
79612
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
79613
- formatter.formatDependencyError(err);
79614
- process.exit(1);
79615
- return;
79616
- }
79617
- formatter.error(err.message);
79618
- process.exit(1);
79991
+ handleCommandError(err);
79619
79992
  }
79620
79993
  }
79621
79994
  );
79622
79995
  }
79623
- function parseTarget2(target) {
79624
- const parts = target.split("/");
79625
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
79626
- throw new Error(`Invalid target "${target}". Expected format: namespace/environment`);
79627
- }
79628
- return [parts[0], parts[1]];
79629
- }
79630
79996
 
79631
79997
  // src/commands/compare.ts
79632
79998
  init_src();
@@ -79637,7 +80003,7 @@ function registerCompareCommand(program3, deps2) {
79637
80003
  "Compare a stored secret with a supplied value.\n\n target: namespace/environment (e.g. payments/staging)\n key: the key name to compare\n value: optional \u2014 if omitted, prompts with hidden input\n\nNeither value is ever printed to stdout.\n\nExit codes:\n 0 values match\n 1 values do not match or operation failed"
79638
80004
  ).action(async (target, key, value) => {
79639
80005
  try {
79640
- const [namespace, environment] = parseTarget3(target);
80006
+ const [namespace, environment] = parseTarget(target);
79641
80007
  const repoRoot = program3.opts().dir || process.cwd();
79642
80008
  const parser = new ManifestParser();
79643
80009
  const manifest = parser.parse(path23.join(repoRoot, "clef.yaml"));
@@ -79667,7 +80033,15 @@ function registerCompareCommand(program3, deps2) {
79667
80033
  return;
79668
80034
  }
79669
80035
  const stored = decrypted.values[key];
79670
- const match = stored.length === compareValue.length && crypto5.timingSafeEqual(Buffer.from(stored), Buffer.from(compareValue));
80036
+ const storedBuf = Buffer.from(stored);
80037
+ const compareBuf = Buffer.from(compareValue);
80038
+ const maxLen = Math.max(storedBuf.length, compareBuf.length, 1);
80039
+ const paddedStored = Buffer.alloc(maxLen);
80040
+ const paddedCompare = Buffer.alloc(maxLen);
80041
+ storedBuf.copy(paddedStored);
80042
+ compareBuf.copy(paddedCompare);
80043
+ const timingEqual = crypto5.timingSafeEqual(paddedStored, paddedCompare);
80044
+ const match = storedBuf.length === compareBuf.length && timingEqual;
79671
80045
  if (match) {
79672
80046
  formatter.success(`${key} ${sym("arrow")} values match`);
79673
80047
  } else {
@@ -79675,23 +80049,10 @@ function registerCompareCommand(program3, deps2) {
79675
80049
  process.exit(1);
79676
80050
  }
79677
80051
  } catch (err) {
79678
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
79679
- formatter.formatDependencyError(err);
79680
- process.exit(1);
79681
- return;
79682
- }
79683
- formatter.error(err.message);
79684
- process.exit(1);
80052
+ handleCommandError(err);
79685
80053
  }
79686
80054
  });
79687
80055
  }
79688
- function parseTarget3(target) {
79689
- const parts = target.split("/");
79690
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
79691
- throw new Error(`Invalid target "${target}". Expected format: namespace/environment`);
79692
- }
79693
- return [parts[0], parts[1]];
79694
- }
79695
80056
 
79696
80057
  // src/commands/delete.ts
79697
80058
  init_src();
@@ -79723,7 +80084,7 @@ Type the key name to confirm:`
79723
80084
  await bulkOps.deleteAcrossEnvironments(namespace, key, manifest, sopsClient, repoRoot);
79724
80085
  formatter.success(`Deleted '${key}' from ${namespace} in all environments`);
79725
80086
  } else {
79726
- const [namespace, environment] = parseTarget4(target);
80087
+ const [namespace, environment] = parseTarget(target);
79727
80088
  if (matrixManager.isProtectedEnvironment(manifest, environment)) {
79728
80089
  const protConfirmed = await formatter.confirm(
79729
80090
  `This is a protected environment (${environment}). Are you sure you want to delete '${key}'?`
@@ -79765,23 +80126,10 @@ Type the key name to confirm:`
79765
80126
  );
79766
80127
  }
79767
80128
  } catch (err) {
79768
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
79769
- formatter.formatDependencyError(err);
79770
- process.exit(1);
79771
- return;
79772
- }
79773
- formatter.error(err.message);
79774
- process.exit(1);
80129
+ handleCommandError(err);
79775
80130
  }
79776
80131
  });
79777
80132
  }
79778
- function parseTarget4(target) {
79779
- const parts = target.split("/");
79780
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
79781
- throw new Error(`Invalid target "${target}". Expected format: namespace/environment`);
79782
- }
79783
- return [parts[0], parts[1]];
79784
- }
79785
80133
 
79786
80134
  // src/commands/diff.ts
79787
80135
  var import_picocolors2 = __toESM(require_picocolors());
@@ -79836,13 +80184,7 @@ function registerDiffCommand(program3, deps2) {
79836
80184
  const hasDiffs = result.rows.some((r) => r.status !== "identical");
79837
80185
  process.exit(hasDiffs ? 1 : 0);
79838
80186
  } catch (err) {
79839
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
79840
- formatter.formatDependencyError(err);
79841
- process.exit(1);
79842
- return;
79843
- }
79844
- formatter.error(err.message);
79845
- process.exit(1);
80187
+ handleCommandError(err);
79846
80188
  }
79847
80189
  }
79848
80190
  );
@@ -80129,7 +80471,7 @@ async function fetchCheckpoint(config) {
80129
80471
  }
80130
80472
 
80131
80473
  // package.json
80132
- var version = "0.1.8-beta.52";
80474
+ var version = "0.1.9-beta.57";
80133
80475
  var package_default = {
80134
80476
  name: "@clef-sh/cli",
80135
80477
  version,
@@ -80234,13 +80576,7 @@ function registerLintCommand(program3, deps2) {
80234
80576
  const hasErrors = result.issues.some((i) => i.severity === "error");
80235
80577
  process.exit(hasErrors ? 1 : 0);
80236
80578
  } catch (err) {
80237
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
80238
- formatter.formatDependencyError(err);
80239
- process.exit(1);
80240
- return;
80241
- }
80242
- formatter.error(err.message);
80243
- process.exit(1);
80579
+ handleCommandError(err);
80244
80580
  }
80245
80581
  });
80246
80582
  }
@@ -80310,7 +80646,7 @@ function registerRotateCommand(program3, deps2) {
80310
80646
  "Rotate encryption key for a namespace/environment file.\n\n target: namespace/environment (e.g. payments/production)\n --new-key: the new age public key to add (required)\n\nExit codes:\n 0 key rotated successfully\n 1 operation failed"
80311
80647
  ).requiredOption("--new-key <key>", "New age public key to rotate to").action(async (target, options) => {
80312
80648
  try {
80313
- const [namespace, environment] = parseTarget5(target);
80649
+ const [namespace, environment] = parseTarget(target);
80314
80650
  const repoRoot = program3.opts().dir || process.cwd();
80315
80651
  const parser = new ManifestParser();
80316
80652
  const manifest = parser.parse(path27.join(repoRoot, "clef.yaml"));
@@ -80337,27 +80673,14 @@ function registerRotateCommand(program3, deps2) {
80337
80673
  `git add ${relativeFile} && git commit -m "rotate: ${namespace}/${environment}"`
80338
80674
  );
80339
80675
  } catch (err) {
80340
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
80341
- formatter.formatDependencyError(err);
80342
- process.exit(1);
80343
- return;
80344
- }
80345
- formatter.error(err.message);
80346
- process.exit(1);
80676
+ handleCommandError(err);
80347
80677
  }
80348
80678
  });
80349
80679
  }
80350
- function parseTarget5(target) {
80351
- const parts = target.split("/");
80352
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
80353
- throw new Error(`Invalid target "${target}". Expected format: namespace/environment`);
80354
- }
80355
- return [parts[0], parts[1]];
80356
- }
80357
80680
 
80358
80681
  // src/commands/hooks.ts
80359
80682
  init_src();
80360
- import * as fs19 from "fs";
80683
+ import * as fs18 from "fs";
80361
80684
  import * as path28 from "path";
80362
80685
  function registerHooksCommand(program3, deps2) {
80363
80686
  const hooks = program3.command("hooks").description("Manage git hooks for Clef");
@@ -80365,8 +80688,8 @@ function registerHooksCommand(program3, deps2) {
80365
80688
  try {
80366
80689
  const repoRoot = program3.opts().dir || process.cwd();
80367
80690
  const hookPath = path28.join(repoRoot, ".git", "hooks", "pre-commit");
80368
- if (fs19.existsSync(hookPath)) {
80369
- const content = fs19.readFileSync(hookPath, "utf-8");
80691
+ if (fs18.existsSync(hookPath)) {
80692
+ const content = fs18.readFileSync(hookPath, "utf-8");
80370
80693
  if (content.includes("clef") || content.includes("SOPS")) {
80371
80694
  const confirmed = await formatter.confirm(
80372
80695
  "A Clef pre-commit hook already exists. Overwrite?"
@@ -80497,6 +80820,7 @@ async function openBrowser(url, runner2) {
80497
80820
 
80498
80821
  // src/commands/exec.ts
80499
80822
  init_src();
80823
+ import * as os2 from "os";
80500
80824
  import * as path30 from "path";
80501
80825
  import { spawn } from "child_process";
80502
80826
  function collect(value, previous) {
@@ -80532,7 +80856,7 @@ function registerExecCommand(program3, deps2) {
80532
80856
  process.exit(1);
80533
80857
  return;
80534
80858
  }
80535
- const [namespace, environment] = parseTarget6(target);
80859
+ const [namespace, environment] = parseTarget(target);
80536
80860
  const repoRoot = program3.opts().dir || process.cwd();
80537
80861
  const parser = new ManifestParser();
80538
80862
  const manifest = parser.parse(path30.join(repoRoot, "clef.yaml"));
@@ -80549,7 +80873,7 @@ function registerExecCommand(program3, deps2) {
80549
80873
  const mergedValues = { ...primaryDecrypted.values };
80550
80874
  for (const alsoTarget of options.also) {
80551
80875
  try {
80552
- const [alsoNs, alsoEnv] = parseTarget6(alsoTarget);
80876
+ const [alsoNs, alsoEnv] = parseTarget(alsoTarget);
80553
80877
  const alsoFilePath = path30.join(
80554
80878
  repoRoot,
80555
80879
  manifest.file_pattern.replace("{namespace}", alsoNs).replace("{environment}", alsoEnv)
@@ -80586,14 +80910,7 @@ function registerExecCommand(program3, deps2) {
80586
80910
  const exitCode = await spawnChild(childCommand, childCommandArgs, childEnv);
80587
80911
  process.exit(exitCode);
80588
80912
  } catch (err) {
80589
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
80590
- formatter.formatDependencyError(err);
80591
- process.exit(1);
80592
- return;
80593
- }
80594
- const message = err instanceof Error ? err.message : "Execution failed";
80595
- formatter.error(message);
80596
- process.exit(1);
80913
+ handleCommandError(err);
80597
80914
  }
80598
80915
  }
80599
80916
  );
@@ -80619,12 +80936,8 @@ function spawnChild(command, args, env) {
80619
80936
  process.off("SIGTERM", sigtermHandler);
80620
80937
  process.off("SIGINT", sigintHandler);
80621
80938
  if (signal) {
80622
- const signalCodes = {
80623
- SIGHUP: 129,
80624
- SIGINT: 130,
80625
- SIGTERM: 143
80626
- };
80627
- resolve6(signalCodes[signal] ?? 128);
80939
+ const sigNum = os2.constants?.signals?.[signal];
80940
+ resolve6(sigNum ? 128 + sigNum : 128);
80628
80941
  } else {
80629
80942
  resolve6(code ?? 1);
80630
80943
  }
@@ -80642,13 +80955,6 @@ function spawnChild(command, args, env) {
80642
80955
  process.on("SIGINT", sigintHandler);
80643
80956
  });
80644
80957
  }
80645
- function parseTarget6(target) {
80646
- const parts = target.split("/");
80647
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
80648
- throw new Error(`Invalid target "${target}". Expected format: namespace/environment`);
80649
- }
80650
- return [parts[0], parts[1]];
80651
- }
80652
80958
 
80653
80959
  // src/commands/export.ts
80654
80960
  init_src();
@@ -80677,7 +80983,7 @@ Usage: clef export payments/production --format env`
80677
80983
  process.exit(1);
80678
80984
  return;
80679
80985
  }
80680
- const [namespace, environment] = parseTarget7(target);
80986
+ const [namespace, environment] = parseTarget(target);
80681
80987
  const repoRoot = program3.opts().dir || process.cwd();
80682
80988
  const parser = new ManifestParser();
80683
80989
  const manifest = parser.parse(path31.join(repoRoot, "clef.yaml"));
@@ -80712,29 +81018,15 @@ Usage: clef export payments/production --format env`
80712
81018
  }
80713
81019
  }
80714
81020
  } catch (err) {
80715
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
80716
- formatter.formatDependencyError(err);
80717
- process.exit(1);
80718
- return;
80719
- }
80720
- const message = err instanceof Error ? err.message : "Export failed";
80721
- formatter.error(message);
80722
- process.exit(1);
81021
+ handleCommandError(err);
80723
81022
  }
80724
81023
  });
80725
81024
  }
80726
- function parseTarget7(target) {
80727
- const parts = target.split("/");
80728
- if (parts.length !== 2 || !parts[0] || !parts[1]) {
80729
- throw new Error(`Invalid target "${target}". Expected format: namespace/environment`);
80730
- }
80731
- return [parts[0], parts[1]];
80732
- }
80733
81025
 
80734
81026
  // src/commands/doctor.ts
80735
- var YAML14 = __toESM(require_dist());
81027
+ var YAML13 = __toESM(require_dist());
80736
81028
  init_src();
80737
- import * as fs20 from "fs";
81029
+ import * as fs19 from "fs";
80738
81030
  import * as path32 from "path";
80739
81031
  function registerDoctorCommand(program3, deps2) {
80740
81032
  program3.command("doctor").description(
@@ -80784,7 +81076,7 @@ function registerDoctorCommand(program3, deps2) {
80784
81076
  });
80785
81077
  }
80786
81078
  const manifestPath = path32.join(repoRoot, "clef.yaml");
80787
- const manifestFound = fs20.existsSync(manifestPath);
81079
+ const manifestFound = fs19.existsSync(manifestPath);
80788
81080
  checks.push({
80789
81081
  name: "manifest",
80790
81082
  ok: manifestFound,
@@ -80794,7 +81086,7 @@ function registerDoctorCommand(program3, deps2) {
80794
81086
  const ageKeyResult = await checkAgeKey(repoRoot, deps2.runner);
80795
81087
  checks.push(ageKeyResult);
80796
81088
  const sopsYamlPath = path32.join(repoRoot, ".sops.yaml");
80797
- const sopsYamlFound = fs20.existsSync(sopsYamlPath);
81089
+ const sopsYamlFound = fs19.existsSync(sopsYamlPath);
80798
81090
  checks.push({
80799
81091
  name: ".sops.yaml",
80800
81092
  ok: sopsYamlFound,
@@ -80802,11 +81094,11 @@ function registerDoctorCommand(program3, deps2) {
80802
81094
  hint: sopsYamlFound ? void 0 : "run: clef init"
80803
81095
  });
80804
81096
  const clefignorePath = path32.join(repoRoot, ".clefignore");
80805
- const clefignoreFound = fs20.existsSync(clefignorePath);
81097
+ const clefignoreFound = fs19.existsSync(clefignorePath);
80806
81098
  let clefignoreRuleCount = 0;
80807
81099
  if (clefignoreFound) {
80808
81100
  try {
80809
- const content = fs20.readFileSync(clefignorePath, "utf-8");
81101
+ const content = fs19.readFileSync(clefignorePath, "utf-8");
80810
81102
  clefignoreRuleCount = content.split("\n").filter(
80811
81103
  (l) => l.trim() && !l.trim().startsWith("#") && !l.trim().startsWith("ignore-pattern:")
80812
81104
  ).length;
@@ -80838,7 +81130,7 @@ function registerDoctorCommand(program3, deps2) {
80838
81130
  formatter.info("Attempting to fix: generating .sops.yaml from manifest...");
80839
81131
  try {
80840
81132
  scaffoldSopsConfig(repoRoot);
80841
- const nowFound = fs20.existsSync(sopsYamlPath);
81133
+ const nowFound = fs19.existsSync(sopsYamlPath);
80842
81134
  if (nowFound) {
80843
81135
  const sopsYamlCheck = checks.find((c) => c.name === ".sops.yaml");
80844
81136
  if (sopsYamlCheck) {
@@ -80962,7 +81254,7 @@ async function checkAgeKey(repoRoot, runner2) {
80962
81254
  source: "env"
80963
81255
  };
80964
81256
  case "config-file":
80965
- if (!fs20.existsSync(credential.path)) {
81257
+ if (!fs19.existsSync(credential.path)) {
80966
81258
  return {
80967
81259
  name: "age key",
80968
81260
  ok: false,
@@ -80981,9 +81273,9 @@ async function checkAgeKey(repoRoot, runner2) {
80981
81273
  }
80982
81274
  function countAgeRecipients(sopsYamlPath) {
80983
81275
  try {
80984
- if (!fs20.existsSync(sopsYamlPath)) return 0;
80985
- const content = fs20.readFileSync(sopsYamlPath, "utf-8");
80986
- const config = YAML14.parse(content);
81276
+ if (!fs19.existsSync(sopsYamlPath)) return 0;
81277
+ const content = fs19.readFileSync(sopsYamlPath, "utf-8");
81278
+ const config = YAML13.parse(content);
80987
81279
  if (!config?.creation_rules || !Array.isArray(config.creation_rules)) {
80988
81280
  return 0;
80989
81281
  }
@@ -81010,7 +81302,7 @@ function getSopsInstallHint() {
81010
81302
 
81011
81303
  // src/commands/update.ts
81012
81304
  init_src();
81013
- import * as fs21 from "fs";
81305
+ import * as fs20 from "fs";
81014
81306
  import * as path33 from "path";
81015
81307
  function registerUpdateCommand(program3, deps2) {
81016
81308
  program3.command("update").description(
@@ -81019,7 +81311,7 @@ function registerUpdateCommand(program3, deps2) {
81019
81311
  try {
81020
81312
  const repoRoot = program3.opts().dir || process.cwd();
81021
81313
  const manifestPath = path33.join(repoRoot, "clef.yaml");
81022
- if (!fs21.existsSync(manifestPath)) {
81314
+ if (!fs20.existsSync(manifestPath)) {
81023
81315
  formatter.error("clef.yaml not found. Run 'clef init' to initialise this repository.");
81024
81316
  process.exit(1);
81025
81317
  return;
@@ -81053,19 +81345,12 @@ function registerUpdateCommand(program3, deps2) {
81053
81345
  formatter.success(`Scaffolded ${scaffoldedCount} encrypted file(s)`);
81054
81346
  }
81055
81347
  if (failedCount === 0) {
81056
- process.exit(0);
81057
81348
  return;
81058
81349
  }
81059
81350
  formatter.error(`${failedCount} cell(s) could not be scaffolded.`);
81060
81351
  process.exit(1);
81061
81352
  } catch (err) {
81062
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
81063
- formatter.formatDependencyError(err);
81064
- process.exit(1);
81065
- return;
81066
- }
81067
- formatter.error(err.message);
81068
- process.exit(1);
81353
+ handleCommandError(err);
81069
81354
  }
81070
81355
  });
81071
81356
  }
@@ -81191,7 +81476,7 @@ function formatScanOutput(result) {
81191
81476
 
81192
81477
  // src/commands/import.ts
81193
81478
  init_src();
81194
- import * as fs22 from "fs";
81479
+ import * as fs21 from "fs";
81195
81480
  import * as path35 from "path";
81196
81481
  async function readStdin() {
81197
81482
  return new Promise((resolve6, reject) => {
@@ -81252,13 +81537,13 @@ function registerImportCommand(program3, deps2) {
81252
81537
  if (opts2.stdin) {
81253
81538
  content = await readStdin();
81254
81539
  } else if (source) {
81255
- if (!fs22.existsSync(source)) {
81540
+ if (!fs21.existsSync(source)) {
81256
81541
  formatter.error(`Source file not found: ${source}`);
81257
81542
  process.exit(2);
81258
81543
  return;
81259
81544
  }
81260
81545
  try {
81261
- content = fs22.readFileSync(source, "utf-8");
81546
+ content = fs21.readFileSync(source, "utf-8");
81262
81547
  sourcePath = source;
81263
81548
  } catch (err) {
81264
81549
  formatter.error(`Could not read source file: ${err.message}`);
@@ -81346,13 +81631,7 @@ ${result.imported.length} imported, ${result.skipped.length} skipped, ${result.f
81346
81631
  }
81347
81632
  }
81348
81633
  } catch (err) {
81349
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
81350
- formatter.formatDependencyError(err);
81351
- process.exit(1);
81352
- return;
81353
- }
81354
- formatter.error(err.message);
81355
- process.exit(1);
81634
+ handleCommandError(err);
81356
81635
  }
81357
81636
  }
81358
81637
  );
@@ -81411,13 +81690,7 @@ function registerRecipientsCommand(program3, deps2) {
81411
81690
  formatter.recipientItem(r.label || r.preview, r.label ? r.preview : "");
81412
81691
  }
81413
81692
  } catch (err) {
81414
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
81415
- formatter.formatDependencyError(err);
81416
- process.exit(1);
81417
- return;
81418
- }
81419
- formatter.error(err.message);
81420
- process.exit(1);
81693
+ handleCommandError(err);
81421
81694
  }
81422
81695
  });
81423
81696
  recipientsCmd.command("add <key>").description(
@@ -81447,13 +81720,7 @@ function registerRecipientsCommand(program3, deps2) {
81447
81720
  );
81448
81721
  }
81449
81722
  } catch (err) {
81450
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
81451
- formatter.formatDependencyError(err);
81452
- process.exit(1);
81453
- return;
81454
- }
81455
- formatter.error(err.message);
81456
- process.exit(1);
81723
+ handleCommandError(err);
81457
81724
  }
81458
81725
  });
81459
81726
  recipientsCmd.command("remove <key>").description("Remove an age recipient and re-encrypt all files in the matrix.").option("-e, --environment <env>", "Scope removal to a specific environment").action(async (key, opts2) => {
@@ -81561,13 +81828,7 @@ ${sym("failure")} Re-encryption failed on ${path36.basename(failedFile)}`
81561
81828
  `git add clef.yaml && git add -A && git commit -m "remove recipient: ${label2}${envSuffix}"`
81562
81829
  );
81563
81830
  } catch (err) {
81564
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
81565
- formatter.formatDependencyError(err);
81566
- process.exit(1);
81567
- return;
81568
- }
81569
- formatter.error(err.message);
81570
- process.exit(1);
81831
+ handleCommandError(err);
81571
81832
  }
81572
81833
  });
81573
81834
  recipientsCmd.command("request").description(
@@ -81685,13 +81946,7 @@ ${sym("failure")} Re-encryption failed on ${path36.basename(failedFile)}`
81685
81946
  );
81686
81947
  }
81687
81948
  } catch (err) {
81688
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
81689
- formatter.formatDependencyError(err);
81690
- process.exit(1);
81691
- return;
81692
- }
81693
- formatter.error(err.message);
81694
- process.exit(1);
81949
+ handleCommandError(err);
81695
81950
  }
81696
81951
  });
81697
81952
  }
@@ -81762,13 +82017,13 @@ ${sym("failure")} Re-encryption failed on ${path36.basename(failedFile)}`);
81762
82017
 
81763
82018
  // src/commands/merge-driver.ts
81764
82019
  init_src();
81765
- import * as fs23 from "fs";
82020
+ import * as fs22 from "fs";
81766
82021
  import * as path37 from "path";
81767
82022
  async function findRepoRoot(filePath, runner2) {
81768
82023
  try {
81769
82024
  let dir = path37.dirname(path37.resolve(filePath));
81770
82025
  for (let i = 0; i < 50; i++) {
81771
- if (fs23.existsSync(path37.join(dir, "clef.yaml"))) return dir;
82026
+ if (fs22.existsSync(path37.join(dir, "clef.yaml"))) return dir;
81772
82027
  const parent = path37.dirname(dir);
81773
82028
  if (parent === dir) break;
81774
82029
  dir = parent;
@@ -81801,7 +82056,7 @@ function registerMergeDriverCommand(program3, deps2) {
81801
82056
  const manifestPath = path37.join(repoRoot, "clef.yaml");
81802
82057
  let manifest;
81803
82058
  let environment;
81804
- if (fs23.existsSync(manifestPath)) {
82059
+ if (fs22.existsSync(manifestPath)) {
81805
82060
  const parser = new ManifestParser();
81806
82061
  manifest = parser.parse(manifestPath);
81807
82062
  for (const ns of manifest.namespaces) {
@@ -81895,40 +82150,7 @@ function registerServiceCommand(program3, deps2) {
81895
82150
  const parser = new ManifestParser();
81896
82151
  const manifest = parser.parse(path38.join(repoRoot, "clef.yaml"));
81897
82152
  const namespaces = opts2.namespaces.split(",").map((s) => s.trim());
81898
- let kmsEnvConfigs;
81899
- if (opts2.kmsEnv.length > 0) {
81900
- kmsEnvConfigs = {};
81901
- for (const mapping of opts2.kmsEnv) {
81902
- const eqIdx = mapping.indexOf("=");
81903
- if (eqIdx === -1) {
81904
- throw new Error(
81905
- `Invalid --kms-env format: '${mapping}'. Expected: env=provider:keyId`
81906
- );
81907
- }
81908
- const envName = mapping.slice(0, eqIdx);
81909
- const rest = mapping.slice(eqIdx + 1);
81910
- const colonIdx = rest.indexOf(":");
81911
- if (colonIdx === -1) {
81912
- throw new Error(
81913
- `Invalid --kms-env format: '${mapping}'. Expected: env=provider:keyId`
81914
- );
81915
- }
81916
- const provider = rest.slice(0, colonIdx);
81917
- const keyId = rest.slice(colonIdx + 1);
81918
- if (!["aws", "gcp", "azure"].includes(provider)) {
81919
- throw new Error(
81920
- `Invalid KMS provider '${provider}'. Must be one of: aws, gcp, azure.`
81921
- );
81922
- }
81923
- if (kmsEnvConfigs[envName]) {
81924
- throw new Error(`Duplicate --kms-env for environment '${envName}'.`);
81925
- }
81926
- kmsEnvConfigs[envName] = {
81927
- provider,
81928
- keyId
81929
- };
81930
- }
81931
- }
82153
+ const kmsEnvConfigs = opts2.kmsEnv.length > 0 ? parseKmsEnvMappings(opts2.kmsEnv) : void 0;
81932
82154
  const hasAgeEnvs = !kmsEnvConfigs || manifest.environments.some((e) => !kmsEnvConfigs[e.name]);
81933
82155
  const protectedEnvs = manifest.environments.filter((e) => e.protected).map((e) => e.name);
81934
82156
  if (protectedEnvs.length > 0 && hasAgeEnvs) {
@@ -81993,13 +82215,7 @@ function registerServiceCommand(program3, deps2) {
81993
82215
  `git add clef.yaml && git commit -m "feat: add service identity '${name}'"`
81994
82216
  );
81995
82217
  } catch (err) {
81996
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
81997
- formatter.formatDependencyError(err);
81998
- process.exit(1);
81999
- return;
82000
- }
82001
- formatter.error(err.message);
82002
- process.exit(1);
82218
+ handleCommandError(err);
82003
82219
  }
82004
82220
  }
82005
82221
  );
@@ -82024,13 +82240,7 @@ function registerServiceCommand(program3, deps2) {
82024
82240
  });
82025
82241
  formatter.table(rows, ["Name", "Namespaces", "Environments"]);
82026
82242
  } catch (err) {
82027
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
82028
- formatter.formatDependencyError(err);
82029
- process.exit(1);
82030
- return;
82031
- }
82032
- formatter.error(err.message);
82033
- process.exit(1);
82243
+ handleCommandError(err);
82034
82244
  }
82035
82245
  });
82036
82246
  serviceCmd.command("show <name>").description("Show details of a service identity.").action(async (name) => {
@@ -82063,13 +82273,7 @@ Service Identity: ${identity.name}`);
82063
82273
  }
82064
82274
  formatter.print("");
82065
82275
  } catch (err) {
82066
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
82067
- formatter.formatDependencyError(err);
82068
- process.exit(1);
82069
- return;
82070
- }
82071
- formatter.error(err.message);
82072
- process.exit(1);
82276
+ handleCommandError(err);
82073
82277
  }
82074
82278
  });
82075
82279
  serviceCmd.command("validate").description("Validate service identity configurations and report drift issues.").action(async () => {
@@ -82104,13 +82308,7 @@ Service Identity: ${identity.name}`);
82104
82308
  formatter.warn(`${warnCount} warning(s)`);
82105
82309
  }
82106
82310
  } catch (err) {
82107
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
82108
- formatter.formatDependencyError(err);
82109
- process.exit(1);
82110
- return;
82111
- }
82112
- formatter.error(err.message);
82113
- process.exit(1);
82311
+ handleCommandError(err);
82114
82312
  }
82115
82313
  });
82116
82314
  serviceCmd.command("update <name>").description("Update an existing service identity's environment backends.").option(
@@ -82131,31 +82329,7 @@ Service Identity: ${identity.name}`);
82131
82329
  const repoRoot = program3.opts().dir || process.cwd();
82132
82330
  const parser = new ManifestParser();
82133
82331
  const manifest = parser.parse(path38.join(repoRoot, "clef.yaml"));
82134
- const kmsEnvConfigs = {};
82135
- for (const mapping of opts2.kmsEnv) {
82136
- const eqIdx = mapping.indexOf("=");
82137
- if (eqIdx === -1) {
82138
- throw new Error(`Invalid --kms-env format: '${mapping}'. Expected: env=provider:keyId`);
82139
- }
82140
- const envName = mapping.slice(0, eqIdx);
82141
- const rest = mapping.slice(eqIdx + 1);
82142
- const colonIdx = rest.indexOf(":");
82143
- if (colonIdx === -1) {
82144
- throw new Error(`Invalid --kms-env format: '${mapping}'. Expected: env=provider:keyId`);
82145
- }
82146
- const provider = rest.slice(0, colonIdx);
82147
- const keyId = rest.slice(colonIdx + 1);
82148
- if (!["aws", "gcp", "azure"].includes(provider)) {
82149
- throw new Error(`Invalid KMS provider '${provider}'. Must be one of: aws, gcp, azure.`);
82150
- }
82151
- if (kmsEnvConfigs[envName]) {
82152
- throw new Error(`Duplicate --kms-env for environment '${envName}'.`);
82153
- }
82154
- kmsEnvConfigs[envName] = {
82155
- provider,
82156
- keyId
82157
- };
82158
- }
82332
+ const kmsEnvConfigs = parseKmsEnvMappings(opts2.kmsEnv);
82159
82333
  const matrixManager = new MatrixManager();
82160
82334
  const sopsClient = await createSopsClient(repoRoot, deps2.runner);
82161
82335
  const manager = new ServiceIdentityManager(sopsClient, matrixManager);
@@ -82169,13 +82343,7 @@ Service Identity: ${identity.name}`);
82169
82343
  `git add clef.yaml && git commit -m "chore: update service identity '${name}'"`
82170
82344
  );
82171
82345
  } catch (err) {
82172
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
82173
- formatter.formatDependencyError(err);
82174
- process.exit(1);
82175
- return;
82176
- }
82177
- formatter.error(err.message);
82178
- process.exit(1);
82346
+ handleCommandError(err);
82179
82347
  }
82180
82348
  });
82181
82349
  serviceCmd.command("delete <name>").description("Delete a service identity and remove its recipients from scoped files.").action(async (name) => {
@@ -82207,13 +82375,7 @@ Service Identity: ${identity.name}`);
82207
82375
  `git add clef.yaml && git commit -m "chore: delete service identity '${name}'"`
82208
82376
  );
82209
82377
  } catch (err) {
82210
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
82211
- formatter.formatDependencyError(err);
82212
- process.exit(1);
82213
- return;
82214
- }
82215
- formatter.error(err.message);
82216
- process.exit(1);
82378
+ handleCommandError(err);
82217
82379
  }
82218
82380
  });
82219
82381
  serviceCmd.command("rotate <name>").description("Rotate the age key for a service identity.").option("-e, --environment <env>", "Rotate only a specific environment").action(async (name, opts2) => {
@@ -82267,11 +82429,6 @@ Service Identity: ${identity.name}`);
82267
82429
  `git add clef.yaml && git commit -m "chore: rotate service identity '${name}'"`
82268
82430
  );
82269
82431
  } catch (err) {
82270
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
82271
- formatter.formatDependencyError(err);
82272
- process.exit(1);
82273
- return;
82274
- }
82275
82432
  if (err instanceof PartialRotationError) {
82276
82433
  formatter.error(err.message);
82277
82434
  const partialEntries = Object.entries(err.rotatedKeys);
@@ -82304,11 +82461,37 @@ Service Identity: ${identity.name}`);
82304
82461
  process.exit(1);
82305
82462
  return;
82306
82463
  }
82307
- formatter.error(err.message);
82308
- process.exit(1);
82464
+ handleCommandError(err);
82309
82465
  }
82310
82466
  });
82311
82467
  }
82468
+ function parseKmsEnvMappings(mappings) {
82469
+ const configs = {};
82470
+ for (const mapping of mappings) {
82471
+ const eqIdx = mapping.indexOf("=");
82472
+ if (eqIdx === -1) {
82473
+ throw new Error(`Invalid --kms-env format: '${mapping}'. Expected: env=provider:keyId`);
82474
+ }
82475
+ const envName = mapping.slice(0, eqIdx);
82476
+ const rest = mapping.slice(eqIdx + 1);
82477
+ const colonIdx = rest.indexOf(":");
82478
+ if (colonIdx === -1) {
82479
+ throw new Error(`Invalid --kms-env format: '${mapping}'. Expected: env=provider:keyId`);
82480
+ }
82481
+ const provider = rest.slice(0, colonIdx);
82482
+ const keyId = rest.slice(colonIdx + 1);
82483
+ if (!VALID_KMS_PROVIDERS.includes(provider)) {
82484
+ throw new Error(
82485
+ `Invalid KMS provider '${provider}'. Must be one of: ${VALID_KMS_PROVIDERS.join(", ")}.`
82486
+ );
82487
+ }
82488
+ if (configs[envName]) {
82489
+ throw new Error(`Duplicate --kms-env for environment '${envName}'.`);
82490
+ }
82491
+ configs[envName] = { provider, keyId };
82492
+ }
82493
+ return configs;
82494
+ }
82312
82495
 
82313
82496
  // src/commands/pack.ts
82314
82497
  init_src();
@@ -82382,14 +82565,7 @@ function registerPackCommand(program3, deps2) {
82382
82565
  "\nUpload the artifact to an HTTP-accessible store (S3, GCS, etc.) or commit to\n .clef/packed/ for VCS-based delivery. See: clef.sh/guide/service-identities"
82383
82566
  );
82384
82567
  } catch (err) {
82385
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
82386
- formatter.formatDependencyError(err);
82387
- process.exit(1);
82388
- return;
82389
- }
82390
- const message = err instanceof Error ? err.message : "Pack failed";
82391
- formatter.error(message);
82392
- process.exit(1);
82568
+ handleCommandError(err);
82393
82569
  }
82394
82570
  }
82395
82571
  );
@@ -82397,7 +82573,7 @@ function registerPackCommand(program3, deps2) {
82397
82573
 
82398
82574
  // src/commands/revoke.ts
82399
82575
  init_src();
82400
- import * as fs24 from "fs";
82576
+ import * as fs23 from "fs";
82401
82577
  import * as path40 from "path";
82402
82578
  function registerRevokeCommand(program3, _deps) {
82403
82579
  program3.command("revoke <identity> <environment>").description(
@@ -82430,8 +82606,8 @@ function registerRevokeCommand(program3, _deps) {
82430
82606
  environment,
82431
82607
  revokedAt: (/* @__PURE__ */ new Date()).toISOString()
82432
82608
  };
82433
- fs24.mkdirSync(artifactDir, { recursive: true });
82434
- fs24.writeFileSync(artifactPath, JSON.stringify(revoked, null, 2) + "\n", "utf-8");
82609
+ fs23.mkdirSync(artifactDir, { recursive: true });
82610
+ fs23.writeFileSync(artifactPath, JSON.stringify(revoked, null, 2) + "\n", "utf-8");
82435
82611
  const relPath = path40.relative(repoRoot, artifactPath);
82436
82612
  formatter.success(`Artifact revoked: ${relPath}`);
82437
82613
  formatter.print("");
@@ -82534,11 +82710,11 @@ init_src();
82534
82710
 
82535
82711
  // src/report/historical.ts
82536
82712
  init_src();
82537
- import * as os2 from "os";
82713
+ import * as os3 from "os";
82538
82714
  import * as path42 from "path";
82539
- import * as fs25 from "fs";
82715
+ import * as fs24 from "fs";
82540
82716
  async function generateReportAtCommit(repoRoot, commitSha, clefVersion, runner2) {
82541
- const tmpDir = path42.join(os2.tmpdir(), `clef-report-${commitSha.slice(0, 8)}-${Date.now()}`);
82717
+ const tmpDir = path42.join(os3.tmpdir(), `clef-report-${commitSha.slice(0, 8)}-${Date.now()}`);
82542
82718
  try {
82543
82719
  const addResult = await runner2.run("git", ["worktree", "add", tmpDir, commitSha, "--detach"], {
82544
82720
  cwd: repoRoot
@@ -82556,7 +82732,7 @@ async function generateReportAtCommit(repoRoot, commitSha, clefVersion, runner2)
82556
82732
  await runner2.run("git", ["worktree", "remove", tmpDir, "--force"], { cwd: repoRoot });
82557
82733
  } catch {
82558
82734
  try {
82559
- fs25.rmSync(tmpDir, { recursive: true, force: true });
82735
+ fs24.rmSync(tmpDir, { recursive: true, force: true });
82560
82736
  await runner2.run("git", ["worktree", "prune"], { cwd: repoRoot });
82561
82737
  } catch {
82562
82738
  }
@@ -82646,13 +82822,7 @@ function registerReportCommand(program3, deps2) {
82646
82822
  }
82647
82823
  outputReport(headReport, options);
82648
82824
  } catch (err) {
82649
- if (err instanceof SopsMissingError || err instanceof SopsVersionError) {
82650
- formatter.formatDependencyError(err);
82651
- process.exit(1);
82652
- return;
82653
- }
82654
- formatter.error(err.message);
82655
- process.exit(1);
82825
+ handleCommandError(err);
82656
82826
  }
82657
82827
  }
82658
82828
  );
@@ -82784,7 +82954,7 @@ function formatReportOutput(report) {
82784
82954
 
82785
82955
  // src/commands/install.ts
82786
82956
  var import_yaml = __toESM(require_dist());
82787
- import * as fs26 from "fs";
82957
+ import * as fs25 from "fs";
82788
82958
  import * as path43 from "path";
82789
82959
 
82790
82960
  // src/registry/client.ts
@@ -82833,7 +83003,7 @@ function registerInstallCommand(program3, _deps) {
82833
83003
  return;
82834
83004
  }
82835
83005
  const brokerDir = path43.join(repoRoot, "brokers", entry.name);
82836
- if (fs26.existsSync(brokerDir) && !options.force) {
83006
+ if (fs25.existsSync(brokerDir) && !options.force) {
82837
83007
  const overwrite = await formatter.confirm(
82838
83008
  `brokers/${entry.name}/ already exists. Overwrite?`
82839
83009
  );
@@ -82864,11 +83034,11 @@ function registerInstallCommand(program3, _deps) {
82864
83034
  process.exit(1);
82865
83035
  return;
82866
83036
  }
82867
- if (!fs26.existsSync(brokerDir)) {
82868
- fs26.mkdirSync(brokerDir, { recursive: true });
83037
+ if (!fs25.existsSync(brokerDir)) {
83038
+ fs25.mkdirSync(brokerDir, { recursive: true });
82869
83039
  }
82870
83040
  for (const file of files) {
82871
- fs26.writeFileSync(path43.join(brokerDir, file.name), file.content, "utf-8");
83041
+ fs25.writeFileSync(path43.join(brokerDir, file.name), file.content, "utf-8");
82872
83042
  }
82873
83043
  const manifestFile = files.find((f) => f.name === "broker.yaml");
82874
83044
  const manifest = manifestFile ? (0, import_yaml.parse)(manifestFile.content) : {};