pepr 0.42.0 → 0.42.2

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 (149) hide show
  1. package/dist/cli/build.d.ts +1 -0
  2. package/dist/cli/build.d.ts.map +1 -1
  3. package/dist/cli/build.helpers.d.ts +66 -0
  4. package/dist/cli/build.helpers.d.ts.map +1 -1
  5. package/dist/cli/deploy.d.ts +15 -0
  6. package/dist/cli/deploy.d.ts.map +1 -1
  7. package/dist/cli/dev.d.ts.map +1 -1
  8. package/dist/cli/format.d.ts.map +1 -1
  9. package/dist/cli/format.helpers.d.ts +3 -0
  10. package/dist/cli/format.helpers.d.ts.map +1 -0
  11. package/dist/cli/init/enums.d.ts +10 -0
  12. package/dist/cli/init/enums.d.ts.map +1 -0
  13. package/dist/cli/init/index.d.ts.map +1 -1
  14. package/dist/cli/init/templates.d.ts +15 -11
  15. package/dist/cli/init/templates.d.ts.map +1 -1
  16. package/dist/cli/init/utils.d.ts.map +1 -1
  17. package/dist/cli/init/walkthrough.d.ts +3 -2
  18. package/dist/cli/init/walkthrough.d.ts.map +1 -1
  19. package/dist/cli/kfc.d.ts.map +1 -1
  20. package/dist/cli/monitor.d.ts +23 -0
  21. package/dist/cli/monitor.d.ts.map +1 -1
  22. package/dist/cli/root.d.ts.map +1 -1
  23. package/dist/cli/update.d.ts.map +1 -1
  24. package/dist/cli/uuid.d.ts.map +1 -1
  25. package/dist/cli.js +483 -586
  26. package/dist/controller.js +1 -195
  27. package/dist/fixtures/loader.d.ts.map +1 -1
  28. package/dist/lib/assets/deploy.d.ts.map +1 -1
  29. package/dist/lib/assets/destroy.d.ts.map +1 -1
  30. package/dist/lib/assets/helm.d.ts +1 -1
  31. package/dist/lib/assets/helm.d.ts.map +1 -1
  32. package/dist/lib/assets/index.d.ts +1 -1
  33. package/dist/lib/assets/index.d.ts.map +1 -1
  34. package/dist/lib/assets/pods.d.ts +6 -22
  35. package/dist/lib/assets/pods.d.ts.map +1 -1
  36. package/dist/lib/assets/rbac.d.ts.map +1 -1
  37. package/dist/lib/assets/webhooks.d.ts.map +1 -1
  38. package/dist/lib/assets/yaml.d.ts.map +1 -1
  39. package/dist/lib/controller/index.d.ts +2 -2
  40. package/dist/lib/controller/index.d.ts.map +1 -1
  41. package/dist/lib/controller/store.d.ts +1 -2
  42. package/dist/lib/controller/store.d.ts.map +1 -1
  43. package/dist/lib/controller/storeCache.d.ts +2 -1
  44. package/dist/lib/controller/storeCache.d.ts.map +1 -1
  45. package/dist/lib/{capability.d.ts → core/capability.d.ts} +1 -1
  46. package/dist/lib/core/capability.d.ts.map +1 -0
  47. package/dist/lib/{module.d.ts → core/module.d.ts} +2 -2
  48. package/dist/lib/core/module.d.ts.map +1 -0
  49. package/dist/lib/core/queue.d.ts.map +1 -0
  50. package/dist/lib/{schedule.d.ts → core/schedule.d.ts} +0 -1
  51. package/dist/lib/core/schedule.d.ts.map +1 -0
  52. package/dist/lib/{storage.d.ts → core/storage.d.ts} +4 -4
  53. package/dist/lib/core/storage.d.ts.map +1 -0
  54. package/dist/lib/deploymentChecks.d.ts.map +1 -1
  55. package/dist/lib/errors.d.ts +0 -5
  56. package/dist/lib/errors.d.ts.map +1 -1
  57. package/dist/lib/filesystemService.d.ts.map +1 -1
  58. package/dist/lib/filter/adjudicators/adjudicators.d.ts +5 -4
  59. package/dist/lib/filter/adjudicators/adjudicators.d.ts.map +1 -1
  60. package/dist/lib/filter/filter.d.ts +33 -1
  61. package/dist/lib/filter/filter.d.ts.map +1 -1
  62. package/dist/lib/finalizer.d.ts.map +1 -1
  63. package/dist/lib/helpers.d.ts +4 -9
  64. package/dist/lib/helpers.d.ts.map +1 -1
  65. package/dist/lib/included-files.d.ts.map +1 -1
  66. package/dist/lib/mutate-request.d.ts +2 -2
  67. package/dist/lib/mutate-request.d.ts.map +1 -1
  68. package/dist/lib/processors/mutate-processor.d.ts +28 -0
  69. package/dist/lib/processors/mutate-processor.d.ts.map +1 -0
  70. package/dist/lib/processors/validate-processor.d.ts +9 -0
  71. package/dist/lib/processors/validate-processor.d.ts.map +1 -0
  72. package/dist/lib/{watch-processor.d.ts → processors/watch-processor.d.ts} +2 -2
  73. package/dist/lib/processors/watch-processor.d.ts.map +1 -0
  74. package/dist/lib/telemetry/logger.d.ts.map +1 -1
  75. package/dist/lib/telemetry/metrics.d.ts.map +1 -1
  76. package/dist/lib/utils.d.ts.map +1 -1
  77. package/dist/lib/validate-request.d.ts +2 -2
  78. package/dist/lib/validate-request.d.ts.map +1 -1
  79. package/dist/lib.d.ts +2 -2
  80. package/dist/lib.d.ts.map +1 -1
  81. package/dist/lib.js +508 -341
  82. package/dist/lib.js.map +4 -4
  83. package/dist/sdk/heredoc.d.ts.map +1 -1
  84. package/package.json +9 -9
  85. package/src/cli/build.helpers.ts +180 -0
  86. package/src/cli/build.ts +85 -133
  87. package/src/cli/deploy.ts +113 -74
  88. package/src/cli/dev.ts +2 -2
  89. package/src/cli/format.helpers.ts +27 -0
  90. package/src/cli/format.ts +4 -18
  91. package/src/cli/init/enums.ts +9 -0
  92. package/src/cli/init/index.ts +4 -3
  93. package/src/cli/init/templates.ts +30 -2
  94. package/src/cli/init/utils.ts +3 -3
  95. package/src/cli/init/walkthrough.ts +7 -8
  96. package/src/cli/kfc.ts +1 -1
  97. package/src/cli/monitor.ts +108 -65
  98. package/src/cli/root.ts +1 -1
  99. package/src/cli/update.ts +1 -1
  100. package/src/cli/uuid.ts +1 -1
  101. package/src/fixtures/loader.ts +2 -2
  102. package/src/lib/assets/deploy.ts +11 -11
  103. package/src/lib/assets/destroy.ts +1 -1
  104. package/src/lib/assets/helm.ts +6 -6
  105. package/src/lib/assets/index.ts +23 -23
  106. package/src/lib/assets/pods.ts +11 -6
  107. package/src/lib/assets/webhooks.ts +31 -46
  108. package/src/lib/assets/yaml.ts +12 -9
  109. package/src/lib/controller/index.ts +13 -11
  110. package/src/lib/controller/store.ts +25 -12
  111. package/src/lib/controller/storeCache.ts +16 -3
  112. package/src/lib/{capability.ts → core/capability.ts} +25 -14
  113. package/src/lib/{module.ts → core/module.ts} +10 -10
  114. package/src/lib/{queue.ts → core/queue.ts} +13 -5
  115. package/src/lib/{storage.ts → core/storage.ts} +33 -24
  116. package/src/lib/deploymentChecks.ts +2 -2
  117. package/src/lib/errors.ts +3 -8
  118. package/src/lib/filesystemService.ts +1 -1
  119. package/src/lib/filter/adjudicators/adjudicators.ts +40 -9
  120. package/src/lib/filter/filter.ts +204 -111
  121. package/src/lib/finalizer.ts +2 -2
  122. package/src/lib/helpers.ts +20 -133
  123. package/src/lib/included-files.ts +1 -1
  124. package/src/lib/mutate-request.ts +11 -11
  125. package/src/lib/processors/mutate-processor.ts +225 -0
  126. package/src/lib/processors/validate-processor.ts +93 -0
  127. package/src/lib/{watch-processor.ts → processors/watch-processor.ts} +19 -15
  128. package/src/lib/telemetry/logger.ts +3 -1
  129. package/src/lib/tls.ts +5 -1
  130. package/src/lib/utils.ts +5 -5
  131. package/src/lib/validate-request.ts +4 -4
  132. package/src/lib.ts +2 -2
  133. package/src/runtime/controller.ts +2 -2
  134. package/src/sdk/cosign.ts +4 -4
  135. package/src/sdk/heredoc.ts +1 -1
  136. package/dist/lib/capability.d.ts.map +0 -1
  137. package/dist/lib/module.d.ts.map +0 -1
  138. package/dist/lib/mutate-processor.d.ts +0 -6
  139. package/dist/lib/mutate-processor.d.ts.map +0 -1
  140. package/dist/lib/queue.d.ts.map +0 -1
  141. package/dist/lib/schedule.d.ts.map +0 -1
  142. package/dist/lib/storage.d.ts.map +0 -1
  143. package/dist/lib/validate-processor.d.ts +0 -6
  144. package/dist/lib/validate-processor.d.ts.map +0 -1
  145. package/dist/lib/watch-processor.d.ts.map +0 -1
  146. package/src/lib/mutate-processor.ts +0 -165
  147. package/src/lib/validate-processor.ts +0 -85
  148. /package/dist/lib/{queue.d.ts → core/queue.d.ts} +0 -0
  149. /package/src/lib/{schedule.ts → core/schedule.ts} +0 -0
@@ -5,14 +5,15 @@ import { Operation } from "fast-json-patch";
5
5
  import { K8s } from "kubernetes-fluent-client";
6
6
  import { startsWith } from "ramda";
7
7
 
8
- import { Capability } from "../capability";
8
+ import { Capability } from "../core/capability";
9
9
  import { Store } from "../k8s";
10
10
  import Log, { redactedPatch, redactedStore } from "../telemetry/logger";
11
- import { DataOp, DataSender, DataStore, Storage } from "../storage";
11
+ import { DataOp, DataSender, DataStore, Storage } from "../core/storage";
12
12
  import { fillStoreCache, sendUpdatesAndFlushCache } from "./storeCache";
13
13
 
14
14
  const namespace = "pepr-system";
15
- export const debounceBackoff = 1000;
15
+ const debounceBackoffReceive = 1000;
16
+ const debounceBackoffSend = 4000;
16
17
 
17
18
  export class StoreController {
18
19
  #name: string;
@@ -25,7 +26,7 @@ export class StoreController {
25
26
 
26
27
  this.#name = name;
27
28
 
28
- const setStorageInstance = (registrationFunction: () => Storage, name: string) => {
29
+ const setStorageInstance = (registrationFunction: () => Storage, name: string): void => {
29
30
  const scheduleStore = registrationFunction();
30
31
 
31
32
  // Bind the store sender to the capability
@@ -61,13 +62,22 @@ export class StoreController {
61
62
  );
62
63
  }
63
64
 
64
- #setupWatch = () => {
65
+ #setupWatch = (): void => {
65
66
  const watcher = K8s(Store, { name: this.#name, namespace }).Watch(this.#receive);
66
67
  watcher.start().catch(e => Log.error(e, "Error starting Pepr store watch"));
67
68
  };
68
69
 
69
- #migrateAndSetupWatch = async (store: Store) => {
70
+ #migrateAndSetupWatch = async (store: Store): Promise<void> => {
70
71
  Log.debug(redactedStore(store), "Pepr Store migration");
72
+ // Add cacheID label to store
73
+ await K8s(Store, { namespace, name: this.#name }).Patch([
74
+ {
75
+ op: "add",
76
+ path: "/metadata/labels/pepr.dev-cacheID",
77
+ value: `${Date.now()}`,
78
+ },
79
+ ]);
80
+
71
81
  const data: DataStore = store.data || {};
72
82
  let storeCache: Record<string, Operation> = {};
73
83
 
@@ -96,11 +106,11 @@ export class StoreController {
96
106
  this.#setupWatch();
97
107
  };
98
108
 
99
- #receive = (store: Store) => {
109
+ #receive = (store: Store): void => {
100
110
  Log.debug(redactedStore(store), "Pepr Store update");
101
111
 
102
112
  // Wrap the update in a debounced function
103
- const debounced = () => {
113
+ const debounced = (): void => {
104
114
  // Base64 decode the data
105
115
  const data: DataStore = store.data || {};
106
116
 
@@ -134,10 +144,10 @@ export class StoreController {
134
144
 
135
145
  // Debounce the update to 1 second to avoid multiple rapid calls
136
146
  clearTimeout(this.#sendDebounce);
137
- this.#sendDebounce = setTimeout(debounced, this.#onReady ? 0 : debounceBackoff);
147
+ this.#sendDebounce = setTimeout(debounced, this.#onReady ? 0 : debounceBackoffReceive);
138
148
  };
139
149
 
140
- #send = (capabilityName: string) => {
150
+ #send = (capabilityName: string): DataSender => {
141
151
  let storeCache: Record<string, Operation> = {};
142
152
 
143
153
  // Create a sender function for the capability to add/remove data from the store
@@ -151,12 +161,12 @@ export class StoreController {
151
161
  Log.debug(redactedPatch(storeCache), "Sending updates to Pepr store");
152
162
  void sendUpdatesAndFlushCache(storeCache, namespace, this.#name);
153
163
  }
154
- }, debounceBackoff);
164
+ }, debounceBackoffSend);
155
165
 
156
166
  return sender;
157
167
  };
158
168
 
159
- #createStoreResource = async (e: unknown) => {
169
+ #createStoreResource = async (e: unknown): Promise<void> => {
160
170
  Log.info(`Pepr store not found, creating...`);
161
171
  Log.debug(e);
162
172
 
@@ -165,6 +175,9 @@ export class StoreController {
165
175
  metadata: {
166
176
  name: this.#name,
167
177
  namespace,
178
+ labels: {
179
+ "pepr.dev-cacheID": `${Date.now()}`,
180
+ },
168
181
  },
169
182
  data: {
170
183
  // JSON Patch will die if the data is empty, so we need to add a placeholder
@@ -1,17 +1,21 @@
1
- import { DataOp } from "../storage";
1
+ import { DataOp } from "../core/storage";
2
2
  import Log from "../telemetry/logger";
3
3
  import { K8s } from "kubernetes-fluent-client";
4
4
  import { Store } from "../k8s";
5
5
  import { StatusCodes } from "http-status-codes";
6
6
  import { Operation } from "fast-json-patch";
7
7
 
8
- export const sendUpdatesAndFlushCache = async (cache: Record<string, Operation>, namespace: string, name: string) => {
8
+ export const sendUpdatesAndFlushCache = async (
9
+ cache: Record<string, Operation>,
10
+ namespace: string,
11
+ name: string,
12
+ ): Promise<Record<string, Operation>> => {
9
13
  const indexes = Object.keys(cache);
10
14
  const payload = Object.values(cache);
11
15
 
12
16
  try {
13
17
  if (payload.length > 0) {
14
- await K8s(Store, { namespace, name }).Patch(payload); // Send patch to cluster
18
+ await K8s(Store, { namespace, name }).Patch(updateCacheID(payload)); // Send patch to cluster
15
19
  Object.keys(cache).forEach(key => delete cache[key]);
16
20
  }
17
21
  } catch (err) {
@@ -61,3 +65,12 @@ export const fillStoreCache = (
61
65
  }
62
66
  return cache;
63
67
  };
68
+
69
+ export function updateCacheID(payload: Operation[]): Operation[] {
70
+ payload.push({
71
+ op: "replace",
72
+ path: "/metadata/labels/pepr.dev-cacheID",
73
+ value: `${Date.now()}`,
74
+ });
75
+ return payload;
76
+ }
@@ -3,11 +3,11 @@
3
3
 
4
4
  import { GenericClass, GroupVersionKind, modelToGroupVersionKind } from "kubernetes-fluent-client";
5
5
  import { pickBy } from "ramda";
6
- import Log from "./telemetry/logger";
6
+ import Log from "../telemetry/logger";
7
7
  import { isBuildMode, isDevMode, isWatchMode } from "./module";
8
8
  import { PeprStore, Storage } from "./storage";
9
9
  import { OnSchedule, Schedule } from "./schedule";
10
- import { Event } from "./enums";
10
+ import { Event } from "../enums";
11
11
  import {
12
12
  Binding,
13
13
  BindingFilter,
@@ -22,8 +22,8 @@ import {
22
22
  FinalizeAction,
23
23
  FinalizeActionChain,
24
24
  WhenSelector,
25
- } from "./types";
26
- import { addFinalizer } from "./finalizer";
25
+ } from "../types";
26
+ import { addFinalizer } from "../finalizer";
27
27
 
28
28
  const registerAdmission = isBuildMode() || !isWatchMode();
29
29
  const registerWatch = isBuildMode() || isWatchMode() || isDevMode();
@@ -71,7 +71,7 @@ export class Capability implements CapabilityExport {
71
71
  }
72
72
  };
73
73
 
74
- public getScheduleStore() {
74
+ public getScheduleStore(): Storage {
75
75
  return this.#scheduleStore;
76
76
  }
77
77
 
@@ -111,19 +111,19 @@ export class Capability implements CapabilityExport {
111
111
  onReady: this.#scheduleStore.onReady,
112
112
  };
113
113
 
114
- get bindings() {
114
+ get bindings(): Binding[] {
115
115
  return this.#bindings;
116
116
  }
117
117
 
118
- get name() {
118
+ get name(): string {
119
119
  return this.#name;
120
120
  }
121
121
 
122
- get description() {
122
+ get description(): string {
123
123
  return this.#description;
124
124
  }
125
125
 
126
- get namespaces() {
126
+ get namespaces(): string[] {
127
127
  return this.#namespaces || [];
128
128
  }
129
129
 
@@ -207,8 +207,19 @@ export class Capability implements CapabilityExport {
207
207
  const bindings = this.#bindings;
208
208
  const prefix = `${this.#name}: ${model.name}`;
209
209
  const commonChain = { WithLabel, WithAnnotation, WithDeletionTimestamp, Mutate, Validate, Watch, Reconcile, Alias };
210
- const isNotEmpty = (value: object) => Object.keys(value).length > 0;
211
- const log = (message: string, cbString: string) => {
210
+
211
+ type CommonChainType = typeof commonChain;
212
+ type ExtendedCommonChainType = CommonChainType & {
213
+ Alias: (alias: string) => CommonChainType;
214
+ InNamespace: (...namespaces: string[]) => BindingWithName<T>;
215
+ InNamespaceRegex: (...namespaces: RegExp[]) => BindingWithName<T>;
216
+ WithName: (name: string) => BindingFilter<T>;
217
+ WithNameRegex: (regexName: RegExp) => BindingFilter<T>;
218
+ WithDeletionTimestamp: () => BindingFilter<T>;
219
+ };
220
+
221
+ const isNotEmpty = (value: object): boolean => Object.keys(value).length > 0;
222
+ const log = (message: string, cbString: string): void => {
212
223
  const filteredObj = pickBy(isNotEmpty, binding.filters);
213
224
 
214
225
  Log.info(`${message} configured for ${binding.event}`, prefix);
@@ -329,7 +340,7 @@ export class Capability implements CapabilityExport {
329
340
  isWatch: true,
330
341
  isFinalize: true,
331
342
  event: Event.UPDATE,
332
- finalizeCallback: async (update: InstanceType<T>, logger = aliasLogger) => {
343
+ finalizeCallback: async (update: InstanceType<T>, logger = aliasLogger): Promise<boolean | void> => {
333
344
  Log.info(`Executing finalize action with alias: ${binding.alias || "no alias provided"}`);
334
345
  return await finalizeCallback(update, logger);
335
346
  },
@@ -380,13 +391,13 @@ export class Capability implements CapabilityExport {
380
391
  return commonChain;
381
392
  }
382
393
 
383
- function Alias(alias: string) {
394
+ function Alias(alias: string): CommonChainType {
384
395
  Log.debug(`Adding prefix alias ${alias}`, prefix);
385
396
  binding.alias = alias;
386
397
  return commonChain;
387
398
  }
388
399
 
389
- function bindEvent(event: Event) {
400
+ function bindEvent(event: Event): ExtendedCommonChainType {
390
401
  binding.event = event;
391
402
  return {
392
403
  ...commonChain,
@@ -2,12 +2,12 @@
2
2
  // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
3
  import { clone } from "ramda";
4
4
  import { Capability } from "./capability";
5
- import { Controller } from "./controller";
6
- import { ValidateError } from "./errors";
7
- import { MutateResponse, ValidateResponse, WebhookIgnore } from "./k8s";
8
- import { CapabilityExport, AdmissionRequest } from "./types";
9
- import { setupWatch } from "./watch-processor";
10
- import { Log } from "../lib";
5
+ import { Controller } from "../controller";
6
+ import { ValidateError } from "../errors";
7
+ import { MutateResponse, ValidateResponse, WebhookIgnore } from "../k8s";
8
+ import { CapabilityExport, AdmissionRequest } from "../types";
9
+ import { setupWatch } from "../processors/watch-processor";
10
+ import { Log } from "../../lib";
11
11
  import { V1PolicyRule as PolicyRule } from "@kubernetes/client-node";
12
12
 
13
13
  /** Custom Labels Type for package.json */
@@ -58,12 +58,12 @@ export type PeprModuleOptions = {
58
58
  };
59
59
 
60
60
  // Track if this is a watch mode controller
61
- export const isWatchMode = () => process.env.PEPR_WATCH_MODE === "true";
61
+ export const isWatchMode = (): boolean => process.env.PEPR_WATCH_MODE === "true";
62
62
 
63
63
  // Track if Pepr is running in build mode
64
- export const isBuildMode = () => process.env.PEPR_MODE === "build";
64
+ export const isBuildMode = (): boolean => process.env.PEPR_MODE === "build";
65
65
 
66
- export const isDevMode = () => process.env.PEPR_MODE === "dev";
66
+ export const isDevMode = (): boolean => process.env.PEPR_MODE === "dev";
67
67
 
68
68
  export class PeprModule {
69
69
  #controller!: Controller;
@@ -135,7 +135,7 @@ export class PeprModule {
135
135
  *
136
136
  * @param port
137
137
  */
138
- start = (port = 3000) => {
138
+ start = (port = 3000): void => {
139
139
  this.#controller.startServer(port);
140
140
  };
141
141
  }
@@ -3,7 +3,7 @@
3
3
  import { KubernetesObject } from "@kubernetes/client-node";
4
4
  import { WatchPhase } from "kubernetes-fluent-client/dist/fluent/types";
5
5
  import { randomBytes } from "node:crypto";
6
- import Log from "./telemetry/logger";
6
+ import Log from "../telemetry/logger";
7
7
 
8
8
  type WatchCallback = (obj: KubernetesObject, phase: WatchPhase) => Promise<void>;
9
9
 
@@ -29,11 +29,19 @@ export class Queue<K extends KubernetesObject> {
29
29
  this.#uid = `${Date.now()}-${randomBytes(2).toString("hex")}`;
30
30
  }
31
31
 
32
- label() {
32
+ label(): { name: string; uid: string } {
33
33
  return { name: this.#name, uid: this.#uid };
34
34
  }
35
35
 
36
- stats() {
36
+ stats(): {
37
+ queue: {
38
+ name: string;
39
+ uid: string;
40
+ };
41
+ stats: {
42
+ length: number;
43
+ };
44
+ } {
37
45
  return {
38
46
  queue: this.label(),
39
47
  stats: {
@@ -51,7 +59,7 @@ export class Queue<K extends KubernetesObject> {
51
59
  * @param reconcile The callback to enqueue for reconcile
52
60
  * @returns A promise that resolves when the object is reconciled
53
61
  */
54
- enqueue(item: K, phase: WatchPhase, reconcile: WatchCallback) {
62
+ enqueue(item: K, phase: WatchPhase, reconcile: WatchCallback): Promise<void> {
55
63
  const note = {
56
64
  queue: this.label(),
57
65
  item: {
@@ -73,7 +81,7 @@ export class Queue<K extends KubernetesObject> {
73
81
  *
74
82
  * @returns A promise that resolves when the webapp is reconciled
75
83
  */
76
- async #dequeue() {
84
+ async #dequeue(): Promise<false | undefined> {
77
85
  // If there is a pending promise, do nothing
78
86
  if (this.#pendingPromise) {
79
87
  Log.debug("Pending promise, not dequeuing");
@@ -12,6 +12,11 @@ export type Unsubscribe = () => void;
12
12
  const MAX_WAIT_TIME = 15000;
13
13
  const STORE_VERSION_PREFIX = "v2";
14
14
 
15
+ interface WaitRecord {
16
+ timeout?: ReturnType<typeof setTimeout>;
17
+ unsubscribe?: () => void;
18
+ }
19
+
15
20
  export function v2StoreKey(key: string): string {
16
21
  return `${STORE_VERSION_PREFIX}-${pointer.escape(key)}`;
17
22
  }
@@ -58,13 +63,13 @@ export interface PeprStore {
58
63
  * Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
59
64
  * Resolves when the key/value show up in the store.
60
65
  */
61
- setItemAndWait(key: string, value: string): Promise<void>;
66
+ setItemAndWait(key: string, value: string): Promise<string>;
62
67
 
63
68
  /**
64
69
  * Remove the value of the key.
65
70
  * Resolves when the key does not show up in the store.
66
71
  */
67
- removeItemAndWait(key: string): Promise<void>;
72
+ removeItemAndWait(key: string): Promise<string>;
68
73
  }
69
74
 
70
75
  /**
@@ -128,22 +133,24 @@ export class Storage implements PeprStore {
128
133
  * @param value - The value of the key
129
134
  * @returns
130
135
  */
131
- setItemAndWait = (key: string, value: string): Promise<void> => {
136
+ setItemAndWait = (key: string, value: string): Promise<string> => {
132
137
  this.#dispatchUpdate("add", [v2StoreKey(key)], value);
138
+ const record: WaitRecord = {};
133
139
 
134
- return new Promise<void>((resolve, reject) => {
135
- const unsubscribe = this.subscribe(data => {
140
+ return new Promise<string>((resolve, reject) => {
141
+ // If promise has not resolved before MAX_WAIT_TIME reject
142
+ record.timeout = setTimeout(() => {
143
+ record.unsubscribe!();
144
+ return reject(`MAX_WAIT_TIME elapsed: Key ${key} not seen in ${MAX_WAIT_TIME / 1000}s`);
145
+ }, MAX_WAIT_TIME);
146
+
147
+ record.unsubscribe = this.subscribe(data => {
136
148
  if (data[`${v2UnescapedStoreKey(key)}`] === value) {
137
- unsubscribe();
138
- resolve();
149
+ record.unsubscribe!();
150
+ clearTimeout(record.timeout);
151
+ resolve("ok");
139
152
  }
140
153
  });
141
-
142
- // If promise has not resolved before MAX_WAIT_TIME reject
143
- setTimeout(() => {
144
- unsubscribe();
145
- return reject();
146
- }, MAX_WAIT_TIME);
147
154
  });
148
155
  };
149
156
 
@@ -154,21 +161,23 @@ export class Storage implements PeprStore {
154
161
  * @param key - The key to add into the store
155
162
  * @returns
156
163
  */
157
- removeItemAndWait = (key: string): Promise<void> => {
164
+ removeItemAndWait = (key: string): Promise<string> => {
158
165
  this.#dispatchUpdate("remove", [v2StoreKey(key)]);
159
- return new Promise<void>((resolve, reject) => {
160
- const unsubscribe = this.subscribe(data => {
166
+ const record: WaitRecord = {};
167
+ return new Promise<string>((resolve, reject) => {
168
+ // If promise has not resolved before MAX_WAIT_TIME reject
169
+ record.timeout = setTimeout(() => {
170
+ record.unsubscribe!();
171
+ return reject(`MAX_WAIT_TIME elapsed: Key ${key} still seen after ${MAX_WAIT_TIME / 1000}s`);
172
+ }, MAX_WAIT_TIME);
173
+
174
+ record.unsubscribe = this.subscribe(data => {
161
175
  if (!Object.hasOwn(data, `${v2UnescapedStoreKey(key)}`)) {
162
- unsubscribe();
163
- resolve();
176
+ record.unsubscribe!();
177
+ clearTimeout(record.timeout);
178
+ resolve("ok");
164
179
  }
165
180
  });
166
-
167
- // If promise has not resolved before MAX_WAIT_TIME reject
168
- setTimeout(() => {
169
- unsubscribe();
170
- return reject();
171
- }, MAX_WAIT_TIME);
172
181
  });
173
182
  };
174
183
 
@@ -4,7 +4,7 @@ import { K8s, kind } from "kubernetes-fluent-client";
4
4
  import Log from "./telemetry/logger";
5
5
 
6
6
  // returns true if all deployments are ready, false otherwise
7
- export async function checkDeploymentStatus(namespace: string) {
7
+ export async function checkDeploymentStatus(namespace: string): Promise<boolean> {
8
8
  const deployments = await K8s(kind.Deployment).InNamespace(namespace).Get();
9
9
  let status = false;
10
10
  let readyCount = 0;
@@ -29,7 +29,7 @@ export async function checkDeploymentStatus(namespace: string) {
29
29
  }
30
30
 
31
31
  // wait for all deployments in the pepr-system namespace to be ready
32
- export async function namespaceDeploymentsReady(namespace: string = "pepr-system") {
32
+ export async function namespaceDeploymentsReady(namespace: string = "pepr-system"): Promise<true | undefined> {
33
33
  Log.info(`Checking ${namespace} deployments status...`);
34
34
  let ready = false;
35
35
  while (!ready) {
package/src/lib/errors.ts CHANGED
@@ -1,19 +1,14 @@
1
1
  // SPDX-License-Identifier: Apache-2.0
2
2
  // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
3
 
4
- export const Errors = {
5
- audit: "audit",
6
- ignore: "ignore",
7
- reject: "reject",
8
- };
9
-
10
- export const ErrorList = Object.values(Errors);
4
+ import { OnError } from "../cli/init/enums";
11
5
 
6
+ export const ErrorList = Object.values(OnError) as string[];
12
7
  /**
13
8
  * Validate the error or throw an error
14
9
  * @param error
15
10
  */
16
- export function ValidateError(error = "") {
11
+ export function ValidateError(error: string = ""): void {
17
12
  if (!ErrorList.includes(error)) {
18
13
  throw new Error(`Invalid error: ${error}. Must be one of: ${ErrorList.join(", ")}`);
19
14
  }
@@ -3,7 +3,7 @@
3
3
 
4
4
  import { promises } from "fs";
5
5
 
6
- export async function createDirectoryIfNotExists(path: string) {
6
+ export async function createDirectoryIfNotExists(path: string): Promise<void> {
7
7
  try {
8
8
  await promises.access(path);
9
9
  } catch (error) {
@@ -2,7 +2,7 @@
2
2
  // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
3
 
4
4
  import { Event, Operation } from "../../enums";
5
- import { AdmissionRequest, Binding } from "../../types";
5
+ import { AdmissionRequest, Binding, FinalizeAction, WatchLogAction, MutateAction, ValidateAction } from "../../types";
6
6
  import {
7
7
  __,
8
8
  allPass,
@@ -19,7 +19,7 @@ import {
19
19
  nthArg,
20
20
  pipe,
21
21
  } from "ramda";
22
- import { KubernetesObject } from "kubernetes-fluent-client";
22
+ import { GenericClass, KubernetesObject } from "kubernetes-fluent-client";
23
23
 
24
24
  /*
25
25
  Naming scheme:
@@ -77,6 +77,7 @@ export const carriedNamespace = pipe(
77
77
  (kubernetesObject: KubernetesObject): string | undefined => kubernetesObject?.metadata?.namespace,
78
78
  defaultTo(""),
79
79
  );
80
+
80
81
  export const carriesNamespace = pipe(carriedNamespace, equals(""), not);
81
82
 
82
83
  export const carriedAnnotations = pipe(
@@ -144,7 +145,7 @@ export const definesVersion = pipe(definedVersion, equals(""), not);
144
145
  export const definedKind = pipe((binding): string => binding?.kind?.kind, defaultTo(""));
145
146
  export const definesKind = pipe(definedKind, equals(""), not);
146
147
 
147
- export const definedCategory = (binding: Partial<Binding>) => {
148
+ export const definedCategory = (binding: Partial<Binding>): string => {
148
149
  // Ordering matters, finalize is a "watch"
149
150
  // prettier-ignore
150
151
  return binding.isFinalize ? "Finalize" :
@@ -153,8 +154,15 @@ export const definedCategory = (binding: Partial<Binding>) => {
153
154
  binding.isValidate ? "Validate" :
154
155
  "";
155
156
  };
156
-
157
- export const definedCallback = (binding: Partial<Binding>) => {
157
+ export type DefinedCallbackReturnType =
158
+ | FinalizeAction<GenericClass, InstanceType<GenericClass>>
159
+ | WatchLogAction<GenericClass, InstanceType<GenericClass>>
160
+ | MutateAction<GenericClass, InstanceType<GenericClass>>
161
+ | ValidateAction<GenericClass, InstanceType<GenericClass>>
162
+ | null
163
+ | undefined;
164
+
165
+ export const definedCallback = (binding: Partial<Binding>): DefinedCallbackReturnType => {
158
166
  // Ordering matters, finalize is a "watch"
159
167
  // prettier-ignore
160
168
  return binding.isFinalize ? binding.finalizeCallback :
@@ -241,10 +249,21 @@ export const mismatchedLabels = allPass([
241
249
  pipe((binding, kubernetesObject) => metasMismatch(definedLabels(binding), carriedLabels(kubernetesObject))),
242
250
  ]);
243
251
 
252
+ /*
253
+ * If the object does not have a namespace, and it is not a namespace,
254
+ * then we must return false because it cannot be uncarryable
255
+ */
244
256
  export const uncarryableNamespace = allPass([
245
257
  pipe(nthArg(0), length, gt(__, 0)),
246
- pipe(nthArg(1), carriesNamespace),
247
- pipe((namespaceSelector, kubernetesObject) => namespaceSelector.includes(carriedNamespace(kubernetesObject)), not),
258
+ pipe((namespaceSelector, kubernetesObject) => {
259
+ if (kubernetesObject?.kind === "Namespace") {
260
+ return namespaceSelector.includes(kubernetesObject?.metadata?.name);
261
+ }
262
+ if (carriesNamespace(kubernetesObject)) {
263
+ return namespaceSelector.includes(carriedNamespace(kubernetesObject));
264
+ }
265
+ return true;
266
+ }, not),
248
267
  ]);
249
268
 
250
269
  export const missingCarriableNamespace = allPass([
@@ -256,10 +275,22 @@ export const missingCarriableNamespace = allPass([
256
275
  ),
257
276
  ]);
258
277
 
278
+ /*
279
+ * If the object does not have a namespace, and it is not a namespace,
280
+ * then we must return false because it cannot be ignored
281
+ */
259
282
  export const carriesIgnoredNamespace = allPass([
260
283
  pipe(nthArg(0), length, gt(__, 0)),
261
- pipe(nthArg(1), carriesNamespace),
262
- pipe((namespaceSelector, kubernetesObject) => namespaceSelector.includes(carriedNamespace(kubernetesObject))),
284
+ pipe((namespaceSelector, kubernetesObject) => {
285
+ if (kubernetesObject?.kind === "Namespace") {
286
+ return namespaceSelector.includes(kubernetesObject?.metadata?.name);
287
+ }
288
+ if (carriesNamespace(kubernetesObject)) {
289
+ return namespaceSelector.includes(carriedNamespace(kubernetesObject));
290
+ }
291
+
292
+ return false;
293
+ }),
263
294
  ]);
264
295
 
265
296
  export const unbindableNamespaces = allPass([