pepr 0.37.1 → 0.37.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.
- package/dist/cli.js +4 -3
- package/dist/controller.js +3 -2
- package/dist/lib/adjudicators.d.ts.map +1 -1
- package/dist/lib/filter.d.ts +1 -1
- package/dist/lib/filter.d.ts.map +1 -1
- package/dist/lib/mutate-processor.d.ts.map +1 -1
- package/dist/lib/validate-processor.d.ts.map +1 -1
- package/dist/lib.js +10 -4
- package/dist/lib.js.map +2 -2
- package/package.json +1 -1
- package/src/cli/init/index.ts +1 -1
- package/src/fixtures/data/create-pod.json +2 -1
- package/src/fixtures/data/delete-pod.json +2 -1
- package/src/lib/adjudicators.test.ts +4 -0
- package/src/lib/adjudicators.ts +2 -0
- package/src/lib/filter.test.ts +82 -45
- package/src/lib/filter.ts +103 -18
- package/src/lib/mutate-processor.ts +3 -1
- package/src/lib/validate-processor.ts +3 -1
package/package.json
CHANGED
package/src/cli/init/index.ts
CHANGED
|
@@ -33,7 +33,7 @@ export default function (program: RootCmd) {
|
|
|
33
33
|
.option("--description <string>", "Explain the purpose of the new module.")
|
|
34
34
|
.option("--name <string>", "Set the name of the new module.")
|
|
35
35
|
.option("--skip-post-init", "Skip npm install, git init, and VSCode launch.")
|
|
36
|
-
.option(`--errorBehavior <${ErrorList.join("|")}>`, "Set
|
|
36
|
+
.option(`--errorBehavior <${ErrorList.join("|")}>`, "Set an errorBehavior.", Errors.reject)
|
|
37
37
|
.hook("preAction", async thisCommand => {
|
|
38
38
|
// TODO: Overrides for testing. Don't be so gross with Node CLI testing
|
|
39
39
|
// TODO: See pepr/#1140
|
|
@@ -39,7 +39,8 @@
|
|
|
39
39
|
"labels": {
|
|
40
40
|
"app.kubernetes.io/name": "cool-name-podinfo",
|
|
41
41
|
"pod-template-hash": "66bbff7cf4",
|
|
42
|
-
"zarf-agent": "patched"
|
|
42
|
+
"zarf-agent": "patched",
|
|
43
|
+
"test-op": "create"
|
|
43
44
|
},
|
|
44
45
|
"name": "cool-name-podinfo-66bbff7cf4-fwhl2",
|
|
45
46
|
"namespace": "helm-releasename",
|
|
@@ -36,7 +36,8 @@
|
|
|
36
36
|
"labels": {
|
|
37
37
|
"app.kubernetes.io/name": "cool-name-podinfo",
|
|
38
38
|
"pod-template-hash": "66bbff7cf4",
|
|
39
|
-
"zarf-agent": "patched"
|
|
39
|
+
"zarf-agent": "patched",
|
|
40
|
+
"test-op": "delete"
|
|
40
41
|
},
|
|
41
42
|
"name": "cool-name-podinfo-66bbff7cf4-fwhl2",
|
|
42
43
|
"namespace": "helm-releasename",
|
|
@@ -550,11 +550,13 @@ describe("metasMismatch", () => {
|
|
|
550
550
|
[{ anno: "tate" }, {}, true],
|
|
551
551
|
[{ anno: "tate" }, { anno: "" }, true],
|
|
552
552
|
[{ anno: "tate" }, { anno: "tate" }, false],
|
|
553
|
+
[{ anno: "tate" }, { anno: "tato" }, true],
|
|
553
554
|
|
|
554
555
|
[{ an: "no", ta: "te" }, { an: "" }, true],
|
|
555
556
|
[{ an: "no", ta: "te" }, { an: "no" }, true],
|
|
556
557
|
[{ an: "no", ta: "te" }, { an: "no", ta: "" }, true],
|
|
557
558
|
[{ an: "no", ta: "te" }, { an: "no", ta: "te" }, false],
|
|
559
|
+
[{ an: "no", ta: "te" }, { an: "no", ta: "to" }, true],
|
|
558
560
|
])("given left %j and right %j, returns %s", (bnd, obj, expected) => {
|
|
559
561
|
const result = sut.metasMismatch(bnd, obj);
|
|
560
562
|
|
|
@@ -575,10 +577,12 @@ describe("mismatchedAnnotations", () => {
|
|
|
575
577
|
[{ filters: { annotations: { anno: "tate" } } }, {}, true],
|
|
576
578
|
[{ filters: { annotations: { anno: "tate" } } }, { metadata: { annotations: { anno: "" } } }, true],
|
|
577
579
|
[{ filters: { annotations: { anno: "tate" } } }, { metadata: { annotations: { anno: "tate" } } }, false],
|
|
580
|
+
[{ filters: { annotations: { anno: "tate" } } }, { metadata: { annotations: { anno: "tato" } } }, true],
|
|
578
581
|
|
|
579
582
|
[{ filters: { annotations: { an: "no", ta: "te" } } }, { metadata: { annotations: { an: "" } } }, true],
|
|
580
583
|
[{ filters: { annotations: { an: "no", ta: "te" } } }, { metadata: { annotations: { an: "no" } } }, true],
|
|
581
584
|
[{ filters: { annotations: { an: "no", ta: "te" } } }, { metadata: { annotations: { an: "no", ta: "" } } }, true],
|
|
585
|
+
[{ filters: { annotations: { an: "no", ta: "te" } } }, { metadata: { annotations: { an: "no", ta: "to" } } }, true],
|
|
582
586
|
[
|
|
583
587
|
{ filters: { annotations: { an: "no", ta: "te" } } },
|
|
584
588
|
{ metadata: { annotations: { an: "no", ta: "te" } } },
|
package/src/lib/adjudicators.ts
CHANGED
|
@@ -162,12 +162,14 @@ export const metasMismatch = pipe(
|
|
|
162
162
|
const keyMissing = !Object.hasOwn(result.carried, key);
|
|
163
163
|
const noValue = !val;
|
|
164
164
|
const valMissing = !result.carried[key];
|
|
165
|
+
const valDiffers = result.carried[key] !== result.defined[key];
|
|
165
166
|
|
|
166
167
|
// prettier-ignore
|
|
167
168
|
return (
|
|
168
169
|
keyMissing ? { [key]: val } :
|
|
169
170
|
noValue ? {} :
|
|
170
171
|
valMissing ? { [key]: val } :
|
|
172
|
+
valDiffers ? { [key]: val } :
|
|
171
173
|
{}
|
|
172
174
|
)
|
|
173
175
|
})
|
package/src/lib/filter.test.ts
CHANGED
|
@@ -58,6 +58,7 @@ describe("Fuzzing shouldSkipRequest", () => {
|
|
|
58
58
|
);
|
|
59
59
|
});
|
|
60
60
|
});
|
|
61
|
+
|
|
61
62
|
describe("Property-Based Testing shouldSkipRequest", () => {
|
|
62
63
|
test("should only skip requests that do not match the binding criteria", () => {
|
|
63
64
|
fc.assert(
|
|
@@ -96,7 +97,7 @@ describe("Property-Based Testing shouldSkipRequest", () => {
|
|
|
96
97
|
fc.array(fc.string()),
|
|
97
98
|
(binding, req, capabilityNamespaces) => {
|
|
98
99
|
const shouldSkip = shouldSkipRequest(binding as Binding, req as AdmissionRequest, capabilityNamespaces);
|
|
99
|
-
expect(typeof shouldSkip).toBe("
|
|
100
|
+
expect(typeof shouldSkip).toBe("string");
|
|
100
101
|
},
|
|
101
102
|
),
|
|
102
103
|
{ numRuns: 100 },
|
|
@@ -113,7 +114,7 @@ test("create: should reject when regex name does not match", () => {
|
|
|
113
114
|
name: "",
|
|
114
115
|
namespaces: [],
|
|
115
116
|
regexNamespaces: [],
|
|
116
|
-
regexName:
|
|
117
|
+
regexName: "^default$",
|
|
117
118
|
labels: {},
|
|
118
119
|
annotations: {},
|
|
119
120
|
deletionTimestamp: false,
|
|
@@ -121,8 +122,11 @@ test("create: should reject when regex name does not match", () => {
|
|
|
121
122
|
callback,
|
|
122
123
|
};
|
|
123
124
|
const pod = CreatePod();
|
|
124
|
-
expect(shouldSkipRequest(binding, pod, [])).
|
|
125
|
+
expect(shouldSkipRequest(binding, pod, [])).toMatch(
|
|
126
|
+
/Ignoring Admission Callback: Binding defines name regex '.*' but Object carries '.*'./,
|
|
127
|
+
);
|
|
125
128
|
});
|
|
129
|
+
|
|
126
130
|
test("create: should not reject when regex name does match", () => {
|
|
127
131
|
const binding = {
|
|
128
132
|
model: kind.Pod,
|
|
@@ -132,7 +136,7 @@ test("create: should not reject when regex name does match", () => {
|
|
|
132
136
|
name: "",
|
|
133
137
|
namespaces: [],
|
|
134
138
|
regexNamespaces: [],
|
|
135
|
-
regexName:
|
|
139
|
+
regexName: "^cool",
|
|
136
140
|
labels: {},
|
|
137
141
|
annotations: {},
|
|
138
142
|
deletionTimestamp: false,
|
|
@@ -140,8 +144,9 @@ test("create: should not reject when regex name does match", () => {
|
|
|
140
144
|
callback,
|
|
141
145
|
};
|
|
142
146
|
const pod = CreatePod();
|
|
143
|
-
expect(shouldSkipRequest(binding, pod, [])).toBe(
|
|
147
|
+
expect(shouldSkipRequest(binding, pod, [])).toBe("");
|
|
144
148
|
});
|
|
149
|
+
|
|
145
150
|
test("delete: should reject when regex name does not match", () => {
|
|
146
151
|
const binding = {
|
|
147
152
|
model: kind.Pod,
|
|
@@ -151,7 +156,7 @@ test("delete: should reject when regex name does not match", () => {
|
|
|
151
156
|
name: "",
|
|
152
157
|
namespaces: [],
|
|
153
158
|
regexNamespaces: [],
|
|
154
|
-
regexName:
|
|
159
|
+
regexName: "^default$",
|
|
155
160
|
labels: {},
|
|
156
161
|
annotations: {},
|
|
157
162
|
deletionTimestamp: false,
|
|
@@ -159,8 +164,11 @@ test("delete: should reject when regex name does not match", () => {
|
|
|
159
164
|
callback,
|
|
160
165
|
};
|
|
161
166
|
const pod = DeletePod();
|
|
162
|
-
expect(shouldSkipRequest(binding, pod, [])).
|
|
167
|
+
expect(shouldSkipRequest(binding, pod, [])).toMatch(
|
|
168
|
+
/Ignoring Admission Callback: Binding defines name regex '.*' but Object carries '.*'./,
|
|
169
|
+
);
|
|
163
170
|
});
|
|
171
|
+
|
|
164
172
|
test("delete: should not reject when regex name does match", () => {
|
|
165
173
|
const binding = {
|
|
166
174
|
model: kind.Pod,
|
|
@@ -170,7 +178,7 @@ test("delete: should not reject when regex name does match", () => {
|
|
|
170
178
|
name: "",
|
|
171
179
|
namespaces: [],
|
|
172
180
|
regexNamespaces: [],
|
|
173
|
-
regexName:
|
|
181
|
+
regexName: "^cool",
|
|
174
182
|
labels: {},
|
|
175
183
|
annotations: {},
|
|
176
184
|
deletionTimestamp: false,
|
|
@@ -178,7 +186,7 @@ test("delete: should not reject when regex name does match", () => {
|
|
|
178
186
|
callback,
|
|
179
187
|
};
|
|
180
188
|
const pod = DeletePod();
|
|
181
|
-
expect(shouldSkipRequest(binding, pod, [])).toBe(
|
|
189
|
+
expect(shouldSkipRequest(binding, pod, [])).toBe("");
|
|
182
190
|
});
|
|
183
191
|
|
|
184
192
|
test("create: should not reject when regex namespace does match", () => {
|
|
@@ -189,7 +197,7 @@ test("create: should not reject when regex namespace does match", () => {
|
|
|
189
197
|
filters: {
|
|
190
198
|
name: "",
|
|
191
199
|
namespaces: [],
|
|
192
|
-
regexNamespaces: [
|
|
200
|
+
regexNamespaces: ["^helm"],
|
|
193
201
|
regexName: "",
|
|
194
202
|
labels: {},
|
|
195
203
|
annotations: {},
|
|
@@ -198,7 +206,7 @@ test("create: should not reject when regex namespace does match", () => {
|
|
|
198
206
|
callback,
|
|
199
207
|
};
|
|
200
208
|
const pod = CreatePod();
|
|
201
|
-
expect(shouldSkipRequest(binding, pod, [])).toBe(
|
|
209
|
+
expect(shouldSkipRequest(binding, pod, [])).toBe("");
|
|
202
210
|
});
|
|
203
211
|
|
|
204
212
|
test("create: should reject when regex namespace does not match", () => {
|
|
@@ -209,7 +217,7 @@ test("create: should reject when regex namespace does not match", () => {
|
|
|
209
217
|
filters: {
|
|
210
218
|
name: "",
|
|
211
219
|
namespaces: [],
|
|
212
|
-
regexNamespaces: [
|
|
220
|
+
regexNamespaces: ["^argo"],
|
|
213
221
|
regexName: "",
|
|
214
222
|
labels: {},
|
|
215
223
|
annotations: {},
|
|
@@ -218,7 +226,9 @@ test("create: should reject when regex namespace does not match", () => {
|
|
|
218
226
|
callback,
|
|
219
227
|
};
|
|
220
228
|
const pod = CreatePod();
|
|
221
|
-
expect(shouldSkipRequest(binding, pod, [])).
|
|
229
|
+
expect(shouldSkipRequest(binding, pod, [])).toMatch(
|
|
230
|
+
/Ignoring Admission Callback: Binding defines namespace regexes '.*' but Object carries '.*'./,
|
|
231
|
+
);
|
|
222
232
|
});
|
|
223
233
|
|
|
224
234
|
test("delete: should reject when regex namespace does not match", () => {
|
|
@@ -227,9 +237,9 @@ test("delete: should reject when regex namespace does not match", () => {
|
|
|
227
237
|
event: Event.Any,
|
|
228
238
|
kind: podKind,
|
|
229
239
|
filters: {
|
|
230
|
-
name: "
|
|
240
|
+
name: "",
|
|
231
241
|
namespaces: [],
|
|
232
|
-
regexNamespaces: [
|
|
242
|
+
regexNamespaces: ["^argo"],
|
|
233
243
|
regexName: "",
|
|
234
244
|
labels: {},
|
|
235
245
|
annotations: {},
|
|
@@ -238,7 +248,9 @@ test("delete: should reject when regex namespace does not match", () => {
|
|
|
238
248
|
callback,
|
|
239
249
|
};
|
|
240
250
|
const pod = DeletePod();
|
|
241
|
-
expect(shouldSkipRequest(binding, pod, [])).
|
|
251
|
+
expect(shouldSkipRequest(binding, pod, [])).toMatch(
|
|
252
|
+
/Ignoring Admission Callback: Binding defines namespace regexes '.*' but Object carries '.*'./,
|
|
253
|
+
);
|
|
242
254
|
});
|
|
243
255
|
|
|
244
256
|
test("delete: should not reject when regex namespace does match", () => {
|
|
@@ -249,7 +261,7 @@ test("delete: should not reject when regex namespace does match", () => {
|
|
|
249
261
|
filters: {
|
|
250
262
|
name: "",
|
|
251
263
|
namespaces: [],
|
|
252
|
-
regexNamespaces: [
|
|
264
|
+
regexNamespaces: ["^helm"],
|
|
253
265
|
regexName: "",
|
|
254
266
|
labels: {},
|
|
255
267
|
annotations: {},
|
|
@@ -258,7 +270,7 @@ test("delete: should not reject when regex namespace does match", () => {
|
|
|
258
270
|
callback,
|
|
259
271
|
};
|
|
260
272
|
const pod = DeletePod();
|
|
261
|
-
expect(shouldSkipRequest(binding, pod, [])).toBe(
|
|
273
|
+
expect(shouldSkipRequest(binding, pod, [])).toBe("");
|
|
262
274
|
});
|
|
263
275
|
|
|
264
276
|
test("delete: should reject when name does not match", () => {
|
|
@@ -270,7 +282,7 @@ test("delete: should reject when name does not match", () => {
|
|
|
270
282
|
name: "bleh",
|
|
271
283
|
namespaces: [],
|
|
272
284
|
regexNamespaces: [],
|
|
273
|
-
regexName:
|
|
285
|
+
regexName: "^not-cool",
|
|
274
286
|
labels: {},
|
|
275
287
|
annotations: {},
|
|
276
288
|
deletionTimestamp: false,
|
|
@@ -278,13 +290,20 @@ test("delete: should reject when name does not match", () => {
|
|
|
278
290
|
callback,
|
|
279
291
|
};
|
|
280
292
|
const pod = DeletePod();
|
|
281
|
-
expect(shouldSkipRequest(binding, pod, [])).
|
|
293
|
+
expect(shouldSkipRequest(binding, pod, [])).toMatch(
|
|
294
|
+
/Ignoring Admission Callback: Binding defines name '.*' but Object carries '.*'./,
|
|
295
|
+
);
|
|
282
296
|
});
|
|
297
|
+
|
|
283
298
|
test("should reject when kind does not match", () => {
|
|
284
299
|
const binding = {
|
|
285
300
|
model: kind.Pod,
|
|
286
301
|
event: Event.Any,
|
|
287
|
-
kind:
|
|
302
|
+
kind: {
|
|
303
|
+
group: "",
|
|
304
|
+
version: "v1",
|
|
305
|
+
kind: "Nope",
|
|
306
|
+
},
|
|
288
307
|
filters: {
|
|
289
308
|
name: "",
|
|
290
309
|
namespaces: [],
|
|
@@ -298,14 +317,20 @@ test("should reject when kind does not match", () => {
|
|
|
298
317
|
};
|
|
299
318
|
const pod = CreatePod();
|
|
300
319
|
|
|
301
|
-
expect(shouldSkipRequest(binding, pod, [])).
|
|
320
|
+
expect(shouldSkipRequest(binding, pod, [])).toMatch(
|
|
321
|
+
/Ignoring Admission Callback: Binding defines kind '.*' but Request declares '.*'./,
|
|
322
|
+
);
|
|
302
323
|
});
|
|
303
324
|
|
|
304
325
|
test("should reject when group does not match", () => {
|
|
305
326
|
const binding = {
|
|
306
327
|
model: kind.Pod,
|
|
307
328
|
event: Event.Any,
|
|
308
|
-
kind:
|
|
329
|
+
kind: {
|
|
330
|
+
group: "Nope",
|
|
331
|
+
version: "v1",
|
|
332
|
+
kind: "Pod",
|
|
333
|
+
},
|
|
309
334
|
filters: {
|
|
310
335
|
name: "",
|
|
311
336
|
namespaces: [],
|
|
@@ -319,7 +344,9 @@ test("should reject when group does not match", () => {
|
|
|
319
344
|
};
|
|
320
345
|
const pod = CreatePod();
|
|
321
346
|
|
|
322
|
-
expect(shouldSkipRequest(binding, pod, [])).
|
|
347
|
+
expect(shouldSkipRequest(binding, pod, [])).toMatch(
|
|
348
|
+
/Ignoring Admission Callback: Binding defines group '.*' but Request declares '.*'./,
|
|
349
|
+
);
|
|
323
350
|
});
|
|
324
351
|
|
|
325
352
|
test("should reject when version does not match", () => {
|
|
@@ -328,7 +355,7 @@ test("should reject when version does not match", () => {
|
|
|
328
355
|
event: Event.Any,
|
|
329
356
|
kind: {
|
|
330
357
|
group: "",
|
|
331
|
-
version: "
|
|
358
|
+
version: "Nope",
|
|
332
359
|
kind: "Pod",
|
|
333
360
|
},
|
|
334
361
|
filters: {
|
|
@@ -344,7 +371,9 @@ test("should reject when version does not match", () => {
|
|
|
344
371
|
};
|
|
345
372
|
const pod = CreatePod();
|
|
346
373
|
|
|
347
|
-
expect(shouldSkipRequest(binding, pod, [])).
|
|
374
|
+
expect(shouldSkipRequest(binding, pod, [])).toMatch(
|
|
375
|
+
/Ignoring Admission Callback: Binding defines version '.*' but Request declares '.*'./,
|
|
376
|
+
);
|
|
348
377
|
});
|
|
349
378
|
|
|
350
379
|
test("should allow when group, version, and kind match", () => {
|
|
@@ -365,7 +394,7 @@ test("should allow when group, version, and kind match", () => {
|
|
|
365
394
|
};
|
|
366
395
|
const pod = CreatePod();
|
|
367
396
|
|
|
368
|
-
expect(shouldSkipRequest(binding, pod, [])).toBe(
|
|
397
|
+
expect(shouldSkipRequest(binding, pod, [])).toBe("");
|
|
369
398
|
});
|
|
370
399
|
|
|
371
400
|
test("should allow when kind match and others are empty", () => {
|
|
@@ -390,7 +419,7 @@ test("should allow when kind match and others are empty", () => {
|
|
|
390
419
|
};
|
|
391
420
|
const pod = CreatePod();
|
|
392
421
|
|
|
393
|
-
expect(shouldSkipRequest(binding, pod, [])).toBe(
|
|
422
|
+
expect(shouldSkipRequest(binding, pod, [])).toBe("");
|
|
394
423
|
});
|
|
395
424
|
|
|
396
425
|
test("should reject when the capability namespace does not match", () => {
|
|
@@ -411,7 +440,9 @@ test("should reject when the capability namespace does not match", () => {
|
|
|
411
440
|
};
|
|
412
441
|
const pod = CreatePod();
|
|
413
442
|
|
|
414
|
-
expect(shouldSkipRequest(binding, pod, ["bleh", "bleh2"])).
|
|
443
|
+
expect(shouldSkipRequest(binding, pod, ["bleh", "bleh2"])).toMatch(
|
|
444
|
+
/Ignoring Admission Callback: Object carries namespace '.*' but namespaces allowed by Capability are '.*'./,
|
|
445
|
+
);
|
|
415
446
|
});
|
|
416
447
|
|
|
417
448
|
test("should reject when namespace does not match", () => {
|
|
@@ -432,7 +463,9 @@ test("should reject when namespace does not match", () => {
|
|
|
432
463
|
};
|
|
433
464
|
const pod = CreatePod();
|
|
434
465
|
|
|
435
|
-
expect(shouldSkipRequest(binding, pod, [])).
|
|
466
|
+
expect(shouldSkipRequest(binding, pod, [])).toMatch(
|
|
467
|
+
/Ignoring Admission Callback: Binding defines namespaces '.*' but Object carries '.*'./,
|
|
468
|
+
);
|
|
436
469
|
});
|
|
437
470
|
|
|
438
471
|
test("should allow when namespace is match", () => {
|
|
@@ -453,7 +486,7 @@ test("should allow when namespace is match", () => {
|
|
|
453
486
|
};
|
|
454
487
|
const pod = CreatePod();
|
|
455
488
|
|
|
456
|
-
expect(shouldSkipRequest(binding, pod, [])).toBe(
|
|
489
|
+
expect(shouldSkipRequest(binding, pod, [])).toBe("");
|
|
457
490
|
});
|
|
458
491
|
|
|
459
492
|
test("should reject when label does not match", () => {
|
|
@@ -476,7 +509,9 @@ test("should reject when label does not match", () => {
|
|
|
476
509
|
};
|
|
477
510
|
const pod = CreatePod();
|
|
478
511
|
|
|
479
|
-
expect(shouldSkipRequest(binding, pod, [])).
|
|
512
|
+
expect(shouldSkipRequest(binding, pod, [])).toMatch(
|
|
513
|
+
/Ignoring Admission Callback: Binding defines labels '.*' but Object carries '.*'./,
|
|
514
|
+
);
|
|
480
515
|
});
|
|
481
516
|
|
|
482
517
|
test("should allow when label is match", () => {
|
|
@@ -507,7 +542,7 @@ test("should allow when label is match", () => {
|
|
|
507
542
|
test2: "test2",
|
|
508
543
|
};
|
|
509
544
|
|
|
510
|
-
expect(shouldSkipRequest(binding, pod, [])).toBe(
|
|
545
|
+
expect(shouldSkipRequest(binding, pod, [])).toBe("");
|
|
511
546
|
});
|
|
512
547
|
|
|
513
548
|
test("should reject when annotation does not match", () => {
|
|
@@ -530,7 +565,9 @@ test("should reject when annotation does not match", () => {
|
|
|
530
565
|
};
|
|
531
566
|
const pod = CreatePod();
|
|
532
567
|
|
|
533
|
-
expect(shouldSkipRequest(binding, pod, [])).
|
|
568
|
+
expect(shouldSkipRequest(binding, pod, [])).toMatch(
|
|
569
|
+
/Ignoring Admission Callback: Binding defines annotations '.*' but Object carries '.*'./,
|
|
570
|
+
);
|
|
534
571
|
});
|
|
535
572
|
|
|
536
573
|
test("should allow when annotation is match", () => {
|
|
@@ -561,7 +598,7 @@ test("should allow when annotation is match", () => {
|
|
|
561
598
|
test2: "test2",
|
|
562
599
|
};
|
|
563
600
|
|
|
564
|
-
expect(shouldSkipRequest(binding, pod, [])).toBe(
|
|
601
|
+
expect(shouldSkipRequest(binding, pod, [])).toBe("");
|
|
565
602
|
});
|
|
566
603
|
|
|
567
604
|
test("should use `oldObject` when the operation is `DELETE`", () => {
|
|
@@ -576,21 +613,19 @@ test("should use `oldObject` when the operation is `DELETE`", () => {
|
|
|
576
613
|
regexName: "",
|
|
577
614
|
deletionTimestamp: false,
|
|
578
615
|
labels: {
|
|
579
|
-
"
|
|
580
|
-
},
|
|
581
|
-
annotations: {
|
|
582
|
-
"prometheus.io/scrape": "true",
|
|
616
|
+
"test-op": "delete",
|
|
583
617
|
},
|
|
618
|
+
annotations: {},
|
|
584
619
|
},
|
|
585
620
|
callback,
|
|
586
621
|
};
|
|
587
622
|
|
|
588
623
|
const pod = DeletePod();
|
|
589
624
|
|
|
590
|
-
expect(shouldSkipRequest(binding, pod, [])).toBe(
|
|
625
|
+
expect(shouldSkipRequest(binding, pod, [])).toBe("");
|
|
591
626
|
});
|
|
592
627
|
|
|
593
|
-
test("should
|
|
628
|
+
test("should allow when deletionTimestamp is present on pod", () => {
|
|
594
629
|
const binding = {
|
|
595
630
|
model: kind.Pod,
|
|
596
631
|
event: Event.Any,
|
|
@@ -612,16 +647,17 @@ test("should skip processing when deletionTimestamp is not present on pod", () =
|
|
|
612
647
|
|
|
613
648
|
const pod = CreatePod();
|
|
614
649
|
pod.object.metadata = pod.object.metadata || {};
|
|
650
|
+
pod.object.metadata!.deletionTimestamp = new Date("2021-09-01T00:00:00Z");
|
|
615
651
|
pod.object.metadata.annotations = {
|
|
616
652
|
foo: "bar",
|
|
617
653
|
test: "test1",
|
|
618
654
|
test2: "test2",
|
|
619
655
|
};
|
|
620
656
|
|
|
621
|
-
expect(shouldSkipRequest(binding, pod, [])).toBe(
|
|
657
|
+
expect(shouldSkipRequest(binding, pod, [])).toBe("");
|
|
622
658
|
});
|
|
623
659
|
|
|
624
|
-
test("should
|
|
660
|
+
test("should reject when deletionTimestamp is not present on pod", () => {
|
|
625
661
|
const binding = {
|
|
626
662
|
model: kind.Pod,
|
|
627
663
|
event: Event.Any,
|
|
@@ -643,12 +679,13 @@ test("should processing when deletionTimestamp is not present on pod", () => {
|
|
|
643
679
|
|
|
644
680
|
const pod = CreatePod();
|
|
645
681
|
pod.object.metadata = pod.object.metadata || {};
|
|
646
|
-
pod.object.metadata!.deletionTimestamp = new Date("2021-09-01T00:00:00Z");
|
|
647
682
|
pod.object.metadata.annotations = {
|
|
648
683
|
foo: "bar",
|
|
649
684
|
test: "test1",
|
|
650
685
|
test2: "test2",
|
|
651
686
|
};
|
|
652
687
|
|
|
653
|
-
expect(shouldSkipRequest(binding, pod, [])).
|
|
688
|
+
expect(shouldSkipRequest(binding, pod, [])).toMatch(
|
|
689
|
+
/Ignoring Admission Callback: Binding defines deletionTimestamp but Object does not carry it./,
|
|
690
|
+
);
|
|
654
691
|
});
|
package/src/lib/filter.ts
CHANGED
|
@@ -4,6 +4,24 @@
|
|
|
4
4
|
import { AdmissionRequest, Binding, Operation } from "./types";
|
|
5
5
|
import {
|
|
6
6
|
carriesIgnoredNamespace,
|
|
7
|
+
carriedName,
|
|
8
|
+
definedEvent,
|
|
9
|
+
declaredOperation,
|
|
10
|
+
definedName,
|
|
11
|
+
definedGroup,
|
|
12
|
+
declaredGroup,
|
|
13
|
+
definedVersion,
|
|
14
|
+
declaredVersion,
|
|
15
|
+
definedKind,
|
|
16
|
+
declaredKind,
|
|
17
|
+
definedNamespaces,
|
|
18
|
+
carriedNamespace,
|
|
19
|
+
definedLabels,
|
|
20
|
+
carriedLabels,
|
|
21
|
+
definedAnnotations,
|
|
22
|
+
carriedAnnotations,
|
|
23
|
+
definedNamespaceRegexes,
|
|
24
|
+
definedNameRegex,
|
|
7
25
|
misboundDeleteWithDeletionTimestamp,
|
|
8
26
|
mismatchedDeletionTimestamp,
|
|
9
27
|
mismatchedAnnotations,
|
|
@@ -32,27 +50,94 @@ export function shouldSkipRequest(
|
|
|
32
50
|
req: AdmissionRequest,
|
|
33
51
|
capabilityNamespaces: string[],
|
|
34
52
|
ignoredNamespaces?: string[],
|
|
35
|
-
):
|
|
53
|
+
): string {
|
|
54
|
+
const prefix = "Ignoring Admission Callback:";
|
|
36
55
|
const obj = req.operation === Operation.DELETE ? req.oldObject : req.object;
|
|
37
56
|
|
|
38
57
|
// prettier-ignore
|
|
39
58
|
return (
|
|
40
|
-
misboundDeleteWithDeletionTimestamp(binding) ?
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
59
|
+
misboundDeleteWithDeletionTimestamp(binding) ?
|
|
60
|
+
`${prefix} Cannot use deletionTimestamp filter on a DELETE operation.` :
|
|
61
|
+
|
|
62
|
+
mismatchedDeletionTimestamp(binding, obj) ?
|
|
63
|
+
`${prefix} Binding defines deletionTimestamp but Object does not carry it.` :
|
|
64
|
+
|
|
65
|
+
mismatchedEvent(binding, req) ?
|
|
66
|
+
(
|
|
67
|
+
`${prefix} Binding defines event '${definedEvent(binding)}' but ` +
|
|
68
|
+
`Request declares '${declaredOperation(req)}'.`
|
|
69
|
+
) :
|
|
70
|
+
|
|
71
|
+
mismatchedName(binding, obj) ?
|
|
72
|
+
`${prefix} Binding defines name '${definedName(binding)}' but Object carries '${carriedName(obj)}'.` :
|
|
73
|
+
|
|
74
|
+
mismatchedGroup(binding, req) ?
|
|
75
|
+
(
|
|
76
|
+
`${prefix} Binding defines group '${definedGroup(binding)}' but ` +
|
|
77
|
+
`Request declares '${declaredGroup(req)}'.`
|
|
78
|
+
) :
|
|
79
|
+
|
|
80
|
+
mismatchedVersion(binding, req) ?
|
|
81
|
+
(
|
|
82
|
+
`${prefix} Binding defines version '${definedVersion(binding)}' but ` +
|
|
83
|
+
`Request declares '${declaredVersion(req)}'.`
|
|
84
|
+
) :
|
|
85
|
+
|
|
86
|
+
mismatchedKind(binding, req) ?
|
|
87
|
+
(
|
|
88
|
+
`${prefix} Binding defines kind '${definedKind(binding)}' but ` +
|
|
89
|
+
`Request declares '${declaredKind(req)}'.`
|
|
90
|
+
) :
|
|
91
|
+
|
|
92
|
+
unbindableNamespaces(capabilityNamespaces, binding) ?
|
|
93
|
+
(
|
|
94
|
+
`${prefix} Binding defines namespaces ${JSON.stringify(definedNamespaces(binding))} ` +
|
|
95
|
+
`but namespaces allowed by Capability are '${JSON.stringify(capabilityNamespaces)}'.`
|
|
96
|
+
) :
|
|
97
|
+
|
|
98
|
+
uncarryableNamespace(capabilityNamespaces, obj) ?
|
|
99
|
+
(
|
|
100
|
+
`${prefix} Object carries namespace '${carriedNamespace(obj)}' ` +
|
|
101
|
+
`but namespaces allowed by Capability are '${JSON.stringify(capabilityNamespaces)}'.`
|
|
102
|
+
) :
|
|
103
|
+
|
|
104
|
+
mismatchedNamespace(binding, obj) ?
|
|
105
|
+
(
|
|
106
|
+
`${prefix} Binding defines namespaces '${JSON.stringify(definedNamespaces(binding))}' ` +
|
|
107
|
+
`but Object carries '${carriedNamespace(obj)}'.`
|
|
108
|
+
) :
|
|
109
|
+
|
|
110
|
+
mismatchedLabels(binding, obj) ?
|
|
111
|
+
(
|
|
112
|
+
`${prefix} Binding defines labels '${JSON.stringify(definedLabels(binding))}' ` +
|
|
113
|
+
`but Object carries '${JSON.stringify(carriedLabels(obj))}'.`
|
|
114
|
+
) :
|
|
115
|
+
|
|
116
|
+
mismatchedAnnotations(binding, obj) ?
|
|
117
|
+
(
|
|
118
|
+
`${prefix} Binding defines annotations '${JSON.stringify(definedAnnotations(binding))}' ` +
|
|
119
|
+
`but Object carries '${JSON.stringify(carriedAnnotations(obj))}'.`
|
|
120
|
+
) :
|
|
121
|
+
|
|
122
|
+
mismatchedNamespaceRegex(binding, obj) ?
|
|
123
|
+
(
|
|
124
|
+
`${prefix} Binding defines namespace regexes ` +
|
|
125
|
+
`'${JSON.stringify(definedNamespaceRegexes(binding))}' ` +
|
|
126
|
+
`but Object carries '${carriedNamespace(obj)}'.`
|
|
127
|
+
) :
|
|
128
|
+
|
|
129
|
+
mismatchedNameRegex(binding, obj) ?
|
|
130
|
+
(
|
|
131
|
+
`${prefix} Binding defines name regex '${definedNameRegex(binding)}' ` +
|
|
132
|
+
`but Object carries '${carriedName(obj)}'.`
|
|
133
|
+
) :
|
|
134
|
+
|
|
135
|
+
carriesIgnoredNamespace(ignoredNamespaces, obj) ?
|
|
136
|
+
(
|
|
137
|
+
`${prefix} Object carries namespace '${carriedNamespace(obj)}' ` +
|
|
138
|
+
`but ignored namespaces include '${JSON.stringify(ignoredNamespaces)}'.`
|
|
139
|
+
) :
|
|
140
|
+
|
|
141
|
+
""
|
|
57
142
|
);
|
|
58
143
|
}
|
|
@@ -50,7 +50,9 @@ export async function mutateProcessor(
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
// Continue to the next action without doing anything if this one should be skipped
|
|
53
|
-
|
|
53
|
+
const shouldSkip = shouldSkipRequest(action, req, namespaces, config?.alwaysIgnore?.namespaces);
|
|
54
|
+
if (shouldSkip !== "") {
|
|
55
|
+
Log.debug(shouldSkip);
|
|
54
56
|
continue;
|
|
55
57
|
}
|
|
56
58
|
|
|
@@ -44,7 +44,9 @@ export async function validateProcessor(
|
|
|
44
44
|
};
|
|
45
45
|
|
|
46
46
|
// Continue to the next action without doing anything if this one should be skipped
|
|
47
|
-
|
|
47
|
+
const shouldSkip = shouldSkipRequest(action, req, namespaces, config?.alwaysIgnore?.namespaces);
|
|
48
|
+
if (shouldSkip !== "") {
|
|
49
|
+
Log.debug(shouldSkip);
|
|
48
50
|
continue;
|
|
49
51
|
}
|
|
50
52
|
|