pepr 0.42.1 → 0.42.3

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 (138) hide show
  1. package/dist/cli/build.helpers.d.ts +1 -1
  2. package/dist/cli/build.helpers.d.ts.map +1 -1
  3. package/dist/cli/deploy.d.ts +15 -0
  4. package/dist/cli/deploy.d.ts.map +1 -1
  5. package/dist/cli/dev.d.ts.map +1 -1
  6. package/dist/cli/format.d.ts.map +1 -1
  7. package/dist/cli/format.helpers.d.ts +3 -0
  8. package/dist/cli/format.helpers.d.ts.map +1 -0
  9. package/dist/cli/init/enums.d.ts +10 -0
  10. package/dist/cli/init/enums.d.ts.map +1 -0
  11. package/dist/cli/init/index.d.ts.map +1 -1
  12. package/dist/cli/init/templates.d.ts +15 -11
  13. package/dist/cli/init/templates.d.ts.map +1 -1
  14. package/dist/cli/init/utils.d.ts.map +1 -1
  15. package/dist/cli/init/walkthrough.d.ts +3 -2
  16. package/dist/cli/init/walkthrough.d.ts.map +1 -1
  17. package/dist/cli/kfc.d.ts.map +1 -1
  18. package/dist/cli/root.d.ts.map +1 -1
  19. package/dist/cli/update.d.ts.map +1 -1
  20. package/dist/cli/uuid.d.ts.map +1 -1
  21. package/dist/cli.js +1073 -1220
  22. package/dist/controller.js +1 -195
  23. package/dist/fixtures/loader.d.ts.map +1 -1
  24. package/dist/lib/assets/assets.d.ts +27 -0
  25. package/dist/lib/assets/assets.d.ts.map +1 -0
  26. package/dist/lib/assets/deploy.d.ts +1 -1
  27. package/dist/lib/assets/deploy.d.ts.map +1 -1
  28. package/dist/lib/assets/index.d.ts +5 -24
  29. package/dist/lib/assets/index.d.ts.map +1 -1
  30. package/dist/lib/assets/pods.d.ts +2 -4
  31. package/dist/lib/assets/pods.d.ts.map +1 -1
  32. package/dist/lib/assets/rbac.d.ts.map +1 -1
  33. package/dist/lib/assets/webhooks.d.ts +1 -1
  34. package/dist/lib/assets/webhooks.d.ts.map +1 -1
  35. package/dist/lib/assets/yaml.d.ts +31 -5
  36. package/dist/lib/assets/yaml.d.ts.map +1 -1
  37. package/dist/lib/controller/index.d.ts +2 -2
  38. package/dist/lib/controller/index.d.ts.map +1 -1
  39. package/dist/lib/controller/store.d.ts +1 -1
  40. package/dist/lib/controller/store.d.ts.map +1 -1
  41. package/dist/lib/controller/storeCache.d.ts +1 -1
  42. package/dist/lib/controller/storeCache.d.ts.map +1 -1
  43. package/dist/lib/{capability.d.ts → core/capability.d.ts} +1 -1
  44. package/dist/lib/core/capability.d.ts.map +1 -0
  45. package/dist/lib/{module.d.ts → core/module.d.ts} +2 -2
  46. package/dist/lib/core/module.d.ts.map +1 -0
  47. package/dist/lib/core/queue.d.ts.map +1 -0
  48. package/dist/lib/{schedule.d.ts → core/schedule.d.ts} +0 -1
  49. package/dist/lib/core/schedule.d.ts.map +1 -0
  50. package/dist/lib/core/storage.d.ts.map +1 -0
  51. package/dist/lib/deploymentChecks.d.ts.map +1 -1
  52. package/dist/lib/errors.d.ts +0 -5
  53. package/dist/lib/errors.d.ts.map +1 -1
  54. package/dist/lib/filesystemService.d.ts.map +1 -1
  55. package/dist/lib/filter/adjudicators/adjudicators.d.ts +5 -4
  56. package/dist/lib/filter/adjudicators/adjudicators.d.ts.map +1 -1
  57. package/dist/lib/filter/filter.d.ts +33 -1
  58. package/dist/lib/filter/filter.d.ts.map +1 -1
  59. package/dist/lib/finalizer.d.ts.map +1 -1
  60. package/dist/lib/helpers.d.ts +4 -9
  61. package/dist/lib/helpers.d.ts.map +1 -1
  62. package/dist/lib/included-files.d.ts.map +1 -1
  63. package/dist/lib/mutate-request.d.ts.map +1 -1
  64. package/dist/lib/processors/mutate-processor.d.ts +28 -0
  65. package/dist/lib/processors/mutate-processor.d.ts.map +1 -0
  66. package/dist/lib/{validate-processor.d.ts → processors/validate-processor.d.ts} +5 -5
  67. package/dist/lib/processors/validate-processor.d.ts.map +1 -0
  68. package/dist/lib/{watch-processor.d.ts → processors/watch-processor.d.ts} +2 -2
  69. package/dist/lib/processors/watch-processor.d.ts.map +1 -0
  70. package/dist/lib/telemetry/logger.d.ts.map +1 -1
  71. package/dist/lib/telemetry/metrics.d.ts.map +1 -1
  72. package/dist/lib/validate-request.d.ts +2 -2
  73. package/dist/lib/validate-request.d.ts.map +1 -1
  74. package/dist/lib.d.ts +2 -2
  75. package/dist/lib.d.ts.map +1 -1
  76. package/dist/lib.js +383 -243
  77. package/dist/lib.js.map +4 -4
  78. package/dist/sdk/heredoc.d.ts.map +1 -1
  79. package/package.json +9 -9
  80. package/src/cli/build.helpers.ts +1 -1
  81. package/src/cli/build.ts +1 -1
  82. package/src/cli/deploy.ts +114 -75
  83. package/src/cli/dev.ts +3 -3
  84. package/src/cli/format.helpers.ts +27 -0
  85. package/src/cli/format.ts +4 -18
  86. package/src/cli/init/enums.ts +9 -0
  87. package/src/cli/init/index.ts +4 -3
  88. package/src/cli/init/templates.ts +30 -2
  89. package/src/cli/init/utils.ts +3 -3
  90. package/src/cli/init/walkthrough.ts +7 -8
  91. package/src/cli/kfc.ts +1 -1
  92. package/src/cli/root.ts +1 -1
  93. package/src/cli/update.ts +1 -1
  94. package/src/cli/uuid.ts +1 -1
  95. package/src/fixtures/loader.ts +2 -2
  96. package/src/lib/assets/assets.ts +176 -0
  97. package/src/lib/assets/deploy.ts +6 -6
  98. package/src/lib/assets/index.ts +10 -144
  99. package/src/lib/assets/pods.ts +2 -2
  100. package/src/lib/assets/webhooks.ts +32 -56
  101. package/src/lib/assets/yaml.ts +47 -25
  102. package/src/lib/controller/index.ts +4 -4
  103. package/src/lib/controller/store.ts +2 -2
  104. package/src/lib/controller/storeCache.ts +6 -2
  105. package/src/lib/{capability.ts → core/capability.ts} +4 -4
  106. package/src/lib/{module.ts → core/module.ts} +10 -10
  107. package/src/lib/{queue.ts → core/queue.ts} +1 -1
  108. package/src/lib/deploymentChecks.ts +2 -2
  109. package/src/lib/errors.ts +3 -8
  110. package/src/lib/filesystemService.ts +1 -1
  111. package/src/lib/filter/adjudicators/adjudicators.ts +40 -9
  112. package/src/lib/filter/filter.ts +204 -111
  113. package/src/lib/finalizer.ts +2 -2
  114. package/src/lib/helpers.ts +20 -133
  115. package/src/lib/included-files.ts +1 -1
  116. package/src/lib/processors/mutate-processor.ts +225 -0
  117. package/src/lib/{validate-processor.ts → processors/validate-processor.ts} +8 -8
  118. package/src/lib/{watch-processor.ts → processors/watch-processor.ts} +8 -8
  119. package/src/lib/telemetry/logger.ts +3 -1
  120. package/src/lib/tls.ts +5 -1
  121. package/src/lib/validate-request.ts +4 -4
  122. package/src/lib.ts +2 -2
  123. package/src/runtime/controller.ts +2 -2
  124. package/src/sdk/heredoc.ts +1 -1
  125. package/dist/lib/capability.d.ts.map +0 -1
  126. package/dist/lib/module.d.ts.map +0 -1
  127. package/dist/lib/mutate-processor.d.ts +0 -6
  128. package/dist/lib/mutate-processor.d.ts.map +0 -1
  129. package/dist/lib/queue.d.ts.map +0 -1
  130. package/dist/lib/schedule.d.ts.map +0 -1
  131. package/dist/lib/storage.d.ts.map +0 -1
  132. package/dist/lib/validate-processor.d.ts.map +0 -1
  133. package/dist/lib/watch-processor.d.ts.map +0 -1
  134. package/src/lib/mutate-processor.ts +0 -165
  135. /package/dist/lib/{queue.d.ts → core/queue.d.ts} +0 -0
  136. /package/dist/lib/{storage.d.ts → core/storage.d.ts} +0 -0
  137. /package/src/lib/{schedule.ts → core/schedule.ts} +0 -0
  138. /package/src/lib/{storage.ts → core/storage.ts} +0 -0
@@ -5,13 +5,13 @@ import express, { NextFunction } from "express";
5
5
  import fs from "fs";
6
6
  import https from "https";
7
7
 
8
- import { Capability } from "../capability";
8
+ import { Capability } from "../core/capability";
9
9
  import { MutateResponse, ValidateResponse } from "../k8s";
10
10
  import Log from "../telemetry/logger";
11
11
  import { metricsCollector, MetricsCollector } from "../telemetry/metrics";
12
- import { ModuleConfig, isWatchMode } from "../module";
13
- import { mutateProcessor } from "../mutate-processor";
14
- import { validateProcessor } from "../validate-processor";
12
+ import { ModuleConfig, isWatchMode } from "../core/module";
13
+ import { mutateProcessor } from "../processors/mutate-processor";
14
+ import { validateProcessor } from "../processors/validate-processor";
15
15
  import { StoreController } from "./store";
16
16
  import { AdmissionRequest } from "../types";
17
17
  import { karForMutate, karForValidate, KubeAdmissionReview } from "./index.util";
@@ -5,10 +5,10 @@ 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";
@@ -1,11 +1,15 @@
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
 
@@ -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();
@@ -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
 
@@ -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([
@@ -3,48 +3,55 @@
3
3
 
4
4
  import { AdmissionRequest, Binding } from "../types";
5
5
  import { Operation } from "../enums";
6
+ import { KubernetesObject } from "kubernetes-fluent-client";
6
7
  import {
7
- carriesIgnoredNamespace,
8
+ carriedAnnotations,
9
+ carriedLabels,
8
10
  carriedName,
9
- definedEvent,
10
- declaredOperation,
11
- definedName,
12
- definedGroup,
11
+ carriedNamespace,
12
+ carriesIgnoredNamespace,
13
13
  declaredGroup,
14
- definedVersion,
14
+ declaredKind,
15
+ declaredOperation,
15
16
  declaredVersion,
17
+ definedAnnotations,
18
+ definedEvent,
19
+ definedGroup,
16
20
  definedKind,
17
- declaredKind,
18
- definedNamespaces,
19
- carriedNamespace,
20
21
  definedLabels,
21
- carriedLabels,
22
- definedAnnotations,
23
- carriedAnnotations,
24
- definedNamespaceRegexes,
22
+ definedName,
25
23
  definedNameRegex,
24
+ definedNamespaceRegexes,
25
+ definedNamespaces,
26
+ definedVersion,
26
27
  misboundDeleteWithDeletionTimestamp,
27
- mismatchedDeletionTimestamp,
28
+ misboundNamespace,
28
29
  mismatchedAnnotations,
30
+ mismatchedDeletionTimestamp,
31
+ mismatchedEvent,
32
+ mismatchedGroup,
33
+ mismatchedKind,
29
34
  mismatchedLabels,
30
35
  mismatchedName,
31
36
  mismatchedNameRegex,
32
37
  mismatchedNamespace,
33
38
  mismatchedNamespaceRegex,
34
- mismatchedEvent,
35
- mismatchedGroup,
36
39
  mismatchedVersion,
37
- mismatchedKind,
38
40
  missingCarriableNamespace,
39
41
  unbindableNamespaces,
40
42
  uncarryableNamespace,
41
43
  } from "./adjudicators/adjudicators";
42
44
 
45
+ type AdjudicationResult = string | null;
46
+ type Adjudicator = () => AdjudicationResult;
47
+
43
48
  /**
44
- * shouldSkipRequest determines if a request should be skipped based on the binding filters.
49
+ * shouldSkipRequest determines if an admission request should be skipped based on the binding filters.
45
50
  *
46
51
  * @param binding the action binding
47
52
  * @param req the incoming request
53
+ * @param capabilityNamespaces the namespaces allowed by capability
54
+ * @param ignoredNamespaces the namespaces ignored by module config
48
55
  * @returns
49
56
  */
50
57
  export function shouldSkipRequest(
@@ -53,99 +60,185 @@ export function shouldSkipRequest(
53
60
  capabilityNamespaces: string[],
54
61
  ignoredNamespaces?: string[],
55
62
  ): string {
56
- const prefix = "Ignoring Admission Callback:";
57
63
  const obj = (req.operation === Operation.DELETE ? req.oldObject : req.object)!;
64
+ const prefix = "Ignoring Admission Callback:";
58
65
 
59
- // prettier-ignore
60
- return (
61
- misboundDeleteWithDeletionTimestamp(binding) ?
62
- `${prefix} Cannot use deletionTimestamp filter on a DELETE operation.` :
63
-
64
- mismatchedDeletionTimestamp(binding, obj) ?
65
- `${prefix} Binding defines deletionTimestamp but Object does not carry it.` :
66
-
67
- mismatchedEvent(binding, req) ?
68
- (
69
- `${prefix} Binding defines event '${definedEvent(binding)}' but ` +
70
- `Request declares '${declaredOperation(req)}'.`
71
- ) :
72
-
73
- mismatchedName(binding, obj) ?
74
- `${prefix} Binding defines name '${definedName(binding)}' but Object carries '${carriedName(obj)}'.` :
75
-
76
- mismatchedGroup(binding, req) ?
77
- (
78
- `${prefix} Binding defines group '${definedGroup(binding)}' but ` +
79
- `Request declares '${declaredGroup(req)}'.`
80
- ) :
81
-
82
- mismatchedVersion(binding, req) ?
83
- (
84
- `${prefix} Binding defines version '${definedVersion(binding)}' but ` +
85
- `Request declares '${declaredVersion(req)}'.`
86
- ) :
87
-
88
- mismatchedKind(binding, req) ?
89
- (
90
- `${prefix} Binding defines kind '${definedKind(binding)}' but ` +
91
- `Request declares '${declaredKind(req)}'.`
92
- ) :
93
-
94
- unbindableNamespaces(capabilityNamespaces, binding) ?
95
- (
96
- `${prefix} Binding defines namespaces ${JSON.stringify(definedNamespaces(binding))} ` +
97
- `but namespaces allowed by Capability are '${JSON.stringify(capabilityNamespaces)}'.`
98
- ) :
99
-
100
- uncarryableNamespace(capabilityNamespaces, obj) ?
101
- (
102
- `${prefix} Object carries namespace '${carriedNamespace(obj)}' ` +
103
- `but namespaces allowed by Capability are '${JSON.stringify(capabilityNamespaces)}'.`
104
- ) :
105
-
106
- mismatchedNamespace(binding, obj) ?
107
- (
108
- `${prefix} Binding defines namespaces '${JSON.stringify(definedNamespaces(binding))}' ` +
109
- `but Object carries '${carriedNamespace(obj)}'.`
110
- ) :
111
-
112
- mismatchedLabels(binding, obj) ?
113
- (
114
- `${prefix} Binding defines labels '${JSON.stringify(definedLabels(binding))}' ` +
115
- `but Object carries '${JSON.stringify(carriedLabels(obj))}'.`
116
- ) :
117
-
118
- mismatchedAnnotations(binding, obj) ?
119
- (
120
- `${prefix} Binding defines annotations '${JSON.stringify(definedAnnotations(binding))}' ` +
121
- `but Object carries '${JSON.stringify(carriedAnnotations(obj))}'.`
122
- ) :
123
-
124
- mismatchedNamespaceRegex(binding, obj) ?
125
- (
126
- `${prefix} Binding defines namespace regexes ` +
127
- `'${JSON.stringify(definedNamespaceRegexes(binding))}' ` +
128
- `but Object carries '${carriedNamespace(obj)}'.`
129
- ) :
130
-
131
- mismatchedNameRegex(binding, obj) ?
132
- (
133
- `${prefix} Binding defines name regex '${definedNameRegex(binding)}' ` +
134
- `but Object carries '${carriedName(obj)}'.`
135
- ) :
136
-
137
- carriesIgnoredNamespace(ignoredNamespaces, obj) ?
138
- (
139
- `${prefix} Object carries namespace '${carriedNamespace(obj)}' ` +
140
- `but ignored namespaces include '${JSON.stringify(ignoredNamespaces)}'.`
141
- ) :
142
-
143
- missingCarriableNamespace(capabilityNamespaces, obj) ?
144
- (
145
- `${prefix} Object does not carry a namespace ` +
146
- `but namespaces allowed by Capability are '${JSON.stringify(capabilityNamespaces)}'.`
147
- ) :
148
-
149
- ""
150
- );
66
+ const adjudicators: Adjudicator[] = [
67
+ (): AdjudicationResult => adjudicateMisboundDeleteWithDeletionTimestamp(binding),
68
+ (): AdjudicationResult => adjudicateMismatchedDeletionTimestamp(binding, obj),
69
+ (): AdjudicationResult => adjudicateMismatchedEvent(binding, req),
70
+ (): AdjudicationResult => adjudicateMismatchedName(binding, obj),
71
+ (): AdjudicationResult => adjudicateMismatchedGroup(binding, req),
72
+ (): AdjudicationResult => adjudicateMismatchedVersion(binding, req),
73
+ (): AdjudicationResult => adjudicateMismatchedKind(binding, req),
74
+ (): AdjudicationResult => adjudicateUnbindableNamespaces(capabilityNamespaces, binding),
75
+ (): AdjudicationResult => adjudicateUncarryableNamespace(capabilityNamespaces, obj),
76
+ (): AdjudicationResult => adjudicateMismatchedNamespace(binding, obj),
77
+ (): AdjudicationResult => adjudicateMismatchedLabels(binding, obj),
78
+ (): AdjudicationResult => adjudicateMismatchedAnnotations(binding, obj),
79
+ (): AdjudicationResult => adjudicateMismatchedNamespaceRegex(binding, obj),
80
+ (): AdjudicationResult => adjudicateMismatchedNameRegex(binding, obj),
81
+ (): AdjudicationResult => adjudicateCarriesIgnoredNamespace(ignoredNamespaces, obj),
82
+ (): AdjudicationResult => adjudicateMissingCarriableNamespace(capabilityNamespaces, obj),
83
+ ];
84
+
85
+ for (const adjudicator of adjudicators) {
86
+ const result = adjudicator();
87
+ if (result) {
88
+ return `${prefix} ${result}`;
89
+ }
90
+ }
91
+
92
+ return "";
93
+ }
94
+
95
+ /**
96
+ * filterNoMatchReason determines whether a callback should be skipped after
97
+ * receiving an update event from the API server, based on the binding filters.
98
+ *
99
+ * @param binding the action binding
100
+ * @param kubernetesObject the incoming kubernetes object
101
+ * @param capabilityNamespaces the namespaces allowed by capability
102
+ * @param ignoredNamespaces the namespaces ignored by module config
103
+ */
104
+ export function filterNoMatchReason(
105
+ binding: Binding,
106
+ obj: Partial<KubernetesObject>,
107
+ capabilityNamespaces: string[],
108
+ ignoredNamespaces?: string[],
109
+ ): string {
110
+ const prefix = "Ignoring Watch Callback:";
111
+
112
+ const adjudicators: Adjudicator[] = [
113
+ (): AdjudicationResult => adjudicateMismatchedDeletionTimestamp(binding, obj),
114
+ (): AdjudicationResult => adjudicateMismatchedName(binding, obj),
115
+ (): AdjudicationResult => adjudicateMisboundNamespace(binding),
116
+ (): AdjudicationResult => adjudicateMismatchedLabels(binding, obj),
117
+ (): AdjudicationResult => adjudicateMismatchedAnnotations(binding, obj),
118
+ (): AdjudicationResult => adjudicateUncarryableNamespace(capabilityNamespaces, obj),
119
+ (): AdjudicationResult => adjudicateUnbindableNamespaces(capabilityNamespaces, binding),
120
+ (): AdjudicationResult => adjudicateMismatchedNamespace(binding, obj),
121
+ (): AdjudicationResult => adjudicateMismatchedNamespaceRegex(binding, obj),
122
+ (): AdjudicationResult => adjudicateMismatchedNameRegex(binding, obj),
123
+ (): AdjudicationResult => adjudicateCarriesIgnoredNamespace(ignoredNamespaces, obj),
124
+ (): AdjudicationResult => adjudicateMissingCarriableNamespace(capabilityNamespaces, obj),
125
+ ];
126
+
127
+ for (const adjudicator of adjudicators) {
128
+ const result = adjudicator();
129
+ if (result) {
130
+ return `${prefix} ${result}`;
131
+ }
132
+ }
133
+
134
+ return "";
135
+ }
136
+
137
+ export function adjudicateMisboundNamespace(binding: Binding): AdjudicationResult {
138
+ return misboundNamespace(binding) ? "Cannot use namespace filter on a namespace object." : null;
139
+ }
140
+
141
+ export function adjudicateMisboundDeleteWithDeletionTimestamp(binding: Binding): AdjudicationResult {
142
+ return misboundDeleteWithDeletionTimestamp(binding)
143
+ ? "Cannot use deletionTimestamp filter on a DELETE operation."
144
+ : null;
145
+ }
146
+
147
+ export function adjudicateMismatchedDeletionTimestamp(binding: Binding, obj: KubernetesObject): AdjudicationResult {
148
+ return mismatchedDeletionTimestamp(binding, obj)
149
+ ? "Binding defines deletionTimestamp but Object does not carry it."
150
+ : null;
151
+ }
152
+
153
+ export function adjudicateMismatchedEvent(binding: Binding, req: AdmissionRequest): AdjudicationResult {
154
+ return mismatchedEvent(binding, req)
155
+ ? `Binding defines event '${definedEvent(binding)}' but Request declares '${declaredOperation(req)}'.`
156
+ : null;
157
+ }
158
+
159
+ export function adjudicateMismatchedName(binding: Binding, obj: KubernetesObject): AdjudicationResult {
160
+ return mismatchedName(binding, obj)
161
+ ? `Binding defines name '${definedName(binding)}' but Object carries '${carriedName(obj)}'.`
162
+ : null;
163
+ }
164
+
165
+ export function adjudicateMismatchedGroup(binding: Binding, req: AdmissionRequest): AdjudicationResult {
166
+ return mismatchedGroup(binding, req)
167
+ ? `Binding defines group '${definedGroup(binding)}' but Request declares '${declaredGroup(req)}'.`
168
+ : null;
169
+ }
170
+
171
+ export function adjudicateMismatchedVersion(binding: Binding, req: AdmissionRequest): AdjudicationResult {
172
+ return mismatchedVersion(binding, req)
173
+ ? `Binding defines version '${definedVersion(binding)}' but Request declares '${declaredVersion(req)}'.`
174
+ : null;
175
+ }
176
+
177
+ export function adjudicateMismatchedKind(binding: Binding, req: AdmissionRequest): AdjudicationResult {
178
+ return mismatchedKind(binding, req)
179
+ ? `Binding defines kind '${definedKind(binding)}' but Request declares '${declaredKind(req)}'.`
180
+ : null;
181
+ }
182
+
183
+ export function adjudicateUnbindableNamespaces(capabilityNamespaces: string[], binding: Binding): AdjudicationResult {
184
+ return unbindableNamespaces(capabilityNamespaces, binding)
185
+ ? `Binding defines namespaces ${JSON.stringify(definedNamespaces(binding))} but namespaces allowed by Capability are '${JSON.stringify(capabilityNamespaces)}'.`
186
+ : null;
187
+ }
188
+
189
+ export function adjudicateUncarryableNamespace(
190
+ capabilityNamespaces: string[],
191
+ obj: KubernetesObject,
192
+ ): AdjudicationResult {
193
+ return uncarryableNamespace(capabilityNamespaces, obj)
194
+ ? `Object carries namespace '${obj.kind && obj.kind === "Namespace" ? obj.metadata?.name : carriedNamespace(obj)}' but namespaces allowed by Capability are '${JSON.stringify(capabilityNamespaces)}'.`
195
+ : null;
196
+ }
197
+
198
+ export function adjudicateMismatchedNamespace(binding: Binding, obj: KubernetesObject): AdjudicationResult {
199
+ return mismatchedNamespace(binding, obj)
200
+ ? `Binding defines namespaces '${JSON.stringify(definedNamespaces(binding))}' but Object carries '${carriedNamespace(obj)}'.`
201
+ : null;
202
+ }
203
+
204
+ export function adjudicateMismatchedLabels(binding: Binding, obj: KubernetesObject): AdjudicationResult {
205
+ return mismatchedLabels(binding, obj)
206
+ ? `Binding defines labels '${JSON.stringify(definedLabels(binding))}' but Object carries '${JSON.stringify(carriedLabels(obj))}'.`
207
+ : null;
208
+ }
209
+
210
+ export function adjudicateMismatchedAnnotations(binding: Binding, obj: KubernetesObject): AdjudicationResult {
211
+ return mismatchedAnnotations(binding, obj)
212
+ ? `Binding defines annotations '${JSON.stringify(definedAnnotations(binding))}' but Object carries '${JSON.stringify(carriedAnnotations(obj))}'.`
213
+ : null;
214
+ }
215
+
216
+ export function adjudicateMismatchedNamespaceRegex(binding: Binding, obj: KubernetesObject): AdjudicationResult {
217
+ return mismatchedNamespaceRegex(binding, obj)
218
+ ? `Binding defines namespace regexes '${JSON.stringify(definedNamespaceRegexes(binding))}' but Object carries '${carriedNamespace(obj)}'.`
219
+ : null;
220
+ }
221
+
222
+ export function adjudicateMismatchedNameRegex(binding: Binding, obj: KubernetesObject): AdjudicationResult {
223
+ return mismatchedNameRegex(binding, obj)
224
+ ? `Binding defines name regex '${definedNameRegex(binding)}' but Object carries '${carriedName(obj)}'.`
225
+ : null;
226
+ }
227
+
228
+ export function adjudicateCarriesIgnoredNamespace(
229
+ ignoredNamespaces: string[] | undefined,
230
+ obj: KubernetesObject,
231
+ ): AdjudicationResult {
232
+ return carriesIgnoredNamespace(ignoredNamespaces, obj)
233
+ ? `Object carries namespace '${obj.kind && obj.kind === "Namespace" ? obj.metadata?.name : carriedNamespace(obj)}' but ignored namespaces include '${JSON.stringify(ignoredNamespaces)}'.`
234
+ : null;
235
+ }
236
+
237
+ export function adjudicateMissingCarriableNamespace(
238
+ capabilityNamespaces: string[],
239
+ obj: KubernetesObject,
240
+ ): AdjudicationResult {
241
+ return missingCarriableNamespace(capabilityNamespaces, obj)
242
+ ? `Object does not carry a namespace but namespaces allowed by Capability are '${JSON.stringify(capabilityNamespaces)}'.`
243
+ : null;
151
244
  }
@@ -7,7 +7,7 @@ import { Binding, DeepPartial } from "./types";
7
7
  import { Operation } from "./enums";
8
8
  import { PeprMutateRequest } from "./mutate-request";
9
9
 
10
- export function addFinalizer<K extends KubernetesObject>(request: PeprMutateRequest<K>) {
10
+ export function addFinalizer<K extends KubernetesObject>(request: PeprMutateRequest<K>): void {
11
11
  // if a DELETE is being processed, don't add a finalizer
12
12
  if (request.Request.operation === Operation.DELETE) {
13
13
  return;
@@ -28,7 +28,7 @@ export function addFinalizer<K extends KubernetesObject>(request: PeprMutateRequ
28
28
  request.Merge({ metadata: { finalizers } } as DeepPartial<K>);
29
29
  }
30
30
 
31
- export async function removeFinalizer(binding: Binding, obj: KubernetesObject) {
31
+ export async function removeFinalizer(binding: Binding, obj: KubernetesObject): Promise<void> {
32
32
  const peprFinal = "pepr.dev/finalizer";
33
33
  const meta = obj.metadata!;
34
34
  const resource = `${meta.namespace || "ClusterScoped"}/${meta.name}`;