pepr 0.36.0 → 0.37.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.
- package/dist/cli/init/index.d.ts.map +1 -1
- package/dist/cli/init/templates.d.ts +3 -1
- package/dist/cli/init/templates.d.ts.map +1 -1
- package/dist/cli/init/utils.d.ts.map +1 -1
- package/dist/cli/init/walkthrough.d.ts +10 -3
- package/dist/cli/init/walkthrough.d.ts.map +1 -1
- package/dist/cli.js +253 -31
- package/dist/controller.js +138 -1
- package/dist/lib/adjudicators.d.ts +63 -0
- package/dist/lib/adjudicators.d.ts.map +1 -0
- package/dist/lib/adjudicators.test.d.ts +2 -0
- package/dist/lib/adjudicators.test.d.ts.map +1 -0
- package/dist/lib/assets/loader.d.ts.map +1 -1
- package/dist/lib/assets/pods.d.ts +1 -0
- package/dist/lib/assets/pods.d.ts.map +1 -1
- package/dist/lib/capability.d.ts +1 -0
- package/dist/lib/capability.d.ts.map +1 -1
- package/dist/lib/capability.test.d.ts +2 -0
- package/dist/lib/capability.test.d.ts.map +1 -0
- package/dist/lib/controller/index.d.ts.map +1 -1
- package/dist/lib/controller/store.d.ts +4 -0
- package/dist/lib/controller/store.d.ts.map +1 -1
- package/dist/lib/controller/store.test.d.ts +2 -0
- package/dist/lib/controller/store.test.d.ts.map +1 -0
- package/dist/lib/filter.d.ts +2 -3
- package/dist/lib/filter.d.ts.map +1 -1
- package/dist/lib/filter.test.d.ts +2 -1
- package/dist/lib/filter.test.d.ts.map +1 -1
- package/dist/lib/finalizer.d.ts +6 -0
- package/dist/lib/finalizer.d.ts.map +1 -0
- package/dist/lib/finalizer.test.d.ts +2 -0
- package/dist/lib/finalizer.test.d.ts.map +1 -0
- package/dist/lib/helpers.d.ts +2 -2
- package/dist/lib/helpers.d.ts.map +1 -1
- package/dist/lib/helpers.test.d.ts +1 -1
- package/dist/lib/helpers.test.d.ts.map +1 -1
- package/dist/lib/k8s.d.ts.map +1 -1
- package/dist/lib/module.d.ts +2 -1
- package/dist/lib/module.d.ts.map +1 -1
- package/dist/lib/mutate-processor.d.ts +2 -1
- package/dist/lib/mutate-processor.d.ts.map +1 -1
- package/dist/lib/mutate-request.d.ts +1 -2
- package/dist/lib/mutate-request.d.ts.map +1 -1
- package/dist/lib/schedule.d.ts +1 -2
- package/dist/lib/schedule.d.ts.map +1 -1
- package/dist/lib/storage.d.ts.map +1 -1
- package/dist/lib/types.d.ts +115 -6
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/validate-processor.d.ts +4 -2
- package/dist/lib/validate-processor.d.ts.map +1 -1
- package/dist/lib/validate-request.d.ts +1 -1
- package/dist/lib/validate-request.d.ts.map +1 -1
- package/dist/lib/watch-processor.d.ts +1 -1
- package/dist/lib/watch-processor.d.ts.map +1 -1
- package/dist/lib.js +383 -204
- package/dist/lib.js.map +4 -4
- package/package.json +9 -7
- package/src/cli/build.ts +3 -3
- package/src/cli/init/index.ts +20 -11
- package/src/cli/init/templates.ts +1 -1
- package/src/cli/init/utils.test.ts +11 -20
- package/src/cli/init/utils.ts +5 -0
- package/src/cli/init/walkthrough.test.ts +92 -11
- package/src/cli/init/walkthrough.ts +71 -16
- package/src/cli/monitor.ts +1 -1
- package/src/cli.ts +4 -2
- package/src/fixtures/data/create-pod.json +1 -1
- package/src/fixtures/data/delete-pod.json +1 -1
- package/src/lib/adjudicators.test.ts +1232 -0
- package/src/lib/adjudicators.ts +235 -0
- package/src/lib/assets/index.ts +1 -1
- package/src/lib/assets/loader.ts +1 -0
- package/src/lib/assets/webhooks.ts +1 -1
- package/src/lib/capability.test.ts +655 -0
- package/src/lib/capability.ts +104 -11
- package/src/lib/controller/index.ts +7 -4
- package/src/lib/controller/store.test.ts +131 -0
- package/src/lib/controller/store.ts +43 -5
- package/src/lib/filter.test.ts +194 -8
- package/src/lib/filter.ts +46 -107
- package/src/lib/finalizer.test.ts +236 -0
- package/src/lib/finalizer.ts +63 -0
- package/src/lib/helpers.test.ts +329 -69
- package/src/lib/helpers.ts +141 -100
- package/src/lib/k8s.ts +4 -0
- package/src/lib/module.ts +3 -3
- package/src/lib/mutate-processor.ts +5 -4
- package/src/lib/mutate-request.test.ts +1 -2
- package/src/lib/mutate-request.ts +1 -3
- package/src/lib/schedule.ts +1 -1
- package/src/lib/storage.ts +5 -6
- package/src/lib/types.ts +151 -5
- package/src/lib/validate-processor.ts +5 -2
- package/src/lib/validate-request.test.ts +1 -4
- package/src/lib/validate-request.ts +1 -1
- package/src/lib/watch-processor.ts +19 -5
package/src/lib/helpers.test.ts
CHANGED
|
@@ -1,37 +1,38 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors
|
|
3
3
|
|
|
4
|
-
import { Binding, CapabilityExport } from "./types";
|
|
4
|
+
import { Binding, CapabilityExport, Event } from "./types";
|
|
5
5
|
import {
|
|
6
|
-
createRBACMap,
|
|
7
6
|
addVerbIfNotExists,
|
|
8
|
-
|
|
7
|
+
bindingAndCapabilityNSConflict,
|
|
8
|
+
createDirectoryIfNotExists,
|
|
9
|
+
createRBACMap,
|
|
10
|
+
checkDeploymentStatus,
|
|
9
11
|
filterNoMatchReason,
|
|
12
|
+
dedent,
|
|
13
|
+
generateWatchNamespaceError,
|
|
14
|
+
hasAnyOverlap,
|
|
15
|
+
hasEveryOverlap,
|
|
16
|
+
ignoredNamespaceConflict,
|
|
17
|
+
matchesRegex,
|
|
18
|
+
namespaceDeploymentsReady,
|
|
19
|
+
namespaceComplianceValidator,
|
|
20
|
+
parseTimeout,
|
|
21
|
+
replaceString,
|
|
22
|
+
secretOverLimit,
|
|
10
23
|
validateHash,
|
|
11
|
-
ValidationError,
|
|
12
24
|
validateCapabilityNames,
|
|
25
|
+
ValidationError,
|
|
13
26
|
} from "./helpers";
|
|
14
27
|
import { sanitizeResourceName } from "../sdk/sdk";
|
|
15
28
|
import * as fc from "fast-check";
|
|
16
29
|
import { expect, describe, test, jest, beforeEach, afterEach } from "@jest/globals";
|
|
17
|
-
import { parseTimeout, secretOverLimit, replaceString } from "./helpers";
|
|
18
30
|
import { promises as fs } from "fs";
|
|
19
|
-
|
|
20
|
-
import {
|
|
21
|
-
createDirectoryIfNotExists,
|
|
22
|
-
hasAnyOverlap,
|
|
23
|
-
hasEveryOverlap,
|
|
24
|
-
ignoredNamespaceConflict,
|
|
25
|
-
bindingAndCapabilityNSConflict,
|
|
26
|
-
generateWatchNamespaceError,
|
|
27
|
-
namespaceComplianceValidator,
|
|
28
|
-
dedent,
|
|
29
|
-
} from "./helpers";
|
|
30
31
|
import { SpiedFunction } from "jest-mock";
|
|
31
|
-
|
|
32
|
-
import { K8s, GenericClass, KubernetesObject } from "kubernetes-fluent-client";
|
|
32
|
+
import { K8s, GenericClass, KubernetesObject, kind } from "kubernetes-fluent-client";
|
|
33
33
|
import { K8sInit } from "kubernetes-fluent-client/dist/fluent/types";
|
|
34
|
-
|
|
34
|
+
|
|
35
|
+
export const callback = () => undefined;
|
|
35
36
|
|
|
36
37
|
jest.mock("kubernetes-fluent-client", () => {
|
|
37
38
|
return {
|
|
@@ -336,6 +337,7 @@ describe("validateCapabilityNames", () => {
|
|
|
336
337
|
expect(validateCapabilityNames(undefined)).toBe(undefined);
|
|
337
338
|
});
|
|
338
339
|
});
|
|
340
|
+
|
|
339
341
|
describe("createRBACMap", () => {
|
|
340
342
|
test("should return the correct RBACMap for given capabilities", () => {
|
|
341
343
|
const result = createRBACMap(mockCapabilities);
|
|
@@ -606,8 +608,75 @@ describe("namespaceComplianceValidator", () => {
|
|
|
606
608
|
afterEach(() => {
|
|
607
609
|
errorSpy.mockRestore();
|
|
608
610
|
});
|
|
609
|
-
|
|
610
|
-
|
|
611
|
+
test("should throw error for invalid regex namespaces", () => {
|
|
612
|
+
const nsViolationCapability: CapabilityExport = {
|
|
613
|
+
...nonNsViolation[0],
|
|
614
|
+
bindings: nonNsViolation[0].bindings.map(binding => ({
|
|
615
|
+
...binding,
|
|
616
|
+
filters: {
|
|
617
|
+
...binding.filters,
|
|
618
|
+
namespaces: [],
|
|
619
|
+
regexNamespaces: [new RegExp(/^system/).source],
|
|
620
|
+
},
|
|
621
|
+
})),
|
|
622
|
+
};
|
|
623
|
+
expect(() => {
|
|
624
|
+
namespaceComplianceValidator(nsViolationCapability);
|
|
625
|
+
}).toThrowError(
|
|
626
|
+
`Ignoring Watch Callback: Object namespace does not match any capability namespace with regex ${nsViolationCapability.bindings[0].filters.regexNamespaces[0]}.`,
|
|
627
|
+
);
|
|
628
|
+
});
|
|
629
|
+
test("should not throw an error for valid regex namespaces", () => {
|
|
630
|
+
const nonnsViolationCapability: CapabilityExport = {
|
|
631
|
+
...nonNsViolation[0],
|
|
632
|
+
bindings: nonNsViolation[0].bindings.map(binding => ({
|
|
633
|
+
...binding,
|
|
634
|
+
filters: {
|
|
635
|
+
...binding.filters,
|
|
636
|
+
namespaces: [],
|
|
637
|
+
regexNamespaces: [new RegExp(/^mia/).source],
|
|
638
|
+
},
|
|
639
|
+
})),
|
|
640
|
+
};
|
|
641
|
+
expect(() => {
|
|
642
|
+
namespaceComplianceValidator(nonnsViolationCapability);
|
|
643
|
+
}).not.toThrow();
|
|
644
|
+
});
|
|
645
|
+
test("should throw error for invalid regex ignored namespaces", () => {
|
|
646
|
+
const nsViolationCapability: CapabilityExport = {
|
|
647
|
+
...nonNsViolation[0],
|
|
648
|
+
bindings: nonNsViolation[0].bindings.map(binding => ({
|
|
649
|
+
...binding,
|
|
650
|
+
filters: {
|
|
651
|
+
...binding.filters,
|
|
652
|
+
namespaces: [],
|
|
653
|
+
regexNamespaces: [new RegExp(/^mia/).source],
|
|
654
|
+
},
|
|
655
|
+
})),
|
|
656
|
+
};
|
|
657
|
+
expect(() => {
|
|
658
|
+
namespaceComplianceValidator(nsViolationCapability, ["miami"]);
|
|
659
|
+
}).toThrowError(
|
|
660
|
+
`Ignoring Watch Callback: Regex namespace: ${nsViolationCapability.bindings[0].filters.regexNamespaces[0]}, is an ignored namespace: miami.`,
|
|
661
|
+
);
|
|
662
|
+
});
|
|
663
|
+
test("should not throw an error for valid regex ignored namespaces", () => {
|
|
664
|
+
const nonnsViolationCapability: CapabilityExport = {
|
|
665
|
+
...nonNsViolation[0],
|
|
666
|
+
bindings: nonNsViolation[0].bindings.map(binding => ({
|
|
667
|
+
...binding,
|
|
668
|
+
filters: {
|
|
669
|
+
...binding.filters,
|
|
670
|
+
namespaces: [],
|
|
671
|
+
regexNamespaces: [new RegExp(/^mia/).source],
|
|
672
|
+
},
|
|
673
|
+
})),
|
|
674
|
+
};
|
|
675
|
+
expect(() => {
|
|
676
|
+
namespaceComplianceValidator(nonnsViolationCapability, ["Seattle"]);
|
|
677
|
+
}).not.toThrow();
|
|
678
|
+
});
|
|
679
|
+
test("should not throw an error for valid namespaces", () => {
|
|
611
680
|
expect(() => {
|
|
612
681
|
namespaceComplianceValidator(nonNsViolation[0]);
|
|
613
682
|
}).not.toThrow();
|
|
@@ -998,49 +1067,109 @@ describe("replaceString", () => {
|
|
|
998
1067
|
});
|
|
999
1068
|
});
|
|
1000
1069
|
|
|
1001
|
-
describe("
|
|
1002
|
-
test("
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
test("should return false if there is no overlap", () => {
|
|
1027
|
-
expect(checkOverlap({ key1: "value1" }, { key2: "value2" })).toBe(false);
|
|
1070
|
+
describe("filterNoMatchReason", () => {
|
|
1071
|
+
test("returns regex namespace filter error for Pods whos namespace does not match the regex", () => {
|
|
1072
|
+
const binding = {
|
|
1073
|
+
kind: { kind: "Pod" },
|
|
1074
|
+
filters: { regexNamespaces: ["(.*)-system"], namespaces: [] },
|
|
1075
|
+
};
|
|
1076
|
+
const obj = { metadata: { namespace: "pepr-demo" } };
|
|
1077
|
+
const objArray = [
|
|
1078
|
+
{ ...obj },
|
|
1079
|
+
{ ...obj, metadata: { namespace: "pepr-uds" } },
|
|
1080
|
+
{ ...obj, metadata: { namespace: "pepr-core" } },
|
|
1081
|
+
{ ...obj, metadata: { namespace: "uds-ns" } },
|
|
1082
|
+
{ ...obj, metadata: { namespace: "uds" } },
|
|
1083
|
+
];
|
|
1084
|
+
const capabilityNamespaces: string[] = [];
|
|
1085
|
+
objArray.map(object => {
|
|
1086
|
+
const result = filterNoMatchReason(
|
|
1087
|
+
binding as unknown as Partial<Binding>,
|
|
1088
|
+
object as unknown as Partial<KubernetesObject>,
|
|
1089
|
+
capabilityNamespaces,
|
|
1090
|
+
);
|
|
1091
|
+
expect(result).toEqual(
|
|
1092
|
+
`Ignoring Watch Callback: Binding defines namespace regexes '["(.*)-system"]' but Object carries '${object?.metadata?.namespace}'.`,
|
|
1093
|
+
);
|
|
1094
|
+
});
|
|
1028
1095
|
});
|
|
1029
1096
|
|
|
1030
|
-
test("
|
|
1031
|
-
|
|
1097
|
+
test("returns no regex namespace filter error for Pods whos namespace does match the regex", () => {
|
|
1098
|
+
const binding = {
|
|
1099
|
+
kind: { kind: "Pod" },
|
|
1100
|
+
filters: { regexNamespaces: [/(.*)-system/], namespaces: [] },
|
|
1101
|
+
};
|
|
1102
|
+
const obj = { metadata: { namespace: "pepr-demo" } };
|
|
1103
|
+
const objArray = [
|
|
1104
|
+
{ ...obj, metadata: { namespace: "pepr-system" } },
|
|
1105
|
+
{ ...obj, metadata: { namespace: "pepr-uds-system" } },
|
|
1106
|
+
{ ...obj, metadata: { namespace: "uds-system" } },
|
|
1107
|
+
{ ...obj, metadata: { namespace: "some-thing-that-is-a-system" } },
|
|
1108
|
+
{ ...obj, metadata: { namespace: "your-system" } },
|
|
1109
|
+
];
|
|
1110
|
+
const capabilityNamespaces: string[] = [];
|
|
1111
|
+
objArray.map(object => {
|
|
1112
|
+
const result = filterNoMatchReason(
|
|
1113
|
+
binding as unknown as Partial<Binding>,
|
|
1114
|
+
object as unknown as Partial<KubernetesObject>,
|
|
1115
|
+
capabilityNamespaces,
|
|
1116
|
+
);
|
|
1117
|
+
expect(result).toEqual(``);
|
|
1118
|
+
});
|
|
1032
1119
|
});
|
|
1033
1120
|
|
|
1034
|
-
|
|
1035
|
-
|
|
1121
|
+
// Names Fail
|
|
1122
|
+
test("returns regex name filter error for Pods whos name does not match the regex", () => {
|
|
1123
|
+
const binding = {
|
|
1124
|
+
kind: { kind: "Pod" },
|
|
1125
|
+
filters: { regexName: "^system", namespaces: [] },
|
|
1126
|
+
};
|
|
1127
|
+
const obj = { metadata: { name: "pepr-demo" } };
|
|
1128
|
+
const objArray = [
|
|
1129
|
+
{ ...obj },
|
|
1130
|
+
{ ...obj, metadata: { name: "pepr-uds" } },
|
|
1131
|
+
{ ...obj, metadata: { name: "pepr-core" } },
|
|
1132
|
+
{ ...obj, metadata: { name: "uds-ns" } },
|
|
1133
|
+
{ ...obj, metadata: { name: "uds" } },
|
|
1134
|
+
];
|
|
1135
|
+
const capabilityNamespaces: string[] = [];
|
|
1136
|
+
objArray.map(object => {
|
|
1137
|
+
const result = filterNoMatchReason(
|
|
1138
|
+
binding as unknown as Partial<Binding>,
|
|
1139
|
+
object as unknown as Partial<KubernetesObject>,
|
|
1140
|
+
capabilityNamespaces,
|
|
1141
|
+
);
|
|
1142
|
+
expect(result).toEqual(
|
|
1143
|
+
`Ignoring Watch Callback: Binding defines name regex '^system' but Object carries '${object?.metadata?.name}'.`,
|
|
1144
|
+
);
|
|
1145
|
+
});
|
|
1036
1146
|
});
|
|
1037
1147
|
|
|
1038
|
-
|
|
1039
|
-
|
|
1148
|
+
// Names Pass
|
|
1149
|
+
test("returns no regex name filter error for Pods whos name does match the regex", () => {
|
|
1150
|
+
const binding = {
|
|
1151
|
+
kind: { kind: "Pod" },
|
|
1152
|
+
filters: { regexName: /^system/, namespaces: [] },
|
|
1153
|
+
};
|
|
1154
|
+
const obj = { metadata: { name: "pepr-demo" } };
|
|
1155
|
+
const objArray = [
|
|
1156
|
+
{ ...obj, metadata: { name: "systemd" } },
|
|
1157
|
+
{ ...obj, metadata: { name: "systemic" } },
|
|
1158
|
+
{ ...obj, metadata: { name: "system-of-kube-apiserver" } },
|
|
1159
|
+
{ ...obj, metadata: { name: "system" } },
|
|
1160
|
+
{ ...obj, metadata: { name: "system-uds" } },
|
|
1161
|
+
];
|
|
1162
|
+
const capabilityNamespaces: string[] = [];
|
|
1163
|
+
objArray.map(object => {
|
|
1164
|
+
const result = filterNoMatchReason(
|
|
1165
|
+
binding as unknown as Partial<Binding>,
|
|
1166
|
+
object as unknown as Partial<KubernetesObject>,
|
|
1167
|
+
capabilityNamespaces,
|
|
1168
|
+
);
|
|
1169
|
+
expect(result).toEqual(``);
|
|
1170
|
+
});
|
|
1040
1171
|
});
|
|
1041
|
-
});
|
|
1042
1172
|
|
|
1043
|
-
describe("filterMatcher", () => {
|
|
1044
1173
|
test("returns namespace filter error for namespace objects with namespace filters", () => {
|
|
1045
1174
|
const binding = {
|
|
1046
1175
|
kind: { kind: "Namespace" },
|
|
@@ -1053,7 +1182,40 @@ describe("filterMatcher", () => {
|
|
|
1053
1182
|
obj as unknown as Partial<KubernetesObject>,
|
|
1054
1183
|
capabilityNamespaces,
|
|
1055
1184
|
);
|
|
1056
|
-
expect(result).toEqual("Ignoring Watch Callback: Cannot use
|
|
1185
|
+
expect(result).toEqual("Ignoring Watch Callback: Cannot use namespace filter on a namespace object.");
|
|
1186
|
+
});
|
|
1187
|
+
|
|
1188
|
+
test("return an Ignoring Watch Callback string if the binding name and object name are different", () => {
|
|
1189
|
+
const binding = {
|
|
1190
|
+
filters: { name: "pepr" },
|
|
1191
|
+
};
|
|
1192
|
+
const obj = {
|
|
1193
|
+
metadata: {
|
|
1194
|
+
name: "not-pepr",
|
|
1195
|
+
},
|
|
1196
|
+
};
|
|
1197
|
+
const capabilityNamespaces: string[] = [];
|
|
1198
|
+
const result = filterNoMatchReason(
|
|
1199
|
+
binding as unknown as Partial<Binding>,
|
|
1200
|
+
obj as unknown as Partial<KubernetesObject>,
|
|
1201
|
+
capabilityNamespaces,
|
|
1202
|
+
);
|
|
1203
|
+
expect(result).toEqual(`Ignoring Watch Callback: Binding defines name 'pepr' but Object carries 'not-pepr'.`);
|
|
1204
|
+
});
|
|
1205
|
+
test("returns no Ignoring Watch Callback string if the binding name and object name are the same", () => {
|
|
1206
|
+
const binding = {
|
|
1207
|
+
filters: { name: "pepr" },
|
|
1208
|
+
};
|
|
1209
|
+
const obj = {
|
|
1210
|
+
metadata: { name: "pepr" },
|
|
1211
|
+
};
|
|
1212
|
+
const capabilityNamespaces: string[] = [];
|
|
1213
|
+
const result = filterNoMatchReason(
|
|
1214
|
+
binding as unknown as Partial<Binding>,
|
|
1215
|
+
obj as unknown as Partial<KubernetesObject>,
|
|
1216
|
+
capabilityNamespaces,
|
|
1217
|
+
);
|
|
1218
|
+
expect(result).toEqual("");
|
|
1057
1219
|
});
|
|
1058
1220
|
|
|
1059
1221
|
test("return deletionTimestamp error when there is no deletionTimestamp in the object", () => {
|
|
@@ -1069,7 +1231,7 @@ describe("filterMatcher", () => {
|
|
|
1069
1231
|
obj as unknown as Partial<KubernetesObject>,
|
|
1070
1232
|
capabilityNamespaces,
|
|
1071
1233
|
);
|
|
1072
|
-
expect(result).toEqual("Ignoring Watch Callback: Object does not
|
|
1234
|
+
expect(result).toEqual("Ignoring Watch Callback: Binding defines deletionTimestamp but Object does not carry it.");
|
|
1073
1235
|
});
|
|
1074
1236
|
|
|
1075
1237
|
test("return no deletionTimestamp error when there is a deletionTimestamp in the object", () => {
|
|
@@ -1087,7 +1249,7 @@ describe("filterMatcher", () => {
|
|
|
1087
1249
|
obj as unknown as Partial<KubernetesObject>,
|
|
1088
1250
|
capabilityNamespaces,
|
|
1089
1251
|
);
|
|
1090
|
-
expect(result).not.toEqual("Ignoring Watch Callback: Object does not
|
|
1252
|
+
expect(result).not.toEqual("Ignoring Watch Callback: Binding defines deletionTimestamp Object does not carry it.");
|
|
1091
1253
|
});
|
|
1092
1254
|
|
|
1093
1255
|
test("returns label overlap error when there is no overlap between binding and object labels", () => {
|
|
@@ -1104,7 +1266,7 @@ describe("filterMatcher", () => {
|
|
|
1104
1266
|
capabilityNamespaces,
|
|
1105
1267
|
);
|
|
1106
1268
|
expect(result).toEqual(
|
|
1107
|
-
|
|
1269
|
+
`Ignoring Watch Callback: Binding defines labels '{"key":"value"}' but Object carries '{"anotherKey":"anotherValue"}'.`,
|
|
1108
1270
|
);
|
|
1109
1271
|
});
|
|
1110
1272
|
|
|
@@ -1122,29 +1284,48 @@ describe("filterMatcher", () => {
|
|
|
1122
1284
|
capabilityNamespaces,
|
|
1123
1285
|
);
|
|
1124
1286
|
expect(result).toEqual(
|
|
1125
|
-
|
|
1287
|
+
`Ignoring Watch Callback: Binding defines annotations '{"key":"value"}' but Object carries '{"anotherKey":"anotherValue"}'.`,
|
|
1126
1288
|
);
|
|
1127
1289
|
});
|
|
1128
1290
|
|
|
1129
1291
|
test("returns capability namespace error when object is not in capability namespaces", () => {
|
|
1130
|
-
const binding = {
|
|
1292
|
+
const binding = {
|
|
1293
|
+
model: kind.Pod,
|
|
1294
|
+
event: Event.Any,
|
|
1295
|
+
kind: {
|
|
1296
|
+
group: "",
|
|
1297
|
+
version: "v1",
|
|
1298
|
+
kind: "Pod",
|
|
1299
|
+
},
|
|
1300
|
+
filters: {
|
|
1301
|
+
name: "bleh",
|
|
1302
|
+
namespaces: [],
|
|
1303
|
+
regexNamespaces: [],
|
|
1304
|
+
regexName: "",
|
|
1305
|
+
labels: {},
|
|
1306
|
+
annotations: {},
|
|
1307
|
+
deletionTimestamp: false,
|
|
1308
|
+
},
|
|
1309
|
+
callback,
|
|
1310
|
+
};
|
|
1311
|
+
|
|
1131
1312
|
const obj = {
|
|
1132
|
-
metadata: { namespace: "ns2" },
|
|
1313
|
+
metadata: { namespace: "ns2", name: "bleh" },
|
|
1133
1314
|
};
|
|
1134
1315
|
const capabilityNamespaces = ["ns1"];
|
|
1135
1316
|
const result = filterNoMatchReason(
|
|
1136
|
-
binding as
|
|
1317
|
+
binding as Binding,
|
|
1137
1318
|
obj as unknown as Partial<KubernetesObject>,
|
|
1138
1319
|
capabilityNamespaces,
|
|
1139
1320
|
);
|
|
1140
1321
|
expect(result).toEqual(
|
|
1141
|
-
|
|
1322
|
+
`Ignoring Watch Callback: Object carries namespace 'ns2' but namespaces allowed by Capability are '["ns1"]'.`,
|
|
1142
1323
|
);
|
|
1143
1324
|
});
|
|
1144
1325
|
|
|
1145
1326
|
test("returns binding namespace error when filter namespace is not part of capability namespaces", () => {
|
|
1146
1327
|
const binding = {
|
|
1147
|
-
filters: { namespaces: ["ns3"] },
|
|
1328
|
+
filters: { namespaces: ["ns3"], regexNamespaces: [] },
|
|
1148
1329
|
};
|
|
1149
1330
|
const obj = {};
|
|
1150
1331
|
const capabilityNamespaces = ["ns1", "ns2"];
|
|
@@ -1154,13 +1335,13 @@ describe("filterMatcher", () => {
|
|
|
1154
1335
|
capabilityNamespaces,
|
|
1155
1336
|
);
|
|
1156
1337
|
expect(result).toEqual(
|
|
1157
|
-
|
|
1338
|
+
`Ignoring Watch Callback: Binding defines namespaces ["ns3"] but namespaces allowed by Capability are '["ns1","ns2"]'.`,
|
|
1158
1339
|
);
|
|
1159
1340
|
});
|
|
1160
1341
|
|
|
1161
1342
|
test("returns binding and object namespace error when they do not overlap", () => {
|
|
1162
1343
|
const binding = {
|
|
1163
|
-
filters: { namespaces: ["ns1"] },
|
|
1344
|
+
filters: { namespaces: ["ns1"], regexNamespaces: [] },
|
|
1164
1345
|
};
|
|
1165
1346
|
const obj = {
|
|
1166
1347
|
metadata: { namespace: "ns2" },
|
|
@@ -1171,8 +1352,26 @@ describe("filterMatcher", () => {
|
|
|
1171
1352
|
obj as unknown as Partial<KubernetesObject>,
|
|
1172
1353
|
capabilityNamespaces,
|
|
1173
1354
|
);
|
|
1355
|
+
expect(result).toEqual(`Ignoring Watch Callback: Binding defines namespaces '["ns1"]' but Object carries 'ns2'.`);
|
|
1356
|
+
});
|
|
1357
|
+
|
|
1358
|
+
test("return watch violation message when object is in an ignored namespace", () => {
|
|
1359
|
+
const binding = {
|
|
1360
|
+
filters: { namespaces: ["ns3"] },
|
|
1361
|
+
};
|
|
1362
|
+
const obj = {
|
|
1363
|
+
metadata: { namespace: "ns3" },
|
|
1364
|
+
};
|
|
1365
|
+
const capabilityNamespaces = ["ns3"];
|
|
1366
|
+
const ignoredNamespaces = ["ns3"];
|
|
1367
|
+
const result = filterNoMatchReason(
|
|
1368
|
+
binding as unknown as Partial<Binding>,
|
|
1369
|
+
obj as unknown as Partial<KubernetesObject>,
|
|
1370
|
+
capabilityNamespaces,
|
|
1371
|
+
ignoredNamespaces,
|
|
1372
|
+
);
|
|
1174
1373
|
expect(result).toEqual(
|
|
1175
|
-
|
|
1374
|
+
`Ignoring Watch Callback: Object carries namespace 'ns3' but ignored namespaces include '["ns3"]'.`,
|
|
1176
1375
|
);
|
|
1177
1376
|
});
|
|
1178
1377
|
|
|
@@ -1224,3 +1423,64 @@ describe("validateHash", () => {
|
|
|
1224
1423
|
expect(() => validateHash(validHash)).not.toThrow();
|
|
1225
1424
|
});
|
|
1226
1425
|
});
|
|
1426
|
+
|
|
1427
|
+
describe("matchesRegex", () => {
|
|
1428
|
+
test("should return true for a valid pattern that matches the string", () => {
|
|
1429
|
+
const pattern = /abc/;
|
|
1430
|
+
const testString = "abc123";
|
|
1431
|
+
const result = matchesRegex(new RegExp(pattern).source, testString);
|
|
1432
|
+
expect(result).toBe(true);
|
|
1433
|
+
});
|
|
1434
|
+
|
|
1435
|
+
test("should return false for a valid pattern that does not match the string", () => {
|
|
1436
|
+
const pattern = /xyz/;
|
|
1437
|
+
const testString = "abc123";
|
|
1438
|
+
const result = matchesRegex(new RegExp(pattern).source, testString);
|
|
1439
|
+
expect(result).toBe(false);
|
|
1440
|
+
});
|
|
1441
|
+
|
|
1442
|
+
test("should return false for an invalid regex pattern", () => {
|
|
1443
|
+
const invalidPattern = new RegExp(/^p/); // Invalid regex with unclosed bracket
|
|
1444
|
+
const testString = "test";
|
|
1445
|
+
const result = matchesRegex(invalidPattern.source, testString);
|
|
1446
|
+
expect(result).toBe(false);
|
|
1447
|
+
});
|
|
1448
|
+
|
|
1449
|
+
test("should return false when pattern is null or undefined", () => {
|
|
1450
|
+
const testString = "abc123";
|
|
1451
|
+
// Check for undefined
|
|
1452
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1453
|
+
expect(matchesRegex(undefined as any, testString)).toBe(false);
|
|
1454
|
+
// Check for null
|
|
1455
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1456
|
+
expect(matchesRegex(null as any, testString)).toBe(false);
|
|
1457
|
+
});
|
|
1458
|
+
|
|
1459
|
+
test("should return true for an empty string matching an empty regex", () => {
|
|
1460
|
+
const pattern = new RegExp("");
|
|
1461
|
+
const testString = "";
|
|
1462
|
+
const result = matchesRegex(new RegExp(pattern).source, testString);
|
|
1463
|
+
expect(result).toBe(true);
|
|
1464
|
+
});
|
|
1465
|
+
|
|
1466
|
+
test("should return false for an empty string and a non-empty regex", () => {
|
|
1467
|
+
const pattern = new RegExp("abc");
|
|
1468
|
+
const testString = "";
|
|
1469
|
+
const result = matchesRegex(new RegExp(pattern).source, testString);
|
|
1470
|
+
expect(result).toBe(false);
|
|
1471
|
+
});
|
|
1472
|
+
|
|
1473
|
+
test("should return true for a complex valid regex that matches", () => {
|
|
1474
|
+
const pattern = /^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[A-Za-z]+$/;
|
|
1475
|
+
const testString = "test@example.com";
|
|
1476
|
+
const result = matchesRegex(new RegExp(pattern).source, testString);
|
|
1477
|
+
expect(result).toBe(true);
|
|
1478
|
+
});
|
|
1479
|
+
|
|
1480
|
+
test("should return false for a complex valid regex that does not match", () => {
|
|
1481
|
+
const pattern = /^[a-zA-Z0-9]+@[a-zA-Z0-9]+\.[A-Za-z]+$/;
|
|
1482
|
+
const testString = "invalid-email.com";
|
|
1483
|
+
const result = matchesRegex(new RegExp(pattern).source, testString);
|
|
1484
|
+
expect(result).toBe(false);
|
|
1485
|
+
});
|
|
1486
|
+
});
|