pepr 0.3.0-rc0 → 0.3.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/docs/cli.md DELETED
@@ -1,58 +0,0 @@
1
- # Pepr CLI
2
-
3
- ## `pepr init`
4
-
5
- Initialize a new Pepr Module.
6
-
7
- **Options:**
8
-
9
- - `-l, --log-level [level]` - Log level: debug, info, warn, error (default: "info")
10
- - `--skip-post-init` - Skip npm install, git init and VSCode launch
11
-
12
- ---
13
-
14
- ## `pepr update`
15
-
16
- Update the current Pepr Module to the latest SDK version and update the global Pepr CLI to the same version.
17
-
18
- **Options:**
19
-
20
- - `-l, --log-level [level]` - Log level: debug, info, warn, error (default: "info")
21
- - `--skip-template-update` - Skip updating the template files
22
-
23
- ---
24
-
25
- ## `pepr dev`
26
-
27
- Connect a local cluster to a local version of the Pepr Controller to do real-time debugging of your module. Note
28
- the `pepr dev` assumes a K3d cluster is running by default. If you are working with Kind or another docker-based
29
- K8s distro, you will need to pass the `--host host.docker.internal` option to `pepr dev`. If working with a remote
30
- cluster you will have to give Pepr a host path to your machine that is reachable from the K8s cluster.
31
-
32
- **Options:**
33
-
34
- - `-l, --log-level [level]` - Log level: debug, info, warn, error (default: "info")
35
- - `-h, --host [host]` - Host to listen on (default: "host.k3d.internal")
36
- - `--confirm` - Skip confirmation prompt
37
-
38
- ---
39
-
40
- ## `pepr deploy`
41
-
42
- Deploy the current module into a Kubernetes cluster, useful for CI systems. Not recommended for production use.
43
-
44
- **Options:**
45
-
46
- - `-l, --log-level [level]` - Log level: debug, info, warn, error (default: "info")
47
- - `-i, --image [image]` - Override the image tag
48
- - `--confirm` - Skip confirmation prompt
49
-
50
- ---
51
-
52
- ## `pepr build`
53
-
54
- Create a [zarf.yaml](https://zarf.dev) and K8s manifest for the current module. This includes everything needed to deploy Pepr and the current module into production environments.
55
-
56
- **Options:**
57
-
58
- - `-l, --log-level [level]` - Log level: debug, info, warn, error (default: "info")
package/docs/module.md DELETED
@@ -1,90 +0,0 @@
1
- # Pepr Module
2
-
3
- Each Pepr Module is it's own Typescript project, produced by [`pepr init`](./cli.md#pepr-init). Typically a module is maintained by a unique group or system. For example, a module for internal [Zarf](https://zarf.dev/) mutations would be different from a module for [Big Bang](https://p1.dso.mil/products/big-bang). An important idea with modules is that they are _wholly independent of one another_. This means that 2 different modules can be on completely different versions of Pepr and any other dependencies; their only interaction is through the standard K8s interfaces like any other webhook or controller.
4
-
5
- ## Module development lifecycle
6
-
7
- 1. **Create the module**:
8
-
9
- Use [`pepr init`](./cli.md#pepr-init) to generate a new module.
10
-
11
- 1. **Quickly validate system setup**:
12
-
13
- Every new module includes a sample Pepr Capability called `HelloPepr`. By default,
14
- this capability is deployed and monitoring the `pepr-demo` namespace. There is a sample
15
- yaml also included you can use to see Pepr in your cluster. Here's the quick steps to do
16
- that after `pepr init`:
17
-
18
- ```bash
19
- # cd to the newly-created Pepr module folder
20
- cd my-module-name
21
-
22
- # If you don't already have a local K8s cluster, you can set one up with k3d
23
- npm run k3d-setup
24
-
25
- # Launch pepr dev mode (npm start or pepr dev)
26
- # If using another local K8s distro instead of k3d, use `pepr dev --host host.docker.internal`
27
- pepr dev
28
-
29
- # From another terminal, apply the sample yaml
30
- kubectl apply -f capabilities/hello-pepr.samples.yaml
31
-
32
- # Verify the configmaps were transformed using kubectl, k9s or another tool
33
- ```
34
-
35
- 1. **Create your custom Pepr Capabilities**
36
-
37
- Now that you have confirmed Pepr is working, you can now create new [capabilities](./capabilities.md). You'll also want to disable the `HelloPepr` capability in your module (`pepr.ts`) before pushing to production. You can disable by commenting out or deleting the `HelloPepr` variable below:
38
-
39
- ```typescript
40
- new PeprModule(cfg, [
41
- // Remove or comment the line below to disable the HelloPepr capability
42
- HelloPepr,
43
-
44
- // Your additional capabilities go here
45
- ]);
46
- ```
47
-
48
- _Note: if you also delete the `capabilities/hello-pepr.ts` file, it will be added again on the next [`pepr update`](./cli.md#pepr-update) so you have the latest examples usages from the Pepr SDK. Therefore, it is sufficient to remove the entry from your `pepr.ts` module
49
- config._
50
-
51
- 1. **Build and deploy the Pepr Module**
52
-
53
- Most of the time, you'll likely be iterating on a module with `perp dev` for real-time feedback and validation Once you are ready to move beyond the local dev environment, Pepr provides deployment and build tools you can use.
54
-
55
- `pepr deploy` - you can use this command to build your module and deploy it into any K8s cluster your current `kubecontext` has access to. This setup is ideal for CI systems during testing, but is not recommended for production use. See [`pepr deploy`](./cli.md#pepr-deploy) for more info.
56
-
57
- ## Advanced Module Configuration
58
-
59
- By default, when you run `pepr init`, the module is not configured with any additional options. Currently, there are 3 options you can configure:
60
-
61
- - `deferStart` - if set to `true`, the module will not start automatically. You will need to call `start()` manually. This is useful if you want to do some additional setup before the module controller starts. You can also use this to change the default port that the controller listens on.
62
-
63
- - `beforeHook` - an optional callback that will be called before every request is processed. This is useful if you want to do some additional logging or validation before the request is processed.
64
-
65
- - `afterHook` - an optional callback that will be called after every request is processed. This is useful if you want to do some additional logging or validation after the request is processed.
66
-
67
- You can configure each of these by modifying the `pepr.ts` file in your module. Here's an example of how you would configure each of these options:
68
-
69
- ```typescript
70
- const module = new PeprModule(
71
- cfg,
72
- [
73
- // Your capabilities go here
74
- ],
75
- {
76
- deferStart: true,
77
-
78
- beforeHook: req => {
79
- // Any actions you want to perform before the request is processed, including modifying the request.
80
- },
81
-
82
- afterHook: res => {
83
- // Any actions you want to perform after the request is processed, including modifying the response.
84
- },
85
- }
86
- );
87
-
88
- // Do any additional setup before starting the controller
89
- module.start();
90
- ```
package/osv-scanner.toml DELETED
@@ -1,4 +0,0 @@
1
- # One entry for each vulnerability group
2
- [[IgnoredVulns]]
3
- id = "GHSA-p8p7-x288-28g6"
4
- reason = "Library only used client-side and not affected by this vulnerability."
@@ -1,115 +0,0 @@
1
- // SPDX-License-Identifier: Apache-2.0
2
- // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
- // fetch.test.ts
4
-
5
- import test from "ava";
6
- import { StatusCodes } from "http-status-codes";
7
- import nock from "nock";
8
- import { RequestInit } from "node-fetch";
9
- import { fetch } from "./fetch";
10
-
11
- test.beforeEach(() => {
12
- nock("https://jsonplaceholder.typicode.com")
13
- .get("/todos/1")
14
- .reply(200, {
15
- userId: 1,
16
- id: 1,
17
- title: "Example title",
18
- completed: false,
19
- })
20
- .post("/todos", {
21
- title: "test todo",
22
- userId: 1,
23
- completed: false,
24
- })
25
- .reply(200, (uri, requestBody) => requestBody)
26
- .get("/todos/empty-null")
27
- .reply(200, undefined)
28
- .get("/todos/empty-string")
29
- .reply(200, "")
30
- .get("/todos/empty-object")
31
- .reply(200, {})
32
- .get("/todos/invalid")
33
- .replyWithError("Something bad happened");
34
- });
35
-
36
- test("fetch: should return without type data", async t => {
37
- const url = "https://jsonplaceholder.typicode.com/todos/1";
38
- const { data, ok } = await fetch<{ title: string }>(url);
39
- t.is(ok, true);
40
- t.is(data["title"], "Example title");
41
- });
42
-
43
- test("fetch: should return parsed JSON response as a specific type", async t => {
44
- interface Todo {
45
- userId: number;
46
- id: number;
47
- title: string;
48
- completed: boolean;
49
- }
50
-
51
- const url = "https://jsonplaceholder.typicode.com/todos/1";
52
- const { data, ok } = await fetch<Todo>(url);
53
- t.is(ok, true);
54
- t.is(data.id, 1);
55
- t.is(typeof data.title, "string");
56
- t.is(typeof data.completed, "boolean");
57
- });
58
-
59
- test("fetch: should handle additional request options", async t => {
60
- const url = "https://jsonplaceholder.typicode.com/todos";
61
- const requestOptions: RequestInit = {
62
- method: "POST",
63
- body: JSON.stringify({
64
- title: "test todo",
65
- userId: 1,
66
- completed: false,
67
- }),
68
- headers: {
69
- "Content-type": "application/json; charset=UTF-8",
70
- },
71
- };
72
-
73
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
74
- const { data, ok } = await fetch<any>(url, requestOptions);
75
- t.is(ok, true);
76
- t.is(data["title"], "test todo");
77
- t.is(data["userId"], 1);
78
- t.is(data["completed"], false);
79
- });
80
-
81
- test("fetch: should handle empty (null) responses", async t => {
82
- const url = "https://jsonplaceholder.typicode.com/todos/empty-null";
83
- const resp = await fetch(url);
84
-
85
- t.is(resp.data, "");
86
- t.is(resp.ok, true);
87
- t.is(resp.status, StatusCodes.OK);
88
- });
89
-
90
- test("fetch: should handle empty (string) responses", async t => {
91
- const url = "https://jsonplaceholder.typicode.com/todos/empty-string";
92
- const resp = await fetch(url);
93
-
94
- t.is(resp.data, "");
95
- t.is(resp.ok, true);
96
- t.is(resp.status, StatusCodes.OK);
97
- });
98
-
99
- test("fetch: should handle empty (object) responses", async t => {
100
- const url = "https://jsonplaceholder.typicode.com/todos/empty-object";
101
- const resp = await fetch(url);
102
-
103
- t.deepEqual(resp.data, {});
104
- t.is(resp.ok, true);
105
- t.is(resp.status, StatusCodes.OK);
106
- });
107
-
108
- test("fetch: should handle failed requests without throwing an error", async t => {
109
- const url = "https://jsonplaceholder.typicode.com/todos/invalid";
110
- const resp = await fetch(url);
111
-
112
- t.is(resp.data, undefined);
113
- t.is(resp.ok, false);
114
- t.is(resp.status, StatusCodes.BAD_REQUEST);
115
- });
@@ -1,231 +0,0 @@
1
- import test from "ava";
2
- import { POD1 } from "../../fixtures/loader";
3
- import { shouldSkipRequest } from "./filter";
4
- import { gvkMap } from "./k8s";
5
-
6
- const callback = () => undefined;
7
-
8
- test("should reject when name does not match", t => {
9
- const binding = {
10
- kind: gvkMap.V1Pod,
11
- filters: {
12
- name: "bleh",
13
- namespaces: [],
14
- labels: {},
15
- annotations: {},
16
- },
17
- callback,
18
- };
19
- const pod = POD1();
20
-
21
- t.true(shouldSkipRequest(binding, pod));
22
- });
23
-
24
- test("should reject when kind does not match", t => {
25
- const binding = {
26
- kind: gvkMap.V1ConfigMap,
27
- filters: {
28
- name: "",
29
- namespaces: [],
30
- labels: {},
31
- annotations: {},
32
- },
33
- callback,
34
- };
35
- const pod = POD1();
36
-
37
- t.true(shouldSkipRequest(binding, pod));
38
- });
39
-
40
- test("should reject when group does not match", t => {
41
- const binding = {
42
- kind: gvkMap.V1CronJob,
43
- filters: {
44
- name: "",
45
- namespaces: [],
46
- labels: {},
47
- annotations: {},
48
- },
49
- callback,
50
- };
51
- const pod = POD1();
52
-
53
- t.true(shouldSkipRequest(binding, pod));
54
- });
55
-
56
- test("should reject when version does not match", t => {
57
- const binding = {
58
- kind: {
59
- group: "",
60
- version: "v2",
61
- kind: "Pod",
62
- },
63
- filters: {
64
- name: "",
65
- namespaces: [],
66
- labels: {},
67
- annotations: {},
68
- },
69
- callback,
70
- };
71
- const pod = POD1();
72
-
73
- t.true(shouldSkipRequest(binding, pod));
74
- });
75
-
76
- test("should allow when group, version, and kind match", t => {
77
- const binding = {
78
- kind: gvkMap.V1Pod,
79
- filters: {
80
- name: "",
81
- namespaces: [],
82
- labels: {},
83
- annotations: {},
84
- },
85
- callback,
86
- };
87
- const pod = POD1();
88
-
89
- t.false(shouldSkipRequest(binding, pod));
90
- });
91
-
92
- test("should allow when kind match and others are empty", t => {
93
- const binding = {
94
- kind: {
95
- group: "",
96
- version: "",
97
- kind: "Pod",
98
- },
99
- filters: {
100
- name: "",
101
- namespaces: [],
102
- labels: {},
103
- annotations: {},
104
- },
105
- callback,
106
- };
107
- const pod = POD1();
108
-
109
- t.false(shouldSkipRequest(binding, pod));
110
- });
111
-
112
- test("should reject when namespace does not match", t => {
113
- const binding = {
114
- kind: gvkMap.V1Pod,
115
- filters: {
116
- name: "",
117
- namespaces: ["bleh"],
118
- labels: {},
119
- annotations: {},
120
- },
121
- callback,
122
- };
123
- const pod = POD1();
124
-
125
- t.true(shouldSkipRequest(binding, pod));
126
- });
127
-
128
- test("should allow when namespace is match", t => {
129
- const binding = {
130
- kind: gvkMap.V1Pod,
131
- filters: {
132
- name: "",
133
- namespaces: ["default", "unicorn", "things"],
134
- labels: {},
135
- annotations: {},
136
- },
137
- callback,
138
- };
139
- const pod = POD1();
140
-
141
- t.false(shouldSkipRequest(binding, pod));
142
- });
143
-
144
- test("should reject when label does not match", t => {
145
- const binding = {
146
- kind: gvkMap.V1Pod,
147
- filters: {
148
- name: "",
149
- namespaces: [],
150
- labels: {
151
- foo: "bar",
152
- },
153
- annotations: {},
154
- },
155
- callback,
156
- };
157
- const pod = POD1();
158
-
159
- t.true(shouldSkipRequest(binding, pod));
160
- });
161
-
162
- test("should allow when label is match", t => {
163
- const binding = {
164
- kind: gvkMap.V1Pod,
165
- filters: {
166
- name: "",
167
-
168
- namespaces: [],
169
- labels: {
170
- foo: "bar",
171
- test: "test1",
172
- },
173
- annotations: {},
174
- },
175
- callback,
176
- };
177
-
178
- const pod = POD1();
179
- pod.object.metadata = pod.object.metadata || {};
180
- pod.object.metadata.labels = {
181
- foo: "bar",
182
- test: "test1",
183
- test2: "test2",
184
- };
185
-
186
- t.false(shouldSkipRequest(binding, pod));
187
- });
188
-
189
- test("should reject when annotation does not match", t => {
190
- const binding = {
191
- kind: gvkMap.V1Pod,
192
- filters: {
193
- name: "",
194
- namespaces: [],
195
- labels: {},
196
- annotations: {
197
- foo: "bar",
198
- },
199
- },
200
- callback,
201
- };
202
- const pod = POD1();
203
-
204
- t.true(shouldSkipRequest(binding, pod));
205
- });
206
-
207
- test("should allow when annotation is match", t => {
208
- const binding = {
209
- kind: gvkMap.V1Pod,
210
- filters: {
211
- name: "",
212
- namespaces: [],
213
- labels: {},
214
- annotations: {
215
- foo: "bar",
216
- test: "test1",
217
- },
218
- },
219
- callback,
220
- };
221
-
222
- const pod = POD1();
223
- pod.object.metadata = pod.object.metadata || {};
224
- pod.object.metadata.annotations = {
225
- foo: "bar",
226
- test: "test1",
227
- test2: "test2",
228
- };
229
-
230
- t.false(shouldSkipRequest(binding, pod));
231
- });