pepr 0.40.1 → 0.42.1

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.
Files changed (107) hide show
  1. package/README.md +11 -5
  2. package/dist/cli/build.d.ts +1 -0
  3. package/dist/cli/build.d.ts.map +1 -1
  4. package/dist/cli/build.helpers.d.ts +66 -0
  5. package/dist/cli/build.helpers.d.ts.map +1 -1
  6. package/dist/cli/deploy.d.ts.map +1 -1
  7. package/dist/cli/init/templates.d.ts +2 -2
  8. package/dist/cli/monitor.d.ts +23 -0
  9. package/dist/cli/monitor.d.ts.map +1 -1
  10. package/dist/cli.js +536 -429
  11. package/dist/controller.js +52 -27
  12. package/dist/lib/assets/destroy.d.ts.map +1 -1
  13. package/dist/lib/assets/helm.d.ts +1 -1
  14. package/dist/lib/assets/helm.d.ts.map +1 -1
  15. package/dist/lib/assets/index.d.ts.map +1 -1
  16. package/dist/lib/assets/pods.d.ts +5 -19
  17. package/dist/lib/assets/pods.d.ts.map +1 -1
  18. package/dist/lib/assets/webhooks.d.ts.map +1 -1
  19. package/dist/lib/assets/yaml.d.ts.map +1 -1
  20. package/dist/lib/capability.d.ts.map +1 -1
  21. package/dist/lib/controller/index.d.ts.map +1 -1
  22. package/dist/lib/controller/index.util.d.ts +10 -0
  23. package/dist/lib/controller/index.util.d.ts.map +1 -0
  24. package/dist/lib/controller/store.d.ts +0 -1
  25. package/dist/lib/controller/store.d.ts.map +1 -1
  26. package/dist/lib/controller/storeCache.d.ts +1 -0
  27. package/dist/lib/controller/storeCache.d.ts.map +1 -1
  28. package/dist/lib/deploymentChecks.d.ts +3 -0
  29. package/dist/lib/deploymentChecks.d.ts.map +1 -0
  30. package/dist/lib/enums.d.ts +5 -5
  31. package/dist/lib/enums.d.ts.map +1 -1
  32. package/dist/lib/filesystemService.d.ts +2 -0
  33. package/dist/lib/filesystemService.d.ts.map +1 -0
  34. package/dist/lib/filter/adjudicators/adjudicators.d.ts +73 -0
  35. package/dist/lib/filter/adjudicators/adjudicators.d.ts.map +1 -0
  36. package/dist/lib/filter/adjudicators/defaultTestObjects.d.ts +7 -0
  37. package/dist/lib/filter/adjudicators/defaultTestObjects.d.ts.map +1 -0
  38. package/dist/lib/helpers.d.ts +1 -4
  39. package/dist/lib/helpers.d.ts.map +1 -1
  40. package/dist/lib/mutate-request.d.ts +2 -2
  41. package/dist/lib/mutate-request.d.ts.map +1 -1
  42. package/dist/lib/queue.d.ts.map +1 -1
  43. package/dist/lib/schedule.d.ts.map +1 -1
  44. package/dist/lib/storage.d.ts +5 -5
  45. package/dist/lib/storage.d.ts.map +1 -1
  46. package/dist/lib/{logger.d.ts → telemetry/logger.d.ts} +1 -1
  47. package/dist/lib/telemetry/logger.d.ts.map +1 -0
  48. package/dist/lib/{metrics.d.ts → telemetry/metrics.d.ts} +3 -1
  49. package/dist/lib/telemetry/metrics.d.ts.map +1 -0
  50. package/dist/lib/types.d.ts +10 -9
  51. package/dist/lib/types.d.ts.map +1 -1
  52. package/dist/lib/utils.d.ts.map +1 -1
  53. package/dist/lib/validate-processor.d.ts +4 -1
  54. package/dist/lib/validate-processor.d.ts.map +1 -1
  55. package/dist/lib/watch-processor.d.ts.map +1 -1
  56. package/dist/lib.d.ts +1 -1
  57. package/dist/lib.d.ts.map +1 -1
  58. package/dist/lib.js +283 -231
  59. package/dist/lib.js.map +4 -4
  60. package/dist/sdk/sdk.d.ts +3 -4
  61. package/dist/sdk/sdk.d.ts.map +1 -1
  62. package/package.json +5 -5
  63. package/src/cli/build.helpers.ts +180 -0
  64. package/src/cli/build.ts +85 -132
  65. package/src/cli/deploy.ts +2 -1
  66. package/src/cli/init/templates.ts +1 -1
  67. package/src/cli/monitor.ts +108 -65
  68. package/src/lib/assets/deploy.ts +7 -7
  69. package/src/lib/assets/destroy.ts +2 -2
  70. package/src/lib/assets/helm.ts +6 -6
  71. package/src/lib/assets/index.ts +110 -89
  72. package/src/lib/assets/pods.ts +10 -5
  73. package/src/lib/assets/webhooks.ts +3 -3
  74. package/src/lib/assets/yaml.ts +12 -9
  75. package/src/lib/capability.ts +29 -19
  76. package/src/lib/controller/index.ts +41 -69
  77. package/src/lib/controller/index.util.ts +47 -0
  78. package/src/lib/controller/store.ts +24 -11
  79. package/src/lib/controller/storeCache.ts +11 -2
  80. package/src/lib/deploymentChecks.ts +43 -0
  81. package/src/lib/enums.ts +5 -5
  82. package/src/lib/filesystemService.ts +16 -0
  83. package/src/lib/filter/{adjudicators.ts → adjudicators/adjudicators.ts} +67 -35
  84. package/src/lib/filter/adjudicators/defaultTestObjects.ts +46 -0
  85. package/src/lib/filter/filter.ts +1 -1
  86. package/src/lib/finalizer.ts +1 -1
  87. package/src/lib/helpers.ts +31 -88
  88. package/src/lib/mutate-processor.ts +1 -1
  89. package/src/lib/mutate-request.ts +11 -11
  90. package/src/lib/queue.ts +13 -5
  91. package/src/lib/schedule.ts +8 -8
  92. package/src/lib/storage.ts +48 -39
  93. package/src/lib/{logger.ts → telemetry/logger.ts} +1 -1
  94. package/src/lib/{metrics.ts → telemetry/metrics.ts} +18 -17
  95. package/src/lib/types.ts +12 -9
  96. package/src/lib/utils.ts +6 -6
  97. package/src/lib/validate-processor.ts +48 -40
  98. package/src/lib/watch-processor.ts +19 -15
  99. package/src/lib.ts +1 -1
  100. package/src/runtime/controller.ts +1 -1
  101. package/src/sdk/cosign.ts +4 -4
  102. package/src/sdk/sdk.ts +6 -9
  103. package/src/templates/capabilities/hello-pepr.ts +19 -9
  104. package/dist/lib/filter/adjudicators.d.ts +0 -69
  105. package/dist/lib/filter/adjudicators.d.ts.map +0 -1
  106. package/dist/lib/logger.d.ts.map +0 -1
  107. package/dist/lib/metrics.d.ts.map +0 -1
package/dist/cli.js CHANGED
@@ -86,26 +86,10 @@ var banner = `\x1B[107;40m\x1B[38;5;m \x1B[38;5;m \x1B[38;5;m \x1B[38;5;m \x1B[3
86
86
  `;
87
87
 
88
88
  // src/cli/build.ts
89
- var import_child_process2 = require("child_process");
90
- var import_esbuild = require("esbuild");
91
- var import_fs8 = require("fs");
92
- var import_path2 = require("path");
93
-
94
- // src/lib/included-files.ts
95
- var import_fs = require("fs");
96
- async function createDockerfile(version3, description, includedFiles) {
97
- const file = `
98
- # Use an official Node.js runtime as the base image
99
- FROM ghcr.io/defenseunicorns/pepr/controller:v${version3}
100
-
101
- LABEL description="${description}"
102
-
103
- # Add the included files to the image
104
- ${includedFiles.map((f) => `ADD ${f} ${f}`).join("\n")}
105
-
106
- `;
107
- await import_fs.promises.writeFile("Dockerfile.controller", file, { encoding: "utf-8" });
108
- }
89
+ var import_child_process3 = require("child_process");
90
+ var import_esbuild2 = require("esbuild");
91
+ var import_fs9 = require("fs");
92
+ var import_path3 = require("path");
109
93
 
110
94
  // src/lib/assets/index.ts
111
95
  var import_crypto3 = __toESM(require("crypto"));
@@ -170,10 +154,10 @@ function genCert(key, name2, issuer) {
170
154
 
171
155
  // src/lib/assets/deploy.ts
172
156
  var import_crypto = __toESM(require("crypto"));
173
- var import_fs3 = require("fs");
174
- var import_kubernetes_fluent_client4 = require("kubernetes-fluent-client");
157
+ var import_fs = require("fs");
158
+ var import_kubernetes_fluent_client3 = require("kubernetes-fluent-client");
175
159
 
176
- // src/lib/logger.ts
160
+ // src/lib/telemetry/logger.ts
177
161
  var import_pino = require("pino");
178
162
  var isPrettyLog = true;
179
163
  var pretty = {
@@ -277,17 +261,13 @@ function watcherService(name2) {
277
261
  // src/lib/assets/pods.ts
278
262
  var import_zlib = require("zlib");
279
263
 
280
- // src/lib/helpers.ts
281
- var import_fs2 = require("fs");
282
- var import_kubernetes_fluent_client2 = require("kubernetes-fluent-client");
283
-
284
264
  // src/sdk/sdk.ts
285
265
  var import_kubernetes_fluent_client = require("kubernetes-fluent-client");
286
266
  function sanitizeResourceName(name2) {
287
267
  return name2.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 250).replace(/^[^a-z]+|[^a-z]+$/g, "");
288
268
  }
289
269
 
290
- // src/lib/filter/adjudicators.ts
270
+ // src/lib/filter/adjudicators/adjudicators.ts
291
271
  var import_ramda = require("ramda");
292
272
  var declaredOperation = (0, import_ramda.pipe)(
293
273
  (request) => request?.operation,
@@ -311,23 +291,49 @@ var carriesDeletionTimestamp = (0, import_ramda.pipe)(
311
291
  (0, import_ramda.defaultTo)(false)
312
292
  );
313
293
  var missingDeletionTimestamp = (0, import_ramda.complement)(carriesDeletionTimestamp);
314
- var carriedKind = (0, import_ramda.pipe)((kubernetesObject) => kubernetesObject?.metadata?.kind, (0, import_ramda.defaultTo)("not set"));
315
- var carriedVersion = (0, import_ramda.pipe)((kubernetesObject) => kubernetesObject?.metadata?.version, (0, import_ramda.defaultTo)("not set"));
316
- var carriedName = (0, import_ramda.pipe)((kubernetesObject) => kubernetesObject?.metadata?.name, (0, import_ramda.defaultTo)(""));
294
+ var carriedKind = (0, import_ramda.pipe)(
295
+ (kubernetesObject) => kubernetesObject?.kind,
296
+ (0, import_ramda.defaultTo)("not set")
297
+ );
298
+ var carriedVersion = (0, import_ramda.pipe)(
299
+ (kubernetesObject) => kubernetesObject?.metadata?.resourceVersion,
300
+ (0, import_ramda.defaultTo)("not set")
301
+ );
302
+ var carriedName = (0, import_ramda.pipe)(
303
+ (kubernetesObject) => kubernetesObject?.metadata?.name,
304
+ (0, import_ramda.defaultTo)("")
305
+ );
317
306
  var carriesName = (0, import_ramda.pipe)(carriedName, (0, import_ramda.equals)(""), import_ramda.not);
318
307
  var missingName = (0, import_ramda.complement)(carriesName);
319
- var carriedNamespace = (0, import_ramda.pipe)((kubernetesObject) => kubernetesObject?.metadata?.namespace, (0, import_ramda.defaultTo)(""));
308
+ var carriedNamespace = (0, import_ramda.pipe)(
309
+ (kubernetesObject) => kubernetesObject?.metadata?.namespace,
310
+ (0, import_ramda.defaultTo)("")
311
+ );
320
312
  var carriesNamespace = (0, import_ramda.pipe)(carriedNamespace, (0, import_ramda.equals)(""), import_ramda.not);
321
- var carriedAnnotations = (0, import_ramda.pipe)((kubernetesObject) => kubernetesObject?.metadata?.annotations, (0, import_ramda.defaultTo)({}));
313
+ var carriedAnnotations = (0, import_ramda.pipe)(
314
+ (kubernetesObject) => kubernetesObject?.metadata?.annotations,
315
+ (0, import_ramda.defaultTo)({})
316
+ );
322
317
  var carriesAnnotations = (0, import_ramda.pipe)(carriedAnnotations, (0, import_ramda.equals)({}), import_ramda.not);
323
- var carriedLabels = (0, import_ramda.pipe)((kubernetesObject) => kubernetesObject?.metadata?.labels, (0, import_ramda.defaultTo)({}));
318
+ var carriedLabels = (0, import_ramda.pipe)(
319
+ (kubernetesObject) => kubernetesObject?.metadata?.labels,
320
+ (0, import_ramda.defaultTo)({})
321
+ );
324
322
  var carriesLabels = (0, import_ramda.pipe)(carriedLabels, (0, import_ramda.equals)({}), import_ramda.not);
325
- var definesDeletionTimestamp = (0, import_ramda.pipe)((binding) => binding?.filters?.deletionTimestamp, (0, import_ramda.defaultTo)(false));
323
+ var definesDeletionTimestamp = (0, import_ramda.pipe)(
324
+ (binding) => binding?.filters?.deletionTimestamp ?? false,
325
+ (0, import_ramda.defaultTo)(false)
326
+ );
326
327
  var ignoresDeletionTimestamp = (0, import_ramda.complement)(definesDeletionTimestamp);
327
- var definedName = (0, import_ramda.pipe)((binding) => binding?.filters?.name, (0, import_ramda.defaultTo)(""));
328
+ var definedName = (0, import_ramda.pipe)((binding) => {
329
+ return binding.filters.name;
330
+ }, (0, import_ramda.defaultTo)(""));
328
331
  var definesName = (0, import_ramda.pipe)(definedName, (0, import_ramda.equals)(""), import_ramda.not);
329
332
  var ignoresName = (0, import_ramda.complement)(definesName);
330
- var definedNameRegex = (0, import_ramda.pipe)((binding) => binding?.filters?.regexName, (0, import_ramda.defaultTo)(""));
333
+ var definedNameRegex = (0, import_ramda.pipe)(
334
+ (binding) => binding.filters?.regexName,
335
+ (0, import_ramda.defaultTo)("")
336
+ );
331
337
  var definesNameRegex = (0, import_ramda.pipe)(definedNameRegex, (0, import_ramda.equals)(""), import_ramda.not);
332
338
  var definedNamespaces = (0, import_ramda.pipe)((binding) => binding?.filters?.namespaces, (0, import_ramda.defaultTo)([]));
333
339
  var definesNamespaces = (0, import_ramda.pipe)(definedNamespaces, (0, import_ramda.equals)([]), import_ramda.not);
@@ -337,20 +343,22 @@ var definedAnnotations = (0, import_ramda.pipe)((binding) => binding?.filters?.a
337
343
  var definesAnnotations = (0, import_ramda.pipe)(definedAnnotations, (0, import_ramda.equals)({}), import_ramda.not);
338
344
  var definedLabels = (0, import_ramda.pipe)((binding) => binding?.filters?.labels, (0, import_ramda.defaultTo)({}));
339
345
  var definesLabels = (0, import_ramda.pipe)(definedLabels, (0, import_ramda.equals)({}), import_ramda.not);
340
- var definedEvent = (0, import_ramda.pipe)((binding) => binding?.event, (0, import_ramda.defaultTo)(""));
346
+ var definedEvent = (binding) => {
347
+ return binding.event;
348
+ };
341
349
  var definesDelete = (0, import_ramda.pipe)(definedEvent, (0, import_ramda.equals)("DELETE" /* DELETE */));
342
350
  var definedGroup = (0, import_ramda.pipe)((binding) => binding?.kind?.group, (0, import_ramda.defaultTo)(""));
343
351
  var definesGroup = (0, import_ramda.pipe)(definedGroup, (0, import_ramda.equals)(""), import_ramda.not);
344
- var definedVersion = (0, import_ramda.pipe)((binding) => binding?.kind?.version, (0, import_ramda.defaultTo)(""));
352
+ var definedVersion = (0, import_ramda.pipe)(
353
+ (binding) => binding?.kind?.version,
354
+ (0, import_ramda.defaultTo)("")
355
+ );
345
356
  var definesVersion = (0, import_ramda.pipe)(definedVersion, (0, import_ramda.equals)(""), import_ramda.not);
346
357
  var definedKind = (0, import_ramda.pipe)((binding) => binding?.kind?.kind, (0, import_ramda.defaultTo)(""));
347
358
  var definesKind = (0, import_ramda.pipe)(definedKind, (0, import_ramda.equals)(""), import_ramda.not);
348
- var definedCategory = (0, import_ramda.pipe)((binding) => {
349
- return binding.isFinalize ? "Finalize" : binding.isWatch ? "Watch" : binding.isMutate ? "Mutate" : binding.isValidate ? "Validate" : "";
350
- });
351
- var definedCallback = (0, import_ramda.pipe)((binding) => {
359
+ var definedCallback = (binding) => {
352
360
  return binding.isFinalize ? binding.finalizeCallback : binding.isWatch ? binding.watchCallback : binding.isMutate ? binding.mutateCallback : binding.isValidate ? binding.validateCallback : null;
353
- });
361
+ };
354
362
  var definedCallbackName = (0, import_ramda.pipe)(definedCallback, (0, import_ramda.defaultTo)({ name: "" }), (callback) => callback.name);
355
363
  var mismatchedDeletionTimestamp = (0, import_ramda.allPass)([
356
364
  (0, import_ramda.pipe)((0, import_ramda.nthArg)(0), definesDeletionTimestamp),
@@ -432,8 +440,8 @@ var unbindableNamespaces = (0, import_ramda.allPass)([
432
440
  ]);
433
441
  var misboundDeleteWithDeletionTimestamp = (0, import_ramda.allPass)([definesDelete, definesDeletionTimestamp]);
434
442
  var operationMatchesEvent = (0, import_ramda.anyPass)([
435
- (0, import_ramda.pipe)((0, import_ramda.nthArg)(1), (0, import_ramda.equals)("*" /* Any */)),
436
- (0, import_ramda.pipe)((operation, event) => operation === event),
443
+ (0, import_ramda.pipe)((0, import_ramda.nthArg)(1), (0, import_ramda.equals)("*" /* ANY */)),
444
+ (0, import_ramda.pipe)((operation, event) => operation.valueOf() === event.valueOf()),
437
445
  (0, import_ramda.pipe)((operation, event) => operation ? event.includes(operation) : false)
438
446
  ]);
439
447
  var mismatchedEvent = (0, import_ramda.pipe)(
@@ -455,11 +463,7 @@ var mismatchedKind = (0, import_ramda.allPass)([
455
463
 
456
464
  // src/lib/helpers.ts
457
465
  function matchesRegex(pattern, testString) {
458
- if (!pattern) {
459
- return false;
460
- }
461
- const regex = new RegExp(pattern);
462
- return regex.test(testString);
466
+ return new RegExp(pattern).test(testString);
463
467
  }
464
468
  var ValidationError = class extends Error {
465
469
  };
@@ -500,17 +504,6 @@ function createRBACMap(capabilities) {
500
504
  return acc;
501
505
  }, {});
502
506
  }
503
- async function createDirectoryIfNotExists(path) {
504
- try {
505
- await import_fs2.promises.access(path);
506
- } catch (error) {
507
- if (error.code === "ENOENT") {
508
- await import_fs2.promises.mkdir(path, { recursive: true });
509
- } else {
510
- throw error;
511
- }
512
- }
513
- }
514
507
  function hasEveryOverlap(array1, array2) {
515
508
  if (!Array.isArray(array1) || !Array.isArray(array2)) {
516
509
  return false;
@@ -549,7 +542,9 @@ function generateWatchNamespaceError(ignoredNamespaces, bindingNamespaces, capab
549
542
  function namespaceComplianceValidator(capability, ignoredNamespaces) {
550
543
  const { namespaces: capabilityNamespaces, bindings, name: name2 } = capability;
551
544
  const bindingNamespaces = bindings.flatMap((binding) => binding.filters.namespaces);
552
- const bindingRegexNamespaces = bindings.flatMap((binding) => binding.filters.regexNamespaces || []);
545
+ const bindingRegexNamespaces = bindings.flatMap(
546
+ (binding) => binding.filters.regexNamespaces || []
547
+ );
553
548
  const namespaceError = generateWatchNamespaceError(
554
549
  ignoredNamespaces ? ignoredNamespaces : [],
555
550
  bindingNamespaces,
@@ -582,40 +577,6 @@ function namespaceComplianceValidator(capability, ignoredNamespaces) {
582
577
  }
583
578
  }
584
579
  }
585
- async function checkDeploymentStatus(namespace2) {
586
- const deployments = await (0, import_kubernetes_fluent_client2.K8s)(import_kubernetes_fluent_client2.kind.Deployment).InNamespace(namespace2).Get();
587
- let status = false;
588
- let readyCount = 0;
589
- for (const deployment2 of deployments.items) {
590
- const readyReplicas = deployment2.status?.readyReplicas ? deployment2.status?.readyReplicas : 0;
591
- if (deployment2.status?.readyReplicas !== deployment2.spec?.replicas) {
592
- logger_default.info(
593
- `Waiting for deployment ${deployment2.metadata?.name} rollout to finish: ${readyReplicas} of ${deployment2.spec?.replicas} replicas are available`
594
- );
595
- } else {
596
- logger_default.info(
597
- `Deployment ${deployment2.metadata?.name} rolled out: ${readyReplicas} of ${deployment2.spec?.replicas} replicas are available`
598
- );
599
- readyCount++;
600
- }
601
- }
602
- if (readyCount === deployments.items.length) {
603
- status = true;
604
- }
605
- return status;
606
- }
607
- async function namespaceDeploymentsReady(namespace2 = "pepr-system") {
608
- logger_default.info(`Checking ${namespace2} deployments status...`);
609
- let ready = false;
610
- while (!ready) {
611
- ready = await checkDeploymentStatus(namespace2);
612
- if (ready) {
613
- return ready;
614
- }
615
- await new Promise((resolve5) => setTimeout(resolve5, 1e3));
616
- }
617
- logger_default.info(`All ${namespace2} deployments are ready`);
618
- }
619
580
  function secretOverLimit(str) {
620
581
  const encoder = new TextEncoder();
621
582
  const encoded = encoder.encode(str);
@@ -656,7 +617,7 @@ function replaceString(str, stringA, stringB) {
656
617
  }
657
618
 
658
619
  // src/lib/assets/pods.ts
659
- function namespace(namespaceLabels) {
620
+ function getNamespace(namespaceLabels) {
660
621
  if (namespaceLabels) {
661
622
  return {
662
623
  apiVersion: "v1",
@@ -676,7 +637,7 @@ function namespace(namespaceLabels) {
676
637
  };
677
638
  }
678
639
  }
679
- function watcher(assets, hash, buildTimestamp, imagePullSecret) {
640
+ function getWatcher(assets, hash, buildTimestamp, imagePullSecret) {
680
641
  const { name: name2, image, capabilities, config } = assets;
681
642
  let hasSchedule = false;
682
643
  const app = `${name2}-watcher`;
@@ -820,7 +781,7 @@ function watcher(assets, hash, buildTimestamp, imagePullSecret) {
820
781
  }
821
782
  return deploy2;
822
783
  }
823
- function deployment(assets, hash, buildTimestamp, imagePullSecret) {
784
+ function getDeployment(assets, hash, buildTimestamp, imagePullSecret) {
824
785
  const { name: name2, image, config } = assets;
825
786
  const app = name2;
826
787
  const deploy2 = {
@@ -961,7 +922,7 @@ function deployment(assets, hash, buildTimestamp, imagePullSecret) {
961
922
  }
962
923
  return deploy2;
963
924
  }
964
- function moduleSecret(name2, data, hash) {
925
+ function getModuleSecret(name2, data, hash) {
965
926
  const compressed = (0, import_zlib.gzipSync)(data);
966
927
  const path = `module-${hash}.js.gz`;
967
928
  const compressedData = compressed.toString("base64");
@@ -1103,19 +1064,19 @@ function storeRoleBinding(name2) {
1103
1064
  }
1104
1065
 
1105
1066
  // src/lib/k8s.ts
1106
- var import_kubernetes_fluent_client3 = require("kubernetes-fluent-client");
1107
- var Store = class extends import_kubernetes_fluent_client3.GenericKind {
1067
+ var import_kubernetes_fluent_client2 = require("kubernetes-fluent-client");
1068
+ var Store = class extends import_kubernetes_fluent_client2.GenericKind {
1108
1069
  };
1109
1070
  var peprStoreGVK = {
1110
1071
  kind: "PeprStore",
1111
1072
  version: "v1",
1112
1073
  group: "pepr.dev"
1113
1074
  };
1114
- (0, import_kubernetes_fluent_client3.RegisterKind)(Store, peprStoreGVK);
1075
+ (0, import_kubernetes_fluent_client2.RegisterKind)(Store, peprStoreGVK);
1115
1076
 
1116
1077
  // src/lib/assets/store.ts
1117
- var { group, version, kind: kind3 } = peprStoreGVK;
1118
- var singular = kind3.toLocaleLowerCase();
1078
+ var { group, version, kind: kind2 } = peprStoreGVK;
1079
+ var singular = kind2.toLocaleLowerCase();
1119
1080
  var plural = `${singular}s`;
1120
1081
  var name = `${plural}.${group}`;
1121
1082
  var peprStoreCRD = {
@@ -1151,7 +1112,7 @@ var peprStoreCRD = {
1151
1112
  names: {
1152
1113
  plural,
1153
1114
  singular,
1154
- kind: kind3
1115
+ kind: kind2
1155
1116
  }
1156
1117
  }
1157
1118
  };
@@ -1178,8 +1139,8 @@ async function generateWebhookRules(assets, isMutateWebhook) {
1178
1139
  continue;
1179
1140
  }
1180
1141
  const operations = [];
1181
- if (event === "CREATEORUPDATE" /* CreateOrUpdate */) {
1182
- operations.push("CREATE" /* Create */, "UPDATE" /* Update */);
1142
+ if (event === "CREATEORUPDATE" /* CREATE_OR_UPDATE */) {
1143
+ operations.push("CREATE" /* CREATE */, "UPDATE" /* UPDATE */);
1183
1144
  } else {
1184
1145
  operations.push(event);
1185
1146
  }
@@ -1256,12 +1217,12 @@ async function webhookConfig(assets, mutateOrValidate, timeoutSeconds = 10) {
1256
1217
  // src/lib/assets/deploy.ts
1257
1218
  async function deployImagePullSecret(imagePullSecret, name2) {
1258
1219
  try {
1259
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.Namespace).Get("pepr-system");
1220
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Namespace).Get("pepr-system");
1260
1221
  } catch {
1261
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.Namespace).Apply(namespace());
1222
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Namespace).Apply(getNamespace());
1262
1223
  }
1263
1224
  try {
1264
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.Secret).Apply(
1225
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Secret).Apply(
1265
1226
  {
1266
1227
  apiVersion: "v1",
1267
1228
  kind: "Secret",
@@ -1284,29 +1245,29 @@ async function deploy(assets, force, webhookTimeout) {
1284
1245
  logger_default.info("Establishing connection to Kubernetes");
1285
1246
  const { name: name2, host, path } = assets;
1286
1247
  logger_default.info("Applying pepr-system namespace");
1287
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.Namespace).Apply(namespace(assets.config.customLabels?.namespace));
1248
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Namespace).Apply(getNamespace(assets.config.customLabels?.namespace));
1288
1249
  const mutateWebhook = await webhookConfig(assets, "mutate", webhookTimeout);
1289
1250
  if (mutateWebhook) {
1290
1251
  logger_default.info("Applying mutating webhook");
1291
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.MutatingWebhookConfiguration).Apply(mutateWebhook, { force });
1252
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.MutatingWebhookConfiguration).Apply(mutateWebhook, { force });
1292
1253
  } else {
1293
1254
  logger_default.info("Mutating webhook not needed, removing if it exists");
1294
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.MutatingWebhookConfiguration).Delete(name2);
1255
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.MutatingWebhookConfiguration).Delete(name2);
1295
1256
  }
1296
1257
  const validateWebhook = await webhookConfig(assets, "validate", webhookTimeout);
1297
1258
  if (validateWebhook) {
1298
1259
  logger_default.info("Applying validating webhook");
1299
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.ValidatingWebhookConfiguration).Apply(validateWebhook, { force });
1260
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.ValidatingWebhookConfiguration).Apply(validateWebhook, { force });
1300
1261
  } else {
1301
1262
  logger_default.info("Validating webhook not needed, removing if it exists");
1302
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.ValidatingWebhookConfiguration).Delete(name2);
1263
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.ValidatingWebhookConfiguration).Delete(name2);
1303
1264
  }
1304
1265
  logger_default.info("Applying the Pepr Store CRD if it doesn't exist");
1305
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.CustomResourceDefinition).Apply(peprStoreCRD, { force });
1266
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.CustomResourceDefinition).Apply(peprStoreCRD, { force });
1306
1267
  if (host) {
1307
1268
  return;
1308
1269
  }
1309
- const code = await import_fs3.promises.readFile(path);
1270
+ const code = await import_fs.promises.readFile(path);
1310
1271
  const hash = import_crypto.default.createHash("sha256").update(code).digest("hex");
1311
1272
  if (code.length < 1) {
1312
1273
  throw new Error("No code provided");
@@ -1319,53 +1280,53 @@ async function setupRBAC(name2, capabilities, force, config) {
1319
1280
  const { rbacMode, rbac } = config;
1320
1281
  logger_default.info("Applying cluster role binding");
1321
1282
  const crb = clusterRoleBinding(name2);
1322
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.ClusterRoleBinding).Apply(crb, { force });
1283
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.ClusterRoleBinding).Apply(crb, { force });
1323
1284
  logger_default.info("Applying cluster role");
1324
1285
  const cr = clusterRole(name2, capabilities, rbacMode, rbac);
1325
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.ClusterRole).Apply(cr, { force });
1286
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.ClusterRole).Apply(cr, { force });
1326
1287
  logger_default.info("Applying service account");
1327
1288
  const sa = serviceAccount(name2);
1328
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.ServiceAccount).Apply(sa, { force });
1289
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.ServiceAccount).Apply(sa, { force });
1329
1290
  logger_default.info("Applying store role");
1330
1291
  const role = storeRole(name2);
1331
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.Role).Apply(role, { force });
1292
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Role).Apply(role, { force });
1332
1293
  logger_default.info("Applying store role binding");
1333
1294
  const roleBinding = storeRoleBinding(name2);
1334
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.RoleBinding).Apply(roleBinding, { force });
1295
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.RoleBinding).Apply(roleBinding, { force });
1335
1296
  }
1336
1297
  async function setupController(assets, code, hash, force) {
1337
1298
  const { name: name2 } = assets;
1338
1299
  logger_default.info("Applying module secret");
1339
- const mod = moduleSecret(name2, code, hash);
1340
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.Secret).Apply(mod, { force });
1300
+ const mod = getModuleSecret(name2, code, hash);
1301
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Secret).Apply(mod, { force });
1341
1302
  logger_default.info("Applying controller service");
1342
1303
  const svc = service(name2);
1343
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.Service).Apply(svc, { force });
1304
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Service).Apply(svc, { force });
1344
1305
  logger_default.info("Applying TLS secret");
1345
1306
  const tls = tlsSecret(name2, assets.tls);
1346
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.Secret).Apply(tls, { force });
1307
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Secret).Apply(tls, { force });
1347
1308
  logger_default.info("Applying API token secret");
1348
1309
  const apiToken = apiTokenSecret(name2, assets.apiToken);
1349
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.Secret).Apply(apiToken, { force });
1310
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Secret).Apply(apiToken, { force });
1350
1311
  logger_default.info("Applying deployment");
1351
- const dep = deployment(assets, hash, assets.buildTimestamp);
1352
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.Deployment).Apply(dep, { force });
1312
+ const dep = getDeployment(assets, hash, assets.buildTimestamp);
1313
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Deployment).Apply(dep, { force });
1353
1314
  }
1354
1315
  async function setupWatcher(assets, hash, force) {
1355
- const watchDeployment = watcher(assets, hash, assets.buildTimestamp);
1316
+ const watchDeployment = getWatcher(assets, hash, assets.buildTimestamp);
1356
1317
  if (watchDeployment) {
1357
1318
  logger_default.info("Applying watcher deployment");
1358
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.Deployment).Apply(watchDeployment, { force });
1319
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Deployment).Apply(watchDeployment, { force });
1359
1320
  logger_default.info("Applying watcher service");
1360
1321
  const watchSvc = watcherService(assets.name);
1361
- await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.Service).Apply(watchSvc, { force });
1322
+ await (0, import_kubernetes_fluent_client3.K8s)(import_kubernetes_fluent_client3.kind.Service).Apply(watchSvc, { force });
1362
1323
  }
1363
1324
  }
1364
1325
 
1365
1326
  // src/lib/assets/loader.ts
1366
1327
  var import_child_process = require("child_process");
1367
1328
  function loadCapabilities(path) {
1368
- return new Promise((resolve5, reject) => {
1329
+ return new Promise((resolve6, reject) => {
1369
1330
  const program2 = (0, import_child_process.fork)(path, {
1370
1331
  env: {
1371
1332
  ...process.env,
@@ -1379,7 +1340,7 @@ function loadCapabilities(path) {
1379
1340
  for (const capability of capabilities) {
1380
1341
  console.info(`Registered Pepr Capability "${capability.name}"`);
1381
1342
  }
1382
- resolve5(capabilities);
1343
+ resolve6(capabilities);
1383
1344
  });
1384
1345
  program2.on("error", (error) => {
1385
1346
  reject(error);
@@ -1390,7 +1351,7 @@ function loadCapabilities(path) {
1390
1351
  // src/lib/assets/yaml.ts
1391
1352
  var import_client_node = require("@kubernetes/client-node");
1392
1353
  var import_crypto2 = __toESM(require("crypto"));
1393
- var import_fs4 = require("fs");
1354
+ var import_fs2 = require("fs");
1394
1355
  async function overridesFile({ hash, name: name2, image, config, apiToken, capabilities }, path) {
1395
1356
  const rbacOverrides = clusterRole(name2, capabilities, config.rbacMode, config.rbac).rules;
1396
1357
  const overrides = {
@@ -1541,7 +1502,7 @@ async function overridesFile({ hash, name: name2, image, config, apiToken, capab
1541
1502
  }
1542
1503
  }
1543
1504
  };
1544
- await import_fs4.promises.writeFile(path, (0, import_client_node.dumpYaml)(overrides, { noRefs: true, forceQuotes: true }));
1505
+ await import_fs2.promises.writeFile(path, (0, import_client_node.dumpYaml)(overrides, { noRefs: true, forceQuotes: true }));
1545
1506
  }
1546
1507
  function zarfYaml({ name: name2, image, config }, path) {
1547
1508
  const zarfCfg = {
@@ -1598,22 +1559,22 @@ function zarfYamlChart({ name: name2, image, config }, path) {
1598
1559
  }
1599
1560
  async function allYaml(assets, imagePullSecret) {
1600
1561
  const { name: name2, tls, apiToken, path, config } = assets;
1601
- const code = await import_fs4.promises.readFile(path);
1562
+ const code = await import_fs2.promises.readFile(path);
1602
1563
  assets.hash = import_crypto2.default.createHash("sha256").update(code).digest("hex");
1603
1564
  const mutateWebhook = await webhookConfig(assets, "mutate", assets.config.webhookTimeout);
1604
1565
  const validateWebhook = await webhookConfig(assets, "validate", assets.config.webhookTimeout);
1605
- const watchDeployment = watcher(assets, assets.hash, assets.buildTimestamp, imagePullSecret);
1566
+ const watchDeployment = getWatcher(assets, assets.hash, assets.buildTimestamp, imagePullSecret);
1606
1567
  const resources = [
1607
- namespace(assets.config.customLabels?.namespace),
1568
+ getNamespace(assets.config.customLabels?.namespace),
1608
1569
  clusterRole(name2, assets.capabilities, config.rbacMode, config.rbac),
1609
1570
  clusterRoleBinding(name2),
1610
1571
  serviceAccount(name2),
1611
1572
  apiTokenSecret(name2, apiToken),
1612
1573
  tlsSecret(name2, tls),
1613
- deployment(assets, assets.hash, assets.buildTimestamp, imagePullSecret),
1574
+ getDeployment(assets, assets.hash, assets.buildTimestamp, imagePullSecret),
1614
1575
  service(name2),
1615
1576
  watcherService(name2),
1616
- moduleSecret(name2, code, assets.hash),
1577
+ getModuleSecret(name2, code, assets.hash),
1617
1578
  storeRole(name2),
1618
1579
  storeRoleBinding(name2)
1619
1580
  ];
@@ -1646,7 +1607,7 @@ function clusterRoleTemplate() {
1646
1607
  {{- end }}
1647
1608
  `;
1648
1609
  }
1649
- function nsTemplate() {
1610
+ function namespaceTemplate() {
1650
1611
  return `
1651
1612
  apiVersion: v1
1652
1613
  kind: Namespace
@@ -1883,7 +1844,74 @@ function serviceMonitorTemplate(name2) {
1883
1844
  }
1884
1845
 
1885
1846
  // src/lib/assets/index.ts
1886
- var import_fs5 = require("fs");
1847
+ var import_fs4 = require("fs");
1848
+
1849
+ // src/lib/filesystemService.ts
1850
+ var import_fs3 = require("fs");
1851
+ async function createDirectoryIfNotExists(path) {
1852
+ try {
1853
+ await import_fs3.promises.access(path);
1854
+ } catch (error) {
1855
+ if (error.code === "ENOENT") {
1856
+ await import_fs3.promises.mkdir(path, { recursive: true });
1857
+ } else {
1858
+ throw error;
1859
+ }
1860
+ }
1861
+ }
1862
+
1863
+ // src/lib/assets/index.ts
1864
+ function toYaml(obj) {
1865
+ return (0, import_client_node2.dumpYaml)(obj, { noRefs: true });
1866
+ }
1867
+ function createWebhookYaml(assets, webhookConfiguration) {
1868
+ const yaml = toYaml(webhookConfiguration);
1869
+ return replaceString(
1870
+ replaceString(
1871
+ replaceString(yaml, assets.name, "{{ .Values.uuid }}"),
1872
+ assets.config.onError === "reject" ? "Fail" : "Ignore",
1873
+ "{{ .Values.admission.failurePolicy }}"
1874
+ ),
1875
+ `${assets.config.webhookTimeout}` || "10",
1876
+ "{{ .Values.admission.webhookTimeout }}"
1877
+ );
1878
+ }
1879
+ function helmLayout(basePath, unique) {
1880
+ const helm = {
1881
+ dirs: {
1882
+ chart: (0, import_path.resolve)(`${basePath}/${unique}-chart`)
1883
+ },
1884
+ files: {}
1885
+ };
1886
+ helm.dirs = {
1887
+ ...helm.dirs,
1888
+ charts: `${helm.dirs.chart}/charts`,
1889
+ tmpls: `${helm.dirs.chart}/templates`
1890
+ };
1891
+ helm.files = {
1892
+ ...helm.files,
1893
+ valuesYaml: `${helm.dirs.chart}/values.yaml`,
1894
+ chartYaml: `${helm.dirs.chart}/Chart.yaml`,
1895
+ namespaceYaml: `${helm.dirs.tmpls}/namespace.yaml`,
1896
+ watcherServiceYaml: `${helm.dirs.tmpls}/watcher-service.yaml`,
1897
+ admissionServiceYaml: `${helm.dirs.tmpls}/admission-service.yaml`,
1898
+ mutationWebhookYaml: `${helm.dirs.tmpls}/mutation-webhook.yaml`,
1899
+ validationWebhookYaml: `${helm.dirs.tmpls}/validation-webhook.yaml`,
1900
+ admissionDeploymentYaml: `${helm.dirs.tmpls}/admission-deployment.yaml`,
1901
+ admissionServiceMonitorYaml: `${helm.dirs.tmpls}/admission-service-monitor.yaml`,
1902
+ watcherDeploymentYaml: `${helm.dirs.tmpls}/watcher-deployment.yaml`,
1903
+ watcherServiceMonitorYaml: `${helm.dirs.tmpls}/watcher-service-monitor.yaml`,
1904
+ tlsSecretYaml: `${helm.dirs.tmpls}/tls-secret.yaml`,
1905
+ apiTokenSecretYaml: `${helm.dirs.tmpls}/api-token-secret.yaml`,
1906
+ moduleSecretYaml: `${helm.dirs.tmpls}/module-secret.yaml`,
1907
+ storeRoleYaml: `${helm.dirs.tmpls}/store-role.yaml`,
1908
+ storeRoleBindingYaml: `${helm.dirs.tmpls}/store-role-binding.yaml`,
1909
+ clusterRoleYaml: `${helm.dirs.tmpls}/cluster-role.yaml`,
1910
+ clusterRoleBindingYaml: `${helm.dirs.tmpls}/cluster-role-binding.yaml`,
1911
+ serviceAccountYaml: `${helm.dirs.tmpls}/service-account.yaml`
1912
+ };
1913
+ return helm;
1914
+ }
1887
1915
  var Assets = class {
1888
1916
  constructor(config, path, host) {
1889
1917
  this.config = config;
@@ -1921,82 +1949,48 @@ var Assets = class {
1921
1949
  }
1922
1950
  return allYaml(this, imagePullSecret);
1923
1951
  };
1952
+ /* eslint max-statements: ["warn", 21] */
1924
1953
  generateHelmChart = async (basePath) => {
1925
- const CHART_DIR = `${basePath}/${this.config.uuid}-chart`;
1926
- const CHAR_TEMPLATES_DIR = `${CHART_DIR}/templates`;
1927
- const valuesPath = (0, import_path.resolve)(CHART_DIR, `values.yaml`);
1928
- const chartPath = (0, import_path.resolve)(CHART_DIR, `Chart.yaml`);
1929
- const nsPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `namespace.yaml`);
1930
- const watcherSVCPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `watcher-service.yaml`);
1931
- const admissionSVCPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `admission-service.yaml`);
1932
- const mutationWebhookPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `mutation-webhook.yaml`);
1933
- const validationWebhookPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `validation-webhook.yaml`);
1934
- const admissionDeployPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `admission-deployment.yaml`);
1935
- const admissionServiceMonitorPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `admission-service-monitor.yaml`);
1936
- const watcherDeployPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `watcher-deployment.yaml`);
1937
- const watcherServiceMonitorPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `watcher-service-monitor.yaml`);
1938
- const tlsSecretPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `tls-secret.yaml`);
1939
- const apiTokenSecretPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `api-token-secret.yaml`);
1940
- const moduleSecretPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `module-secret.yaml`);
1941
- const storeRolePath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `store-role.yaml`);
1942
- const storeRoleBindingPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `store-role-binding.yaml`);
1943
- const clusterRolePath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `cluster-role.yaml`);
1944
- const clusterRoleBindingPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `cluster-role-binding.yaml`);
1945
- const serviceAccountPath = (0, import_path.resolve)(CHAR_TEMPLATES_DIR, `service-account.yaml`);
1954
+ const helm = helmLayout(basePath, this.config.uuid);
1946
1955
  try {
1947
- await createDirectoryIfNotExists(CHART_DIR);
1948
- await createDirectoryIfNotExists(`${CHART_DIR}/charts`);
1949
- await createDirectoryIfNotExists(`${CHAR_TEMPLATES_DIR}`);
1950
- await overridesFile(this, valuesPath);
1951
- await import_fs5.promises.writeFile(chartPath, dedent(chartYaml(this.config.uuid, this.config.description || "")));
1952
- await import_fs5.promises.writeFile(nsPath, dedent(nsTemplate()));
1953
- const code = await import_fs5.promises.readFile(this.path);
1954
- await import_fs5.promises.writeFile(watcherSVCPath, (0, import_client_node2.dumpYaml)(watcherService(this.name), { noRefs: true }));
1955
- await import_fs5.promises.writeFile(admissionSVCPath, (0, import_client_node2.dumpYaml)(service(this.name), { noRefs: true }));
1956
- await import_fs5.promises.writeFile(tlsSecretPath, (0, import_client_node2.dumpYaml)(tlsSecret(this.name, this.tls), { noRefs: true }));
1957
- await import_fs5.promises.writeFile(apiTokenSecretPath, (0, import_client_node2.dumpYaml)(apiTokenSecret(this.name, this.apiToken), { noRefs: true }));
1958
- await import_fs5.promises.writeFile(moduleSecretPath, (0, import_client_node2.dumpYaml)(moduleSecret(this.name, code, this.hash), { noRefs: true }));
1959
- await import_fs5.promises.writeFile(storeRolePath, (0, import_client_node2.dumpYaml)(storeRole(this.name), { noRefs: true }));
1960
- await import_fs5.promises.writeFile(storeRoleBindingPath, (0, import_client_node2.dumpYaml)(storeRoleBinding(this.name), { noRefs: true }));
1961
- await import_fs5.promises.writeFile(clusterRolePath, dedent(clusterRoleTemplate()));
1962
- await import_fs5.promises.writeFile(clusterRoleBindingPath, (0, import_client_node2.dumpYaml)(clusterRoleBinding(this.name), { noRefs: true }));
1963
- await import_fs5.promises.writeFile(serviceAccountPath, (0, import_client_node2.dumpYaml)(serviceAccount(this.name), { noRefs: true }));
1964
- const mutateWebhook = await webhookConfig(this, "mutate", this.config.webhookTimeout);
1965
- const validateWebhook = await webhookConfig(this, "validate", this.config.webhookTimeout);
1966
- const watchDeployment = watcher(this, this.hash, this.buildTimestamp);
1956
+ await Promise.all(
1957
+ Object.values(helm.dirs).sort((l, r) => l.split("/").length - r.split("/").length).map(async (dir) => await createDirectoryIfNotExists(dir))
1958
+ );
1959
+ const code = await import_fs4.promises.readFile(this.path);
1960
+ const pairs = [
1961
+ [helm.files.chartYaml, () => dedent(chartYaml(this.config.uuid, this.config.description || ""))],
1962
+ [helm.files.namespaceYaml, () => dedent(namespaceTemplate())],
1963
+ [helm.files.watcherServiceYaml, () => toYaml(watcherService(this.name))],
1964
+ [helm.files.admissionServiceYaml, () => toYaml(service(this.name))],
1965
+ [helm.files.tlsSecretYaml, () => toYaml(tlsSecret(this.name, this.tls))],
1966
+ [helm.files.apiTokenSecretYaml, () => toYaml(apiTokenSecret(this.name, this.apiToken))],
1967
+ [helm.files.storeRoleYaml, () => toYaml(storeRole(this.name))],
1968
+ [helm.files.storeRoleBindingYaml, () => toYaml(storeRoleBinding(this.name))],
1969
+ [helm.files.clusterRoleYaml, () => dedent(clusterRoleTemplate())],
1970
+ [helm.files.clusterRoleBindingYaml, () => toYaml(clusterRoleBinding(this.name))],
1971
+ [helm.files.serviceAccountYaml, () => toYaml(serviceAccount(this.name))],
1972
+ [helm.files.moduleSecretYaml, () => toYaml(getModuleSecret(this.name, code, this.hash))]
1973
+ ];
1974
+ await Promise.all(pairs.map(async ([file, content]) => await import_fs4.promises.writeFile(file, content())));
1975
+ await overridesFile(this, helm.files.valuesYaml);
1976
+ const [mutateWebhook, validateWebhook] = await Promise.all([
1977
+ webhookConfig(this, "mutate", this.config.webhookTimeout),
1978
+ webhookConfig(this, "validate", this.config.webhookTimeout)
1979
+ ]);
1967
1980
  if (validateWebhook || mutateWebhook) {
1968
- await import_fs5.promises.writeFile(admissionDeployPath, dedent(admissionDeployTemplate(this.buildTimestamp)));
1969
- await import_fs5.promises.writeFile(admissionServiceMonitorPath, dedent(serviceMonitorTemplate("admission")));
1981
+ await import_fs4.promises.writeFile(helm.files.admissionDeploymentYaml, dedent(admissionDeployTemplate(this.buildTimestamp)));
1982
+ await import_fs4.promises.writeFile(helm.files.admissionServiceMonitorYaml, dedent(serviceMonitorTemplate("admission")));
1970
1983
  }
1971
1984
  if (mutateWebhook) {
1972
- const yamlMutateWebhook = (0, import_client_node2.dumpYaml)(mutateWebhook, { noRefs: true });
1973
- const mutateWebhookTemplate = replaceString(
1974
- replaceString(
1975
- replaceString(yamlMutateWebhook, this.name, "{{ .Values.uuid }}"),
1976
- this.config.onError === "reject" ? "Fail" : "Ignore",
1977
- "{{ .Values.admission.failurePolicy }}"
1978
- ),
1979
- `${this.config.webhookTimeout}` || "10",
1980
- "{{ .Values.admission.webhookTimeout }}"
1981
- );
1982
- await import_fs5.promises.writeFile(mutationWebhookPath, mutateWebhookTemplate);
1985
+ await import_fs4.promises.writeFile(helm.files.mutationWebhookYaml, createWebhookYaml(this, mutateWebhook));
1983
1986
  }
1984
1987
  if (validateWebhook) {
1985
- const yamlValidateWebhook = (0, import_client_node2.dumpYaml)(validateWebhook, { noRefs: true });
1986
- const validateWebhookTemplate = replaceString(
1987
- replaceString(
1988
- replaceString(yamlValidateWebhook, this.name, "{{ .Values.uuid }}"),
1989
- this.config.onError === "reject" ? "Fail" : "Ignore",
1990
- "{{ .Values.admission.failurePolicy }}"
1991
- ),
1992
- `${this.config.webhookTimeout}` || "10",
1993
- "{{ .Values.admission.webhookTimeout }}"
1994
- );
1995
- await import_fs5.promises.writeFile(validationWebhookPath, validateWebhookTemplate);
1988
+ await import_fs4.promises.writeFile(helm.files.validationWebhookYaml, createWebhookYaml(this, validateWebhook));
1996
1989
  }
1990
+ const watchDeployment = getWatcher(this, this.hash, this.buildTimestamp);
1997
1991
  if (watchDeployment) {
1998
- await import_fs5.promises.writeFile(watcherDeployPath, dedent(watcherDeployTemplate(this.buildTimestamp)));
1999
- await import_fs5.promises.writeFile(watcherServiceMonitorPath, dedent(serviceMonitorTemplate("watcher")));
1992
+ await import_fs4.promises.writeFile(helm.files.watcherDeploymentYaml, dedent(watcherDeployTemplate(this.buildTimestamp)));
1993
+ await import_fs4.promises.writeFile(helm.files.watcherServiceMonitorYaml, dedent(serviceMonitorTemplate("watcher")));
2000
1994
  }
2001
1995
  } catch (err) {
2002
1996
  console.error(`Error generating helm chart: ${err.message}`);
@@ -2211,8 +2205,8 @@ var hello_pepr_samples_default = [
2211
2205
  var gitIgnore = "# Ignore node_modules and Pepr build artifacts\nnode_modules\ndist\ninsecure*\n";
2212
2206
  var readmeMd = '# Pepr Module\n\nThis is a Pepr Module. [Pepr](https://github.com/defenseunicorns/pepr) is a type-safe Kubernetes middleware system.\n\nThe `capabilities` directory contains all the capabilities for this module. By default,\na capability is a single typescript file in the format of `capability-name.ts` that is\nimported in the root `pepr.ts` file as `import { HelloPepr } from "./capabilities/hello-pepr";`.\nBecause this is typescript, you can organize this however you choose, e.g. creating a sub-folder\nper-capability or common logic in shared files or folders.\n\nExample Structure:\n\n```\nModule Root\n\u251C\u2500\u2500 package.json\n\u251C\u2500\u2500 pepr.ts\n\u2514\u2500\u2500 capabilities\n \u251C\u2500\u2500 example-one.ts\n \u251C\u2500\u2500 example-three.ts\n \u2514\u2500\u2500 example-two.ts\n```\n';
2213
2207
  var peprTS = 'import { PeprModule } from "pepr";\n// cfg loads your pepr configuration from package.json\nimport cfg from "./package.json";\n\n// HelloPepr is a demo capability that is included with Pepr. Comment or delete the line below to remove it.\nimport { HelloPepr } from "./capabilities/hello-pepr";\n\n/**\n * This is the main entrypoint for this Pepr module. It is run when the module is started.\n * This is where you register your Pepr configurations and capabilities.\n */\nnew PeprModule(cfg, [\n // "HelloPepr" is a demo capability that is included with Pepr. Comment or delete the line below to remove it.\n HelloPepr,\n\n // Your additional capabilities go here\n]);\n';
2214
- var helloPeprTS = 'import {\n Capability,\n K8s,\n Log,\n PeprMutateRequest,\n RegisterKind,\n a,\n fetch,\n fetchStatus,\n kind,\n} from "pepr";\nimport nock from "nock";\n\n/**\n * The HelloPepr Capability is an example capability to demonstrate some general concepts of Pepr.\n * To test this capability you run `pepr dev`and then run the following command:\n * `kubectl apply -f capabilities/hello-pepr.samples.yaml`\n */\nexport const HelloPepr = new Capability({\n name: "hello-pepr",\n description: "A simple example capability to show how things work.",\n namespaces: ["pepr-demo", "pepr-demo-2"],\n});\n\n// Use the \'When\' function to create a new action, use \'Store\' to persist data\nconst { When, Store } = HelloPepr;\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Namespace) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action removes the label `remove-me` when a Namespace is created.\n * Note we don\'t need to specify the namespace here, because we\'ve already specified\n * it in the Capability definition above.\n */\nWhen(a.Namespace)\n .IsCreated()\n .Mutate(ns => ns.RemoveLabel("remove-me"));\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Watch Action with K8s SSA (Namespace) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action watches for the `pepr-demo-2` namespace to be created, then creates a ConfigMap with\n * the name `pepr-ssa-demo` and adds the namespace UID to the ConfigMap data. Because Pepr uses\n * server-side apply for this operation, the ConfigMap will be created or updated if it already exists.\n */\nWhen(a.Namespace)\n .IsCreated()\n .WithName("pepr-demo-2")\n .Watch(async ns => {\n Log.info("Namespace pepr-demo-2 was created.");\n\n try {\n // Apply the ConfigMap using K8s server-side apply\n await K8s(kind.ConfigMap).Apply({\n metadata: {\n name: "pepr-ssa-demo",\n namespace: "pepr-demo-2",\n },\n data: {\n "ns-uid": ns.metadata.uid,\n },\n });\n } catch (error) {\n // You can use the Log object to log messages to the Pepr controller pod\n Log.error(error, "Failed to apply ConfigMap using server-side apply.");\n }\n\n // You can share data between actions using the Store, including between different types of actions\n Store.setItem("watch-data", "This data was stored by a Watch Action.");\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 1) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This is a single action. They can be in the same file or put imported from other files.\n * In this example, when a ConfigMap is created with the name `example-1`, then add a label and annotation.\n *\n * Equivalent to manually running:\n * `kubectl label configmap example-1 pepr=was-here`\n * `kubectl annotate configmap example-1 pepr.dev=annotations-work-too`\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .WithName("example-1")\n .Mutate(request => {\n request\n .SetLabel("pepr", "was-here")\n .SetAnnotation("pepr.dev", "annotations-work-too");\n\n // Use the Store to persist data between requests and Pepr controller pods\n Store.setItem("example-1", "was-here");\n\n // This data is written asynchronously and can be read back via `Store.getItem()` or `Store.subscribe()`\n Store.setItem("example-1-data", JSON.stringify(request.Raw.data));\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate & Validate Actions (CM Example 2) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This combines 3 different types of actions: \'Mutate\', \'Validate\', and \'Watch\'. The order\n * of the actions is required, but each action is optional. In this example, when a ConfigMap is created\n * with the name `example-2`, then add a label and annotation, validate that the ConfigMap has the label\n * `pepr`, and log the request.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .WithName("example-2")\n .Mutate(request => {\n // This Mutate Action will mutate the request before it is persisted to the cluster\n\n // Use `request.Merge()` to merge the new data with the existing data\n request.Merge({\n metadata: {\n labels: {\n pepr: "was-here",\n },\n annotations: {\n "pepr.dev": "annotations-work-too",\n },\n },\n });\n })\n .Validate(request => {\n // This Validate Action will validate the request before it is persisted to the cluster\n\n // Approve the request if the ConfigMap has the label \'pepr\'\n if (request.HasLabel("pepr")) {\n return request.Approve();\n }\n\n // Otherwise, deny the request with an error message (optional)\n return request.Deny("ConfigMap must have label \'pepr\'");\n })\n .Watch((cm, phase) => {\n // This Watch Action will watch the ConfigMap after it has been persisted to the cluster\n Log.info(cm, `ConfigMap was ${phase} with the name example-2`);\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 2a) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action shows a simple validation that will deny any ConfigMap that has the\n * annotation `evil`. Note that the `Deny()` function takes an optional second parameter that is a\n * user-defined status code to return.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .Validate(request => {\n if (request.HasAnnotation("evil")) {\n return request.Deny("No evil CM annotations allowed.", 400);\n }\n\n return request.Approve();\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 3) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action combines different styles. Unlike the previous actions, this one will look\n * for any ConfigMap in the `pepr-demo` namespace that has the label `change=by-label` during either\n * CREATE or UPDATE. Note that all conditions added such as `WithName()`, `WithLabel()`, `InNamespace()`,\n * are ANDs so all conditions must be true for the request to be processed.\n */\nWhen(a.ConfigMap)\n .IsCreatedOrUpdated()\n .WithLabel("change", "by-label")\n .Mutate(request => {\n // The K8s object e are going to mutate\n const cm = request.Raw;\n\n // Get the username and uid of the K8s request\n const { username, uid } = request.Request.userInfo;\n\n // Store some data about the request in the configmap\n cm.data["username"] = username;\n cm.data["uid"] = uid;\n\n // You can still mix other ways of making changes too\n request.SetAnnotation("pepr.dev", "making-waves");\n });\n\n// This action validates the label `change=by-label` is deleted\nWhen(a.ConfigMap)\n .IsDeleted()\n .WithLabel("change", "by-label")\n .Validate(request => {\n // Log and then always approve the request\n Log.info("CM with label \'change=by-label\' was deleted.");\n return request.Approve();\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 4) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action show how you can use the `Mutate()` function without an inline function.\n * This is useful if you want to keep your actions small and focused on a single task,\n * or if you want to reuse the same function in multiple actions.\n */\nWhen(a.ConfigMap).IsCreated().WithName("example-4").Mutate(example4Cb);\n\n// This function uses the complete type definition, but is not required.\nfunction example4Cb(cm: PeprMutateRequest<a.ConfigMap>) {\n cm.SetLabel("pepr.dev/first", "true");\n cm.SetLabel("pepr.dev/second", "true");\n cm.SetLabel("pepr.dev/third", "true");\n}\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 4a) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This is the same as Example 4, except this only operates on a CM in the `pepr-demo-2` namespace.\n * Note because the Capability defines namespaces, the namespace specified here must be one of those.\n * Alternatively, you can remove the namespace from the Capability definition and specify it here.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .InNamespace("pepr-demo-2")\n .WithName("example-4a")\n .Mutate(example4Cb);\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 5) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action is a bit more complex. It will look for any ConfigMap in the `pepr-demo`\n * namespace that has the label `chuck-norris` during CREATE. When it finds one, it will fetch a\n * random Chuck Norris joke from the API and add it to the ConfigMap. This is a great example of how\n * you can use Pepr to make changes to your K8s objects based on external data.\n *\n * Note the use of the `async` keyword. This is required for any action that uses `await` or `fetch()`.\n *\n * Also note we are passing a type to the `fetch()` function. This is optional, but it will help you\n * avoid mistakes when working with the data returned from the API. You can also use the `as` keyword to\n * cast the data returned from the API.\n *\n * These are equivalent:\n * ```ts\n * const joke = await fetch<TheChuckNorrisJoke>("https://icanhazdadjoke.com/");\n * const joke = await fetch("https://icanhazdadjoke.com/") as TheChuckNorrisJoke;\n * ```\n *\n * Alternatively, you can drop the type completely:\n *\n * ```ts\n * fetch("https://icanhazdadjoke.com")\n * ```\n */\ninterface TheChuckNorrisJoke {\n id: string;\n joke: string;\n status: number;\n}\n\nWhen(a.ConfigMap)\n .IsCreatedOrUpdated()\n .WithLabel("chuck-norris")\n .Mutate(cm => cm.SetLabel("got-jokes", "true"))\n .Watch(async cm => {\n const jokeURL = "https://icanhazdadjoke.com/";\n\n // Set up Nock to mock the API calls globally with header matching\n nock(jokeURL).get("/").reply(200, {\n id: "R7UfaahVfFd",\n joke: "Funny joke goes here.",\n status: 200,\n });\n\n // Try/catch is not needed as a response object will always be returned\n const response = await fetch<TheChuckNorrisJoke>(jokeURL, {\n headers: {\n Accept: "application/json",\n },\n });\n\n // Instead, check the `response.ok` field\n if (response.ok) {\n const { joke } = response.data;\n // Add Joke to the Store\n await Store.setItemAndWait(jokeURL, joke);\n // Add the Chuck Norris joke to the configmap\n try {\n await K8s(kind.ConfigMap).Apply({\n metadata: {\n name: cm.metadata.name,\n namespace: cm.metadata.namespace,\n },\n data: {\n "chuck-says": Store.getItem(jokeURL),\n },\n });\n } catch (error) {\n Log.error(error, "Failed to apply ConfigMap using server-side apply.", {\n cm,\n });\n }\n }\n\n // You can also assert on different HTTP response codes\n if (response.status === fetchStatus.NOT_FOUND) {\n // Do something else\n return;\n }\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Secret Base64 Handling) *\n * ---------------------------------------------------------------------------------------------------\n *\n * The K8s JS client provides incomplete support for base64 encoding/decoding handling for secrets,\n * unlike the GO client. To make this less painful, Pepr automatically handles base64 encoding/decoding\n * secret data before and after the action is executed.\n */\nWhen(a.Secret)\n .IsCreated()\n .WithName("secret-1")\n .Mutate(request => {\n const secret = request.Raw;\n\n // This will be encoded at the end of all processing back to base64: "Y2hhbmdlLXdpdGhvdXQtZW5jb2Rpbmc="\n secret.data.magic = "change-without-encoding";\n\n // You can modify the data directly, and it will be encoded at the end of all processing\n secret.data.example += " - modified by Pepr";\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Untyped Custom Resource) *\n * ---------------------------------------------------------------------------------------------------\n *\n * Out of the box, Pepr supports all the standard Kubernetes objects. However, you can also create\n * your own types. This is useful if you are working with an Operator that creates custom resources.\n * There are two ways to do this, the first is to use the `When()` function with a `GenericKind`,\n * the second is to create a new class that extends `GenericKind` and use the `RegisterKind()` function.\n *\n * This example shows how to use the `When()` function with a `GenericKind`. Note that you\n * must specify the `group`, `version`, and `kind` of the object (if applicable). This is how Pepr knows\n * if the action should be triggered or not. Since we are using a `GenericKind`,\n * Pepr will not be able to provide any intellisense for the object, so you will need to refer to the\n * Kubernetes API documentation for the object you are working with.\n *\n * You will need to wait for the CRD in `hello-pepr.samples.yaml` to be created, then you can apply\n *\n * ```yaml\n * apiVersion: pepr.dev/v1\n * kind: Unicorn\n * metadata:\n * name: example-1\n * namespace: pepr-demo\n * spec:\n * message: replace-me\n * counter: 0\n * ```\n */\nWhen(a.GenericKind, {\n group: "pepr.dev",\n version: "v1",\n kind: "Unicorn",\n})\n .IsCreated()\n .WithName("example-1")\n .Mutate(request => {\n request.Merge({\n spec: {\n message: "Hello Pepr without type data!",\n counter: Math.random(),\n },\n });\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Typed Custom Resource) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This example shows how to use the `RegisterKind()` function to create a new type. This is useful\n * if you are working with an Operator that creates custom resources and you want to have intellisense\n * for the object. Note that you must specify the `group`, `version`, and `kind` of the object (if applicable)\n * as this is how Pepr knows if the action should be triggered or not.\n *\n * Once you register a new Kind with Pepr, you can use the `When()` function with the new Kind. Ideally,\n * you should register custom Kinds at the top of your Capability file or Pepr Module so they are available\n * to all actions, but we are putting it here for demonstration purposes.\n *\n * You will need to wait for the CRD in `hello-pepr.samples.yaml` to be created, then you can apply\n *\n * ```yaml\n * apiVersion: pepr.dev/v1\n * kind: Unicorn\n * metadata:\n * name: example-2\n * namespace: pepr-demo\n * spec:\n * message: replace-me\n * counter: 0\n * ```*\n */\nclass UnicornKind extends a.GenericKind {\n spec: {\n /**\n * JSDoc comments can be added to explain more details about the field.\n *\n * @example\n * ```ts\n * request.Raw.spec.message = "Hello Pepr!";\n * ```\n * */\n message: string;\n counter: number;\n };\n}\n\nRegisterKind(UnicornKind, {\n group: "pepr.dev",\n version: "v1",\n kind: "Unicorn",\n});\n\nWhen(UnicornKind)\n .IsCreated()\n .WithName("example-2")\n .Mutate(request => {\n request.Merge({\n spec: {\n message: "Hello Pepr with type data!",\n counter: Math.random(),\n },\n });\n });\n\n/**\n * A callback function that is called once the Pepr Store is fully loaded.\n */\nStore.onReady(data => {\n Log.info(data, "Pepr Store Ready");\n});\n';
2215
- var packageJSON = { name: "pepr", description: "Kubernetes application engine", author: "Defense Unicorns", homepage: "https://github.com/defenseunicorns/pepr", license: "Apache-2.0", bin: "dist/cli.js", repository: "defenseunicorns/pepr", engines: { node: ">=18.0.0" }, files: ["/dist", "/src", "!src/**/*.test.ts", "!dist/**/*.test.d.ts*"], version: "0.40.1", main: "dist/lib.js", types: "dist/lib.d.ts", scripts: { ci: "npm ci", "gen-data-json": "node hack/build-template-data.js", prebuild: "rm -fr dist/* && npm run gen-data-json", version: "node scripts/set-version.js", build: "tsc && node build.mjs && npm pack", "build:image": "npm run build && docker buildx build --output type=docker --tag pepr:dev .", test: "npm run test:unit && npm run test:journey", "test:unit": "npm run gen-data-json && jest src --coverage --detectOpenHandles --coverageDirectory=./coverage --testPathIgnorePatterns='cosign.e2e.test.ts'", "test:journey": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run", "test:journey:prep": "if [ ! -d ./pepr-upgrade-test ]; then git clone https://github.com/defenseunicorns/pepr-upgrade-test.git ; fi", "test:journey-wasm": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run-wasm", "test:journey:k3d": "k3d cluster delete pepr-dev && k3d cluster create pepr-dev --k3s-arg '--debug@server:0' --wait && kubectl rollout status deployment -n kube-system", "test:journey:image": "docker buildx build --output type=docker --tag pepr:dev . && k3d image import pepr:dev -c pepr-dev", "test:journey:run": "jest --detectOpenHandles journey/entrypoint.test.ts && npm run test:journey:prep && npm run test:journey:upgrade", "test:journey:run-wasm": "jest --detectOpenHandles journey/entrypoint-wasm.test.ts", "test:journey:upgrade": "npm run test:journey:k3d && npm run test:journey:image && jest --detectOpenHandles journey/pepr-upgrade.test.ts", "format:check": "eslint src && prettier src --check", "format:fix": "eslint src --fix && prettier src --write", prepare: `if [ "$NODE_ENV" != 'production' ]; then husky; fi` }, dependencies: { "@types/ramda": "0.30.2", express: "4.21.1", "fast-json-patch": "3.1.1", "follow-redirects": "1.15.9", "http-status-codes": "^2.3.0", "json-pointer": "^0.6.2", "kubernetes-fluent-client": "3.3.4", pino: "9.5.0", "pino-pretty": "13.0.0", "prom-client": "15.1.3", ramda: "0.30.1", sigstore: "3.0.0" }, devDependencies: { "@commitlint/cli": "19.6.0", "@commitlint/config-conventional": "19.6.0", "@fast-check/jest": "^2.0.1", "@jest/globals": "29.7.0", "@types/eslint": "9.6.1", "@types/express": "5.0.0", "@types/follow-redirects": "1.14.4", "@types/json-pointer": "^1.0.34", "@types/node": "22.x.x", "@types/node-forge": "1.3.11", "@types/uuid": "10.0.0", "fast-check": "^3.19.0", husky: "^9.1.6", jest: "29.7.0", "js-yaml": "^4.1.0", nock: "^13.5.4", "ts-jest": "29.2.5" }, peerDependencies: { "@types/prompts": "2.4.9", "@typescript-eslint/eslint-plugin": "7.18.0", "@typescript-eslint/parser": "7.18.0", commander: "12.1.0", esbuild: "0.23.0", eslint: "8.57.0", "node-forge": "1.3.1", prettier: "3.3.3", prompts: "2.4.2", typescript: "5.3.3", uuid: "10.0.0" } };
2208
+ var helloPeprTS = 'import {\n Capability,\n K8s,\n Log,\n PeprMutateRequest,\n RegisterKind,\n a,\n fetch,\n fetchStatus,\n kind,\n} from "pepr";\nimport { MockAgent, setGlobalDispatcher } from "undici";\n\n/**\n * The HelloPepr Capability is an example capability to demonstrate some general concepts of Pepr.\n * To test this capability you run `pepr dev`and then run the following command:\n * `kubectl apply -f capabilities/hello-pepr.samples.yaml`\n */\nexport const HelloPepr = new Capability({\n name: "hello-pepr",\n description: "A simple example capability to show how things work.",\n namespaces: ["pepr-demo", "pepr-demo-2"],\n});\n\n// Use the \'When\' function to create a new action, use \'Store\' to persist data\nconst { When, Store } = HelloPepr;\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Namespace) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action removes the label `remove-me` when a Namespace is created.\n * Note we don\'t need to specify the namespace here, because we\'ve already specified\n * it in the Capability definition above.\n */\nWhen(a.Namespace)\n .IsCreated()\n .Mutate(ns => ns.RemoveLabel("remove-me"));\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Watch Action with K8s SSA (Namespace) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action watches for the `pepr-demo-2` namespace to be created, then creates a ConfigMap with\n * the name `pepr-ssa-demo` and adds the namespace UID to the ConfigMap data. Because Pepr uses\n * server-side apply for this operation, the ConfigMap will be created or updated if it already exists.\n */\nWhen(a.Namespace)\n .IsCreated()\n .WithName("pepr-demo-2")\n .Watch(async ns => {\n Log.info("Namespace pepr-demo-2 was created.");\n\n try {\n // Apply the ConfigMap using K8s server-side apply\n await K8s(kind.ConfigMap).Apply({\n metadata: {\n name: "pepr-ssa-demo",\n namespace: "pepr-demo-2",\n },\n data: {\n "ns-uid": ns.metadata.uid,\n },\n });\n } catch (error) {\n // You can use the Log object to log messages to the Pepr controller pod\n Log.error(error, "Failed to apply ConfigMap using server-side apply.");\n }\n\n // You can share data between actions using the Store, including between different types of actions\n Store.setItem("watch-data", "This data was stored by a Watch Action.");\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 1) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This is a single action. They can be in the same file or put imported from other files.\n * In this example, when a ConfigMap is created with the name `example-1`, then add a label and annotation.\n *\n * Equivalent to manually running:\n * `kubectl label configmap example-1 pepr=was-here`\n * `kubectl annotate configmap example-1 pepr.dev=annotations-work-too`\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .WithName("example-1")\n .Mutate(request => {\n request\n .SetLabel("pepr", "was-here")\n .SetAnnotation("pepr.dev", "annotations-work-too");\n\n // Use the Store to persist data between requests and Pepr controller pods\n Store.setItem("example-1", "was-here");\n\n // This data is written asynchronously and can be read back via `Store.getItem()` or `Store.subscribe()`\n Store.setItem("example-1-data", JSON.stringify(request.Raw.data));\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate & Validate Actions (CM Example 2) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This combines 3 different types of actions: \'Mutate\', \'Validate\', and \'Watch\'. The order\n * of the actions is required, but each action is optional. In this example, when a ConfigMap is created\n * with the name `example-2`, then add a label and annotation, validate that the ConfigMap has the label\n * `pepr`, and log the request.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .WithName("example-2")\n .Mutate(request => {\n // This Mutate Action will mutate the request before it is persisted to the cluster\n\n // Use `request.Merge()` to merge the new data with the existing data\n request.Merge({\n metadata: {\n labels: {\n pepr: "was-here",\n },\n annotations: {\n "pepr.dev": "annotations-work-too",\n },\n },\n });\n })\n .Validate(request => {\n // This Validate Action will validate the request before it is persisted to the cluster\n\n // Approve the request if the ConfigMap has the label \'pepr\'\n if (request.HasLabel("pepr")) {\n return request.Approve();\n }\n\n // Otherwise, deny the request with an error message (optional)\n return request.Deny("ConfigMap must have label \'pepr\'");\n })\n .Watch((cm, phase) => {\n // This Watch Action will watch the ConfigMap after it has been persisted to the cluster\n Log.info(cm, `ConfigMap was ${phase} with the name example-2`);\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 2a) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action shows a simple validation that will deny any ConfigMap that has the\n * annotation `evil`. Note that the `Deny()` function takes an optional second parameter that is a\n * user-defined status code to return.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .Validate(request => {\n if (request.HasAnnotation("evil")) {\n return request.Deny("No evil CM annotations allowed.", 400);\n }\n\n return request.Approve();\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 3) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action combines different styles. Unlike the previous actions, this one will look\n * for any ConfigMap in the `pepr-demo` namespace that has the label `change=by-label` during either\n * CREATE or UPDATE. Note that all conditions added such as `WithName()`, `WithLabel()`, `InNamespace()`,\n * are ANDs so all conditions must be true for the request to be processed.\n */\nWhen(a.ConfigMap)\n .IsCreatedOrUpdated()\n .WithLabel("change", "by-label")\n .Mutate(request => {\n // The K8s object e are going to mutate\n const cm = request.Raw;\n\n // Get the username and uid of the K8s request\n const { username, uid } = request.Request.userInfo;\n\n // Store some data about the request in the configmap\n cm.data["username"] = username;\n cm.data["uid"] = uid;\n\n // You can still mix other ways of making changes too\n request.SetAnnotation("pepr.dev", "making-waves");\n });\n\n// This action validates the label `change=by-label` is deleted\nWhen(a.ConfigMap)\n .IsDeleted()\n .WithLabel("change", "by-label")\n .Validate(request => {\n // Log and then always approve the request\n Log.info("CM with label \'change=by-label\' was deleted.");\n return request.Approve();\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 4) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action show how you can use the `Mutate()` function without an inline function.\n * This is useful if you want to keep your actions small and focused on a single task,\n * or if you want to reuse the same function in multiple actions.\n */\nWhen(a.ConfigMap).IsCreated().WithName("example-4").Mutate(example4Cb);\n\n// This function uses the complete type definition, but is not required.\nfunction example4Cb(cm: PeprMutateRequest<a.ConfigMap>) {\n cm.SetLabel("pepr.dev/first", "true");\n cm.SetLabel("pepr.dev/second", "true");\n cm.SetLabel("pepr.dev/third", "true");\n}\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 4a) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This is the same as Example 4, except this only operates on a CM in the `pepr-demo-2` namespace.\n * Note because the Capability defines namespaces, the namespace specified here must be one of those.\n * Alternatively, you can remove the namespace from the Capability definition and specify it here.\n */\nWhen(a.ConfigMap)\n .IsCreated()\n .InNamespace("pepr-demo-2")\n .WithName("example-4a")\n .Mutate(example4Cb);\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (CM Example 5) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This action is a bit more complex. It will look for any ConfigMap in the `pepr-demo`\n * namespace that has the label `chuck-norris` during CREATE. When it finds one, it will fetch a\n * random Chuck Norris joke from the API and add it to the ConfigMap. This is a great example of how\n * you can use Pepr to make changes to your K8s objects based on external data.\n *\n * Note the use of the `async` keyword. This is required for any action that uses `await` or `fetch()`.\n *\n * Also note we are passing a type to the `fetch()` function. This is optional, but it will help you\n * avoid mistakes when working with the data returned from the API. You can also use the `as` keyword to\n * cast the data returned from the API.\n *\n * These are equivalent:\n * ```ts\n * const joke = await fetch<TheChuckNorrisJoke>("https://icanhazdadjoke.com/");\n * const joke = await fetch("https://icanhazdadjoke.com/") as TheChuckNorrisJoke;\n * ```\n *\n * Alternatively, you can drop the type completely:\n *\n * ```ts\n * fetch("https://icanhazdadjoke.com")\n * ```\n */\ninterface TheChuckNorrisJoke {\n id: string;\n joke: string;\n status: number;\n}\n\nWhen(a.ConfigMap)\n .IsCreatedOrUpdated()\n .WithLabel("chuck-norris")\n .Mutate(cm => cm.SetLabel("got-jokes", "true"))\n .Watch(async cm => {\n const jokeURL = "https://icanhazdadjoke.com";\n\n const mockAgent: MockAgent = new MockAgent();\n setGlobalDispatcher(mockAgent);\n const mockClient = mockAgent.get(jokeURL);\n mockClient.intercept({ path: "/", method: "GET" }).reply(\n 200,\n {\n id: "R7UfaahVfFd",\n joke: "Funny joke goes here.",\n status: 200,\n },\n {\n headers: {\n "Content-Type": "application/json; charset=utf-8",\n },\n },\n );\n\n // Try/catch is not needed as a response object will always be returned\n const response = await fetch<TheChuckNorrisJoke>(jokeURL, {\n headers: {\n Accept: "application/json",\n },\n });\n\n // Instead, check the `response.ok` field\n if (response.ok) {\n const { joke } = response.data;\n // Add Joke to the Store\n await Store.setItemAndWait(jokeURL, joke);\n // Add the Chuck Norris joke to the configmap\n try {\n await K8s(kind.ConfigMap).Apply({\n metadata: {\n name: cm.metadata.name,\n namespace: cm.metadata.namespace,\n },\n data: {\n "chuck-says": Store.getItem(jokeURL),\n },\n });\n } catch (error) {\n Log.error(error, "Failed to apply ConfigMap using server-side apply.", {\n cm,\n });\n }\n }\n\n // You can also assert on different HTTP response codes\n if (response.status === fetchStatus.NOT_FOUND) {\n // Do something else\n return;\n }\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Secret Base64 Handling) *\n * ---------------------------------------------------------------------------------------------------\n *\n * The K8s JS client provides incomplete support for base64 encoding/decoding handling for secrets,\n * unlike the GO client. To make this less painful, Pepr automatically handles base64 encoding/decoding\n * secret data before and after the action is executed.\n */\nWhen(a.Secret)\n .IsCreated()\n .WithName("secret-1")\n .Mutate(request => {\n const secret = request.Raw;\n\n // This will be encoded at the end of all processing back to base64: "Y2hhbmdlLXdpdGhvdXQtZW5jb2Rpbmc="\n secret.data.magic = "change-without-encoding";\n\n // You can modify the data directly, and it will be encoded at the end of all processing\n secret.data.example += " - modified by Pepr";\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Untyped Custom Resource) *\n * ---------------------------------------------------------------------------------------------------\n *\n * Out of the box, Pepr supports all the standard Kubernetes objects. However, you can also create\n * your own types. This is useful if you are working with an Operator that creates custom resources.\n * There are two ways to do this, the first is to use the `When()` function with a `GenericKind`,\n * the second is to create a new class that extends `GenericKind` and use the `RegisterKind()` function.\n *\n * This example shows how to use the `When()` function with a `GenericKind`. Note that you\n * must specify the `group`, `version`, and `kind` of the object (if applicable). This is how Pepr knows\n * if the action should be triggered or not. Since we are using a `GenericKind`,\n * Pepr will not be able to provide any intellisense for the object, so you will need to refer to the\n * Kubernetes API documentation for the object you are working with.\n *\n * You will need to wait for the CRD in `hello-pepr.samples.yaml` to be created, then you can apply\n *\n * ```yaml\n * apiVersion: pepr.dev/v1\n * kind: Unicorn\n * metadata:\n * name: example-1\n * namespace: pepr-demo\n * spec:\n * message: replace-me\n * counter: 0\n * ```\n */\nWhen(a.GenericKind, {\n group: "pepr.dev",\n version: "v1",\n kind: "Unicorn",\n})\n .IsCreated()\n .WithName("example-1")\n .Mutate(request => {\n request.Merge({\n spec: {\n message: "Hello Pepr without type data!",\n counter: Math.random(),\n },\n });\n });\n\n/**\n * ---------------------------------------------------------------------------------------------------\n * Mutate Action (Typed Custom Resource) *\n * ---------------------------------------------------------------------------------------------------\n *\n * This example shows how to use the `RegisterKind()` function to create a new type. This is useful\n * if you are working with an Operator that creates custom resources and you want to have intellisense\n * for the object. Note that you must specify the `group`, `version`, and `kind` of the object (if applicable)\n * as this is how Pepr knows if the action should be triggered or not.\n *\n * Once you register a new Kind with Pepr, you can use the `When()` function with the new Kind. Ideally,\n * you should register custom Kinds at the top of your Capability file or Pepr Module so they are available\n * to all actions, but we are putting it here for demonstration purposes.\n *\n * You will need to wait for the CRD in `hello-pepr.samples.yaml` to be created, then you can apply\n *\n * ```yaml\n * apiVersion: pepr.dev/v1\n * kind: Unicorn\n * metadata:\n * name: example-2\n * namespace: pepr-demo\n * spec:\n * message: replace-me\n * counter: 0\n * ```*\n */\nclass UnicornKind extends a.GenericKind {\n spec: {\n /**\n * JSDoc comments can be added to explain more details about the field.\n *\n * @example\n * ```ts\n * request.Raw.spec.message = "Hello Pepr!";\n * ```\n * */\n message: string;\n counter: number;\n };\n}\n\nRegisterKind(UnicornKind, {\n group: "pepr.dev",\n version: "v1",\n kind: "Unicorn",\n});\n\nWhen(UnicornKind)\n .IsCreated()\n .WithName("example-2")\n .Mutate(request => {\n request.Merge({\n spec: {\n message: "Hello Pepr with type data!",\n counter: Math.random(),\n },\n });\n });\n\n/**\n * A callback function that is called once the Pepr Store is fully loaded.\n */\nStore.onReady(data => {\n Log.info(data, "Pepr Store Ready");\n});\n';
2209
+ var packageJSON = { name: "pepr", description: "Kubernetes application engine", author: "Defense Unicorns", homepage: "https://github.com/defenseunicorns/pepr", license: "Apache-2.0", bin: "dist/cli.js", repository: "defenseunicorns/pepr", engines: { node: ">=18.0.0" }, files: ["/dist", "/src", "!src/**/*.test.ts", "!dist/**/*.test.d.ts*"], version: "0.42.1", main: "dist/lib.js", types: "dist/lib.d.ts", scripts: { ci: "npm ci", "gen-data-json": "node hack/build-template-data.js", prebuild: "rm -fr dist/* && npm run gen-data-json", version: "node scripts/set-version.js", build: "tsc && node build.mjs && npm pack", "build:image": "npm run build && docker buildx build --output type=docker --tag pepr:dev .", test: "npm run test:unit && npm run test:journey", "test:unit": "npm run gen-data-json && jest src --coverage --detectOpenHandles --coverageDirectory=./coverage --testPathIgnorePatterns='cosign.e2e.test.ts'", "test:journey": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run", "test:journey:prep": "if [ ! -d ./pepr-upgrade-test ]; then git clone https://github.com/defenseunicorns/pepr-upgrade-test.git ; fi", "test:journey-wasm": "npm run test:journey:k3d && npm run build && npm run test:journey:image && npm run test:journey:run-wasm", "test:journey:k3d": "k3d cluster delete pepr-dev && k3d cluster create pepr-dev --k3s-arg '--debug@server:0' --wait && kubectl rollout status deployment -n kube-system", "test:journey:image": "docker buildx build --output type=docker --tag pepr:dev . && k3d image import pepr:dev -c pepr-dev", "test:journey:run": "jest --detectOpenHandles journey/entrypoint.test.ts && npm run test:journey:prep && npm run test:journey:upgrade", "test:journey:run-wasm": "jest --detectOpenHandles journey/entrypoint-wasm.test.ts", "test:journey:upgrade": "npm run test:journey:k3d && npm run test:journey:image && jest --detectOpenHandles journey/pepr-upgrade.test.ts", "format:check": "eslint src && prettier src --check", "format:fix": "eslint src --fix && prettier src --write", prepare: `if [ "$NODE_ENV" != 'production' ]; then husky; fi` }, dependencies: { "@types/ramda": "0.30.2", express: "4.21.2", "fast-json-patch": "3.1.1", "follow-redirects": "1.15.9", "http-status-codes": "^2.3.0", "json-pointer": "^0.6.2", "kubernetes-fluent-client": "3.3.7", pino: "9.5.0", "pino-pretty": "13.0.0", "prom-client": "15.1.3", ramda: "0.30.1", sigstore: "3.0.0" }, devDependencies: { "@commitlint/cli": "19.6.0", "@commitlint/config-conventional": "19.6.0", "@fast-check/jest": "^2.0.1", "@jest/globals": "29.7.0", "@types/eslint": "9.6.1", "@types/express": "5.0.0", "@types/follow-redirects": "1.14.4", "@types/json-pointer": "^1.0.34", "@types/node": "22.x.x", "@types/node-forge": "1.3.11", "@types/uuid": "10.0.0", "fast-check": "^3.19.0", husky: "^9.1.6", jest: "29.7.0", "js-yaml": "^4.1.0", "ts-jest": "29.2.5", undici: "^7.0.1" }, peerDependencies: { "@types/prompts": "2.4.9", "@typescript-eslint/eslint-plugin": "7.18.0", "@typescript-eslint/parser": "7.18.0", commander: "12.1.0", esbuild: "0.23.0", eslint: "8.57.0", "node-forge": "1.3.1", prettier: "3.3.3", prompts: "2.4.2", typescript: "5.3.3", uuid: "10.0.0" } };
2216
2210
 
2217
2211
  // src/templates/pepr.code-snippets.json
2218
2212
  var pepr_code_snippets_default = {
@@ -2271,7 +2265,7 @@ var tsconfig_module_default = {
2271
2265
  };
2272
2266
 
2273
2267
  // src/cli/init/utils.ts
2274
- var import_fs6 = require("fs");
2268
+ var import_fs5 = require("fs");
2275
2269
  function sanitizeName(name2) {
2276
2270
  if (typeof name2 !== "string") {
2277
2271
  throw TypeError(
@@ -2285,7 +2279,7 @@ function sanitizeName(name2) {
2285
2279
  }
2286
2280
  async function createDir(dir) {
2287
2281
  try {
2288
- await import_fs6.promises.mkdir(dir);
2282
+ await import_fs5.promises.mkdir(dir);
2289
2283
  } catch (err) {
2290
2284
  if (err && err.code === "EEXIST") {
2291
2285
  throw new Error(`Directory ${dir} already exists`);
@@ -2298,7 +2292,7 @@ function write(path, data) {
2298
2292
  if (typeof data !== "string") {
2299
2293
  data = JSON.stringify(data, null, 2);
2300
2294
  }
2301
- return import_fs6.promises.writeFile(path, data);
2295
+ return import_fs5.promises.writeFile(path, data);
2302
2296
  }
2303
2297
 
2304
2298
  // src/cli/init/templates.ts
@@ -2339,7 +2333,7 @@ function genPkgJSON(opts, pgkVerOverride) {
2339
2333
  },
2340
2334
  dependencies: {
2341
2335
  pepr: pgkVerOverride || version2,
2342
- nock: "13.5.4"
2336
+ undici: "^7.0.1"
2343
2337
  },
2344
2338
  devDependencies: {
2345
2339
  typescript
@@ -2394,9 +2388,12 @@ var eslint = {
2394
2388
  data: eslintrc_template_default
2395
2389
  };
2396
2390
 
2391
+ // src/cli/build.ts
2392
+ var import_commander = require("commander");
2393
+
2397
2394
  // src/cli/format.ts
2398
2395
  var import_eslint = require("eslint");
2399
- var import_fs7 = require("fs");
2396
+ var import_fs6 = require("fs");
2400
2397
  var import_prettier = require("prettier");
2401
2398
  function format_default(program2) {
2402
2399
  program2.command("format").description("Lint and format this Pepr module").option("-v, --validate-only", "Do not modify files, only validate formatting").action(async (opts) => {
@@ -2429,14 +2426,14 @@ async function peprFormat(validateOnly) {
2429
2426
  await import_eslint.ESLint.outputFixes(results);
2430
2427
  }
2431
2428
  for (const { filePath } of results) {
2432
- const content = await import_fs7.promises.readFile(filePath, "utf8");
2429
+ const content = await import_fs6.promises.readFile(filePath, "utf8");
2433
2430
  const cfg = await (0, import_prettier.resolveConfig)(filePath);
2434
2431
  const formatted = await (0, import_prettier.format)(content, { filepath: filePath, ...cfg });
2435
2432
  if (validateOnly && formatted !== content) {
2436
2433
  hasFailure = true;
2437
2434
  console.error(`File ${filePath} is not formatted correctly`);
2438
2435
  } else {
2439
- await import_fs7.promises.writeFile(filePath, formatted);
2436
+ await import_fs6.promises.writeFile(filePath, formatted);
2440
2437
  }
2441
2438
  }
2442
2439
  return !hasFailure;
@@ -2447,10 +2444,27 @@ async function peprFormat(validateOnly) {
2447
2444
  }
2448
2445
  }
2449
2446
 
2450
- // src/cli/build.ts
2451
- var import_commander = require("commander");
2447
+ // src/lib/included-files.ts
2448
+ var import_fs7 = require("fs");
2449
+ async function createDockerfile(version3, description, includedFiles) {
2450
+ const file = `
2451
+ # Use an official Node.js runtime as the base image
2452
+ FROM ghcr.io/defenseunicorns/pepr/controller:v${version3}
2453
+
2454
+ LABEL description="${description}"
2455
+
2456
+ # Add the included files to the image
2457
+ ${includedFiles.map((f) => `ADD ${f} ${f}`).join("\n")}
2458
+
2459
+ `;
2460
+ await import_fs7.promises.writeFile("Dockerfile.controller", file, { encoding: "utf-8" });
2461
+ }
2452
2462
 
2453
2463
  // src/cli/build.helpers.ts
2464
+ var import_child_process2 = require("child_process");
2465
+ var import_esbuild = require("esbuild");
2466
+ var import_path2 = require("path");
2467
+ var import_fs8 = require("fs");
2454
2468
  function determineRbacMode(opts, cfg) {
2455
2469
  if (opts.rbacMode) {
2456
2470
  return opts.rbacMode;
@@ -2460,6 +2474,93 @@ function determineRbacMode(opts, cfg) {
2460
2474
  }
2461
2475
  return cfg.pepr.rbacMode || "admin";
2462
2476
  }
2477
+ async function handleCustomOutputDir(outputDir2) {
2478
+ const defaultOutputDir = "dist";
2479
+ if (outputDir2) {
2480
+ try {
2481
+ await createDirectoryIfNotExists(outputDir2);
2482
+ return outputDir2;
2483
+ } catch (error) {
2484
+ console.error(`Error creating output directory: ${error.message}`);
2485
+ process.exit(1);
2486
+ }
2487
+ }
2488
+ return defaultOutputDir;
2489
+ }
2490
+ function checkIronBankImage(registry, image, peprVersion) {
2491
+ return registry === "Iron Bank" ? `registry1.dso.mil/ironbank/opensource/defenseunicorns/pepr/controller:v${peprVersion}` : image;
2492
+ }
2493
+ function validImagePullSecret(imagePullSecretName) {
2494
+ if (imagePullSecretName) {
2495
+ const error = "Invalid imagePullSecret. Please provide a valid name as defined in RFC 1123.";
2496
+ if (sanitizeResourceName(imagePullSecretName) !== imagePullSecretName) {
2497
+ console.error(error);
2498
+ process.exit(1);
2499
+ }
2500
+ }
2501
+ }
2502
+ function handleCustomImage(customImage, registry) {
2503
+ let defaultImage = "";
2504
+ if (customImage) {
2505
+ if (registry) {
2506
+ console.error(`Custom Image and registry cannot be used together.`);
2507
+ process.exit(1);
2508
+ }
2509
+ defaultImage = customImage;
2510
+ }
2511
+ return defaultImage;
2512
+ }
2513
+ async function handleCustomImageBuild(includedFiles, peprVersion, description, image) {
2514
+ if (includedFiles.length > 0) {
2515
+ await createDockerfile(peprVersion, description, includedFiles);
2516
+ (0, import_child_process2.execSync)(`docker build --tag ${image} -f Dockerfile.controller .`, {
2517
+ stdio: "inherit"
2518
+ });
2519
+ (0, import_child_process2.execSync)(`docker push ${image}`, { stdio: "inherit" });
2520
+ }
2521
+ }
2522
+ function handleEmbedding(embed, path) {
2523
+ if (!embed) {
2524
+ console.info(`\u2705 Module built successfully at ${path}`);
2525
+ return;
2526
+ }
2527
+ }
2528
+ function handleValidCapabilityNames(capabilities) {
2529
+ try {
2530
+ validateCapabilityNames(capabilities);
2531
+ } catch (e) {
2532
+ console.error(`Error loading capability:`, e);
2533
+ process.exit(1);
2534
+ }
2535
+ }
2536
+ async function watchForChanges(ctxCfg, reloader) {
2537
+ const ctx = await (0, import_esbuild.context)(ctxCfg);
2538
+ if (reloader) {
2539
+ await ctx.watch();
2540
+ } else {
2541
+ await ctx.rebuild();
2542
+ await ctx.dispose();
2543
+ }
2544
+ return ctx;
2545
+ }
2546
+ async function generateYamlAndWriteToDisk(obj) {
2547
+ const { uuid, imagePullSecret, outputDir: outputDir2, assets, zarf } = obj;
2548
+ const yamlFile = `pepr-module-${uuid}.yaml`;
2549
+ const chartPath = `${uuid}-chart`;
2550
+ const yamlPath = (0, import_path2.resolve)(outputDir2, yamlFile);
2551
+ const yaml = await assets.allYaml(imagePullSecret);
2552
+ const zarfPath = (0, import_path2.resolve)(outputDir2, "zarf.yaml");
2553
+ let localZarf = "";
2554
+ if (zarf === "chart") {
2555
+ localZarf = assets.zarfYamlChart(chartPath);
2556
+ } else {
2557
+ localZarf = assets.zarfYaml(yamlFile);
2558
+ }
2559
+ await import_fs8.promises.writeFile(yamlPath, yaml);
2560
+ await import_fs8.promises.writeFile(zarfPath, localZarf);
2561
+ await assets.generateHelmChart(outputDir2);
2562
+ console.info(`\u2705 K8s resource for the module saved to ${yamlPath}`);
2563
+ }
2463
2564
 
2464
2565
  // src/cli/build.ts
2465
2566
  var peprTS2 = "pepr.ts";
@@ -2499,46 +2600,22 @@ function build_default(program2) {
2499
2600
  ["admin", "scoped"]
2500
2601
  )
2501
2602
  ).action(async (opts) => {
2502
- if (opts.outputDir) {
2503
- outputDir = opts.outputDir;
2504
- createDirectoryIfNotExists(outputDir).catch((error) => {
2505
- console.error(`Error creating output directory: ${error.message}`);
2506
- process.exit(1);
2507
- });
2508
- }
2603
+ outputDir = await handleCustomOutputDir(opts.outputDir);
2509
2604
  const buildModuleResult = await buildModule(void 0, opts.entryPoint, opts.embed);
2510
2605
  if (buildModuleResult?.cfg && buildModuleResult.path && buildModuleResult.uuid) {
2511
2606
  const { cfg, path, uuid } = buildModuleResult;
2512
2607
  const { includedFiles } = cfg.pepr;
2513
- let image = "";
2514
- if (opts.customImage) {
2515
- if (opts.registry) {
2516
- console.error(`Custom Image and registry cannot be used together.`);
2517
- process.exit(1);
2518
- }
2519
- image = opts.customImage;
2520
- }
2608
+ let image = handleCustomImage(opts.customImage, opts.registry);
2521
2609
  if (opts.timeout !== void 0) {
2522
2610
  cfg.pepr.webhookTimeout = opts.timeout;
2523
2611
  }
2524
2612
  if (opts.registryInfo !== void 0) {
2525
2613
  console.info(`Including ${includedFiles.length} files in controller image.`);
2526
2614
  image = `${opts.registryInfo}/custom-pepr-controller:${cfg.pepr.peprVersion}`;
2527
- if (includedFiles.length > 0) {
2528
- await createDockerfile(cfg.pepr.peprVersion, cfg.description, includedFiles);
2529
- (0, import_child_process2.execSync)(`docker build --tag ${image} -f Dockerfile.controller .`, {
2530
- stdio: "inherit"
2531
- });
2532
- (0, import_child_process2.execSync)(`docker push ${image}`, { stdio: "inherit" });
2533
- }
2534
- }
2535
- if (!opts.embed) {
2536
- console.info(`\u2705 Module built successfully at ${path}`);
2537
- return;
2538
- }
2539
- if (opts.version) {
2540
- cfg.pepr.peprVersion = opts.version;
2615
+ await handleCustomImageBuild(includedFiles, cfg.pepr.peprVersion, cfg.description, image);
2541
2616
  }
2617
+ handleEmbedding(opts.embed, path);
2618
+ opts.version ? cfg.pepr.peprVersion = opts.version : null;
2542
2619
  const assets = new Assets(
2543
2620
  {
2544
2621
  ...cfg.pepr,
@@ -2549,46 +2626,17 @@ function build_default(program2) {
2549
2626
  },
2550
2627
  path
2551
2628
  );
2552
- if (opts?.registry === "Iron Bank") {
2553
- console.info(
2554
- `
2555
- This command assumes the latest release. Pepr's Iron Bank image release cycle is dictated by renovate and is typically released a few days after the GitHub release.
2556
- As an alternative you may consider custom --custom-image to target a specific image and version.`
2557
- );
2558
- image = `registry1.dso.mil/ironbank/opensource/defenseunicorns/pepr/controller:v${cfg.pepr.peprVersion}`;
2559
- }
2560
- if (image !== "") {
2561
- assets.image = image;
2562
- }
2563
- if (opts.withPullSecret) {
2564
- if (sanitizeResourceName(opts.withPullSecret) !== opts.withPullSecret) {
2565
- console.error(
2566
- "Invalid imagePullSecret. Please provide a valid name as defined in RFC 1123."
2567
- );
2568
- process.exit(1);
2569
- }
2570
- }
2571
- const yamlFile = `pepr-module-${uuid}.yaml`;
2572
- const chartPath = `${uuid}-chart`;
2573
- const yamlPath = (0, import_path2.resolve)(outputDir, yamlFile);
2574
- const yaml = await assets.allYaml(opts.withPullSecret);
2575
- try {
2576
- validateCapabilityNames(assets.capabilities);
2577
- } catch (e) {
2578
- console.error(`Error loading capability:`, e);
2579
- process.exit(1);
2580
- }
2581
- const zarfPath = (0, import_path2.resolve)(outputDir, "zarf.yaml");
2582
- let zarf = "";
2583
- if (opts.zarf === "chart") {
2584
- zarf = assets.zarfYamlChart(chartPath);
2585
- } else {
2586
- zarf = assets.zarfYaml(yamlFile);
2587
- }
2588
- await import_fs8.promises.writeFile(yamlPath, yaml);
2589
- await import_fs8.promises.writeFile(zarfPath, zarf);
2590
- await assets.generateHelmChart(outputDir);
2591
- console.info(`\u2705 K8s resource for the module saved to ${yamlPath}`);
2629
+ image = checkIronBankImage(opts.registry, image, cfg.pepr.peprVersion);
2630
+ image !== "" ? assets.image = image : null;
2631
+ validImagePullSecret(opts.withPullSecret);
2632
+ handleValidCapabilityNames(assets.capabilities);
2633
+ await generateYamlAndWriteToDisk({
2634
+ uuid,
2635
+ outputDir,
2636
+ imagePullSecret: opts.withPullSecret,
2637
+ zarf: opts.zarf,
2638
+ assets
2639
+ });
2592
2640
  }
2593
2641
  });
2594
2642
  }
@@ -2596,19 +2644,19 @@ var externalLibs = Object.keys(dependencies);
2596
2644
  externalLibs.push("pepr");
2597
2645
  externalLibs.push("@kubernetes/client-node");
2598
2646
  async function loadModule(entryPoint = peprTS2) {
2599
- const entryPointPath = (0, import_path2.resolve)(".", entryPoint);
2600
- const modulePath = (0, import_path2.dirname)(entryPointPath);
2601
- const cfgPath = (0, import_path2.resolve)(modulePath, "package.json");
2647
+ const entryPointPath = (0, import_path3.resolve)(".", entryPoint);
2648
+ const modulePath = (0, import_path3.dirname)(entryPointPath);
2649
+ const cfgPath = (0, import_path3.resolve)(modulePath, "package.json");
2602
2650
  try {
2603
- await import_fs8.promises.access(cfgPath);
2604
- await import_fs8.promises.access(entryPointPath);
2651
+ await import_fs9.promises.access(cfgPath);
2652
+ await import_fs9.promises.access(entryPointPath);
2605
2653
  } catch (e) {
2606
2654
  console.error(
2607
2655
  `Could not find ${cfgPath} or ${entryPointPath} in the current directory. Please run this command from the root of your module's directory.`
2608
2656
  );
2609
2657
  process.exit(1);
2610
2658
  }
2611
- const moduleText = await import_fs8.promises.readFile(cfgPath, { encoding: "utf-8" });
2659
+ const moduleText = await import_fs9.promises.readFile(cfgPath, { encoding: "utf-8" });
2612
2660
  const cfg = JSON.parse(moduleText);
2613
2661
  const { uuid } = cfg.pepr;
2614
2662
  const name2 = `pepr-${uuid}.js`;
@@ -2621,23 +2669,17 @@ async function loadModule(entryPoint = peprTS2) {
2621
2669
  entryPointPath,
2622
2670
  modulePath,
2623
2671
  name: name2,
2624
- path: (0, import_path2.resolve)(outputDir, name2),
2672
+ path: (0, import_path3.resolve)(outputDir, name2),
2625
2673
  uuid
2626
2674
  };
2627
2675
  }
2628
2676
  async function buildModule(reloader, entryPoint = peprTS2, embed = true) {
2629
2677
  try {
2630
2678
  const { cfg, modulePath, path, uuid } = await loadModule(entryPoint);
2631
- const validFormat = await peprFormat(true);
2632
- if (!validFormat) {
2633
- console.log(
2634
- "\x1B[33m%s\x1B[0m",
2635
- "Formatting errors were found. The build will continue, but you may want to run `npx pepr format` to address any issues."
2636
- );
2637
- }
2638
- const npmRoot = (0, import_child_process2.execFileSync)("npm", ["root"]).toString().trim();
2679
+ await checkFormat();
2680
+ const npmRoot = (0, import_child_process3.execFileSync)("npm", ["root"]).toString().trim();
2639
2681
  const args = ["--project", `${modulePath}/tsconfig.json`, "--outdir", outputDir];
2640
- (0, import_child_process2.execFileSync)(`${npmRoot}/.bin/tsc`, args);
2682
+ (0, import_child_process3.execFileSync)(`${npmRoot}/.bin/tsc`, args);
2641
2683
  const ctxCfg = {
2642
2684
  bundle: true,
2643
2685
  entryPoints: [entryPoint],
@@ -2654,7 +2696,7 @@ async function buildModule(reloader, entryPoint = peprTS2, embed = true) {
2654
2696
  setup(build) {
2655
2697
  build.onEnd(async (r) => {
2656
2698
  if (r?.metafile) {
2657
- console.log(await (0, import_esbuild.analyzeMetafile)(r.metafile));
2699
+ console.log(await (0, import_esbuild2.analyzeMetafile)(r.metafile));
2658
2700
  }
2659
2701
  if (reloader) {
2660
2702
  await reloader(r);
@@ -2672,51 +2714,96 @@ async function buildModule(reloader, entryPoint = peprTS2, embed = true) {
2672
2714
  }
2673
2715
  if (!embed) {
2674
2716
  ctxCfg.minify = false;
2675
- ctxCfg.outfile = (0, import_path2.resolve)(outputDir, (0, import_path2.basename)(entryPoint, (0, import_path2.extname)(entryPoint))) + ".js";
2717
+ ctxCfg.outfile = (0, import_path3.resolve)(outputDir, (0, import_path3.basename)(entryPoint, (0, import_path3.extname)(entryPoint))) + ".js";
2676
2718
  ctxCfg.packages = "external";
2677
2719
  ctxCfg.treeShaking = false;
2678
2720
  }
2679
- const ctx = await (0, import_esbuild.context)(ctxCfg);
2680
- if (reloader) {
2681
- await ctx.watch();
2682
- } else {
2683
- await ctx.rebuild();
2684
- await ctx.dispose();
2685
- }
2721
+ const ctx = await watchForChanges(ctxCfg, reloader);
2686
2722
  return { ctx, path, cfg, uuid };
2687
2723
  } catch (e) {
2688
- console.error(`Error building module:`, e);
2689
- if (!e.stdout) process.exit(1);
2690
- const out = e.stdout.toString();
2691
- const err = e.stderr.toString();
2692
- console.log(out);
2693
- console.error(err);
2694
- if (out.includes("Types have separate declarations of a private property '_name'.")) {
2695
- const pgkErrMatch = /error TS2322: .*? 'import\("\/.*?\/node_modules\/(.*?)\/node_modules/g;
2696
- out.matchAll(pgkErrMatch);
2697
- const conflicts = [...out.matchAll(pgkErrMatch)];
2698
- if (conflicts.length < 1) {
2699
- console.info(
2700
- `
2724
+ handleModuleBuildError(e);
2725
+ }
2726
+ }
2727
+ function handleModuleBuildError(e) {
2728
+ console.error(`Error building module:`, e);
2729
+ if (!e.stdout) process.exit(1);
2730
+ const out = e.stdout.toString();
2731
+ const err = e.stderr.toString();
2732
+ console.log(out);
2733
+ console.error(err);
2734
+ if (out.includes("Types have separate declarations of a private property '_name'.")) {
2735
+ const pgkErrMatch = /error TS2322: .*? 'import\("\/.*?\/node_modules\/(.*?)\/node_modules/g;
2736
+ out.matchAll(pgkErrMatch);
2737
+ const conflicts = [...out.matchAll(pgkErrMatch)];
2738
+ if (conflicts.length < 1) {
2739
+ console.info(
2740
+ `
2701
2741
  One or more imported Pepr Capabilities seem to be using an incompatible version of Pepr.
2702
2742
  Try updating your Pepr Capabilities to their latest versions.`,
2703
- "Version Conflict"
2704
- );
2705
- }
2706
- conflicts.forEach((match) => {
2707
- console.info(
2708
- `
2743
+ "Version Conflict"
2744
+ );
2745
+ }
2746
+ conflicts.forEach((match) => {
2747
+ console.info(
2748
+ `
2709
2749
  Package '${match[1]}' seems to be incompatible with your current version of Pepr.
2710
2750
  Try updating to the latest version.`,
2711
- "Version Conflict"
2712
- );
2713
- });
2714
- }
2751
+ "Version Conflict"
2752
+ );
2753
+ });
2754
+ }
2755
+ }
2756
+ async function checkFormat() {
2757
+ const validFormat = await peprFormat(true);
2758
+ if (!validFormat) {
2759
+ console.log(
2760
+ "\x1B[33m%s\x1B[0m",
2761
+ "Formatting errors were found. The build will continue, but you may want to run `npx pepr format` to address any issues."
2762
+ );
2715
2763
  }
2716
2764
  }
2717
2765
 
2718
2766
  // src/cli/deploy.ts
2719
2767
  var import_prompts = __toESM(require("prompts"));
2768
+
2769
+ // src/lib/deploymentChecks.ts
2770
+ var import_kubernetes_fluent_client4 = require("kubernetes-fluent-client");
2771
+ async function checkDeploymentStatus(namespace) {
2772
+ const deployments = await (0, import_kubernetes_fluent_client4.K8s)(import_kubernetes_fluent_client4.kind.Deployment).InNamespace(namespace).Get();
2773
+ let status = false;
2774
+ let readyCount = 0;
2775
+ for (const deployment of deployments.items) {
2776
+ const readyReplicas = deployment.status?.readyReplicas ? deployment.status?.readyReplicas : 0;
2777
+ if (deployment.status?.readyReplicas !== deployment.spec?.replicas) {
2778
+ logger_default.info(
2779
+ `Waiting for deployment ${deployment.metadata?.name} rollout to finish: ${readyReplicas} of ${deployment.spec?.replicas} replicas are available`
2780
+ );
2781
+ } else {
2782
+ logger_default.info(
2783
+ `Deployment ${deployment.metadata?.name} rolled out: ${readyReplicas} of ${deployment.spec?.replicas} replicas are available`
2784
+ );
2785
+ readyCount++;
2786
+ }
2787
+ }
2788
+ if (readyCount === deployments.items.length) {
2789
+ status = true;
2790
+ }
2791
+ return status;
2792
+ }
2793
+ async function namespaceDeploymentsReady(namespace = "pepr-system") {
2794
+ logger_default.info(`Checking ${namespace} deployments status...`);
2795
+ let ready = false;
2796
+ while (!ready) {
2797
+ ready = await checkDeploymentStatus(namespace);
2798
+ if (ready) {
2799
+ return ready;
2800
+ }
2801
+ await new Promise((resolve6) => setTimeout(resolve6, 1e3));
2802
+ }
2803
+ logger_default.info(`All ${namespace} deployments are ready`);
2804
+ }
2805
+
2806
+ // src/cli/deploy.ts
2720
2807
  function deploy_default(program2) {
2721
2808
  program2.command("deploy").description("Deploy a Pepr Module").option("-i, --image [image]", "Override the image tag").option("--confirm", "Skip confirmation prompt").option("--pullSecret <name>", "Deploy imagePullSecret for Controller private registry").option("--docker-server <server>", "Docker server address").option("--docker-username <username>", "Docker registry username").option("--docker-email <email>", "Email for Docker registry").option("--docker-password <password>", "Password for Docker registry").option("--force", "Force deploy the module, override manager field").action(async (opts) => {
2722
2809
  let imagePullSecret;
@@ -2782,8 +2869,8 @@ function deploy_default(program2) {
2782
2869
  }
2783
2870
 
2784
2871
  // src/cli/dev.ts
2785
- var import_child_process3 = require("child_process");
2786
- var import_fs9 = require("fs");
2872
+ var import_child_process4 = require("child_process");
2873
+ var import_fs10 = require("fs");
2787
2874
  var import_prompts2 = __toESM(require("prompts"));
2788
2875
  var import_kubernetes_fluent_client5 = require("kubernetes-fluent-client");
2789
2876
  function dev_default(program2) {
@@ -2807,8 +2894,8 @@ function dev_default(program2) {
2807
2894
  path,
2808
2895
  opts.host
2809
2896
  );
2810
- await import_fs9.promises.writeFile("insecure-tls.crt", webhook.tls.pem.crt);
2811
- await import_fs9.promises.writeFile("insecure-tls.key", webhook.tls.pem.key);
2897
+ await import_fs10.promises.writeFile("insecure-tls.crt", webhook.tls.pem.crt);
2898
+ await import_fs10.promises.writeFile("insecure-tls.key", webhook.tls.pem.key);
2812
2899
  try {
2813
2900
  let program3;
2814
2901
  const name2 = `pepr-${cfg.pepr.uuid}`;
@@ -2823,7 +2910,7 @@ function dev_default(program2) {
2823
2910
  console.error(`Error validating capability names:`, e);
2824
2911
  process.exit(1);
2825
2912
  }
2826
- program3 = (0, import_child_process3.fork)(path, {
2913
+ program3 = (0, import_child_process4.fork)(path, {
2827
2914
  env: {
2828
2915
  ...process.env,
2829
2916
  LOG_LEVEL: "debug",
@@ -2872,59 +2959,15 @@ var import_kubernetes_fluent_client6 = require("kubernetes-fluent-client");
2872
2959
  var import_stream = __toESM(require("stream"));
2873
2960
  function monitor_default(program2) {
2874
2961
  program2.command("monitor [module-uuid]").description("Monitor a Pepr Module").action(async (uuid) => {
2875
- let labels;
2876
- let errorMessage;
2877
- if (!uuid) {
2878
- labels = ["pepr.dev/controller", "admission"];
2879
- errorMessage = `No pods found with admission labels`;
2880
- } else {
2881
- labels = ["app", `pepr-${uuid}`];
2882
- errorMessage = `No pods found for module ${uuid}`;
2883
- }
2962
+ const { labels, errorMessage } = getLabelsAndErrorMessage(uuid);
2884
2963
  const pods = await (0, import_kubernetes_fluent_client6.K8s)(import_kubernetes_fluent_client6.kind.Pod).InNamespace("pepr-system").WithLabel(labels[0], labels[1]).Get();
2885
- const podNames = pods.items.flatMap((pod) => pod.metadata.name);
2964
+ const podNames = pods.items.flatMap((pod) => pod.metadata.name || "");
2886
2965
  if (podNames.length < 1) {
2887
2966
  console.error(errorMessage);
2888
2967
  process.exit(1);
2889
2968
  }
2890
- const kc = new import_client_node4.KubeConfig();
2891
- kc.loadFromDefault();
2892
- const log = new import_client_node4.Log(kc);
2893
- const logStream = new import_stream.default.PassThrough();
2894
- logStream.on("data", async (chunk) => {
2895
- const respMsg = `"msg":"Check response"`;
2896
- const lines = await chunk.toString().split("\n");
2897
- for (const line of lines) {
2898
- if (!line.includes(respMsg)) continue;
2899
- try {
2900
- const payload = JSON.parse(line.trim());
2901
- const isMutate = payload.res.patchType || payload.res.warnings;
2902
- const name2 = `${payload.namespace}${payload.name}`;
2903
- const uid = payload.res.uid;
2904
- if (isMutate) {
2905
- const plainPatch = payload.res?.patch !== void 0 && payload.res?.patch !== null ? atob(payload.res.patch) : "";
2906
- const patch = plainPatch !== "" && JSON.stringify(JSON.parse(plainPatch), null, 2);
2907
- const patchType = payload.res.patchType || payload.res.warnings || "";
2908
- const allowOrDeny = payload.res.allowed ? "\u{1F500}" : "\u{1F6AB}";
2909
- console.log(`
2910
- ${allowOrDeny} MUTATE ${name2} (${uid})`);
2911
- patchType.length > 0 && console.log(`
2912
- \x1B[1;34m${patch}\x1B[0m`);
2913
- } else {
2914
- const failures = Array.isArray(payload.res) ? payload.res : [payload.res];
2915
- const filteredFailures = failures.filter((r) => !r.allowed).map((r) => r.status.message);
2916
- console.log(
2917
- `
2918
- ${filteredFailures.length > 0 ? "\u274C" : "\u2705"} VALIDATE ${name2} (${uid})`
2919
- );
2920
- console.log(
2921
- filteredFailures.length > 0 ? `\x1B[1;31m${filteredFailures}\x1B[0m` : ""
2922
- );
2923
- }
2924
- } catch {
2925
- }
2926
- }
2927
- });
2969
+ const log = getK8sLogFromKubeConfig();
2970
+ const logStream = createLogStream();
2928
2971
  for (const podName of podNames) {
2929
2972
  await log.log("pepr-system", podName, "server", logStream, {
2930
2973
  follow: true,
@@ -2934,14 +2977,78 @@ ${filteredFailures.length > 0 ? "\u274C" : "\u2705"} VALIDATE ${name2} (${uid
2934
2977
  }
2935
2978
  });
2936
2979
  }
2980
+ function getLabelsAndErrorMessage(uuid) {
2981
+ let labels;
2982
+ let errorMessage;
2983
+ if (!uuid) {
2984
+ labels = ["pepr.dev/controller", "admission"];
2985
+ errorMessage = `No pods found with admission labels`;
2986
+ } else {
2987
+ labels = ["app", `pepr-${uuid}`];
2988
+ errorMessage = `No pods found for module ${uuid}`;
2989
+ }
2990
+ return { labels, errorMessage };
2991
+ }
2992
+ function getK8sLogFromKubeConfig() {
2993
+ const kc = new import_client_node4.KubeConfig();
2994
+ kc.loadFromDefault();
2995
+ return new import_client_node4.Log(kc);
2996
+ }
2997
+ function createLogStream() {
2998
+ const logStream = new import_stream.default.PassThrough();
2999
+ logStream.on("data", async (chunk) => {
3000
+ const lines = chunk.toString().split("\n");
3001
+ const respMsg = `"msg":"Check response"`;
3002
+ for (const line of lines) {
3003
+ if (!line.includes(respMsg)) continue;
3004
+ processLogLine(line);
3005
+ }
3006
+ });
3007
+ return logStream;
3008
+ }
3009
+ function processLogLine(line) {
3010
+ try {
3011
+ const payload = JSON.parse(line.trim());
3012
+ const isMutate = payload.res.patchType || payload.res.warnings;
3013
+ const name2 = `${payload.namespace}${payload.name}`;
3014
+ const uid = payload.res.uid;
3015
+ if (isMutate) {
3016
+ processMutateLog(payload, name2, uid);
3017
+ } else {
3018
+ processValidateLog(payload, name2, uid);
3019
+ }
3020
+ } catch {
3021
+ }
3022
+ }
3023
+ function processMutateLog(payload, name2, uid) {
3024
+ const plainPatch = payload.res.patch !== void 0 && payload.res.patch !== null ? atob(payload.res.patch) : "";
3025
+ const patch = plainPatch !== "" && JSON.stringify(JSON.parse(plainPatch), null, 2);
3026
+ const patchType = payload.res.patchType || payload.res.warnings || "";
3027
+ const allowOrDeny = payload.res.allowed ? "\u{1F500}" : "\u{1F6AB}";
3028
+ console.log(`
3029
+ ${allowOrDeny} MUTATE ${name2} (${uid})`);
3030
+ if (patchType.length > 0) {
3031
+ console.log(`
3032
+ \x1B[1;34m${patch}\x1B[0m`);
3033
+ }
3034
+ }
3035
+ function processValidateLog(payload, name2, uid) {
3036
+ const failures = Array.isArray(payload.res) ? payload.res : [payload.res];
3037
+ const filteredFailures = failures.filter((r) => !r.allowed).map((r) => r.status?.message || "");
3038
+ console.log(`
3039
+ ${filteredFailures.length > 0 ? "\u274C" : "\u2705"} VALIDATE ${name2} (${uid})`);
3040
+ if (filteredFailures.length > 0) {
3041
+ console.log(`\x1B[1;31m${filteredFailures}\x1B[0m`);
3042
+ }
3043
+ }
2937
3044
 
2938
3045
  // src/cli/init/index.ts
2939
- var import_child_process4 = require("child_process");
2940
- var import_path3 = require("path");
3046
+ var import_child_process5 = require("child_process");
3047
+ var import_path4 = require("path");
2941
3048
  var import_prompts4 = __toESM(require("prompts"));
2942
3049
 
2943
3050
  // src/cli/init/walkthrough.ts
2944
- var import_fs10 = require("fs");
3051
+ var import_fs11 = require("fs");
2945
3052
  var import_prompts3 = __toESM(require("prompts"));
2946
3053
 
2947
3054
  // src/lib/errors.ts
@@ -2969,7 +3076,7 @@ async function setName(name2) {
2969
3076
  validate: async (val) => {
2970
3077
  try {
2971
3078
  const name3 = sanitizeName(val);
2972
- await import_fs10.promises.access(name3, import_fs10.promises.constants.F_OK);
3079
+ await import_fs11.promises.access(name3, import_fs11.promises.constants.F_OK);
2973
3080
  return "A directory with this name already exists";
2974
3081
  } catch (e) {
2975
3082
  return val.length > 2 || "The name must be at least 3 characters long";
@@ -3083,19 +3190,19 @@ function init_default(program2) {
3083
3190
  console.log("Creating new Pepr module...");
3084
3191
  try {
3085
3192
  await createDir(dirName);
3086
- await createDir((0, import_path3.resolve)(dirName, ".vscode"));
3087
- await createDir((0, import_path3.resolve)(dirName, "capabilities"));
3088
- await write((0, import_path3.resolve)(dirName, gitignore.path), gitignore.data);
3089
- await write((0, import_path3.resolve)(dirName, eslint.path), eslint.data);
3090
- await write((0, import_path3.resolve)(dirName, prettier.path), prettier.data);
3091
- await write((0, import_path3.resolve)(dirName, packageJSON2.path), packageJSON2.data);
3092
- await write((0, import_path3.resolve)(dirName, readme.path), readme.data);
3093
- await write((0, import_path3.resolve)(dirName, tsConfig.path), tsConfig.data);
3094
- await write((0, import_path3.resolve)(dirName, peprTS3.path), peprTS3.data);
3095
- await write((0, import_path3.resolve)(dirName, ".vscode", snippet.path), snippet.data);
3096
- await write((0, import_path3.resolve)(dirName, ".vscode", codeSettings.path), codeSettings.data);
3097
- await write((0, import_path3.resolve)(dirName, "capabilities", samplesYaml.path), samplesYaml.data);
3098
- await write((0, import_path3.resolve)(dirName, "capabilities", helloPepr.path), helloPepr.data);
3193
+ await createDir((0, import_path4.resolve)(dirName, ".vscode"));
3194
+ await createDir((0, import_path4.resolve)(dirName, "capabilities"));
3195
+ await write((0, import_path4.resolve)(dirName, gitignore.path), gitignore.data);
3196
+ await write((0, import_path4.resolve)(dirName, eslint.path), eslint.data);
3197
+ await write((0, import_path4.resolve)(dirName, prettier.path), prettier.data);
3198
+ await write((0, import_path4.resolve)(dirName, packageJSON2.path), packageJSON2.data);
3199
+ await write((0, import_path4.resolve)(dirName, readme.path), readme.data);
3200
+ await write((0, import_path4.resolve)(dirName, tsConfig.path), tsConfig.data);
3201
+ await write((0, import_path4.resolve)(dirName, peprTS3.path), peprTS3.data);
3202
+ await write((0, import_path4.resolve)(dirName, ".vscode", snippet.path), snippet.data);
3203
+ await write((0, import_path4.resolve)(dirName, ".vscode", codeSettings.path), codeSettings.data);
3204
+ await write((0, import_path4.resolve)(dirName, "capabilities", samplesYaml.path), samplesYaml.data);
3205
+ await write((0, import_path4.resolve)(dirName, "capabilities", helloPepr.path), helloPepr.data);
3099
3206
  if (!opts.skipPostInit) {
3100
3207
  doPostInitActions(dirName);
3101
3208
  }
@@ -3112,14 +3219,14 @@ function init_default(program2) {
3112
3219
  }
3113
3220
  var doPostInitActions = (dirName) => {
3114
3221
  process.chdir(dirName);
3115
- (0, import_child_process4.execSync)("npm install", {
3222
+ (0, import_child_process5.execSync)("npm install", {
3116
3223
  stdio: "inherit"
3117
3224
  });
3118
- (0, import_child_process4.execSync)("git init --initial-branch=main", {
3225
+ (0, import_child_process5.execSync)("git init --initial-branch=main", {
3119
3226
  stdio: "inherit"
3120
3227
  });
3121
3228
  try {
3122
- (0, import_child_process4.execSync)("code .", {
3229
+ (0, import_child_process5.execSync)("code .", {
3123
3230
  stdio: "inherit"
3124
3231
  });
3125
3232
  } catch (e) {
@@ -3163,9 +3270,9 @@ var RootCmd = class extends import_commander2.Command {
3163
3270
  };
3164
3271
 
3165
3272
  // src/cli/update.ts
3166
- var import_child_process5 = require("child_process");
3167
- var import_fs11 = __toESM(require("fs"));
3168
- var import_path4 = require("path");
3273
+ var import_child_process6 = require("child_process");
3274
+ var import_fs12 = __toESM(require("fs"));
3275
+ var import_path5 = require("path");
3169
3276
  var import_prompts5 = __toESM(require("prompts"));
3170
3277
  function update_default(program2) {
3171
3278
  program2.command("update").description("Update this Pepr module. Not recommended for prod as it may change files.").option("--skip-template-update", "Skip updating the template files").action(async (opts) => {
@@ -3181,11 +3288,11 @@ function update_default(program2) {
3181
3288
  }
3182
3289
  console.log("Updating the Pepr module...");
3183
3290
  try {
3184
- (0, import_child_process5.execSync)("npm install pepr@latest", {
3291
+ (0, import_child_process6.execSync)("npm install pepr@latest", {
3185
3292
  stdio: "inherit"
3186
3293
  });
3187
3294
  if (!opts.skipTemplateUpdate) {
3188
- (0, import_child_process5.execSync)("npx pepr update-templates", {
3295
+ (0, import_child_process6.execSync)("npx pepr update-templates", {
3189
3296
  stdio: "inherit"
3190
3297
  });
3191
3298
  }
@@ -3199,17 +3306,17 @@ function update_default(program2) {
3199
3306
  console.log("Updating Pepr config and template tiles...");
3200
3307
  try {
3201
3308
  if (!opts.skipTemplateUpdate) {
3202
- await write((0, import_path4.resolve)(prettier.path), prettier.data);
3203
- await write((0, import_path4.resolve)(tsConfig.path), tsConfig.data);
3204
- await write((0, import_path4.resolve)(".vscode", snippet.path), snippet.data);
3205
- await write((0, import_path4.resolve)(".vscode", codeSettings.path), codeSettings.data);
3206
- const samplePath = (0, import_path4.resolve)("capabilities", samplesYaml.path);
3207
- if (import_fs11.default.existsSync(samplePath)) {
3208
- import_fs11.default.unlinkSync(samplePath);
3309
+ await write((0, import_path5.resolve)(prettier.path), prettier.data);
3310
+ await write((0, import_path5.resolve)(tsConfig.path), tsConfig.data);
3311
+ await write((0, import_path5.resolve)(".vscode", snippet.path), snippet.data);
3312
+ await write((0, import_path5.resolve)(".vscode", codeSettings.path), codeSettings.data);
3313
+ const samplePath = (0, import_path5.resolve)("capabilities", samplesYaml.path);
3314
+ if (import_fs12.default.existsSync(samplePath)) {
3315
+ import_fs12.default.unlinkSync(samplePath);
3209
3316
  await write(samplePath, samplesYaml.data);
3210
3317
  }
3211
- const tsPath = (0, import_path4.resolve)("capabilities", helloPepr.path);
3212
- if (import_fs11.default.existsSync(tsPath)) {
3318
+ const tsPath = (0, import_path5.resolve)("capabilities", helloPepr.path);
3319
+ if (import_fs12.default.existsSync(tsPath)) {
3213
3320
  await write(tsPath, helloPepr.data);
3214
3321
  }
3215
3322
  }
@@ -3221,7 +3328,7 @@ function update_default(program2) {
3221
3328
  }
3222
3329
 
3223
3330
  // src/cli/kfc.ts
3224
- var import_child_process6 = require("child_process");
3331
+ var import_child_process7 = require("child_process");
3225
3332
  var import_prompts6 = __toESM(require("prompts"));
3226
3333
  function kfc_default(program2) {
3227
3334
  program2.command("kfc [args...]").description("Execute Kubernetes Fluent Client commands").action(async (args) => {
@@ -3238,7 +3345,7 @@ function kfc_default(program2) {
3238
3345
  args.push("--help");
3239
3346
  }
3240
3347
  const argsString = args.join(" ");
3241
- (0, import_child_process6.execSync)(`kubernetes-fluent-client ${argsString}`, {
3348
+ (0, import_child_process7.execSync)(`kubernetes-fluent-client ${argsString}`, {
3242
3349
  stdio: "inherit"
3243
3350
  });
3244
3351
  } catch (e) {