pepr 0.1.27 → 0.1.29

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.
Files changed (62) hide show
  1. package/cli.ts +3 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +4 -0
  4. package/dist/index.d.ts +5 -0
  5. package/dist/index.js +14 -0
  6. package/dist/package.json +76 -0
  7. package/dist/src/cli/banner.d.ts +1 -0
  8. package/dist/{pepr-cli.js → src/cli/banner.js} +4 -1251
  9. package/dist/src/cli/build.d.ts +7 -0
  10. package/dist/src/cli/build.js +102 -0
  11. package/dist/src/cli/capability.d.ts +2 -0
  12. package/dist/src/cli/capability.js +15 -0
  13. package/dist/src/cli/deploy.d.ts +2 -0
  14. package/dist/src/cli/deploy.js +55 -0
  15. package/dist/src/cli/dev.d.ts +2 -0
  16. package/dist/src/cli/dev.js +96 -0
  17. package/dist/src/cli/index.d.ts +1 -0
  18. package/dist/src/cli/index.js +33 -0
  19. package/dist/src/cli/init/index.d.ts +2 -0
  20. package/dist/src/cli/init/index.js +54 -0
  21. package/dist/src/cli/init/templates.d.ts +82 -0
  22. package/dist/src/cli/init/templates.js +229 -0
  23. package/dist/src/cli/init/utils.d.ts +20 -0
  24. package/dist/src/cli/init/utils.js +56 -0
  25. package/dist/src/cli/init/walkthrough.d.ts +7 -0
  26. package/dist/src/cli/init/walkthrough.js +84 -0
  27. package/dist/src/cli/root.d.ts +4 -0
  28. package/dist/src/cli/root.js +21 -0
  29. package/dist/src/cli/test.d.ts +2 -0
  30. package/dist/src/cli/test.js +51 -0
  31. package/dist/src/lib/capability.d.ts +26 -0
  32. package/dist/src/lib/capability.js +119 -0
  33. package/dist/src/lib/controller.d.ts +13 -0
  34. package/dist/src/lib/controller.js +84 -0
  35. package/dist/src/lib/filter.d.ts +10 -0
  36. package/dist/src/lib/filter.js +48 -0
  37. package/dist/src/lib/k8s/index.d.ts +4 -0
  38. package/dist/src/lib/k8s/index.js +38 -0
  39. package/dist/src/lib/k8s/kinds.d.ts +3 -0
  40. package/dist/src/lib/k8s/kinds.js +431 -0
  41. package/dist/src/lib/k8s/tls.d.ts +17 -0
  42. package/dist/src/lib/k8s/tls.js +74 -0
  43. package/dist/src/lib/k8s/types.d.ts +136 -0
  44. package/dist/src/lib/k8s/types.js +12 -0
  45. package/dist/src/lib/k8s/upstream.d.ts +1 -0
  46. package/dist/src/lib/k8s/upstream.js +47 -0
  47. package/dist/src/lib/k8s/webhook.d.ts +33 -0
  48. package/dist/src/lib/k8s/webhook.js +497 -0
  49. package/dist/src/lib/logger.d.ts +54 -0
  50. package/dist/{types-1709b44f.js → src/lib/logger.js} +6 -39
  51. package/dist/src/lib/module.d.ts +22 -0
  52. package/dist/src/lib/module.js +39 -0
  53. package/dist/src/lib/processor.d.ts +4 -0
  54. package/dist/src/lib/processor.js +73 -0
  55. package/dist/src/lib/request.d.ts +77 -0
  56. package/dist/src/lib/request.js +144 -0
  57. package/dist/src/lib/types.d.ts +187 -0
  58. package/dist/src/lib/types.js +34 -0
  59. package/package.json +8 -11
  60. package/tsconfig.build.json +4 -0
  61. package/dist/pepr-core.js +0 -949
  62. package/tsconfig.json +0 -17
@@ -0,0 +1,229 @@
1
+ "use strict";
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.capabilitySnippet = exports.capabilityHelloPeprTS = exports.readme = exports.prettierRC = exports.gitIgnore = exports.tsConfig = exports.genPkgJSON = exports.genPeprTS = void 0;
6
+ const util_1 = require("util");
7
+ const uuid_1 = require("uuid");
8
+ const package_json_1 = require("../../../package.json");
9
+ const utils_1 = require("./utils");
10
+ function genPeprTS() {
11
+ return {
12
+ path: "pepr.ts",
13
+ data: `import { PeprModule } from "pepr";
14
+ import cfg from "./package.json";
15
+ import { HelloPepr } from "./capabilities/hello-pepr";
16
+
17
+ /**
18
+ * This is the main entrypoint for the Pepr module. It is the file that is run when the module is started.
19
+ * This is where you register your configurations and capabilities with the module.
20
+ */
21
+ new PeprModule(cfg, [
22
+ // "HelloPepr" is a demo capability that is included with Pepr. You can remove it if you want.
23
+ HelloPepr,
24
+
25
+ // Your additional capabilities go here
26
+ ]);
27
+ `,
28
+ };
29
+ }
30
+ exports.genPeprTS = genPeprTS;
31
+ function genPkgJSON(opts) {
32
+ // Generate a random UUID for the module based on the module name
33
+ const uuid = (0, uuid_1.v5)(opts.name, (0, uuid_1.v4)());
34
+ // Generate a name for the module based on the module name
35
+ const name = (0, utils_1.sanitizeName)(opts.name);
36
+ // Make typescript a dev dependency
37
+ const { typescript } = package_json_1.dependencies;
38
+ const data = {
39
+ name,
40
+ version: "0.0.1",
41
+ description: opts.description,
42
+ keywords: ["pepr", "k8s", "policy-engine", "pepr-module", "security"],
43
+ pepr: {
44
+ name: opts.name.trim(),
45
+ version: package_json_1.version,
46
+ uuid,
47
+ onError: opts.errorBehavior,
48
+ alwaysIgnore: {
49
+ namespaces: [],
50
+ labels: [],
51
+ },
52
+ },
53
+ scripts: {
54
+ build: "pepr build",
55
+ start: "pepr dev",
56
+ },
57
+ dependencies: {
58
+ pepr: `^${package_json_1.version}`,
59
+ },
60
+ devDependencies: {
61
+ typescript,
62
+ },
63
+ };
64
+ return {
65
+ data,
66
+ path: "package.json",
67
+ print: (0, util_1.inspect)(data, false, 5, true),
68
+ };
69
+ }
70
+ exports.genPkgJSON = genPkgJSON;
71
+ exports.tsConfig = {
72
+ path: "tsconfig.json",
73
+ data: {
74
+ compilerOptions: {
75
+ esModuleInterop: true,
76
+ lib: ["ES2020"],
77
+ moduleResolution: "node",
78
+ resolveJsonModule: true,
79
+ rootDir: ".",
80
+ strict: false,
81
+ target: "ES2020",
82
+ },
83
+ include: ["**/*.ts"],
84
+ },
85
+ };
86
+ exports.gitIgnore = {
87
+ path: ".gitignore",
88
+ data: `# Ignore node_modules
89
+ node_modules
90
+ dist
91
+ `,
92
+ };
93
+ exports.prettierRC = {
94
+ path: ".prettierrc",
95
+ data: {
96
+ arrowParens: "avoid",
97
+ bracketSameLine: false,
98
+ bracketSpacing: true,
99
+ embeddedLanguageFormatting: "auto",
100
+ insertPragma: false,
101
+ printWidth: 80,
102
+ quoteProps: "as-needed",
103
+ requirePragma: false,
104
+ semi: true,
105
+ tabWidth: 2,
106
+ useTabs: false,
107
+ },
108
+ };
109
+ exports.readme = {
110
+ path: "README.md",
111
+ data: `# Pepr Module
112
+
113
+ This is a Pepr module. It is a module that can be used with the [Pepr]() framework.
114
+
115
+ The \`capabilities\` directory contains all the capabilities for this module. By default,
116
+ a capability is a single typescript file in the format of \`capability-name.ts\` that is
117
+ imported in the root \`pepr.ts\` file as \`import { HelloPepr } from "./capabilities/hello-pepr";\`.
118
+ Because this is typescript, you can organize this however you choose, e.g. creating a sub-folder
119
+ per-capability or common logic in shared files or folders.
120
+
121
+ Example Structure:
122
+
123
+ \`\`\`
124
+ Module Root
125
+ ├── package.json
126
+ ├── pepr.ts
127
+ └── capabilities
128
+ ├── example-one.ts
129
+ ├── example-three.ts
130
+ └── example-two.ts
131
+ \`\`\`
132
+ `,
133
+ };
134
+ exports.capabilityHelloPeprTS = {
135
+ path: "hello-pepr.ts",
136
+ data: `import { Capability, a } from "pepr";
137
+
138
+ export const HelloPepr = new Capability({
139
+ name: "hello-pepr",
140
+ description: "A simple example capability to show how things work.",
141
+ namespaces: ["pepr-demo"],
142
+ });
143
+
144
+ // Use the 'When' function to create a new Capability Action
145
+ const { When } = HelloPepr;
146
+
147
+ /**
148
+ * This is a single Capability Action. They can be in the same file or put imported from other files.
149
+ * In this exmaple, when a ConfigMap is created with the name \`example-1\`, then add a label and annotation.
150
+ *
151
+ * Equivelant to manually running:
152
+ * \`kubectl label configmap example-1 pepr=was-here\`
153
+ * \`kubectl annotate configmap example-1 pepr.dev=annotations-work-too\`
154
+ */
155
+ When(a.ConfigMap)
156
+ .IsCreated()
157
+ .WithName("example-1")
158
+ .Then(request =>
159
+ request
160
+ .SetLabel("pepr", "was-here")
161
+ .SetAnnotation("pepr.dev", "annotations-work-too")
162
+ );
163
+
164
+ /**
165
+ * This Capabiility Action does the exact same changes for example-2, except this time it uses the \`.ThenSet()\` feature.
166
+ * You can stack multiple \`.Then()\` calls, but only a single \`.ThenSet()\`
167
+ */
168
+ When(a.ConfigMap)
169
+ .IsCreated()
170
+ .WithName("example-2")
171
+ .ThenSet({
172
+ metadata: {
173
+ labels: {
174
+ pepr: "was-here",
175
+ },
176
+ annotations: {
177
+ "pepr.dev": "annotations-work-too",
178
+ },
179
+ },
180
+ });
181
+
182
+ /**
183
+ * This Capability Action combines different styles. Unlike the previous actions, this one will look for any ConfigMap
184
+ * in the \`pepr-demo\` namespace that has the label \`change=by-label\`. Note that all conditions added such as \`WithName()\`,
185
+ * \`WithLabel()\`, \`InNamespace()\`, are ANDs so all conditions must be true for the request to be procssed.
186
+ */
187
+ When(a.ConfigMap)
188
+ .IsCreated()
189
+ .WithLabel("change", "by-label")
190
+ .Then(request => {
191
+ // The K8s object e are going to mutate
192
+ const cm = request.Raw;
193
+
194
+ // Get the username and uid of the K8s reuest
195
+ const { username, uid } = request.Request.userInfo;
196
+
197
+ // Store some data about the request in the configmap
198
+ cm.data["username"] = username;
199
+ cm.data["uid"] = uid;
200
+
201
+ // You can still mix other ways of making changes too
202
+ request.SetAnnotation("pepr.dev", "making-waves");
203
+ });
204
+ `,
205
+ };
206
+ exports.capabilitySnippet = {
207
+ path: "pepr.code-snippets",
208
+ data: `{
209
+ "Create a new Pepr capability": {
210
+ "prefix": "create pepr capability",
211
+ "body": [
212
+ "import { Capability, a } from 'pepr';",
213
+ "",
214
+ "export const $\{TM_FILENAME_BASE/(.*)/$\{1:/pascalcase}/} = new Capability({",
215
+ "\\tname: '$\{TM_FILENAME_BASE}',",
216
+ "\\tdescription: '$\{1:A brief description of this capability.}',",
217
+ "\\tnamespaces: [$\{2:}],",
218
+ "});",
219
+ "",
220
+ "// Use the 'When' function to create a new Capability Action",
221
+ "const { When } = $\{TM_FILENAME_BASE/(.*)/$\{1:/pascalcase}/};",
222
+ "",
223
+ "// When(a.<Kind>).Is<Event>().Then(change => change.<changes>",
224
+ "When($\{3:})"
225
+ ],
226
+ "description": "Creates a new Pepr capability with a specified description, and optional namespaces, and adds a When statement for the specified value."
227
+ }
228
+ }`,
229
+ };
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Sanitize a user input name to be used as a pepr module directory name
3
+ *
4
+ * @param name the user input name
5
+ * @returns the sanitized name
6
+ */
7
+ export declare function sanitizeName(name: string): string;
8
+ /**
9
+ * Creates a directory and throws an error if it already exists
10
+ *
11
+ * @param dir - The directory to create
12
+ */
13
+ export declare function createDir(dir: string): Promise<void>;
14
+ /**
15
+ * Write data to a file on disk
16
+ * @param path - The path to the file
17
+ * @param data - The data to write
18
+ * @returns A promise that resolves when the file has been written
19
+ */
20
+ export declare function write(path: string, data: unknown): Promise<void>;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
4
+ Object.defineProperty(exports, "__esModule", { value: true });
5
+ exports.write = exports.createDir = exports.sanitizeName = void 0;
6
+ const fs_1 = require("fs");
7
+ /**
8
+ * Sanitize a user input name to be used as a pepr module directory name
9
+ *
10
+ * @param name the user input name
11
+ * @returns the sanitized name
12
+ */
13
+ function sanitizeName(name) {
14
+ // Replace any characters outside of [^a-z0-9-] with "-"
15
+ let sanitized = name.toLowerCase().replace(/[^a-z0-9-]+/gi, "-");
16
+ // Remove any leading or trailing hyphens
17
+ sanitized = sanitized.replace(/^-+|-+$/g, "");
18
+ // Replace multiple hyphens with a single hyphen
19
+ sanitized = sanitized.replace(/--+/g, "-");
20
+ return sanitized;
21
+ }
22
+ exports.sanitizeName = sanitizeName;
23
+ /**
24
+ * Creates a directory and throws an error if it already exists
25
+ *
26
+ * @param dir - The directory to create
27
+ */
28
+ async function createDir(dir) {
29
+ try {
30
+ await fs_1.promises.mkdir(dir);
31
+ }
32
+ catch (err) {
33
+ // The directory already exists
34
+ if (err.code === "EEXIST") {
35
+ throw new Error(`Directory ${dir} already exists`);
36
+ }
37
+ else {
38
+ throw err;
39
+ }
40
+ }
41
+ }
42
+ exports.createDir = createDir;
43
+ /**
44
+ * Write data to a file on disk
45
+ * @param path - The path to the file
46
+ * @param data - The data to write
47
+ * @returns A promise that resolves when the file has been written
48
+ */
49
+ function write(path, data) {
50
+ // If the data is not a string, stringify it
51
+ if (typeof data !== "string") {
52
+ data = JSON.stringify(data, null, 2);
53
+ }
54
+ return fs_1.promises.writeFile(path, data);
55
+ }
56
+ exports.write = write;
@@ -0,0 +1,7 @@
1
+ import { Answers } from "prompts";
2
+ export type InitOptions = Answers<"name" | "description" | "errorBehavior">;
3
+ export declare function walkthrough(): Promise<InitOptions>;
4
+ export declare function confirm(dirName: string, packageJSON: {
5
+ path: string;
6
+ print: string;
7
+ }, peprTSPath: string): Promise<any>;
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
4
+ var __importDefault = (this && this.__importDefault) || function (mod) {
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+ };
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.confirm = exports.walkthrough = void 0;
9
+ const fs_1 = require("fs");
10
+ const prompts_1 = __importDefault(require("prompts"));
11
+ const types_1 = require("../../lib/types");
12
+ const templates_1 = require("./templates");
13
+ const utils_1 = require("./utils");
14
+ function walkthrough() {
15
+ const askName = {
16
+ type: "text",
17
+ name: "name",
18
+ message: "Enter a name for the new Pepr module. This will create a new directory based on the name.\n",
19
+ validate: async (val) => {
20
+ try {
21
+ const name = (0, utils_1.sanitizeName)(val);
22
+ await fs_1.promises.access(name, fs_1.promises.constants.F_OK);
23
+ return "A directory with this name already exists";
24
+ }
25
+ catch (e) {
26
+ return val.length > 2 || "The name must be at least 3 characters long";
27
+ }
28
+ },
29
+ };
30
+ const askDescription = {
31
+ type: "text",
32
+ name: "description",
33
+ message: "(Recommended) Enter a description for the new Pepr module.\n",
34
+ };
35
+ const askErrorBehavior = {
36
+ type: "select",
37
+ name: "errorBehavior",
38
+ validate: val => types_1.ErrorBehavior[val],
39
+ message: "How do you want Pepr to handle errors encountered during K8s operations?",
40
+ choices: [
41
+ {
42
+ title: "Ignore",
43
+ value: types_1.ErrorBehavior.ignore,
44
+ description: "Pepr will continue processing and generate an entry in the Pepr Controller log.",
45
+ selected: true,
46
+ },
47
+ {
48
+ title: "Log an audit event",
49
+ value: types_1.ErrorBehavior.audit,
50
+ description: "Pepr will continue processing and generate an entry in the Pepr Controller log as well as an audit event in the cluster.",
51
+ },
52
+ {
53
+ title: "Reject the operation",
54
+ value: types_1.ErrorBehavior.reject,
55
+ description: "Pepr will reject the operation and return an error to the client.",
56
+ },
57
+ ],
58
+ };
59
+ return (0, prompts_1.default)([askName, askDescription, askErrorBehavior]);
60
+ }
61
+ exports.walkthrough = walkthrough;
62
+ async function confirm(dirName, packageJSON, peprTSPath) {
63
+ console.log(`
64
+ To be generated:
65
+
66
+ \x1b[1m${dirName}\x1b[0m
67
+ ├── \x1b[1m${templates_1.gitIgnore.path}\x1b[0m
68
+ ├── \x1b[1m${templates_1.prettierRC.path}\x1b[0m
69
+ ├── \x1b[1mcapabilties\x1b[0m
70
+ | └── \x1b[1mhello-pepr.ts\x1b[0m
71
+ ├── \x1b[1m${packageJSON.path}\x1b[0m
72
+ ${packageJSON.print.replace(/^/gm, " │ ")}
73
+ ├── \x1b[1m${peprTSPath}\x1b[0m
74
+ ├── \x1b[1m${templates_1.readme.path}\x1b[0m
75
+ └── \x1b[1m${templates_1.tsConfig.path}\x1b[0m
76
+ `);
77
+ const confirm = await (0, prompts_1.default)({
78
+ type: "confirm",
79
+ name: "confirm",
80
+ message: "Create the new Pepr module?",
81
+ });
82
+ return confirm.confirm;
83
+ }
84
+ exports.confirm = confirm;
@@ -0,0 +1,4 @@
1
+ import { Command } from "commander";
2
+ export declare class RootCmd extends Command {
3
+ createCommand(name: string): Command;
4
+ }
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
4
+ var __importDefault = (this && this.__importDefault) || function (mod) {
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+ };
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.RootCmd = void 0;
9
+ const commander_1 = require("commander");
10
+ const logger_1 = __importDefault(require("../lib/logger"));
11
+ class RootCmd extends commander_1.Command {
12
+ createCommand(name) {
13
+ const cmd = new commander_1.Command(name);
14
+ cmd.option("-l, --log-level [level]", "Log level: debug, info, warn, error", "info");
15
+ cmd.hook("preAction", run => {
16
+ logger_1.default.SetLogLevel(run.opts().logLevel);
17
+ });
18
+ return cmd;
19
+ }
20
+ }
21
+ exports.RootCmd = RootCmd;
@@ -0,0 +1,2 @@
1
+ import { RootCmd } from "./root";
2
+ export default function (program: RootCmd): void;
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
4
+ var __importDefault = (this && this.__importDefault) || function (mod) {
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+ };
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ const child_process_1 = require("child_process");
9
+ const chokidar_1 = require("chokidar");
10
+ const path_1 = require("path");
11
+ const util_1 = require("util");
12
+ const logger_1 = __importDefault(require("../lib/logger"));
13
+ const build_1 = require("./build");
14
+ const exec = (0, util_1.promisify)(child_process_1.exec);
15
+ function default_1(program) {
16
+ program
17
+ .command("test")
18
+ .description("Test a Pepr Module locally")
19
+ .option("-d, --dir [directory]", "Pepr module directory", ".")
20
+ .option("-w, --watch", "Watch for changes and re-run the test")
21
+ .action(async (opts) => {
22
+ logger_1.default.info("Test Module");
23
+ await buildAndTest(opts.dir);
24
+ if (opts.watch) {
25
+ const moduleFiles = (0, path_1.resolve)(opts.dir, "**", "*.ts");
26
+ const watcher = (0, chokidar_1.watch)(moduleFiles);
27
+ watcher.on("ready", () => {
28
+ logger_1.default.info(`Watching for changes in ${moduleFiles}`);
29
+ watcher.on("all", async (event, path) => {
30
+ logger_1.default.debug({ event, path }, "File changed");
31
+ await buildAndTest(opts.dir);
32
+ });
33
+ });
34
+ }
35
+ });
36
+ }
37
+ exports.default = default_1;
38
+ async function buildAndTest(dir) {
39
+ const { path } = await (0, build_1.buildModule)(dir);
40
+ logger_1.default.info(`Module built successfully at ${path}`);
41
+ try {
42
+ const { stdout, stderr } = await exec(`node ${path}`);
43
+ console.log(stdout);
44
+ console.log(stderr);
45
+ }
46
+ catch (e) {
47
+ logger_1.default.debug(e);
48
+ logger_1.default.error(`Error running module: ${e}`);
49
+ process.exit(1);
50
+ }
51
+ }
@@ -0,0 +1,26 @@
1
+ import { Binding, CapabilityCfg, GenericClass, HookPhase, WhenSelector } from "./types";
2
+ /**
3
+ * A capability is a unit of functionality that can be registered with the Pepr runtime.
4
+ */
5
+ export declare class Capability implements CapabilityCfg {
6
+ private _name;
7
+ private _description;
8
+ private _namespaces?;
9
+ private _mutateOrValidate;
10
+ private _bindings;
11
+ get bindings(): Binding[];
12
+ get name(): string;
13
+ get description(): string;
14
+ get namespaces(): string[];
15
+ get mutateOrValidate(): HookPhase;
16
+ constructor(cfg: CapabilityCfg);
17
+ /**
18
+ * The When method is used to register a capability action to be executed when a Kubernetes resource is
19
+ * processed by Pepr. The action will be executed if the resource matches the specified kind and any
20
+ * filters that are applied.
21
+ *
22
+ * @param model if using a custom KubernetesObject not available in `a.*`, specify the GroupVersionKind
23
+ * @returns
24
+ */
25
+ When: <T extends GenericClass>(model: T) => WhenSelector<T>;
26
+ }
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
4
+ var __importDefault = (this && this.__importDefault) || function (mod) {
5
+ return (mod && mod.__esModule) ? mod : { "default": mod };
6
+ };
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.Capability = void 0;
9
+ const k8s_1 = require("./k8s");
10
+ const logger_1 = __importDefault(require("./logger"));
11
+ const types_1 = require("./types");
12
+ /**
13
+ * A capability is a unit of functionality that can be registered with the Pepr runtime.
14
+ */
15
+ class Capability {
16
+ get bindings() {
17
+ return this._bindings;
18
+ }
19
+ get name() {
20
+ return this._name;
21
+ }
22
+ get description() {
23
+ return this._description;
24
+ }
25
+ get namespaces() {
26
+ return this._namespaces || [];
27
+ }
28
+ get mutateOrValidate() {
29
+ return this._mutateOrValidate;
30
+ }
31
+ constructor(cfg) {
32
+ // Currently everything is considered a mutation
33
+ this._mutateOrValidate = types_1.HookPhase.mutate;
34
+ this._bindings = [];
35
+ /**
36
+ * The When method is used to register a capability action to be executed when a Kubernetes resource is
37
+ * processed by Pepr. The action will be executed if the resource matches the specified kind and any
38
+ * filters that are applied.
39
+ *
40
+ * @param model if using a custom KubernetesObject not available in `a.*`, specify the GroupVersionKind
41
+ * @returns
42
+ */
43
+ this.When = (model) => {
44
+ const binding = {
45
+ // If the kind is not specified, use the default KubernetesObject
46
+ kind: (0, k8s_1.modelToGroupVersionKind)(model.name),
47
+ filters: {
48
+ name: "",
49
+ namespaces: [],
50
+ labels: {},
51
+ annotations: {},
52
+ },
53
+ callback: () => null,
54
+ };
55
+ const prefix = `${this._name}: ${model.name}`;
56
+ logger_1.default.info(`Binding created`, prefix);
57
+ const Then = (cb) => {
58
+ logger_1.default.info(`Binding action created`, prefix);
59
+ logger_1.default.debug(cb.toString(), prefix);
60
+ // Push the binding to the list of bindings for this capability as a new BindingAction
61
+ // with the callback function to preserve
62
+ this._bindings.push({
63
+ ...binding,
64
+ callback: cb,
65
+ });
66
+ // Now only allow adding actions to the same binding
67
+ return { Then };
68
+ };
69
+ const ThenSet = (merge) => {
70
+ // Add the new action to the binding
71
+ Then(req => req.Merge(merge));
72
+ return { Then };
73
+ };
74
+ function InNamespace(...namespaces) {
75
+ logger_1.default.debug(`Add namespaces filter ${namespaces}`, prefix);
76
+ binding.filters.namespaces.push(...namespaces);
77
+ return { WithLabel, WithAnnotation, WithName, Then, ThenSet };
78
+ }
79
+ function WithName(name) {
80
+ logger_1.default.debug(`Add name filter ${name}`, prefix);
81
+ binding.filters.name = name;
82
+ return { WithLabel, WithAnnotation, Then, ThenSet };
83
+ }
84
+ function WithLabel(key, value = "") {
85
+ logger_1.default.debug(`Add label filter ${key}=${value}`, prefix);
86
+ binding.filters.labels[key] = value;
87
+ return { WithLabel, WithAnnotation, Then, ThenSet };
88
+ }
89
+ const WithAnnotation = (key, value = "") => {
90
+ logger_1.default.debug(`Add annotation filter ${key}=${value}`, prefix);
91
+ binding.filters.annotations[key] = value;
92
+ return { WithLabel, WithAnnotation, Then, ThenSet };
93
+ };
94
+ const bindEvent = (event) => {
95
+ binding.event = event;
96
+ return {
97
+ InNamespace,
98
+ Then,
99
+ ThenSet,
100
+ WithAnnotation,
101
+ WithLabel,
102
+ WithName,
103
+ };
104
+ };
105
+ return {
106
+ IsCreatedOrUpdated: () => bindEvent(types_1.Event.CreateOrUpdate),
107
+ IsCreated: () => bindEvent(types_1.Event.Create),
108
+ IsUpdated: () => bindEvent(types_1.Event.Update),
109
+ IsDeleted: () => bindEvent(types_1.Event.Delete),
110
+ };
111
+ };
112
+ this._name = cfg.name;
113
+ this._description = cfg.description;
114
+ this._namespaces = cfg.namespaces;
115
+ logger_1.default.info(`Capability ${this._name} registered`);
116
+ logger_1.default.debug(cfg);
117
+ }
118
+ }
119
+ exports.Capability = Capability;
@@ -0,0 +1,13 @@
1
+ import { ModuleConfig } from "./types";
2
+ import { Capability } from "./capability";
3
+ export declare class Controller {
4
+ private readonly config;
5
+ private readonly capabilities;
6
+ private readonly app;
7
+ constructor(config: ModuleConfig, capabilities: Capability[]);
8
+ /** Start the webhook server */
9
+ startServer: (port: number) => void;
10
+ private logger;
11
+ private healthz;
12
+ private mutate;
13
+ }