pepr 0.13.0 → 0.13.1
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 +37 -28
- package/dist/controller.js +1 -1
- package/dist/lib/assets/index.d.ts +5 -6
- package/dist/lib/assets/index.d.ts.map +1 -1
- package/dist/lib/assets/loader.d.ts +2 -8
- package/dist/lib/assets/loader.d.ts.map +1 -1
- package/dist/lib/capability.d.ts +4 -7
- package/dist/lib/capability.d.ts.map +1 -1
- package/dist/lib/controller.d.ts +3 -49
- package/dist/lib/controller.d.ts.map +1 -1
- package/dist/lib/errors.d.ts +12 -0
- package/dist/lib/errors.d.ts.map +1 -0
- package/dist/lib/k8s/types.d.ts +5 -1
- package/dist/lib/k8s/types.d.ts.map +1 -1
- package/dist/lib/metrics.d.ts +6 -12
- package/dist/lib/metrics.d.ts.map +1 -1
- package/dist/lib/module.d.ts +2 -2
- package/dist/lib/module.d.ts.map +1 -1
- package/dist/lib/mutate-processor.d.ts.map +1 -1
- package/dist/lib/mutate-request.d.ts +2 -2
- package/dist/lib/mutate-request.d.ts.map +1 -1
- package/dist/lib/types.d.ts +3 -9
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/lib/validate-processor.d.ts.map +1 -1
- package/dist/lib/validate-request.d.ts +2 -2
- package/dist/lib/validate-request.d.ts.map +1 -1
- package/dist/lib.js +247 -191
- package/dist/lib.js.map +3 -3
- package/jest.config.json +4 -0
- package/journey/before.ts +21 -0
- package/journey/k8s.ts +81 -0
- package/journey/pepr-build.ts +69 -0
- package/journey/pepr-deploy.ts +133 -0
- package/journey/pepr-dev.ts +155 -0
- package/journey/pepr-format.ts +13 -0
- package/journey/pepr-init.ts +12 -0
- package/package.json +20 -21
- package/src/lib/assets/index.ts +15 -8
- package/src/lib/assets/loader.ts +4 -12
- package/src/lib/assets/webhooks.ts +2 -2
- package/src/lib/capability.ts +34 -32
- package/src/lib/controller.ts +111 -93
- package/src/lib/errors.ts +20 -0
- package/src/lib/k8s/types.ts +5 -1
- package/src/lib/metrics.ts +45 -32
- package/src/lib/module.ts +24 -10
- package/src/lib/mutate-processor.ts +5 -3
- package/src/lib/mutate-request.ts +22 -9
- package/src/lib/types.ts +4 -10
- package/src/lib/validate-processor.ts +8 -0
- package/src/lib/validate-request.ts +19 -7
package/src/lib/module.ts
CHANGED
|
@@ -5,8 +5,9 @@ import { clone } from "ramda";
|
|
|
5
5
|
|
|
6
6
|
import { Capability } from "./capability";
|
|
7
7
|
import { Controller } from "./controller";
|
|
8
|
+
import { ValidateError } from "./errors";
|
|
8
9
|
import { MutateResponse, Request, ValidateResponse } from "./k8s/types";
|
|
9
|
-
import { ModuleConfig } from "./types";
|
|
10
|
+
import { CapabilityExport, ModuleConfig } from "./types";
|
|
10
11
|
|
|
11
12
|
export type PackageJSON = {
|
|
12
13
|
description: string;
|
|
@@ -24,33 +25,46 @@ export type PeprModuleOptions = {
|
|
|
24
25
|
};
|
|
25
26
|
|
|
26
27
|
export class PeprModule {
|
|
27
|
-
|
|
28
|
+
#controller!: Controller;
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
31
|
* Create a new Pepr runtime
|
|
31
32
|
*
|
|
32
33
|
* @param config The configuration for the Pepr runtime
|
|
33
34
|
* @param capabilities The capabilities to be loaded into the Pepr runtime
|
|
34
|
-
* @param
|
|
35
|
+
* @param opts Options for the Pepr runtime
|
|
35
36
|
*/
|
|
36
37
|
constructor({ description, pepr }: PackageJSON, capabilities: Capability[] = [], opts: PeprModuleOptions = {}) {
|
|
37
38
|
const config: ModuleConfig = clone(pepr);
|
|
38
39
|
config.description = description;
|
|
39
40
|
|
|
40
41
|
// Need to validate at runtime since TS gets sad about parsing the package.json
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
42
|
+
ValidateError(config.onError);
|
|
43
|
+
|
|
44
|
+
// Bind public methods
|
|
45
|
+
this.start = this.start.bind(this);
|
|
45
46
|
|
|
46
47
|
// Handle build mode
|
|
47
48
|
if (process.env.PEPR_MODE === "build" && process.send) {
|
|
49
|
+
const exportedCapabilities: CapabilityExport[] = [];
|
|
50
|
+
|
|
48
51
|
// Send capability map to parent process
|
|
49
|
-
|
|
52
|
+
for (const capability of capabilities) {
|
|
53
|
+
// Convert the capability to a capability config
|
|
54
|
+
exportedCapabilities.push({
|
|
55
|
+
name: capability.name,
|
|
56
|
+
description: capability.description,
|
|
57
|
+
namespaces: capability.namespaces,
|
|
58
|
+
bindings: capability.bindings,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
process.send(exportedCapabilities);
|
|
63
|
+
|
|
50
64
|
return;
|
|
51
65
|
}
|
|
52
66
|
|
|
53
|
-
this
|
|
67
|
+
this.#controller = new Controller(config, capabilities, opts.beforeHook, opts.afterHook);
|
|
54
68
|
|
|
55
69
|
// Stop processing if deferStart is set to true
|
|
56
70
|
if (opts.deferStart) {
|
|
@@ -67,6 +81,6 @@ export class PeprModule {
|
|
|
67
81
|
* @param port
|
|
68
82
|
*/
|
|
69
83
|
start(port = 3000) {
|
|
70
|
-
this.
|
|
84
|
+
this.#controller.startServer(port);
|
|
71
85
|
}
|
|
72
86
|
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import jsonPatch from "fast-json-patch";
|
|
5
5
|
|
|
6
6
|
import { Capability } from "./capability";
|
|
7
|
+
import { Errors } from "./errors";
|
|
7
8
|
import { shouldSkipRequest } from "./filter";
|
|
8
9
|
import { MutateResponse, Request } from "./k8s/types";
|
|
9
10
|
import { Secret } from "./k8s/upstream";
|
|
@@ -91,13 +92,14 @@ export async function mutateProcessor(
|
|
|
91
92
|
response.warnings.push(`Action failed: ${e}`);
|
|
92
93
|
|
|
93
94
|
switch (config.onError) {
|
|
94
|
-
case
|
|
95
|
+
case Errors.reject:
|
|
95
96
|
Log.error(actionMetadata, `Action failed: ${e}`);
|
|
96
97
|
response.result = "Pepr module configured to reject on error";
|
|
97
98
|
return response;
|
|
98
99
|
|
|
99
|
-
case
|
|
100
|
-
|
|
100
|
+
case Errors.audit:
|
|
101
|
+
response.auditAnnotations = response.auditAnnotations || {};
|
|
102
|
+
response.auditAnnotations[Date.now()] = e;
|
|
101
103
|
break;
|
|
102
104
|
}
|
|
103
105
|
}
|
|
@@ -11,10 +11,12 @@ import { DeepPartial } from "./types";
|
|
|
11
11
|
* of a mutating webhook request.
|
|
12
12
|
*/
|
|
13
13
|
export class PeprMutateRequest<T extends KubernetesObject> {
|
|
14
|
-
|
|
14
|
+
Raw: T;
|
|
15
|
+
|
|
16
|
+
#input: Request<T>;
|
|
15
17
|
|
|
16
18
|
get PermitSideEffects() {
|
|
17
|
-
return !this.
|
|
19
|
+
return !this.#input.dryRun;
|
|
18
20
|
}
|
|
19
21
|
|
|
20
22
|
/**
|
|
@@ -22,7 +24,7 @@ export class PeprMutateRequest<T extends KubernetesObject> {
|
|
|
22
24
|
* @returns true if the request is a dry run, false otherwise.
|
|
23
25
|
*/
|
|
24
26
|
get IsDryRun() {
|
|
25
|
-
return this.
|
|
27
|
+
return this.#input.dryRun;
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
/**
|
|
@@ -30,7 +32,7 @@ export class PeprMutateRequest<T extends KubernetesObject> {
|
|
|
30
32
|
* @returns The old Kubernetes resource object or null if not available.
|
|
31
33
|
*/
|
|
32
34
|
get OldResource() {
|
|
33
|
-
return this.
|
|
35
|
+
return this.#input.oldObject;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
/**
|
|
@@ -38,20 +40,31 @@ export class PeprMutateRequest<T extends KubernetesObject> {
|
|
|
38
40
|
* @returns The request object containing the Kubernetes resource.
|
|
39
41
|
*/
|
|
40
42
|
get Request() {
|
|
41
|
-
return this
|
|
43
|
+
return this.#input;
|
|
42
44
|
}
|
|
43
45
|
|
|
44
46
|
/**
|
|
45
47
|
* Creates a new instance of the action class.
|
|
46
48
|
* @param input - The request object containing the Kubernetes resource to modify.
|
|
47
49
|
*/
|
|
48
|
-
constructor(
|
|
50
|
+
constructor(input: Request<T>) {
|
|
51
|
+
this.#input = input;
|
|
52
|
+
|
|
53
|
+
// Bind public methods
|
|
54
|
+
this.Merge = this.Merge.bind(this);
|
|
55
|
+
this.SetLabel = this.SetLabel.bind(this);
|
|
56
|
+
this.SetAnnotation = this.SetAnnotation.bind(this);
|
|
57
|
+
this.RemoveLabel = this.RemoveLabel.bind(this);
|
|
58
|
+
this.RemoveAnnotation = this.RemoveAnnotation.bind(this);
|
|
59
|
+
this.HasLabel = this.HasLabel.bind(this);
|
|
60
|
+
this.HasAnnotation = this.HasAnnotation.bind(this);
|
|
61
|
+
|
|
49
62
|
// If this is a DELETE operation, use the oldObject instead
|
|
50
|
-
if (
|
|
51
|
-
this.Raw = clone(
|
|
63
|
+
if (input.operation.toUpperCase() === Operation.DELETE) {
|
|
64
|
+
this.Raw = clone(input.oldObject as T);
|
|
52
65
|
} else {
|
|
53
66
|
// Otherwise, use the incoming object
|
|
54
|
-
this.Raw = clone(
|
|
67
|
+
this.Raw = clone(input.object);
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
if (!this.Raw) {
|
package/src/lib/types.ts
CHANGED
|
@@ -10,16 +10,6 @@ export type PackageJSON = {
|
|
|
10
10
|
pepr: ModuleConfig;
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
/**
|
|
14
|
-
* The phase of the Kubernetes admission webhook that the capability is registered for.
|
|
15
|
-
*
|
|
16
|
-
* Currently only `mutate` is supported.
|
|
17
|
-
*/
|
|
18
|
-
export enum HookPhase {
|
|
19
|
-
mutate = "mutate",
|
|
20
|
-
validate = "validate",
|
|
21
|
-
}
|
|
22
|
-
|
|
23
13
|
/**
|
|
24
14
|
* Recursively make all properties in T optional.
|
|
25
15
|
*/
|
|
@@ -54,6 +44,10 @@ export interface CapabilityCfg {
|
|
|
54
44
|
namespaces?: string[];
|
|
55
45
|
}
|
|
56
46
|
|
|
47
|
+
export interface CapabilityExport extends CapabilityCfg {
|
|
48
|
+
bindings: Binding[];
|
|
49
|
+
}
|
|
50
|
+
|
|
57
51
|
export type ModuleSigning = {
|
|
58
52
|
/**
|
|
59
53
|
* Specifies the signing policy.
|
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
import { Capability } from "./capability";
|
|
5
5
|
import { shouldSkipRequest } from "./filter";
|
|
6
6
|
import { Request, ValidateResponse } from "./k8s/types";
|
|
7
|
+
import { Secret } from "./k8s/upstream";
|
|
7
8
|
import Log from "./logger";
|
|
9
|
+
import { convertFromBase64Map } from "./utils";
|
|
8
10
|
import { PeprValidateRequest } from "./validate-request";
|
|
9
11
|
|
|
10
12
|
export async function validateProcessor(
|
|
@@ -18,6 +20,12 @@ export async function validateProcessor(
|
|
|
18
20
|
allowed: true, // Assume it's allowed until a validation check fails
|
|
19
21
|
};
|
|
20
22
|
|
|
23
|
+
// If the resource is a secret, decode the data
|
|
24
|
+
const isSecret = req.kind.version == "v1" && req.kind.kind == "Secret";
|
|
25
|
+
if (isSecret) {
|
|
26
|
+
convertFromBase64Map(wrapped.Raw as unknown as Secret);
|
|
27
|
+
}
|
|
28
|
+
|
|
21
29
|
Log.info(reqMetadata, `Processing validation request`);
|
|
22
30
|
|
|
23
31
|
for (const { name, bindings } of capabilities) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// SPDX-License-Identifier: Apache-2.0
|
|
2
2
|
// SPDX-FileCopyrightText: 2023-Present The Pepr Authors
|
|
3
3
|
|
|
4
|
+
/* eslint-disable class-methods-use-this */
|
|
5
|
+
|
|
4
6
|
import { clone } from "ramda";
|
|
5
7
|
import { KubernetesObject, Operation, Request } from "./k8s/types";
|
|
6
8
|
import { ValidateResponse } from "./types";
|
|
@@ -10,14 +12,16 @@ import { ValidateResponse } from "./types";
|
|
|
10
12
|
* of a mutating webhook request.
|
|
11
13
|
*/
|
|
12
14
|
export class PeprValidateRequest<T extends KubernetesObject> {
|
|
13
|
-
|
|
15
|
+
Raw: T;
|
|
16
|
+
|
|
17
|
+
#input: Request<T>;
|
|
14
18
|
|
|
15
19
|
/**
|
|
16
20
|
* Provides access to the old resource in the request if available.
|
|
17
21
|
* @returns The old Kubernetes resource object or null if not available.
|
|
18
22
|
*/
|
|
19
23
|
get OldResource() {
|
|
20
|
-
return this.
|
|
24
|
+
return this.#input.oldObject;
|
|
21
25
|
}
|
|
22
26
|
|
|
23
27
|
/**
|
|
@@ -25,20 +29,28 @@ export class PeprValidateRequest<T extends KubernetesObject> {
|
|
|
25
29
|
* @returns The request object containing the Kubernetes resource.
|
|
26
30
|
*/
|
|
27
31
|
get Request() {
|
|
28
|
-
return this
|
|
32
|
+
return this.#input;
|
|
29
33
|
}
|
|
30
34
|
|
|
31
35
|
/**
|
|
32
36
|
* Creates a new instance of the Action class.
|
|
33
37
|
* @param input - The request object containing the Kubernetes resource to modify.
|
|
34
38
|
*/
|
|
35
|
-
constructor(
|
|
39
|
+
constructor(input: Request<T>) {
|
|
40
|
+
this.#input = input;
|
|
41
|
+
|
|
42
|
+
// Bind public methods to this instance
|
|
43
|
+
this.HasLabel = this.HasLabel.bind(this);
|
|
44
|
+
this.HasAnnotation = this.HasAnnotation.bind(this);
|
|
45
|
+
this.Approve = this.Approve.bind(this);
|
|
46
|
+
this.Deny = this.Deny.bind(this);
|
|
47
|
+
|
|
36
48
|
// If this is a DELETE operation, use the oldObject instead
|
|
37
|
-
if (
|
|
38
|
-
this.Raw = clone(
|
|
49
|
+
if (input.operation.toUpperCase() === Operation.DELETE) {
|
|
50
|
+
this.Raw = clone(input.oldObject as T);
|
|
39
51
|
} else {
|
|
40
52
|
// Otherwise, use the incoming object
|
|
41
|
-
this.Raw = clone(
|
|
53
|
+
this.Raw = clone(input.object);
|
|
42
54
|
}
|
|
43
55
|
|
|
44
56
|
if (!this.Raw) {
|