pepr 0.50.0 → 0.51.0-nightly.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.
Files changed (40) hide show
  1. package/README.md +1 -1
  2. package/dist/cli/crd/create.d.ts.map +1 -1
  3. package/dist/cli/deploy.d.ts +3 -0
  4. package/dist/cli/deploy.d.ts.map +1 -1
  5. package/dist/cli/dev.d.ts.map +1 -1
  6. package/dist/cli/docs/cli.helper.d.ts.map +1 -1
  7. package/dist/cli/docs/markdown.helper.d.ts.map +1 -1
  8. package/dist/cli/init/templates.d.ts +2 -19
  9. package/dist/cli/init/templates.d.ts.map +1 -1
  10. package/dist/cli/update/index.d.ts.map +1 -1
  11. package/dist/cli.js +239 -251
  12. package/dist/controller.js +1 -1
  13. package/dist/lib/assets/assets.d.ts.map +1 -1
  14. package/dist/lib/assets/defaultTestObjects.d.ts.map +1 -1
  15. package/dist/lib/assets/webhooks.d.ts.map +1 -1
  16. package/dist/lib/controller/index.d.ts.map +1 -1
  17. package/dist/lib/controller/storeCache.d.ts.map +1 -1
  18. package/dist/lib/core/capability.d.ts.map +1 -1
  19. package/dist/lib/core/module.d.ts.map +1 -1
  20. package/dist/lib/core/storage.d.ts.map +1 -1
  21. package/dist/lib/deploymentChecks.d.ts +9 -0
  22. package/dist/lib/deploymentChecks.d.ts.map +1 -1
  23. package/dist/lib/filter/adjudicators/binding.d.ts.map +1 -1
  24. package/dist/lib/helpers.d.ts.map +1 -1
  25. package/dist/lib/mutate-request.d.ts.map +1 -1
  26. package/dist/lib/telemetry/metrics.d.ts.map +1 -1
  27. package/dist/lib/validate-request.d.ts.map +1 -1
  28. package/dist/lib.js +15 -13
  29. package/dist/lib.js.map +2 -2
  30. package/package.json +16 -16
  31. package/src/cli/deploy.ts +12 -8
  32. package/src/cli/dev.ts +6 -3
  33. package/src/cli/init/templates.ts +18 -4
  34. package/src/cli/update/index.ts +4 -29
  35. package/src/lib/core/capability.ts +15 -13
  36. package/src/lib/deploymentChecks.ts +21 -12
  37. package/src/templates/capabilities/hello-pepr.ts +1 -1
  38. package/src/templates/eslint.config.mjs +45 -0
  39. package/src/templates/.eslintrc.json +0 -6
  40. package/src/templates/.eslintrc.template.json +0 -18
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "!dist/**/*.test.d.ts*",
18
18
  "!src/cli/docs/**"
19
19
  ],
20
- "version": "0.50.0",
20
+ "version": "0.51.0-nightly.1",
21
21
  "main": "dist/lib.js",
22
22
  "types": "dist/lib.d.ts",
23
23
  "scripts": {
@@ -45,24 +45,25 @@
45
45
  "test:journey:unicorn": "npm run test:journey:k3d && npm run test:journey:image:unicorn && npm run test:journey:run",
46
46
  "test:journey:upgrade": "npm run test:journey:k3d && npm run test:journey:image && jest --detectOpenHandles journey/pepr-upgrade.test.ts",
47
47
  "test:unit": "npm run gen-data-json && jest src --coverage --detectOpenHandles --coverageDirectory=./coverage --testPathIgnorePatterns=\"build-artifact.test.ts|src/cli/docs/.*\\.test\\.ts\"",
48
- "format:check": "eslint src && prettier --config .prettierrc src --check",
49
- "format:fix": "eslint src --fix && prettier --config .prettierrc src --write",
48
+ "format:check": "eslint --ignore-pattern src/templates/eslint.config.mjs src && prettier --config .prettierrc src --check",
49
+ "format:fix": "eslint --fix --ignore-pattern src/templates/eslint.config.mjs src && prettier --config .prettierrc src --write",
50
50
  "prepare": "if [ \"$NODE_ENV\" != 'production' ]; then husky; fi"
51
51
  },
52
52
  "dependencies": {
53
53
  "@types/ramda": "0.30.2",
54
+ "commander": "14.0.0",
54
55
  "express": "5.1.0",
55
56
  "fast-json-patch": "3.1.1",
56
57
  "heredoc": "^1.3.1",
57
58
  "http-status-codes": "^2.3.0",
58
59
  "json-pointer": "^0.6.2",
59
- "kubernetes-fluent-client": "3.5.3",
60
- "pino": "9.6.0",
60
+ "kubernetes-fluent-client": "3.5.5",
61
+ "pino": "9.7.0",
61
62
  "pino-pretty": "13.0.0",
62
63
  "prom-client": "15.1.3",
63
64
  "ramda": "0.30.1",
64
65
  "sigstore": "3.1.0",
65
- "ts-morph": "^25.0.1"
66
+ "ts-morph": "^26.0.0"
66
67
  },
67
68
  "devDependencies": {
68
69
  "@commitlint/cli": "19.8.1",
@@ -70,7 +71,7 @@
70
71
  "@fast-check/jest": "^2.0.1",
71
72
  "@jest/globals": "29.7.0",
72
73
  "@types/eslint": "9.6.1",
73
- "@types/express": "5.0.1",
74
+ "@types/express": "5.0.2",
74
75
  "@types/json-pointer": "^1.0.34",
75
76
  "@types/node": "22.x.x",
76
77
  "@types/node-forge": "1.3.11",
@@ -81,7 +82,7 @@
81
82
  "jest": "29.7.0",
82
83
  "js-yaml": "^4.1.0",
83
84
  "shellcheck": "^3.0.0",
84
- "ts-jest": "29.3.2",
85
+ "ts-jest": "29.3.4",
85
86
  "undici": "^7.0.1"
86
87
  },
87
88
  "overrides": {
@@ -89,15 +90,14 @@
89
90
  },
90
91
  "peerDependencies": {
91
92
  "@types/prompts": "2.4.9",
92
- "@typescript-eslint/eslint-plugin": "8.23.0",
93
- "@typescript-eslint/parser": "8.23.0",
94
- "commander": "13.1.0",
93
+ "@typescript-eslint/eslint-plugin": "8.32.1",
94
+ "@typescript-eslint/parser": "8.32.1",
95
95
  "esbuild": "0.25.0",
96
- "eslint": "8.57.0",
96
+ "eslint": "^9.26.0",
97
97
  "node-forge": "1.3.1",
98
- "prettier": "3.4.2",
98
+ "prettier": "3.5.3",
99
99
  "prompts": "2.4.2",
100
- "typescript": "5.7.3",
101
- "uuid": "11.0.5"
100
+ "typescript": "5.8.3",
101
+ "uuid": "11.1.0"
102
102
  }
103
- }
103
+ }
package/src/cli/deploy.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
3
 
4
4
  import prompt from "prompts";
5
-
5
+ import { CapabilityExport } from "../lib/types";
6
6
  import { Assets } from "../lib/assets/assets";
7
7
  import { ImagePullSecret } from "../lib/types";
8
8
  import { RootCmd } from "./root";
@@ -109,13 +109,7 @@ async function buildAndDeployModule(image: string, force: boolean): Promise<void
109
109
  webhook.image = image ?? webhook.image;
110
110
  const capabilities = await loadCapabilities(webhook.path);
111
111
  for (const capability of capabilities) {
112
- namespaceComplianceValidator(capability, webhook.alwaysIgnore?.namespaces);
113
- namespaceComplianceValidator(
114
- capability,
115
- webhook.config.admission?.alwaysIgnore?.namespaces,
116
- false,
117
- );
118
- namespaceComplianceValidator(capability, webhook.config.watch?.alwaysIgnore?.namespaces, true);
112
+ validateNamespaces(capability, webhook);
119
113
  }
120
114
  try {
121
115
  await webhook.deploy(deployWebhook, force, builtModule.cfg.pepr.webhookTimeout ?? 10);
@@ -163,3 +157,13 @@ export default function (program: RootCmd): void {
163
157
  await buildAndDeployModule(opts.image, opts.force);
164
158
  });
165
159
  }
160
+
161
+ export function validateNamespaces(capability: CapabilityExport, webhook: Assets): void {
162
+ namespaceComplianceValidator(capability, webhook.alwaysIgnore?.namespaces);
163
+ namespaceComplianceValidator(
164
+ capability,
165
+ webhook.config.admission?.alwaysIgnore?.namespaces,
166
+ false,
167
+ );
168
+ namespaceComplianceValidator(capability, webhook.config.watch?.alwaysIgnore?.namespaces, true);
169
+ }
package/src/cli/dev.ts CHANGED
@@ -29,7 +29,8 @@ export default function (program: RootCmd): void {
29
29
 
30
30
  // Exit if the user doesn't confirm
31
31
  if (!confirm.confirm) {
32
- process.exit(0);
32
+ process.exitCode = 0;
33
+ return;
33
34
  }
34
35
  }
35
36
 
@@ -67,8 +68,10 @@ export default function (program: RootCmd): void {
67
68
  try {
68
69
  // wait for capabilities to be loaded and test names
69
70
  validateCapabilityNames(webhook.capabilities);
70
- } catch (e) {
71
- console.error(`Error validating capability names:`, e);
71
+ } catch (error) {
72
+ console.error(
73
+ `CapabilityValidation Error - Unable to valide capability name(s) in: '${webhook.capabilities.map(item => item.name)}'\n${error}`,
74
+ );
72
75
  process.exit(1);
73
76
  }
74
77
 
@@ -4,8 +4,9 @@
4
4
  import { dumpYaml } from "@kubernetes/client-node";
5
5
  import { inspect } from "util";
6
6
  import { v4 as uuidv4 } from "uuid";
7
+ import { readFileSync } from "fs";
8
+ import path from "path";
7
9
 
8
- import eslintJSON from "../../templates/.eslintrc.template.json";
9
10
  import peprSnippetsJSON from "../../templates/pepr.code-snippets.json";
10
11
  import prettierJSON from "../../templates/.prettierrc.json";
11
12
  import samplesJSON from "../../templates/capabilities/hello-pepr.samples.json";
@@ -67,7 +68,7 @@ export function genPkgJSON(opts: InitOptions, pgkVerOverride?: string): peprPack
67
68
  description: opts.description,
68
69
  keywords: ["pepr", "k8s", "policy-engine", "pepr-module", "security"],
69
70
  engines: {
70
- node: ">=18.0.0",
71
+ node: ">=20.0.0",
71
72
  },
72
73
  pepr: {
73
74
  uuid: pgkVerOverride ? "static-test" : uuid,
@@ -159,6 +160,19 @@ export const prettier = {
159
160
  };
160
161
 
161
162
  export const eslint = {
162
- path: ".eslintrc.json",
163
- data: eslintJSON,
163
+ path: "eslint.config.mjs",
164
+ data: readFileSync(
165
+ path.resolve(
166
+ ((): string => {
167
+ const fullPath = __dirname;
168
+ const lengthOfSuffix = "pepr/".length;
169
+ // Find the last occurrence of "pepr/"
170
+ const lastPeprIndex = fullPath.lastIndexOf("pepr/");
171
+ // Return the path up to and including the last "pepr/"
172
+ return fullPath.substring(0, lastPeprIndex + lengthOfSuffix);
173
+ })(),
174
+ "src/templates/eslint.config.mjs",
175
+ ),
176
+ "utf-8",
177
+ ),
164
178
  };
@@ -16,6 +16,7 @@ import {
16
16
  } from "../init/templates";
17
17
  import { write } from "../init/utils";
18
18
  import { RootCmd } from "../root";
19
+
19
20
  export default function (program: RootCmd): void {
20
21
  program
21
22
  .command("update")
@@ -40,33 +41,6 @@ export default function (program: RootCmd): void {
40
41
  console.log("Updating the Pepr module...");
41
42
 
42
43
  try {
43
- // Check if eslint v8 is a project dependency and warn about future upgrade
44
- let packageLockContent = "";
45
- let foundPackageLock = false;
46
-
47
- try {
48
- // Try to find package-lock.json in the current directory
49
- if (fs.existsSync("./package-lock.json")) {
50
- packageLockContent = fs.readFileSync("./package-lock.json", "utf-8");
51
- foundPackageLock = true;
52
- }
53
- } catch {
54
- // Ignore errors and continue with installation
55
- }
56
-
57
- // If we found the package-lock.json and could read it, check for eslint v8
58
- if (foundPackageLock && packageLockContent) {
59
- // Look for eslint version 8.x.x pattern in the file content
60
- if (
61
- packageLockContent.indexOf('"eslint":') >= 0 &&
62
- packageLockContent.match(/"eslint":\s*"[~^]?8\.[0-9]+\.[0-9]+"/)
63
- ) {
64
- console.warn(
65
- "\nWarning: This Pepr module uses ESLint v8. Pepr will be upgraded to use v9 in a future release.\nSee eslint@9.0.0 release notes for more details: https://eslint.org/blog/2024/04/eslint-v9.0.0-released/",
66
- );
67
- }
68
- }
69
-
70
44
  // Update Pepr for the module
71
45
  execSync("npm install pepr@latest", {
72
46
  stdio: "inherit",
@@ -82,7 +56,7 @@ export default function (program: RootCmd): void {
82
56
  console.log(`✅ Module updated successfully`);
83
57
  } catch (e) {
84
58
  console.error(`Error updating Pepr module:`, e);
85
- process.exit(1);
59
+ process.exitCode = 1;
86
60
  }
87
61
  });
88
62
 
@@ -113,9 +87,10 @@ export default function (program: RootCmd): void {
113
87
  await write(tsPath, helloPepr.data);
114
88
  }
115
89
  }
90
+ throw new Error("another error, for testing");
116
91
  } catch (e) {
117
92
  console.error(`Error updating template files:`, e);
118
- process.exit(1);
93
+ process.exitCode = 1;
119
94
  }
120
95
  });
121
96
  }
@@ -249,9 +249,9 @@ export class Capability implements CapabilityExport {
249
249
  ...binding,
250
250
  isValidate: true,
251
251
  validateCallback: async (req, logger = aliasLogger) => {
252
- Log.info(
253
- `Executing validate action with alias: ${binding.alias || "no alias provided"}`,
254
- );
252
+ if (binding.alias) {
253
+ Log.info(`Executing validate action with alias: ${binding.alias}`);
254
+ }
255
255
  return await validateCallback(req, logger);
256
256
  },
257
257
  });
@@ -273,9 +273,9 @@ export class Capability implements CapabilityExport {
273
273
  ...binding,
274
274
  isMutate: true,
275
275
  mutateCallback: async (req, logger = aliasLogger) => {
276
- Log.info(
277
- `Executing mutation action with alias: ${binding.alias || "no alias provided"}`,
278
- );
276
+ if (binding.alias) {
277
+ Log.info(`Executing mutation action with alias: ${binding.alias}`);
278
+ }
279
279
  await mutateCallback(req, logger);
280
280
  },
281
281
  });
@@ -300,7 +300,9 @@ export class Capability implements CapabilityExport {
300
300
  ...binding,
301
301
  isWatch: true,
302
302
  watchCallback: async (update, phase, logger = aliasLogger) => {
303
- Log.info(`Executing watch action with alias: ${binding.alias || "no alias provided"}`);
303
+ if (binding.alias) {
304
+ Log.info(`Executing watch action with alias: ${binding.alias}`);
305
+ }
304
306
  await watchCallback(update, phase, logger);
305
307
  },
306
308
  });
@@ -324,9 +326,9 @@ export class Capability implements CapabilityExport {
324
326
  isWatch: true,
325
327
  isQueue: true,
326
328
  watchCallback: async (update, phase, logger = aliasLogger) => {
327
- Log.info(
328
- `Executing reconcile action with alias: ${binding.alias || "no alias provided"}`,
329
- );
329
+ if (binding.alias) {
330
+ Log.info(`Executing reconcile action with alias: ${binding.alias}`);
331
+ }
330
332
  await reconcileCallback(update, phase, logger);
331
333
  },
332
334
  });
@@ -363,9 +365,9 @@ export class Capability implements CapabilityExport {
363
365
  update: InstanceType<T>,
364
366
  logger = aliasLogger,
365
367
  ): Promise<boolean | void> => {
366
- Log.info(
367
- `Executing finalize action with alias: ${binding.alias || "no alias provided"}`,
368
- );
368
+ if (binding.alias) {
369
+ Log.info(`Executing finalize action with alias: ${binding.alias}`);
370
+ }
369
371
  return await finalizeCallback(update, logger);
370
372
  },
371
373
  };
@@ -3,29 +3,38 @@
3
3
  import { K8s, kind } from "kubernetes-fluent-client";
4
4
  import Log from "./telemetry/logger";
5
5
 
6
- // returns true if all deployments are ready, false otherwise
6
+ /**
7
+ * Checks whether all deployments in the specified Kubernetes namespace are fully rolled out.
8
+ *
9
+ * A deployment is considered ready when the number of `readyReplicas` equals the desired `replicas`.
10
+ * Logs the rollout status of each deployment.
11
+ *
12
+ * @param {string} namespace - The Kubernetes namespace to check.
13
+ * @returns {Promise<boolean>} - `true` if all deployments are ready, otherwise `false`.
14
+ */
7
15
  export async function checkDeploymentStatus(namespace: string): Promise<boolean> {
8
16
  const deployments = await K8s(kind.Deployment).InNamespace(namespace).Get();
9
- let status = false;
10
- let readyCount = 0;
17
+
18
+ let allReady = true;
11
19
 
12
20
  for (const deployment of deployments.items) {
13
- const readyReplicas = deployment.status?.readyReplicas ? deployment.status?.readyReplicas : 0;
14
- if (deployment.status?.readyReplicas !== deployment.spec?.replicas) {
21
+ const name = deployment.metadata?.name ?? "unknown";
22
+ const specReplicas = deployment.spec?.replicas ?? 0;
23
+ const readyReplicas = deployment.status?.readyReplicas ?? 0;
24
+
25
+ if (readyReplicas !== specReplicas) {
15
26
  Log.info(
16
- `Waiting for deployment ${deployment.metadata?.name} rollout to finish: ${readyReplicas} of ${deployment.spec?.replicas} replicas are available`,
27
+ `Waiting for deployment ${name} rollout to finish: ${readyReplicas} of ${specReplicas} replicas are available`,
17
28
  );
29
+ allReady = false;
18
30
  } else {
19
31
  Log.info(
20
- `Deployment ${deployment.metadata?.name} rolled out: ${readyReplicas} of ${deployment.spec?.replicas} replicas are available`,
32
+ `Deployment ${name} rolled out: ${readyReplicas} of ${specReplicas} replicas are available`,
21
33
  );
22
- readyCount++;
23
34
  }
24
35
  }
25
- if (readyCount === deployments.items.length) {
26
- status = true;
27
- }
28
- return status;
36
+
37
+ return allReady;
29
38
  }
30
39
 
31
40
  // wait for all deployments in the pepr-system namespace to be ready
@@ -211,7 +211,7 @@ When(a.ConfigMap)
211
211
  When(a.ConfigMap).IsCreated().WithName("example-4").Mutate(example4Cb);
212
212
 
213
213
  // This function uses the complete type definition, but is not required.
214
- function example4Cb(cm: PeprMutateRequest<a.ConfigMap>) {
214
+ function example4Cb(cm: PeprMutateRequest<a.ConfigMap>): void {
215
215
  cm.SetLabel("pepr.dev/first", "true");
216
216
  cm.SetLabel("pepr.dev/second", "true");
217
217
  cm.SetLabel("pepr.dev/third", "true");
@@ -0,0 +1,45 @@
1
+ import typescriptEslint from "@typescript-eslint/eslint-plugin";
2
+ import tsParser from "@typescript-eslint/parser";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import js from "@eslint/js";
6
+ import { FlatCompat } from "@eslint/eslintrc";
7
+ import globals from "globals";
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
11
+ const compat = new FlatCompat({
12
+ baseDirectory: __dirname,
13
+ recommendedConfig: js.configs.recommended,
14
+ allConfig: js.configs.all,
15
+ });
16
+
17
+ export default [
18
+ {
19
+ ignores: ["**/node_modules", "**/dist"],
20
+ },
21
+ ...compat.extends("eslint:recommended", "plugin:@typescript-eslint/recommended"),
22
+ {
23
+ plugins: {
24
+ "@typescript-eslint": typescriptEslint,
25
+ },
26
+
27
+ languageOptions: {
28
+ parser: tsParser,
29
+ parserOptions: {
30
+ projectService: {
31
+ allowDefaultProject: ["eslint.config.mjs"],
32
+ },
33
+ tsconfigRootDir: __dirname,
34
+ sourceType: "module",
35
+ },
36
+ globals: {
37
+ ...globals.node,
38
+ },
39
+ },
40
+
41
+ rules: {
42
+ "@typescript-eslint/no-floating-promises": "error",
43
+ },
44
+ },
45
+ ];
@@ -1,6 +0,0 @@
1
- {
2
- "extends": [".eslintrc.template.json"],
3
- "parserOptions": {
4
- "project": ["src/templates/tsconfig.json"]
5
- }
6
- }
@@ -1,18 +0,0 @@
1
- {
2
- "env": {
3
- "browser": false,
4
- "es2021": true
5
- },
6
- "extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
7
- "parser": "@typescript-eslint/parser",
8
- "parserOptions": {
9
- "project": ["./tsconfig.json"],
10
- "ecmaVersion": 2022
11
- },
12
- "plugins": ["@typescript-eslint"],
13
- "ignorePatterns": ["node_modules", "dist"],
14
- "root": true,
15
- "rules": {
16
- "@typescript-eslint/no-floating-promises": ["error"]
17
- }
18
- }