pepr 0.46.0-nightly.0 → 0.46.0-nightly.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.
@@ -1,334 +0,0 @@
1
- // SPDX-License-Identifier: Apache-2.0
2
- // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
-
4
- import { Event, Operation } from "../../enums";
5
- import { AdmissionRequest, Binding, FinalizeAction, WatchLogAction, MutateAction, ValidateAction } from "../../types";
6
- import {
7
- __,
8
- allPass,
9
- any,
10
- anyPass,
11
- complement,
12
- curry,
13
- defaultTo,
14
- difference,
15
- equals,
16
- gt,
17
- length,
18
- not,
19
- nthArg,
20
- pipe,
21
- } from "ramda";
22
- import { GenericClass, KubernetesObject } from "kubernetes-fluent-client";
23
-
24
- /*
25
- Naming scheme:
26
- - AdmissionRequest - "declares" / "neglects"
27
- - KubernetesObject - "carries" / "missing"
28
- - Binding - "defines" / "ignores"
29
- */
30
-
31
- /*
32
- AdmissionRequest collectors
33
- */
34
- export const declaredOperation = pipe(
35
- (request: AdmissionRequest<KubernetesObject>): Operation => request?.operation,
36
- defaultTo(""),
37
- );
38
- export const declaredGroup = pipe(
39
- (request: AdmissionRequest<KubernetesObject>): string => request?.kind?.group,
40
- defaultTo(""),
41
- );
42
- export const declaredVersion = pipe(
43
- (request: AdmissionRequest<KubernetesObject>): string | undefined => request?.kind?.version,
44
- defaultTo(""),
45
- );
46
- export const declaredKind = pipe(
47
- (request: AdmissionRequest<KubernetesObject>): string => request?.kind?.kind,
48
- defaultTo(""),
49
- );
50
- export const declaredUid = pipe((request: AdmissionRequest<KubernetesObject>): string => request?.uid, defaultTo(""));
51
-
52
- /*
53
- KubernetesObject collectors
54
- */
55
- export const carriesDeletionTimestamp = pipe(
56
- kubernetesObject => !!kubernetesObject.metadata?.deletionTimestamp,
57
- defaultTo(false),
58
- );
59
- export const missingDeletionTimestamp = complement(carriesDeletionTimestamp);
60
-
61
- export const carriedKind = pipe(
62
- (kubernetesObject: KubernetesObject): string | undefined => kubernetesObject?.kind,
63
- defaultTo("not set"),
64
- );
65
- export const carriedVersion = pipe(
66
- (kubernetesObject: KubernetesObject): string | undefined => kubernetesObject?.metadata?.resourceVersion,
67
- defaultTo("not set"),
68
- );
69
- export const carriedName = pipe(
70
- (kubernetesObject: KubernetesObject): string | undefined => kubernetesObject?.metadata?.name,
71
- defaultTo(""),
72
- );
73
- export const carriesName = pipe(carriedName, equals(""), not);
74
- export const missingName = complement(carriesName);
75
-
76
- export const carriedNamespace = pipe(
77
- (kubernetesObject: KubernetesObject): string | undefined => kubernetesObject?.metadata?.namespace,
78
- defaultTo(""),
79
- );
80
-
81
- export const carriesNamespace = pipe(carriedNamespace, equals(""), not);
82
-
83
- export const carriedAnnotations = pipe(
84
- (kubernetesObject: KubernetesObject): { [key: string]: string } | undefined =>
85
- kubernetesObject?.metadata?.annotations,
86
- defaultTo({}),
87
- );
88
- export const carriesAnnotations = pipe(carriedAnnotations, equals({}), not);
89
-
90
- export const carriedLabels = pipe(
91
- (kubernetesObject: KubernetesObject): { [key: string]: string } | undefined => kubernetesObject?.metadata?.labels,
92
- defaultTo({}),
93
- );
94
- export const carriesLabels = pipe(carriedLabels, equals({}), not);
95
-
96
- /*
97
- Binding collectors
98
- */
99
-
100
- export const definesDeletionTimestamp = pipe(
101
- (binding: Binding): boolean => binding?.filters?.deletionTimestamp ?? false,
102
- defaultTo(false),
103
- );
104
- export const ignoresDeletionTimestamp = complement(definesDeletionTimestamp);
105
-
106
- export const definedName = pipe((binding: Binding): string => {
107
- return binding.filters.name;
108
- }, defaultTo(""));
109
- export const definesName = pipe(definedName, equals(""), not);
110
- export const ignoresName = complement(definesName);
111
-
112
- export const definedNameRegex = pipe(
113
- (binding: Partial<Binding>): string | undefined => binding.filters?.regexName,
114
- defaultTo(""),
115
- );
116
- export const definesNameRegex = pipe(definedNameRegex, equals(""), not);
117
-
118
- export const definedNamespaces = pipe(binding => binding?.filters?.namespaces, defaultTo([]));
119
- export const definesNamespaces = pipe(definedNamespaces, equals([]), not);
120
-
121
- export const definedNamespaceRegexes = pipe(binding => binding?.filters?.regexNamespaces, defaultTo([]));
122
- export const definesNamespaceRegexes = pipe(definedNamespaceRegexes, equals([]), not);
123
-
124
- export const definedAnnotations = pipe((binding: Partial<Binding>) => binding?.filters?.annotations, defaultTo({}));
125
- export const definesAnnotations = pipe(definedAnnotations, equals({}), not);
126
-
127
- export const definedLabels = pipe((binding: Partial<Binding>) => binding?.filters?.labels, defaultTo({}));
128
- export const definesLabels = pipe(definedLabels, equals({}), not);
129
-
130
- export const definedEvent = (binding: Binding): Event => {
131
- return binding.event;
132
- };
133
-
134
- export const definesDelete = pipe(definedEvent, equals(Event.DELETE));
135
-
136
- export const definedGroup = pipe((binding): string => binding?.kind?.group, defaultTo(""));
137
- export const definesGroup = pipe(definedGroup, equals(""), not);
138
-
139
- export const definedVersion = pipe(
140
- (binding: Partial<Binding>): string | undefined => binding?.kind?.version,
141
- defaultTo(""),
142
- );
143
- export const definesVersion = pipe(definedVersion, equals(""), not);
144
-
145
- export const definedKind = pipe((binding): string => binding?.kind?.kind, defaultTo(""));
146
- export const definesKind = pipe(definedKind, equals(""), not);
147
-
148
- export const definedCategory = (binding: Partial<Binding>): string => {
149
- // Ordering matters, finalize is a "watch"
150
- // prettier-ignore
151
- return binding.isFinalize ? "Finalize" :
152
- binding.isWatch ? "Watch" :
153
- binding.isMutate ? "Mutate" :
154
- binding.isValidate ? "Validate" :
155
- "";
156
- };
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 => {
166
- // Ordering matters, finalize is a "watch"
167
- // prettier-ignore
168
- return binding.isFinalize ? binding.finalizeCallback :
169
- binding.isWatch ? binding.watchCallback :
170
- binding.isMutate ? binding.mutateCallback :
171
- binding.isValidate ? binding.validateCallback :
172
- null;
173
- };
174
- export const definedCallbackName = pipe(definedCallback, defaultTo({ name: "" }), callback => callback.name);
175
-
176
- /*
177
- post-collection comparitors
178
- */
179
- export const mismatchedDeletionTimestamp = allPass([
180
- pipe(nthArg(0), definesDeletionTimestamp),
181
- pipe(nthArg(1), missingDeletionTimestamp),
182
- ]);
183
-
184
- export const mismatchedName = allPass([
185
- pipe(nthArg(0), definesName),
186
- pipe((binding, kubernetesObject) => definedName(binding) !== carriedName(kubernetesObject)),
187
- ]);
188
-
189
- export const mismatchedNameRegex = allPass([
190
- pipe(nthArg(0), definesNameRegex),
191
- pipe((binding, kubernetesObject) => new RegExp(definedNameRegex(binding)).test(carriedName(kubernetesObject)), not),
192
- ]);
193
-
194
- export const bindsToKind = curry(
195
- allPass([pipe(nthArg(0), definedKind, equals(""), not), pipe((binding, kind) => definedKind(binding) === kind)]),
196
- );
197
- export const bindsToNamespace = curry(pipe(bindsToKind(__, "Namespace")));
198
- export const misboundNamespace = allPass([bindsToNamespace, definesNamespaces]);
199
-
200
- export const mismatchedNamespace = allPass([
201
- pipe(nthArg(0), definesNamespaces),
202
- pipe((binding, kubernetesObject) => definedNamespaces(binding).includes(carriedNamespace(kubernetesObject)), not),
203
- ]);
204
-
205
- export const mismatchedNamespaceRegex = allPass([
206
- pipe(nthArg(0), definesNamespaceRegexes),
207
- pipe((binding, kubernetesObject) =>
208
- pipe(
209
- any((regEx: string) => new RegExp(regEx).test(carriedNamespace(kubernetesObject))),
210
- not,
211
- )(definedNamespaceRegexes(binding)),
212
- ),
213
- ]);
214
-
215
- export const metasMismatch = pipe(
216
- (defined, carried) => {
217
- const result = { defined, carried, unalike: {} };
218
-
219
- result.unalike = Object.entries(result.defined)
220
- .map(([key, value]) => {
221
- const keyMissing = !Object.hasOwn(result.carried, key);
222
- const noValue = !value;
223
- const valMissing = !result.carried[key];
224
- const valDiffers = result.carried[key] !== result.defined[key];
225
-
226
- // prettier-ignore
227
- return (
228
- keyMissing ? { [key]: value } :
229
- noValue ? {} :
230
- valMissing ? { [key]: value } :
231
- valDiffers ? { [key]: value } :
232
- {}
233
- )
234
- })
235
- .reduce((acc, cur) => ({ ...acc, ...cur }), {});
236
-
237
- return result.unalike;
238
- },
239
- unalike => Object.keys(unalike).length > 0,
240
- );
241
-
242
- export const mismatchedAnnotations = allPass([
243
- pipe(nthArg(0), definesAnnotations),
244
- pipe((binding, kubernetesObject) => metasMismatch(definedAnnotations(binding), carriedAnnotations(kubernetesObject))),
245
- ]);
246
-
247
- export const mismatchedLabels = allPass([
248
- pipe(nthArg(0), definesLabels),
249
- pipe((binding, kubernetesObject) => metasMismatch(definedLabels(binding), carriedLabels(kubernetesObject))),
250
- ]);
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
- */
256
- export const uncarryableNamespace = allPass([
257
- pipe(nthArg(0), length, gt(__, 0)),
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),
267
- ]);
268
-
269
- export const missingCarriableNamespace = allPass([
270
- pipe(nthArg(0), length, gt(__, 0)),
271
- pipe((namespaceSelector: string[], kubernetesObject: KubernetesObject): boolean =>
272
- kubernetesObject.kind === "Namespace"
273
- ? !namespaceSelector.includes(kubernetesObject.metadata!.name!)
274
- : !carriesNamespace(kubernetesObject),
275
- ),
276
- ]);
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
- */
282
- export const carriesIgnoredNamespace = allPass([
283
- pipe(nthArg(0), length, gt(__, 0)),
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
- }),
294
- ]);
295
-
296
- export const unbindableNamespaces = allPass([
297
- pipe(nthArg(0), length, gt(__, 0)),
298
- pipe(nthArg(1), definesNamespaces),
299
- pipe(
300
- (namespaceSelector, binding) => difference(definedNamespaces(binding), namespaceSelector),
301
- length,
302
- equals(0),
303
- not,
304
- ),
305
- ]);
306
-
307
- export const misboundDeleteWithDeletionTimestamp = allPass([definesDelete, definesDeletionTimestamp]);
308
-
309
- export const operationMatchesEvent = anyPass([
310
- pipe(nthArg(1), equals(Event.ANY)),
311
- pipe((operation: Operation, event: Event): boolean => operation.valueOf() === event.valueOf()),
312
- pipe((operation: Operation, event: Event): boolean => (operation ? event.includes(operation) : false)),
313
- ]);
314
-
315
- export const mismatchedEvent = pipe(
316
- (binding: Binding, request: AdmissionRequest): boolean =>
317
- operationMatchesEvent(declaredOperation(request), definedEvent(binding)),
318
- not,
319
- );
320
-
321
- export const mismatchedGroup = allPass([
322
- pipe(nthArg(0), definesGroup),
323
- pipe((binding, request) => definedGroup(binding) !== declaredGroup(request)),
324
- ]);
325
-
326
- export const mismatchedVersion = allPass([
327
- pipe(nthArg(0), definesVersion),
328
- pipe((binding, request) => definedVersion(binding) !== declaredVersion(request)),
329
- ]);
330
-
331
- export const mismatchedKind = allPass([
332
- pipe(nthArg(0), definesKind),
333
- pipe((binding, request) => definedKind(binding) !== declaredKind(request)),
334
- ]);