pepr 0.32.7 → 0.34.0

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 (143) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +2 -1
  3. package/dist/cli/banner.d.ts +2 -0
  4. package/dist/cli/banner.d.ts.map +1 -0
  5. package/dist/cli/build.d.ts +19 -0
  6. package/dist/cli/build.d.ts.map +1 -0
  7. package/dist/cli/deploy.d.ts +3 -0
  8. package/dist/cli/deploy.d.ts.map +1 -0
  9. package/dist/cli/dev.d.ts +3 -0
  10. package/dist/cli/dev.d.ts.map +1 -0
  11. package/dist/cli/format.d.ts +9 -0
  12. package/dist/cli/format.d.ts.map +1 -0
  13. package/dist/cli/init/index.d.ts +3 -0
  14. package/dist/cli/init/index.d.ts.map +1 -0
  15. package/dist/cli/init/templates.d.ts +196 -0
  16. package/dist/cli/init/templates.d.ts.map +1 -0
  17. package/dist/cli/init/utils.d.ts +21 -0
  18. package/dist/cli/init/utils.d.ts.map +1 -0
  19. package/dist/cli/init/utils.test.d.ts +2 -0
  20. package/dist/cli/init/utils.test.d.ts.map +1 -0
  21. package/dist/cli/init/walkthrough.d.ts +8 -0
  22. package/dist/cli/init/walkthrough.d.ts.map +1 -0
  23. package/dist/cli/init/walkthrough.test.d.ts +2 -0
  24. package/dist/cli/init/walkthrough.test.d.ts.map +1 -0
  25. package/dist/cli/kfc.d.ts +3 -0
  26. package/dist/cli/kfc.d.ts.map +1 -0
  27. package/dist/cli/monitor.d.ts +3 -0
  28. package/dist/cli/monitor.d.ts.map +1 -0
  29. package/dist/cli/root.d.ts +5 -0
  30. package/dist/cli/root.d.ts.map +1 -0
  31. package/dist/cli/update.d.ts +3 -0
  32. package/dist/cli/update.d.ts.map +1 -0
  33. package/dist/cli/uuid.d.ts +3 -0
  34. package/dist/cli/uuid.d.ts.map +1 -0
  35. package/dist/cli.js +66 -25
  36. package/dist/controller.js +1 -1
  37. package/dist/fixtures/loader.d.ts +5 -0
  38. package/dist/fixtures/loader.d.ts.map +1 -0
  39. package/dist/lib/assets/helm.d.ts +1 -0
  40. package/dist/lib/assets/helm.d.ts.map +1 -1
  41. package/dist/lib/assets/helm.test.d.ts +2 -0
  42. package/dist/lib/assets/helm.test.d.ts.map +1 -0
  43. package/dist/lib/assets/index.d.ts.map +1 -1
  44. package/dist/lib/assets/pods.d.ts +3 -0
  45. package/dist/lib/assets/pods.d.ts.map +1 -1
  46. package/dist/lib/assets/pods.test.d.ts +2 -0
  47. package/dist/lib/assets/pods.test.d.ts.map +1 -0
  48. package/dist/lib/assets/yaml.d.ts.map +1 -1
  49. package/dist/lib/controller/store.d.ts.map +1 -1
  50. package/dist/lib/errors.test.d.ts +2 -0
  51. package/dist/lib/errors.test.d.ts.map +1 -0
  52. package/dist/lib/filter.test.d.ts +2 -0
  53. package/dist/lib/filter.test.d.ts.map +1 -0
  54. package/dist/lib/helpers.test.d.ts +2 -0
  55. package/dist/lib/helpers.test.d.ts.map +1 -0
  56. package/dist/lib/included-files.test.d.ts +2 -0
  57. package/dist/lib/included-files.test.d.ts.map +1 -0
  58. package/dist/lib/logger.test.d.ts +2 -0
  59. package/dist/lib/logger.test.d.ts.map +1 -0
  60. package/dist/lib/metrics.d.ts +18 -0
  61. package/dist/lib/metrics.d.ts.map +1 -1
  62. package/dist/lib/metrics.test.d.ts +2 -0
  63. package/dist/lib/metrics.test.d.ts.map +1 -0
  64. package/dist/lib/module.test.d.ts +2 -0
  65. package/dist/lib/module.test.d.ts.map +1 -0
  66. package/dist/lib/mutate-request.test.d.ts +2 -0
  67. package/dist/lib/mutate-request.test.d.ts.map +1 -0
  68. package/dist/lib/queue.test.d.ts +2 -0
  69. package/dist/lib/queue.test.d.ts.map +1 -0
  70. package/dist/lib/schedule.test.d.ts +15 -0
  71. package/dist/lib/schedule.test.d.ts.map +1 -0
  72. package/dist/lib/storage.d.ts +2 -0
  73. package/dist/lib/storage.d.ts.map +1 -1
  74. package/dist/lib/storage.test.d.ts +2 -0
  75. package/dist/lib/storage.test.d.ts.map +1 -0
  76. package/dist/lib/tls.test.d.ts +2 -0
  77. package/dist/lib/tls.test.d.ts.map +1 -0
  78. package/dist/lib/utils.test.d.ts +2 -0
  79. package/dist/lib/utils.test.d.ts.map +1 -0
  80. package/dist/lib/validate-request.test.d.ts +2 -0
  81. package/dist/lib/validate-request.test.d.ts.map +1 -0
  82. package/dist/lib/watch-processor.d.ts.map +1 -1
  83. package/dist/lib/watch-processor.test.d.ts +2 -0
  84. package/dist/lib/watch-processor.test.d.ts.map +1 -0
  85. package/dist/lib.js +142 -20
  86. package/dist/lib.js.map +3 -3
  87. package/dist/sdk/sdk.test.d.ts +2 -0
  88. package/dist/sdk/sdk.test.d.ts.map +1 -0
  89. package/package.json +26 -17
  90. package/src/cli/banner.ts +63 -0
  91. package/src/cli/build.ts +370 -0
  92. package/src/cli/deploy.ts +105 -0
  93. package/src/cli/dev.ts +118 -0
  94. package/src/cli/format.ts +83 -0
  95. package/src/cli/init/index.ts +99 -0
  96. package/src/cli/init/templates.ts +124 -0
  97. package/src/cli/init/utils.test.ts +28 -0
  98. package/src/cli/init/utils.ts +55 -0
  99. package/src/cli/init/walkthrough.test.ts +21 -0
  100. package/src/cli/init/walkthrough.ts +96 -0
  101. package/src/cli/kfc.ts +45 -0
  102. package/src/cli/monitor.ts +101 -0
  103. package/src/cli/root.ts +12 -0
  104. package/src/cli/update.ts +95 -0
  105. package/src/cli/uuid.ts +44 -0
  106. package/src/fixtures/data/create-pod.json +271 -0
  107. package/src/fixtures/data/delete-pod.json +271 -0
  108. package/src/fixtures/loader.ts +18 -0
  109. package/src/lib/.prettierrc +14 -0
  110. package/src/lib/assets/helm.test.ts +64 -0
  111. package/src/lib/assets/helm.ts +35 -0
  112. package/src/lib/assets/index.ts +5 -1
  113. package/src/lib/assets/pods.test.ts +553 -0
  114. package/src/lib/assets/pods.ts +14 -6
  115. package/src/lib/assets/yaml.ts +15 -18
  116. package/src/lib/controller/index.ts +2 -2
  117. package/src/lib/controller/store.ts +88 -2
  118. package/src/lib/errors.test.ts +85 -0
  119. package/src/lib/filter.test.ts +384 -0
  120. package/src/lib/helpers.test.ts +1192 -0
  121. package/src/lib/included-files.test.ts +22 -0
  122. package/src/lib/logger.test.ts +18 -0
  123. package/src/lib/metrics.test.ts +132 -0
  124. package/src/lib/metrics.ts +68 -6
  125. package/src/lib/module.test.ts +126 -0
  126. package/src/lib/mutate-request.test.ts +188 -0
  127. package/src/lib/queue.test.ts +58 -0
  128. package/src/lib/schedule.test.ts +217 -0
  129. package/src/lib/storage.test.ts +203 -0
  130. package/src/lib/storage.ts +22 -9
  131. package/src/lib/tls.test.ts +18 -0
  132. package/src/lib/utils.test.ts +69 -0
  133. package/src/lib/validate-request.test.ts +124 -0
  134. package/src/lib/watch-processor.test.ts +322 -0
  135. package/src/lib/watch-processor.ts +20 -4
  136. package/src/sdk/sdk.test.ts +243 -0
  137. package/src/templates/.eslintrc.json +6 -0
  138. package/.prettierignore +0 -1
  139. package/CODE_OF_CONDUCT.md +0 -133
  140. package/SECURITY.md +0 -18
  141. package/SUPPORT.md +0 -16
  142. package/codecov.yaml +0 -19
  143. package/commitlint.config.js +0 -1
@@ -4,13 +4,12 @@
4
4
  import { dumpYaml } from "@kubernetes/client-node";
5
5
  import crypto from "crypto";
6
6
  import { promises as fs } from "fs";
7
-
8
7
  import { Assets } from ".";
9
8
  import { apiTokenSecret, service, tlsSecret, watcherService } from "./networking";
10
9
  import { deployment, moduleSecret, namespace, watcher } from "./pods";
11
10
  import { clusterRole, clusterRoleBinding, serviceAccount, storeRole, storeRoleBinding } from "./rbac";
12
11
  import { webhookConfig } from "./webhooks";
13
-
12
+ import { genEnv } from "./pods";
14
13
  // Helm Chart overrides file (values.yaml) generated from assets
15
14
  export async function overridesFile({ hash, name, image, config, apiToken }: Assets, path: string) {
16
15
  const overrides = {
@@ -29,11 +28,8 @@ export async function overridesFile({ hash, name, image, config, apiToken }: Ass
29
28
  terminationGracePeriodSeconds: 5,
30
29
  failurePolicy: config.onError === "reject" ? "Fail" : "Ignore",
31
30
  webhookTimeout: config.webhookTimeout,
32
- env: [
33
- { name: "PEPR_WATCH_MODE", value: "false" },
34
- { name: "PEPR_PRETTY_LOG", value: "false" },
35
- { name: "LOG_LEVEL", value: "info" },
36
- ],
31
+ env: genEnv(config, false, true),
32
+ envFrom: [],
37
33
  image,
38
34
  annotations: {
39
35
  "pepr.dev/description": `${config.description}` || "",
@@ -74,14 +70,16 @@ export async function overridesFile({ hash, name, image, config, apiToken }: Ass
74
70
  extraVolumeMounts: [],
75
71
  extraVolumes: [],
76
72
  affinity: {},
73
+ serviceMonitor: {
74
+ enabled: false,
75
+ labels: {},
76
+ annotations: {},
77
+ },
77
78
  },
78
79
  watcher: {
79
80
  terminationGracePeriodSeconds: 5,
80
- env: [
81
- { name: "PEPR_WATCH_MODE", value: "true" },
82
- { name: "PEPR_PRETTY_LOG", value: "false" },
83
- { name: "LOG_LEVEL", value: "info" },
84
- ],
81
+ env: genEnv(config, true, true),
82
+ envFrom: [],
85
83
  image,
86
84
  annotations: {
87
85
  "pepr.dev/description": `${config.description}` || "",
@@ -122,14 +120,13 @@ export async function overridesFile({ hash, name, image, config, apiToken }: Ass
122
120
  extraVolumes: [],
123
121
  affinity: {},
124
122
  podAnnotations: {},
123
+ serviceMonitor: {
124
+ enabled: false,
125
+ labels: {},
126
+ annotations: {},
127
+ },
125
128
  },
126
129
  };
127
- if (process.env.PEPR_MODE === "dev") {
128
- overrides.admission.env.push({ name: "ZARF_VAR", value: "###ZARF_VAR_THING###" });
129
- overrides.watcher.env.push({ name: "ZARF_VAR", value: "###ZARF_VAR_THING###" });
130
- overrides.admission.env.push({ name: "MY_CUSTOM_VAR", value: "example-value" });
131
- overrides.watcher.env.push({ name: "MY_CUSTOM_VAR", value: "example-value" });
132
- }
133
130
 
134
131
  await fs.writeFile(path, dumpYaml(overrides, { noRefs: true, forceQuotes: true }));
135
132
  }
@@ -8,7 +8,7 @@ import https from "https";
8
8
  import { Capability } from "../capability";
9
9
  import { MutateResponse, AdmissionRequest, ValidateResponse } from "../k8s";
10
10
  import Log from "../logger";
11
- import { MetricsCollector } from "../metrics";
11
+ import { metricsCollector, MetricsCollector } from "../metrics";
12
12
  import { ModuleConfig, isWatchMode } from "../module";
13
13
  import { mutateProcessor } from "../mutate-processor";
14
14
  import { validateProcessor } from "../validate-processor";
@@ -20,7 +20,7 @@ export class Controller {
20
20
  #running = false;
21
21
 
22
22
  // Metrics collector
23
- #metricsCollector = new MetricsCollector("pepr");
23
+ #metricsCollector = metricsCollector;
24
24
 
25
25
  // The token used to authenticate requests
26
26
  #token = "";
@@ -61,8 +61,8 @@ export class PeprControllerStore {
61
61
  K8s(PeprStore)
62
62
  .InNamespace(namespace)
63
63
  .Get(this.#name)
64
- // If the get succeeds, setup the watch
65
- .then(this.#setupWatch)
64
+ // If the get succeeds, migrate and setup the watch
65
+ .then(async (store: PeprStore) => await this.#migrateAndSetupWatch(store))
66
66
  // Otherwise, create the resource
67
67
  .catch(this.#createStoreResource),
68
68
  Math.random() * 3000,
@@ -74,6 +74,91 @@ export class PeprControllerStore {
74
74
  watcher.start().catch(e => Log.error(e, "Error starting Pepr store watch"));
75
75
  };
76
76
 
77
+ #migrateAndSetupWatch = async (store: PeprStore) => {
78
+ Log.debug(store, "Pepr Store migration");
79
+ const data: DataStore = store.data || {};
80
+ const migrateCache: Record<string, Operation> = {};
81
+
82
+ // Send the cached updates to the cluster
83
+ const flushCache = async () => {
84
+ const indexes = Object.keys(migrateCache);
85
+ const payload = Object.values(migrateCache);
86
+
87
+ // Loop over each key in the cache and delete it to avoid collisions with other sender calls
88
+ for (const idx of indexes) {
89
+ delete migrateCache[idx];
90
+ }
91
+
92
+ try {
93
+ // Send the patch to the cluster
94
+ await K8s(PeprStore, { namespace, name: this.#name }).Patch(payload);
95
+ } catch (err) {
96
+ Log.error(err, "Pepr store update failure");
97
+
98
+ if (err.status === 422) {
99
+ Object.keys(migrateCache).forEach(key => delete migrateCache[key]);
100
+ } else {
101
+ // On failure to update, re-add the operations to the cache to be retried
102
+ for (const idx of indexes) {
103
+ migrateCache[idx] = payload[Number(idx)];
104
+ }
105
+ }
106
+ }
107
+ };
108
+
109
+ const fillCache = (name: string, op: DataOp, key: string[], val?: string) => {
110
+ if (op === "add") {
111
+ // adjust the path for the capability
112
+ const path = `/data/${name}-v2-${key}`;
113
+ const value = val || "";
114
+ const cacheIdx = [op, path, value].join(":");
115
+
116
+ // Add the operation to the cache
117
+ migrateCache[cacheIdx] = { op, path, value };
118
+
119
+ return;
120
+ }
121
+
122
+ if (op === "remove") {
123
+ if (key.length < 1) {
124
+ throw new Error(`Key is required for REMOVE operation`);
125
+ }
126
+
127
+ for (const k of key) {
128
+ const path = `/data/${name}-${k}`;
129
+ const cacheIdx = [op, path].join(":");
130
+
131
+ // Add the operation to the cache
132
+ migrateCache[cacheIdx] = { op, path };
133
+ }
134
+
135
+ return;
136
+ }
137
+
138
+ // If we get here, the operation is not supported
139
+ throw new Error(`Unsupported operation: ${op}`);
140
+ };
141
+
142
+ for (const name of Object.keys(this.#stores)) {
143
+ // Get the prefix offset for the keys
144
+ const offset = `${name}-`.length;
145
+
146
+ // Loop over each key in the store
147
+ for (const key of Object.keys(data)) {
148
+ // Match on the capability name as a prefix for non v2 keys
149
+ if (startsWith(name, key) && !startsWith(`${name}-v2`, key)) {
150
+ // populate migrate cache
151
+ fillCache(name, "remove", [key.slice(offset)], data[key]);
152
+ fillCache(name, "add", [key.slice(offset)], data[key]);
153
+ }
154
+ }
155
+
156
+ // await K8s(PeprStore, { namespace, name: this.#name }).Patch(payload);
157
+ }
158
+ await flushCache();
159
+ this.#setupWatch();
160
+ };
161
+
77
162
  #receive = (store: PeprStore) => {
78
163
  Log.debug(store, "Pepr Store update");
79
164
 
@@ -121,6 +206,7 @@ export class PeprControllerStore {
121
206
  // Load the sendCache with patch operations
122
207
  const fillCache = (op: DataOp, key: string[], val?: string) => {
123
208
  if (op === "add") {
209
+ // adjust the path for the capability
124
210
  const path = `/data/${capabilityName}-${key}`;
125
211
  const value = val || "";
126
212
  const cacheIdx = [op, path, value].join(":");
@@ -0,0 +1,85 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
+
4
+ import { expect, test, describe } from "@jest/globals";
5
+ import * as fc from "fast-check";
6
+ import { Errors, ErrorList, ValidateError } from "./errors";
7
+
8
+ describe("ValidateError Fuzz Testing", () => {
9
+ test("should only accept predefined error values", () => {
10
+ fc.assert(
11
+ fc.property(fc.string(), error => {
12
+ if (ErrorList.includes(error)) {
13
+ expect(() => ValidateError(error)).not.toThrow();
14
+ } else {
15
+ expect(() => ValidateError(error)).toThrow(
16
+ `Invalid error: ${error}. Must be one of: ${ErrorList.join(", ")}`,
17
+ );
18
+ }
19
+ }),
20
+ { verbose: true },
21
+ );
22
+ });
23
+ });
24
+ describe("ValidateError Fake Data Testing", () => {
25
+ test("should correctly handle typical fake error data", () => {
26
+ const fakeErrors = ["error", "failure", "null", "undefined", "exception"];
27
+ fakeErrors.forEach(fakeError => {
28
+ if (ErrorList.includes(fakeError)) {
29
+ expect(() => ValidateError(fakeError)).not.toThrow();
30
+ } else {
31
+ expect(() => ValidateError(fakeError)).toThrow(
32
+ `Invalid error: ${fakeError}. Must be one of: ${ErrorList.join(", ")}`,
33
+ );
34
+ }
35
+ });
36
+ });
37
+ });
38
+ describe("ValidateError Property-Based Testing", () => {
39
+ test("should only validate errors that are part of the ErrorList", () => {
40
+ fc.assert(
41
+ fc.property(fc.constantFrom(...ErrorList), validError => {
42
+ expect(() => ValidateError(validError)).not.toThrow();
43
+ }),
44
+ { verbose: true },
45
+ );
46
+
47
+ fc.assert(
48
+ fc.property(
49
+ fc.string().filter(e => !ErrorList.includes(e)),
50
+ invalidError => {
51
+ expect(() => ValidateError(invalidError)).toThrow(
52
+ `Invalid error: ${invalidError}. Must be one of: ${ErrorList.join(", ")}`,
53
+ );
54
+ },
55
+ ),
56
+ { verbose: true },
57
+ );
58
+ });
59
+ });
60
+
61
+ test("Errors object should have correct properties", () => {
62
+ expect(Errors).toEqual({
63
+ audit: "audit",
64
+ ignore: "ignore",
65
+ reject: "reject",
66
+ });
67
+ });
68
+
69
+ test("ErrorList should contain correct values", () => {
70
+ expect(ErrorList).toEqual(["audit", "ignore", "reject"]);
71
+ });
72
+
73
+ test("ValidateError should not throw an error for valid errors", () => {
74
+ expect(() => {
75
+ ValidateError("audit");
76
+ ValidateError("ignore");
77
+ ValidateError("reject");
78
+ }).not.toThrow();
79
+ });
80
+
81
+ test("ValidateError should throw an error for invalid errors", () => {
82
+ expect(() => ValidateError("invalidError")).toThrowError({
83
+ message: "Invalid error: invalidError. Must be one of: audit, ignore, reject",
84
+ });
85
+ });
@@ -0,0 +1,384 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
+
4
+ import { expect, test, describe } from "@jest/globals";
5
+ import { kind, modelToGroupVersionKind } from "kubernetes-fluent-client";
6
+ import * as fc from "fast-check";
7
+ import { CreatePod, DeletePod } from "../fixtures/loader";
8
+ import { shouldSkipRequest } from "./filter";
9
+ import { Event, Binding } from "./types";
10
+ import { AdmissionRequest } from "./k8s";
11
+
12
+ const callback = () => undefined;
13
+
14
+ const podKind = modelToGroupVersionKind(kind.Pod.name);
15
+
16
+ describe("Fuzzing shouldSkipRequest", () => {
17
+ test("should handle random inputs without crashing", () => {
18
+ fc.assert(
19
+ fc.property(
20
+ fc.record({
21
+ event: fc.constantFrom("CREATE", "UPDATE", "DELETE", "ANY"),
22
+ kind: fc.record({
23
+ group: fc.string(),
24
+ version: fc.string(),
25
+ kind: fc.string(),
26
+ }),
27
+ filters: fc.record({
28
+ name: fc.string(),
29
+ namespaces: fc.array(fc.string()),
30
+ labels: fc.dictionary(fc.string(), fc.string()),
31
+ annotations: fc.dictionary(fc.string(), fc.string()),
32
+ }),
33
+ }),
34
+ fc.record({
35
+ operation: fc.string(),
36
+ uid: fc.string(),
37
+ name: fc.string(),
38
+ namespace: fc.string(),
39
+ kind: fc.record({
40
+ group: fc.string(),
41
+ version: fc.string(),
42
+ kind: fc.string(),
43
+ }),
44
+ }),
45
+ fc.array(fc.string()),
46
+ (binding, req, capabilityNamespaces) => {
47
+ expect(() =>
48
+ shouldSkipRequest(binding as Binding, req as AdmissionRequest, capabilityNamespaces),
49
+ ).not.toThrow();
50
+ },
51
+ ),
52
+ { numRuns: 100 },
53
+ );
54
+ });
55
+ });
56
+ describe("Property-Based Testing shouldSkipRequest", () => {
57
+ test("should only skip requests that do not match the binding criteria", () => {
58
+ fc.assert(
59
+ fc.property(
60
+ fc.record({
61
+ event: fc.constantFrom("CREATE", "UPDATE", "DELETE", "ANY"),
62
+ kind: fc.record({
63
+ group: fc.string(),
64
+ version: fc.string(),
65
+ kind: fc.string(),
66
+ }),
67
+ filters: fc.record({
68
+ name: fc.string(),
69
+ namespaces: fc.array(fc.string()),
70
+ labels: fc.dictionary(fc.string(), fc.string()),
71
+ annotations: fc.dictionary(fc.string(), fc.string()),
72
+ }),
73
+ }),
74
+ fc.record({
75
+ operation: fc.string(),
76
+ uid: fc.string(),
77
+ name: fc.string(),
78
+ namespace: fc.string(),
79
+ kind: fc.record({
80
+ group: fc.string(),
81
+ version: fc.string(),
82
+ kind: fc.string(),
83
+ }),
84
+ }),
85
+ fc.array(fc.string()),
86
+ (binding, req, capabilityNamespaces) => {
87
+ const shouldSkip = shouldSkipRequest(binding as Binding, req as AdmissionRequest, capabilityNamespaces);
88
+ expect(typeof shouldSkip).toBe("boolean");
89
+ },
90
+ ),
91
+ { numRuns: 100 },
92
+ );
93
+ });
94
+ });
95
+
96
+ test("should reject when name does not match", () => {
97
+ const binding = {
98
+ model: kind.Pod,
99
+ event: Event.Any,
100
+ kind: podKind,
101
+ filters: {
102
+ name: "bleh",
103
+ namespaces: [],
104
+ labels: {},
105
+ annotations: {},
106
+ },
107
+ callback,
108
+ };
109
+ const pod = CreatePod();
110
+
111
+ expect(shouldSkipRequest(binding, pod, [])).toBe(true);
112
+ });
113
+
114
+ test("should reject when kind does not match", () => {
115
+ const binding = {
116
+ model: kind.Pod,
117
+ event: Event.Any,
118
+ kind: modelToGroupVersionKind(kind.CronJob.name),
119
+ filters: {
120
+ name: "",
121
+ namespaces: [],
122
+ labels: {},
123
+ annotations: {},
124
+ },
125
+ callback,
126
+ };
127
+ const pod = CreatePod();
128
+
129
+ expect(shouldSkipRequest(binding, pod, [])).toBe(true);
130
+ });
131
+
132
+ test("should reject when group does not match", () => {
133
+ const binding = {
134
+ model: kind.Pod,
135
+ event: Event.Any,
136
+ kind: modelToGroupVersionKind(kind.CronJob.name),
137
+ filters: {
138
+ name: "",
139
+ namespaces: [],
140
+ labels: {},
141
+ annotations: {},
142
+ },
143
+ callback,
144
+ };
145
+ const pod = CreatePod();
146
+
147
+ expect(shouldSkipRequest(binding, pod, [])).toBe(true);
148
+ });
149
+
150
+ test("should reject when version does not match", () => {
151
+ const binding = {
152
+ model: kind.Pod,
153
+ event: Event.Any,
154
+ kind: {
155
+ group: "",
156
+ version: "v2",
157
+ kind: "Pod",
158
+ },
159
+ filters: {
160
+ name: "",
161
+ namespaces: [],
162
+ labels: {},
163
+ annotations: {},
164
+ },
165
+ callback,
166
+ };
167
+ const pod = CreatePod();
168
+
169
+ expect(shouldSkipRequest(binding, pod, [])).toBe(true);
170
+ });
171
+
172
+ test("should allow when group, version, and kind match", () => {
173
+ const binding = {
174
+ model: kind.Pod,
175
+ event: Event.Any,
176
+ kind: podKind,
177
+ filters: {
178
+ name: "",
179
+ namespaces: [],
180
+ labels: {},
181
+ annotations: {},
182
+ },
183
+ callback,
184
+ };
185
+ const pod = CreatePod();
186
+
187
+ expect(shouldSkipRequest(binding, pod, [])).toBe(false);
188
+ });
189
+
190
+ test("should allow when kind match and others are empty", () => {
191
+ const binding = {
192
+ model: kind.Pod,
193
+ event: Event.Any,
194
+ kind: {
195
+ group: "",
196
+ version: "",
197
+ kind: "Pod",
198
+ },
199
+ filters: {
200
+ name: "",
201
+ namespaces: [],
202
+ labels: {},
203
+ annotations: {},
204
+ },
205
+ callback,
206
+ };
207
+ const pod = CreatePod();
208
+
209
+ expect(shouldSkipRequest(binding, pod, [])).toBe(false);
210
+ });
211
+
212
+ test("should reject when teh capability namespace does not match", () => {
213
+ const binding = {
214
+ model: kind.Pod,
215
+ event: Event.Any,
216
+ kind: podKind,
217
+ filters: {
218
+ name: "",
219
+ namespaces: [],
220
+ labels: {},
221
+ annotations: {},
222
+ },
223
+ callback,
224
+ };
225
+ const pod = CreatePod();
226
+
227
+ expect(shouldSkipRequest(binding, pod, ["bleh", "bleh2"])).toBe(true);
228
+ });
229
+
230
+ test("should reject when namespace does not match", () => {
231
+ const binding = {
232
+ model: kind.Pod,
233
+ event: Event.Any,
234
+ kind: podKind,
235
+ filters: {
236
+ name: "",
237
+ namespaces: ["bleh"],
238
+ labels: {},
239
+ annotations: {},
240
+ },
241
+ callback,
242
+ };
243
+ const pod = CreatePod();
244
+
245
+ expect(shouldSkipRequest(binding, pod, [])).toBe(true);
246
+ });
247
+
248
+ test("should allow when namespace is match", () => {
249
+ const binding = {
250
+ model: kind.Pod,
251
+ event: Event.Any,
252
+ kind: podKind,
253
+ filters: {
254
+ name: "",
255
+ namespaces: ["default", "unicorn", "things"],
256
+ labels: {},
257
+ annotations: {},
258
+ },
259
+ callback,
260
+ };
261
+ const pod = CreatePod();
262
+
263
+ expect(shouldSkipRequest(binding, pod, [])).toBe(false);
264
+ });
265
+
266
+ test("should reject when label does not match", () => {
267
+ const binding = {
268
+ model: kind.Pod,
269
+ event: Event.Any,
270
+ kind: podKind,
271
+ filters: {
272
+ name: "",
273
+ namespaces: [],
274
+ labels: {
275
+ foo: "bar",
276
+ },
277
+ annotations: {},
278
+ },
279
+ callback,
280
+ };
281
+ const pod = CreatePod();
282
+
283
+ expect(shouldSkipRequest(binding, pod, [])).toBe(true);
284
+ });
285
+
286
+ test("should allow when label is match", () => {
287
+ const binding = {
288
+ model: kind.Pod,
289
+ event: Event.Any,
290
+ kind: podKind,
291
+ filters: {
292
+ name: "",
293
+
294
+ namespaces: [],
295
+ labels: {
296
+ foo: "bar",
297
+ test: "test1",
298
+ },
299
+ annotations: {},
300
+ },
301
+ callback,
302
+ };
303
+
304
+ const pod = CreatePod();
305
+ pod.object.metadata = pod.object.metadata || {};
306
+ pod.object.metadata.labels = {
307
+ foo: "bar",
308
+ test: "test1",
309
+ test2: "test2",
310
+ };
311
+
312
+ expect(shouldSkipRequest(binding, pod, [])).toBe(false);
313
+ });
314
+
315
+ test("should reject when annotation does not match", () => {
316
+ const binding = {
317
+ model: kind.Pod,
318
+ event: Event.Any,
319
+ kind: podKind,
320
+ filters: {
321
+ name: "",
322
+ namespaces: [],
323
+ labels: {},
324
+ annotations: {
325
+ foo: "bar",
326
+ },
327
+ },
328
+ callback,
329
+ };
330
+ const pod = CreatePod();
331
+
332
+ expect(shouldSkipRequest(binding, pod, [])).toBe(true);
333
+ });
334
+
335
+ test("should allow when annotation is match", () => {
336
+ const binding = {
337
+ model: kind.Pod,
338
+ event: Event.Any,
339
+ kind: podKind,
340
+ filters: {
341
+ name: "",
342
+ namespaces: [],
343
+ labels: {},
344
+ annotations: {
345
+ foo: "bar",
346
+ test: "test1",
347
+ },
348
+ },
349
+ callback,
350
+ };
351
+
352
+ const pod = CreatePod();
353
+ pod.object.metadata = pod.object.metadata || {};
354
+ pod.object.metadata.annotations = {
355
+ foo: "bar",
356
+ test: "test1",
357
+ test2: "test2",
358
+ };
359
+
360
+ expect(shouldSkipRequest(binding, pod, [])).toBe(false);
361
+ });
362
+
363
+ test("should use `oldObject` when the operation is `DELETE`", () => {
364
+ const binding = {
365
+ model: kind.Pod,
366
+ event: Event.Delete,
367
+ kind: podKind,
368
+ filters: {
369
+ name: "",
370
+ namespaces: [],
371
+ labels: {
372
+ "app.kubernetes.io/name": "cool-name-podinfo",
373
+ },
374
+ annotations: {
375
+ "prometheus.io/scrape": "true",
376
+ },
377
+ },
378
+ callback,
379
+ };
380
+
381
+ const pod = DeletePod();
382
+
383
+ expect(shouldSkipRequest(binding, pod, [])).toBe(false);
384
+ });