pepr 0.35.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/logger.d.ts +1 -1
- package/dist/lib/logger.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/queue.d.ts +19 -3
- package/dist/lib/queue.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 +118 -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 +8 -6
- package/dist/lib/watch-processor.d.ts.map +1 -1
- package/dist/lib.js +467 -233
- package/dist/lib.js.map +4 -4
- package/dist/sdk/sdk.d.ts +5 -3
- package/dist/sdk/sdk.d.ts.map +1 -1
- package/package.json +13 -11
- 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 +112 -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 +279 -9
- package/src/lib/filter.ts +46 -98
- package/src/lib/finalizer.test.ts +236 -0
- package/src/lib/finalizer.ts +63 -0
- package/src/lib/helpers.test.ts +359 -65
- package/src/lib/helpers.ts +141 -95
- 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/queue.test.ts +138 -44
- package/src/lib/queue.ts +48 -13
- package/src/lib/schedule.ts +1 -1
- package/src/lib/storage.ts +5 -6
- package/src/lib/types.ts +154 -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.test.ts +89 -124
- package/src/lib/watch-processor.ts +52 -35
- package/src/sdk/sdk.test.ts +46 -13
- package/src/sdk/sdk.ts +15 -6
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,62 +1067,189 @@ describe("replaceString", () => {
|
|
|
998
1067
|
});
|
|
999
1068
|
});
|
|
1000
1069
|
|
|
1001
|
-
describe("
|
|
1002
|
-
test("
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
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
|
+
});
|
|
1010
1095
|
});
|
|
1011
1096
|
|
|
1012
|
-
test("
|
|
1013
|
-
|
|
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
|
+
});
|
|
1014
1119
|
});
|
|
1015
1120
|
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
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
|
+
});
|
|
1024
1146
|
});
|
|
1025
1147
|
|
|
1026
|
-
|
|
1027
|
-
|
|
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
|
+
});
|
|
1028
1171
|
});
|
|
1029
1172
|
|
|
1030
|
-
test("
|
|
1031
|
-
|
|
1173
|
+
test("returns namespace filter error for namespace objects with namespace filters", () => {
|
|
1174
|
+
const binding = {
|
|
1175
|
+
kind: { kind: "Namespace" },
|
|
1176
|
+
filters: { namespaces: ["ns1"] },
|
|
1177
|
+
};
|
|
1178
|
+
const obj = {};
|
|
1179
|
+
const capabilityNamespaces: string[] = [];
|
|
1180
|
+
const result = filterNoMatchReason(
|
|
1181
|
+
binding as unknown as Partial<Binding>,
|
|
1182
|
+
obj as unknown as Partial<KubernetesObject>,
|
|
1183
|
+
capabilityNamespaces,
|
|
1184
|
+
);
|
|
1185
|
+
expect(result).toEqual("Ignoring Watch Callback: Cannot use namespace filter on a namespace object.");
|
|
1032
1186
|
});
|
|
1033
1187
|
|
|
1034
|
-
test("
|
|
1035
|
-
|
|
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("");
|
|
1036
1219
|
});
|
|
1037
1220
|
|
|
1038
|
-
test("
|
|
1039
|
-
|
|
1221
|
+
test("return deletionTimestamp error when there is no deletionTimestamp in the object", () => {
|
|
1222
|
+
const binding = {
|
|
1223
|
+
filters: { deletionTimestamp: true },
|
|
1224
|
+
};
|
|
1225
|
+
const obj = {
|
|
1226
|
+
metadata: {},
|
|
1227
|
+
};
|
|
1228
|
+
const capabilityNamespaces: string[] = [];
|
|
1229
|
+
const result = filterNoMatchReason(
|
|
1230
|
+
binding as unknown as Partial<Binding>,
|
|
1231
|
+
obj as unknown as Partial<KubernetesObject>,
|
|
1232
|
+
capabilityNamespaces,
|
|
1233
|
+
);
|
|
1234
|
+
expect(result).toEqual("Ignoring Watch Callback: Binding defines deletionTimestamp but Object does not carry it.");
|
|
1040
1235
|
});
|
|
1041
|
-
});
|
|
1042
1236
|
|
|
1043
|
-
|
|
1044
|
-
test("returns namespace filter error for namespace objects with namespace filters", () => {
|
|
1237
|
+
test("return no deletionTimestamp error when there is a deletionTimestamp in the object", () => {
|
|
1045
1238
|
const binding = {
|
|
1046
|
-
|
|
1047
|
-
|
|
1239
|
+
filters: { deletionTimestamp: true },
|
|
1240
|
+
};
|
|
1241
|
+
const obj = {
|
|
1242
|
+
metadata: {
|
|
1243
|
+
deletionTimestamp: "2021-01-01T00:00:00Z",
|
|
1244
|
+
},
|
|
1048
1245
|
};
|
|
1049
|
-
const obj = {};
|
|
1050
1246
|
const capabilityNamespaces: string[] = [];
|
|
1051
1247
|
const result = filterNoMatchReason(
|
|
1052
1248
|
binding as unknown as Partial<Binding>,
|
|
1053
1249
|
obj as unknown as Partial<KubernetesObject>,
|
|
1054
1250
|
capabilityNamespaces,
|
|
1055
1251
|
);
|
|
1056
|
-
expect(result).toEqual("Ignoring Watch Callback:
|
|
1252
|
+
expect(result).not.toEqual("Ignoring Watch Callback: Binding defines deletionTimestamp Object does not carry it.");
|
|
1057
1253
|
});
|
|
1058
1254
|
|
|
1059
1255
|
test("returns label overlap error when there is no overlap between binding and object labels", () => {
|
|
@@ -1070,7 +1266,7 @@ describe("filterMatcher", () => {
|
|
|
1070
1266
|
capabilityNamespaces,
|
|
1071
1267
|
);
|
|
1072
1268
|
expect(result).toEqual(
|
|
1073
|
-
|
|
1269
|
+
`Ignoring Watch Callback: Binding defines labels '{"key":"value"}' but Object carries '{"anotherKey":"anotherValue"}'.`,
|
|
1074
1270
|
);
|
|
1075
1271
|
});
|
|
1076
1272
|
|
|
@@ -1088,29 +1284,48 @@ describe("filterMatcher", () => {
|
|
|
1088
1284
|
capabilityNamespaces,
|
|
1089
1285
|
);
|
|
1090
1286
|
expect(result).toEqual(
|
|
1091
|
-
|
|
1287
|
+
`Ignoring Watch Callback: Binding defines annotations '{"key":"value"}' but Object carries '{"anotherKey":"anotherValue"}'.`,
|
|
1092
1288
|
);
|
|
1093
1289
|
});
|
|
1094
1290
|
|
|
1095
1291
|
test("returns capability namespace error when object is not in capability namespaces", () => {
|
|
1096
|
-
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
|
+
|
|
1097
1312
|
const obj = {
|
|
1098
|
-
metadata: { namespace: "ns2" },
|
|
1313
|
+
metadata: { namespace: "ns2", name: "bleh" },
|
|
1099
1314
|
};
|
|
1100
1315
|
const capabilityNamespaces = ["ns1"];
|
|
1101
1316
|
const result = filterNoMatchReason(
|
|
1102
|
-
binding as
|
|
1317
|
+
binding as Binding,
|
|
1103
1318
|
obj as unknown as Partial<KubernetesObject>,
|
|
1104
1319
|
capabilityNamespaces,
|
|
1105
1320
|
);
|
|
1106
1321
|
expect(result).toEqual(
|
|
1107
|
-
|
|
1322
|
+
`Ignoring Watch Callback: Object carries namespace 'ns2' but namespaces allowed by Capability are '["ns1"]'.`,
|
|
1108
1323
|
);
|
|
1109
1324
|
});
|
|
1110
1325
|
|
|
1111
1326
|
test("returns binding namespace error when filter namespace is not part of capability namespaces", () => {
|
|
1112
1327
|
const binding = {
|
|
1113
|
-
filters: { namespaces: ["ns3"] },
|
|
1328
|
+
filters: { namespaces: ["ns3"], regexNamespaces: [] },
|
|
1114
1329
|
};
|
|
1115
1330
|
const obj = {};
|
|
1116
1331
|
const capabilityNamespaces = ["ns1", "ns2"];
|
|
@@ -1120,13 +1335,13 @@ describe("filterMatcher", () => {
|
|
|
1120
1335
|
capabilityNamespaces,
|
|
1121
1336
|
);
|
|
1122
1337
|
expect(result).toEqual(
|
|
1123
|
-
|
|
1338
|
+
`Ignoring Watch Callback: Binding defines namespaces ["ns3"] but namespaces allowed by Capability are '["ns1","ns2"]'.`,
|
|
1124
1339
|
);
|
|
1125
1340
|
});
|
|
1126
1341
|
|
|
1127
1342
|
test("returns binding and object namespace error when they do not overlap", () => {
|
|
1128
1343
|
const binding = {
|
|
1129
|
-
filters: { namespaces: ["ns1"] },
|
|
1344
|
+
filters: { namespaces: ["ns1"], regexNamespaces: [] },
|
|
1130
1345
|
};
|
|
1131
1346
|
const obj = {
|
|
1132
1347
|
metadata: { namespace: "ns2" },
|
|
@@ -1137,8 +1352,26 @@ describe("filterMatcher", () => {
|
|
|
1137
1352
|
obj as unknown as Partial<KubernetesObject>,
|
|
1138
1353
|
capabilityNamespaces,
|
|
1139
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
|
+
);
|
|
1140
1373
|
expect(result).toEqual(
|
|
1141
|
-
|
|
1374
|
+
`Ignoring Watch Callback: Object carries namespace 'ns3' but ignored namespaces include '["ns3"]'.`,
|
|
1142
1375
|
);
|
|
1143
1376
|
});
|
|
1144
1377
|
|
|
@@ -1190,3 +1423,64 @@ describe("validateHash", () => {
|
|
|
1190
1423
|
expect(() => validateHash(validHash)).not.toThrow();
|
|
1191
1424
|
});
|
|
1192
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
|
+
});
|