@clef-sh/core 0.1.15 → 0.1.16

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.d.mts CHANGED
@@ -34,6 +34,7 @@ export { ReportGenerator, ReportSanitizer, ReportTransformer, CloudClient, colle
34
34
  export { SopsMergeDriver } from "./merge/driver";
35
35
  export type { MergeResult, MergeKey, MergeKeyStatus } from "./merge/driver";
36
36
  export { ServiceIdentityManager } from "./service-identity/manager";
37
+ export type { CreateServiceIdentityOptions } from "./service-identity/manager";
37
38
  export { StructureManager } from "./structure/manager";
38
39
  export type { NamespaceEditOptions, EnvironmentEditOptions, AddNamespaceOptions, AddEnvironmentOptions, } from "./structure/manager";
39
40
  export { resolveIdentitySecrets } from "./artifact/resolve";
package/dist/index.d.ts CHANGED
@@ -34,6 +34,7 @@ export { ReportGenerator, ReportSanitizer, ReportTransformer, CloudClient, colle
34
34
  export { SopsMergeDriver } from "./merge/driver";
35
35
  export type { MergeResult, MergeKey, MergeKeyStatus } from "./merge/driver";
36
36
  export { ServiceIdentityManager } from "./service-identity/manager";
37
+ export type { CreateServiceIdentityOptions } from "./service-identity/manager";
37
38
  export { StructureManager } from "./structure/manager";
38
39
  export type { NamespaceEditOptions, EnvironmentEditOptions, AddNamespaceOptions, AddEnvironmentOptions, } from "./structure/manager";
39
40
  export { resolveIdentitySecrets } from "./artifact/resolve";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -9624,6 +9624,12 @@ var ManifestParser = class {
9624
9624
  "service_identities"
9625
9625
  );
9626
9626
  }
9627
+ if (siObj.pack_only !== void 0 && typeof siObj.pack_only !== "boolean") {
9628
+ throw new ManifestValidationError(
9629
+ `Service identity '${siName}' has a non-boolean 'pack_only' field.`,
9630
+ "service_identities"
9631
+ );
9632
+ }
9627
9633
  if (!Array.isArray(siObj.namespaces) || siObj.namespaces.length === 0) {
9628
9634
  throw new ManifestValidationError(
9629
9635
  `Service identity '${siName}' must have a non-empty 'namespaces' array.`,
@@ -9729,7 +9735,8 @@ var ManifestParser = class {
9729
9735
  name: siName,
9730
9736
  description: siObj.description ?? "",
9731
9737
  namespaces: siObj.namespaces,
9732
- environments: parsedEnvs
9738
+ environments: parsedEnvs,
9739
+ ...siObj.pack_only === true ? { pack_only: true } : {}
9733
9740
  };
9734
9741
  });
9735
9742
  const siNames = /* @__PURE__ */ new Set();
@@ -12075,6 +12082,18 @@ var LintRunner = class {
12075
12082
  });
12076
12083
  }
12077
12084
  }
12085
+ if (si.pack_only) {
12086
+ const ageRecipients = Object.values(si.environments).filter((cfg) => !isKmsEnvelope(cfg) && cfg.recipient).map((cfg) => cfg.recipient);
12087
+ if (ageRecipients.length >= 2 && new Set(ageRecipients).size === 1) {
12088
+ issues.push({
12089
+ severity: "warning",
12090
+ category: "service-identity",
12091
+ file: "clef.yaml",
12092
+ message: `Runtime identity '${si.name}' uses a shared recipient across all environments. A compromised key in any environment decrypts artifacts for all environments. Consider per-environment keys for runtime workloads.`
12093
+ });
12094
+ }
12095
+ continue;
12096
+ }
12078
12097
  for (const cell of existingCells) {
12079
12098
  const envConfig = si.environments[cell.environment];
12080
12099
  if (!envConfig) continue;
@@ -13434,12 +13453,10 @@ var ServiceIdentityManager = class {
13434
13453
  * Create a new service identity with per-environment age key pairs or KMS envelope config.
13435
13454
  * For age-only: generates keys, updates the manifest, and registers public keys as SOPS recipients.
13436
13455
  * For KMS: stores KMS config in manifest, no age keys generated.
13437
- *
13438
- * @param kmsEnvConfigs - Optional per-environment KMS config. When provided, those envs use
13439
- * KMS envelope encryption instead of generating age keys.
13440
- * @returns The created identity definition and the per-environment private keys (empty for KMS envs).
13456
+ * For pack-only (runtime) identities: keys are generated but NOT registered on SOPS files.
13441
13457
  */
13442
- async create(name, namespaces, description, manifest, repoRoot, kmsEnvConfigs) {
13458
+ async create(name, namespaces, description, manifest, repoRoot, options) {
13459
+ const { kmsEnvConfigs, sharedRecipient, packOnly } = options ?? {};
13443
13460
  if (manifest.service_identities?.some((si) => si.name === name)) {
13444
13461
  throw new Error(`Service identity '${name}' already exists.`);
13445
13462
  }
@@ -13451,23 +13468,25 @@ var ServiceIdentityManager = class {
13451
13468
  }
13452
13469
  const environments = {};
13453
13470
  const privateKeys = {};
13471
+ const sharedKey = sharedRecipient ? await generateAgeIdentity() : void 0;
13454
13472
  for (const env of manifest.environments) {
13455
13473
  const kmsConfig = kmsEnvConfigs?.[env.name];
13456
13474
  if (kmsConfig) {
13457
13475
  environments[env.name] = { kms: kmsConfig };
13458
13476
  } else {
13459
- const identity = await generateAgeIdentity();
13460
- environments[env.name] = { recipient: identity.publicKey };
13461
- privateKeys[env.name] = identity.privateKey;
13477
+ const ageIdentity = sharedKey ?? await generateAgeIdentity();
13478
+ environments[env.name] = { recipient: ageIdentity.publicKey };
13479
+ privateKeys[env.name] = ageIdentity.privateKey;
13462
13480
  }
13463
13481
  }
13464
13482
  const definition = {
13465
13483
  name,
13466
13484
  description,
13467
13485
  namespaces,
13468
- environments
13486
+ environments,
13487
+ ...packOnly ? { pack_only: true } : {}
13469
13488
  };
13470
- const cells = this.matrixManager.resolveMatrix(manifest, repoRoot).filter((c) => c.exists && namespaces.includes(c.namespace));
13489
+ const cells = packOnly ? [] : this.matrixManager.resolveMatrix(manifest, repoRoot).filter((c) => c.exists && namespaces.includes(c.namespace));
13471
13490
  await this.tx.run(repoRoot, {
13472
13491
  description: `clef service create ${name}`,
13473
13492
  paths: this.txPaths(repoRoot, cells),
@@ -13481,12 +13500,13 @@ var ServiceIdentityManager = class {
13481
13500
  name,
13482
13501
  description,
13483
13502
  namespaces,
13484
- environments
13503
+ environments,
13504
+ ...packOnly ? { pack_only: true } : {}
13485
13505
  });
13486
13506
  writeManifestYaml(repoRoot, doc);
13487
13507
  }
13488
13508
  });
13489
- return { identity: definition, privateKeys };
13509
+ return { identity: definition, privateKeys, sharedRecipient: sharedKey !== void 0 };
13490
13510
  }
13491
13511
  /**
13492
13512
  * List all service identities from the manifest.
@@ -13509,7 +13529,7 @@ var ServiceIdentityManager = class {
13509
13529
  if (!identity) {
13510
13530
  throw new Error(`Service identity '${name}' not found.`);
13511
13531
  }
13512
- const scopedCells = this.matrixManager.resolveMatrix(manifest, repoRoot).filter((c) => c.exists && identity.namespaces.includes(c.namespace));
13532
+ const scopedCells = identity.pack_only ? [] : this.matrixManager.resolveMatrix(manifest, repoRoot).filter((c) => c.exists && identity.namespaces.includes(c.namespace));
13513
13533
  await this.tx.run(repoRoot, {
13514
13534
  description: `clef service delete ${name}`,
13515
13535
  paths: this.txPaths(repoRoot, scopedCells),
@@ -13565,7 +13585,7 @@ var ServiceIdentityManager = class {
13565
13585
  const envs = siDoc.environments;
13566
13586
  for (const [envName, kmsConfig] of Object.entries(kmsEnvConfigs)) {
13567
13587
  const oldConfig = identity.environments[envName];
13568
- if (oldConfig?.recipient && !isKmsEnvelope(oldConfig)) {
13588
+ if (!identity.pack_only && oldConfig?.recipient && !isKmsEnvelope(oldConfig)) {
13569
13589
  const scopedCells = cells.filter((c) => c.environment === envName);
13570
13590
  for (const cell of scopedCells) {
13571
13591
  try {
@@ -13584,8 +13604,10 @@ var ServiceIdentityManager = class {
13584
13604
  }
13585
13605
  /**
13586
13606
  * Register a service identity's public keys as SOPS recipients on scoped matrix files.
13607
+ * Pack-only (runtime) identities skip registration entirely.
13587
13608
  */
13588
13609
  async registerRecipients(identity, manifest, repoRoot) {
13610
+ if (identity.pack_only) return;
13589
13611
  const cells = this.matrixManager.resolveMatrix(manifest, repoRoot).filter((c) => c.exists);
13590
13612
  for (const cell of cells) {
13591
13613
  if (!identity.namespaces.includes(cell.namespace)) continue;
@@ -13635,18 +13657,20 @@ var ServiceIdentityManager = class {
13635
13657
  description: `clef service update ${name}: add namespaces ${toAdd.join(",")}`,
13636
13658
  paths: this.txPaths(repoRoot, cells),
13637
13659
  mutate: async () => {
13638
- for (const cell of cells) {
13639
- const envConfig = identity.environments[cell.environment];
13640
- if (!envConfig) continue;
13641
- if (isKmsEnvelope(envConfig)) continue;
13642
- if (!envConfig.recipient) continue;
13643
- try {
13644
- await this.encryption.addRecipient(cell.filePath, envConfig.recipient);
13645
- affectedFiles.push(cell.filePath);
13646
- } catch (err) {
13647
- const message = err instanceof Error ? err.message : String(err);
13648
- if (!message.includes("already")) {
13649
- throw err;
13660
+ if (!identity.pack_only) {
13661
+ for (const cell of cells) {
13662
+ const envConfig = identity.environments[cell.environment];
13663
+ if (!envConfig) continue;
13664
+ if (isKmsEnvelope(envConfig)) continue;
13665
+ if (!envConfig.recipient) continue;
13666
+ try {
13667
+ await this.encryption.addRecipient(cell.filePath, envConfig.recipient);
13668
+ affectedFiles.push(cell.filePath);
13669
+ } catch (err) {
13670
+ const message = err instanceof Error ? err.message : String(err);
13671
+ if (!message.includes("already")) {
13672
+ throw err;
13673
+ }
13650
13674
  }
13651
13675
  }
13652
13676
  }
@@ -13694,15 +13718,17 @@ var ServiceIdentityManager = class {
13694
13718
  description: `clef service update ${name}: remove namespaces ${namespacesToRemove.join(",")}`,
13695
13719
  paths: this.txPaths(repoRoot, cells),
13696
13720
  mutate: async () => {
13697
- for (const cell of cells) {
13698
- const envConfig = identity.environments[cell.environment];
13699
- if (!envConfig) continue;
13700
- if (isKmsEnvelope(envConfig)) continue;
13701
- if (!envConfig.recipient) continue;
13702
- try {
13703
- await this.encryption.removeRecipient(cell.filePath, envConfig.recipient);
13704
- affectedFiles.push(cell.filePath);
13705
- } catch {
13721
+ if (!identity.pack_only) {
13722
+ for (const cell of cells) {
13723
+ const envConfig = identity.environments[cell.environment];
13724
+ if (!envConfig) continue;
13725
+ if (isKmsEnvelope(envConfig)) continue;
13726
+ if (!envConfig.recipient) continue;
13727
+ try {
13728
+ await this.encryption.removeRecipient(cell.filePath, envConfig.recipient);
13729
+ affectedFiles.push(cell.filePath);
13730
+ } catch {
13731
+ }
13706
13732
  }
13707
13733
  }
13708
13734
  const doc = readManifestYaml(repoRoot);
@@ -13765,7 +13791,7 @@ var ServiceIdentityManager = class {
13765
13791
  description: `clef service add-env ${name} ${envName}`,
13766
13792
  paths: this.txPaths(repoRoot, cells),
13767
13793
  mutate: async () => {
13768
- if (!isKmsEnvelope(envConfig) && envConfig.recipient) {
13794
+ if (!identity.pack_only && !isKmsEnvelope(envConfig) && envConfig.recipient) {
13769
13795
  for (const cell of cells) {
13770
13796
  try {
13771
13797
  await this.encryption.addRecipient(cell.filePath, envConfig.recipient);
@@ -13824,7 +13850,7 @@ var ServiceIdentityManager = class {
13824
13850
  if (targetEnvNames.size === 0) {
13825
13851
  return newPrivateKeys;
13826
13852
  }
13827
- const cells = this.matrixManager.resolveMatrix(manifest, repoRoot).filter(
13853
+ const cells = identity.pack_only ? [] : this.matrixManager.resolveMatrix(manifest, repoRoot).filter(
13828
13854
  (c) => c.exists && identity.namespaces.includes(c.namespace) && targetEnvNames.has(c.environment)
13829
13855
  );
13830
13856
  await this.tx.run(repoRoot, {
@@ -13841,13 +13867,15 @@ var ServiceIdentityManager = class {
13841
13867
  const oldRecipient = identity.environments[envName].recipient;
13842
13868
  const newPublicKey = newPublicKeys[envName];
13843
13869
  envs[envName] = { recipient: newPublicKey };
13844
- const scopedCells = cells.filter((c) => c.environment === envName);
13845
- for (const cell of scopedCells) {
13846
- try {
13847
- await this.encryption.removeRecipient(cell.filePath, oldRecipient);
13848
- } catch {
13870
+ if (!identity.pack_only) {
13871
+ const scopedCells = cells.filter((c) => c.environment === envName);
13872
+ for (const cell of scopedCells) {
13873
+ try {
13874
+ await this.encryption.removeRecipient(cell.filePath, oldRecipient);
13875
+ } catch {
13876
+ }
13877
+ await this.encryption.addRecipient(cell.filePath, newPublicKey);
13849
13878
  }
13850
- await this.encryption.addRecipient(cell.filePath, newPublicKey);
13851
13879
  }
13852
13880
  }
13853
13881
  writeManifestYaml(repoRoot, doc);
@@ -13887,6 +13915,17 @@ var ServiceIdentityManager = class {
13887
13915
  });
13888
13916
  }
13889
13917
  }
13918
+ if (si.pack_only) {
13919
+ const ageRecipients = Object.values(si.environments).filter((cfg) => !isKmsEnvelope(cfg) && cfg.recipient).map((cfg) => cfg.recipient);
13920
+ if (ageRecipients.length >= 2 && new Set(ageRecipients).size === 1) {
13921
+ issues.push({
13922
+ identity: si.name,
13923
+ type: "runtime_shared_recipient",
13924
+ message: `Runtime identity '${si.name}' uses a shared recipient across all environments. A compromised key in any environment decrypts artifacts for all environments. Consider per-environment keys for runtime workloads.`
13925
+ });
13926
+ }
13927
+ continue;
13928
+ }
13890
13929
  for (const cell of cells) {
13891
13930
  const envConfig = si.environments[cell.environment];
13892
13931
  if (!envConfig) continue;