pepr 0.26.2 → 0.28.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/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "engines": {
10
10
  "node": ">=18.0.0"
11
11
  },
12
- "version": "0.26.2",
12
+ "version": "0.28.0",
13
13
  "main": "dist/lib.js",
14
14
  "types": "dist/lib.d.ts",
15
15
  "scripts": {
@@ -19,7 +19,7 @@
19
19
  "test": "npm run test:unit && npm run test:journey",
20
20
  "test:unit": "npm run gen-data-json && jest src --coverage --detectOpenHandles --coverageDirectory=./coverage",
21
21
  "test:journey": "npm run test:journey:k3d && npm run test:journey:build && npm run test:journey:image && npm run test:journey:run",
22
- "test:journey:prep": "git clone https://github.com/defenseunicorns/pepr-upgrade-test.git",
22
+ "test:journey:prep": "if [ ! -d ./pepr-upgrade-test ]; then git clone https://github.com/defenseunicorns/pepr-upgrade-test.git ; fi",
23
23
  "test:journey-wasm": "npm run test:journey:k3d && npm run test:journey:build && npm run test:journey:image && npm run test:journey:run-wasm",
24
24
  "test:journey:k3d": "k3d cluster delete pepr-dev && k3d cluster create pepr-dev --k3s-arg '--debug@server:0' --wait && kubectl rollout status deployment -n kube-system",
25
25
  "test:journey:build": "npm run build && npm pack",
@@ -31,27 +31,27 @@
31
31
  "format:fix": "eslint src --fix && prettier src --write"
32
32
  },
33
33
  "dependencies": {
34
- "@types/ramda": "0.29.10",
35
- "express": "4.18.2",
34
+ "@types/ramda": "0.29.11",
35
+ "express": "4.18.3",
36
36
  "fast-json-patch": "3.1.1",
37
- "kubernetes-fluent-client": "2.2.0",
37
+ "kubernetes-fluent-client": "2.2.2",
38
38
  "pino": "8.19.0",
39
39
  "pino-pretty": "10.3.1",
40
40
  "prom-client": "15.1.0",
41
41
  "ramda": "0.29.1"
42
42
  },
43
43
  "devDependencies": {
44
- "@commitlint/cli": "18.6.1",
45
- "@commitlint/config-conventional": "18.6.2",
44
+ "@commitlint/cli": "19.0.3",
45
+ "@commitlint/config-conventional": "19.0.3",
46
46
  "@jest/globals": "29.7.0",
47
- "@types/eslint": "8.56.2",
47
+ "@types/eslint": "8.56.5",
48
48
  "@types/express": "4.17.21",
49
49
  "@types/node": "18.x.x",
50
50
  "@types/node-forge": "1.3.11",
51
51
  "@types/prompts": "2.4.9",
52
52
  "@types/uuid": "9.0.8",
53
53
  "jest": "29.7.0",
54
- "nock": "13.5.3",
54
+ "nock": "13.5.4",
55
55
  "ts-jest": "29.1.2"
56
56
  },
57
57
  "peerDependencies": {
package/src/cli.ts CHANGED
@@ -14,6 +14,7 @@ import uuid from "./cli/uuid";
14
14
  import { version } from "./cli/init/templates";
15
15
  import { RootCmd } from "./cli/root";
16
16
  import update from "./cli/update";
17
+ import kfc from "./cli/kfc";
17
18
 
18
19
  if (process.env.npm_lifecycle_event !== "npx") {
19
20
  console.warn("Pepr should be run via `npx pepr <command>` instead of `pepr <command>`.");
@@ -43,4 +44,5 @@ update(program);
43
44
  format(program);
44
45
  monitor(program);
45
46
  uuid(program);
47
+ kfc(program);
46
48
  program.parse();
@@ -104,13 +104,13 @@ async function setupController(assets: Assets, code: Buffer, hash: string, force
104
104
  await K8s(kind.Secret).Apply(apiToken, { force });
105
105
 
106
106
  Log.info("Applying deployment");
107
- const dep = deployment(assets, hash);
107
+ const dep = deployment(assets, hash, assets.buildTimestamp);
108
108
  await K8s(kind.Deployment).Apply(dep, { force });
109
109
  }
110
110
 
111
111
  async function setupWatcher(assets: Assets, hash: string, force: boolean) {
112
112
  // If the module has a watcher, deploy it
113
- const watchDeployment = watcher(assets, hash);
113
+ const watchDeployment = watcher(assets, hash, assets.buildTimestamp);
114
114
  if (watchDeployment) {
115
115
  Log.info("Applying watcher deployment");
116
116
  await K8s(kind.Deployment).Apply(watchDeployment, { force });
@@ -0,0 +1,199 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
+
4
+ export function nsTemplate() {
5
+ return `
6
+ apiVersion: v1
7
+ kind: Namespace
8
+ metadata:
9
+ name: pepr-system
10
+ {{- if .Values.namespace.annotations }}
11
+ annotations:
12
+ {{- toYaml .Values.namespace.annotations | nindent 6 }}
13
+ {{- end }}
14
+ {{- if .Values.namespace.labels }}
15
+ labels:
16
+ {{- toYaml .Values.namespace.labels | nindent 6 }}
17
+ {{- end }}
18
+ `;
19
+ }
20
+
21
+ export function chartYaml(name: string, description?: string) {
22
+ return `
23
+ apiVersion: v2
24
+ name: ${name}
25
+ description: ${description || ""}
26
+
27
+ # A chart can be either an 'application' or a 'library' chart.
28
+ #
29
+ # Application charts are a collection of templates that can be packaged into versioned archives
30
+ # to be deployed.
31
+ #
32
+ # Library charts provide useful utilities or functions for the chart developer. They're included as
33
+ # a dependency of application charts to inject those utilities and functions into the rendering
34
+ # pipeline. Library charts do not define any templates and therefore cannot be deployed.
35
+ type: application
36
+
37
+ # This is the chart version. This version number should be incremented each time you make changes
38
+ # to the chart and its templates, including the app version.
39
+ # Versions are expected to follow Semantic Versioning (https://semver.org/)
40
+ version: 0.1.0
41
+
42
+ # This is the version number of the application being deployed. This version number should be
43
+ # incremented each time you make changes to the application. Versions are not expected to
44
+ # follow Semantic Versioning. They should reflect the version the application is using.
45
+ # It is recommended to use it with quotes.
46
+ appVersion: "1.16.0"
47
+ `;
48
+ }
49
+
50
+ export function watcherDeployTemplate(buildTimestamp: string) {
51
+ return `
52
+ apiVersion: apps/v1
53
+ kind: Deployment
54
+ metadata:
55
+ name: {{ .Values.uuid }}-watcher
56
+ namespace: pepr-system
57
+ annotations:
58
+ {{- toYaml .Values.watcher.annotations | nindent 4 }}
59
+ labels:
60
+ {{- toYaml .Values.watcher.labels | nindent 4 }}
61
+ spec:
62
+ replicas: 1
63
+ strategy:
64
+ type: Recreate
65
+ selector:
66
+ matchLabels:
67
+ app: {{ .Values.uuid }}-watcher
68
+ pepr.dev/controller: watcher
69
+ template:
70
+ metadata:
71
+ annotations:
72
+ buildTimestamp: "${buildTimestamp}"
73
+ labels:
74
+ app: {{ .Values.uuid }}-watcher
75
+ pepr.dev/controller: watcher
76
+ spec:
77
+ serviceAccountName: {{ .Values.uuid }}
78
+ securityContext:
79
+ {{- toYaml .Values.admission.securityContext | nindent 8 }}
80
+ containers:
81
+ - name: watcher
82
+ image: {{ .Values.watcher.image }}
83
+ imagePullPolicy: IfNotPresent
84
+ command:
85
+ - node
86
+ - /app/node_modules/pepr/dist/controller.js
87
+ - {{ .Values.hash }}
88
+ readinessProbe:
89
+ httpGet:
90
+ path: /healthz
91
+ port: 3000
92
+ scheme: HTTPS
93
+ livenessProbe:
94
+ httpGet:
95
+ path: /healthz
96
+ port: 3000
97
+ scheme: HTTPS
98
+ ports:
99
+ - containerPort: 3000
100
+ resources:
101
+ {{- toYaml .Values.watcher.resources | nindent 12 }}
102
+ env:
103
+ {{- toYaml .Values.watcher.env | nindent 12 }}
104
+ securityContext:
105
+ {{- toYaml .Values.watcher.containerSecurityContext | nindent 12 }}
106
+ volumeMounts:
107
+ - name: tls-certs
108
+ mountPath: /etc/certs
109
+ readOnly: true
110
+ - name: module
111
+ mountPath: /app/load
112
+ readOnly: true
113
+ volumes:
114
+ - name: tls-certs
115
+ secret:
116
+ secretName: {{ .Values.uuid }}-tls
117
+ - name: module
118
+ secret:
119
+ secretName: {{ .Values.uuid }}-module
120
+ `;
121
+ }
122
+
123
+ export function admissionDeployTemplate(buildTimestamp: string) {
124
+ return `
125
+ apiVersion: apps/v1
126
+ kind: Deployment
127
+ metadata:
128
+ name: {{ .Values.uuid }}
129
+ namespace: pepr-system
130
+ annotations:
131
+ {{- toYaml .Values.admission.annotations | nindent 4 }}
132
+ labels:
133
+ {{- toYaml .Values.admission.labels | nindent 4 }}
134
+ spec:
135
+ replicas: 2
136
+ selector:
137
+ matchLabels:
138
+ app: {{ .Values.uuid }}
139
+ pepr.dev/controller: admission
140
+ template:
141
+ metadata:
142
+ annotations:
143
+ buildTimestamp: "${buildTimestamp}"
144
+ labels:
145
+ app: {{ .Values.uuid }}
146
+ pepr.dev/controller: admission
147
+ spec:
148
+ priorityClassName: system-node-critical
149
+ serviceAccountName: {{ .Values.uuid }}
150
+ securityContext:
151
+ {{- toYaml .Values.admission.securityContext | nindent 8 }}
152
+ containers:
153
+ - name: server
154
+ image: {{ .Values.admission.image }}
155
+ imagePullPolicy: IfNotPresent
156
+ command:
157
+ - node
158
+ - /app/node_modules/pepr/dist/controller.js
159
+ - {{ .Values.hash }}
160
+ readinessProbe:
161
+ httpGet:
162
+ path: /healthz
163
+ port: 3000
164
+ scheme: HTTPS
165
+ livenessProbe:
166
+ httpGet:
167
+ path: /healthz
168
+ port: 3000
169
+ scheme: HTTPS
170
+ ports:
171
+ - containerPort: 3000
172
+ resources:
173
+ {{- toYaml .Values.admission.resources | nindent 12 }}
174
+ env:
175
+ {{- toYaml .Values.admission.env | nindent 12 }}
176
+ securityContext:
177
+ {{- toYaml .Values.admission.containerSecurityContext | nindent 12 }}
178
+ volumeMounts:
179
+ - name: tls-certs
180
+ mountPath: /etc/certs
181
+ readOnly: true
182
+ - name: api-token
183
+ mountPath: /app/api-token
184
+ readOnly: true
185
+ - name: module
186
+ mountPath: /app/load
187
+ readOnly: true
188
+ volumes:
189
+ - name: tls-certs
190
+ secret:
191
+ secretName: {{ .Values.uuid }}-tls
192
+ - name: api-token
193
+ secret:
194
+ secretName: {{ .Values.uuid }}-api-token
195
+ - name: module
196
+ secret:
197
+ secretName: {{ .Values.uuid }}-module
198
+ `;
199
+ }
@@ -2,16 +2,24 @@
2
2
  // SPDX-FileCopyrightText: 2023-Present The Pepr Authors
3
3
 
4
4
  import crypto from "crypto";
5
-
5
+ import { dumpYaml } from "@kubernetes/client-node";
6
6
  import { ModuleConfig } from "../module";
7
7
  import { TLSOut, genTLS } from "../tls";
8
8
  import { CapabilityExport } from "../types";
9
9
  import { WebhookIgnore } from "../k8s";
10
10
  import { deploy } from "./deploy";
11
11
  import { loadCapabilities } from "./loader";
12
- import { allYaml, zarfYaml } from "./yaml";
13
- import { namespaceComplianceValidator } from "../helpers";
12
+ import { allYaml, zarfYaml, overridesFile } from "./yaml";
13
+ import { namespaceComplianceValidator, replaceString } from "../helpers";
14
+ import { createDirectoryIfNotExists, dedent } from "../helpers";
15
+ import { resolve } from "path";
16
+ import { chartYaml, nsTemplate, admissionDeployTemplate, watcherDeployTemplate } from "./helm";
17
+ import { promises as fs } from "fs";
18
+ import { webhookConfig } from "./webhooks";
19
+ import { apiTokenSecret, service, tlsSecret, watcherService } from "./networking";
20
+ import { watcher, moduleSecret } from "./pods";
14
21
 
22
+ import { clusterRole, clusterRoleBinding, serviceAccount, storeRole, storeRoleBinding } from "./rbac";
15
23
  export class Assets {
16
24
  readonly name: string;
17
25
  readonly tls: TLSOut;
@@ -20,6 +28,8 @@ export class Assets {
20
28
  capabilities!: CapabilityExport[];
21
29
 
22
30
  image: string;
31
+ buildTimestamp: string;
32
+ hash: string;
23
33
 
24
34
  constructor(
25
35
  readonly config: ModuleConfig,
@@ -27,9 +37,10 @@ export class Assets {
27
37
  readonly host?: string,
28
38
  ) {
29
39
  this.name = `pepr-${config.uuid}`;
40
+ this.buildTimestamp = `${Date.now()}`;
30
41
  this.alwaysIgnore = config.alwaysIgnore;
31
42
  this.image = `ghcr.io/defenseunicorns/pepr/controller:v${config.peprVersion}`;
32
-
43
+ this.hash = "";
33
44
  // Generate the ephemeral tls things
34
45
  this.tls = genTLS(this.host || `${this.name}.pepr-system.svc`);
35
46
 
@@ -37,6 +48,10 @@ export class Assets {
37
48
  this.apiToken = crypto.randomBytes(32).toString("hex");
38
49
  }
39
50
 
51
+ setHash = (hash: string) => {
52
+ this.hash = hash;
53
+ };
54
+
40
55
  deploy = async (force: boolean, webhookTimeout?: number) => {
41
56
  this.capabilities = await loadCapabilities(this.path);
42
57
  await deploy(this, force, webhookTimeout);
@@ -53,4 +68,106 @@ export class Assets {
53
68
 
54
69
  return allYaml(this, rbacMode);
55
70
  };
71
+
72
+ generateHelmChart = async (basePath: string) => {
73
+ const CHART_DIR = `${basePath}/${this.config.uuid}-chart`;
74
+ const CHAR_TEMPLATES_DIR = `${CHART_DIR}/templates`;
75
+ const valuesPath = resolve(CHART_DIR, `values.yaml`);
76
+ const chartPath = resolve(CHART_DIR, `Chart.yaml`);
77
+ const nsPath = resolve(CHAR_TEMPLATES_DIR, `namespace.yaml`);
78
+ const watcherSVCPath = resolve(CHAR_TEMPLATES_DIR, `watcher-service.yaml`);
79
+ const admissionSVCPath = resolve(CHAR_TEMPLATES_DIR, `admission-service.yaml`);
80
+ const mutationWebhookPath = resolve(CHAR_TEMPLATES_DIR, `mutation-webhook.yaml`);
81
+ const validationWebhookPath = resolve(CHAR_TEMPLATES_DIR, `validation-webhook.yaml`);
82
+ const admissionDeployPath = resolve(CHAR_TEMPLATES_DIR, `admission-deployment.yaml`);
83
+ const watcherDeployPath = resolve(CHAR_TEMPLATES_DIR, `watcher-deployment.yaml`);
84
+ const tlsSecretPath = resolve(CHAR_TEMPLATES_DIR, `tls-secret.yaml`);
85
+ const apiTokenSecretPath = resolve(CHAR_TEMPLATES_DIR, `api-token-secret.yaml`);
86
+ const moduleSecretPath = resolve(CHAR_TEMPLATES_DIR, `module-secret.yaml`);
87
+ const storeRolePath = resolve(CHAR_TEMPLATES_DIR, `store-role.yaml`);
88
+ const storeRoleBindingPath = resolve(CHAR_TEMPLATES_DIR, `store-role-binding.yaml`);
89
+ const clusterRolePath = resolve(CHAR_TEMPLATES_DIR, `cluster-role.yaml`);
90
+ const clusterRoleBindingPath = resolve(CHAR_TEMPLATES_DIR, `cluster-role-binding.yaml`);
91
+ const serviceAccountPath = resolve(CHAR_TEMPLATES_DIR, `service-account.yaml`);
92
+
93
+ // create helm chart
94
+ try {
95
+ // create chart dir
96
+ await createDirectoryIfNotExists(CHART_DIR);
97
+
98
+ // create charts dir
99
+ await createDirectoryIfNotExists(`${CHART_DIR}/charts`);
100
+
101
+ // create templates dir
102
+ await createDirectoryIfNotExists(`${CHAR_TEMPLATES_DIR}`);
103
+
104
+ // create values file
105
+ await overridesFile(this, valuesPath);
106
+
107
+ // create the chart.yaml
108
+ await fs.writeFile(chartPath, dedent(chartYaml(this.config.uuid, this.config.description || "")));
109
+
110
+ // create the namespace.yaml in templates
111
+ await fs.writeFile(nsPath, dedent(nsTemplate()));
112
+
113
+ const code = await fs.readFile(this.path);
114
+
115
+ await fs.writeFile(watcherSVCPath, dumpYaml(watcherService(this.name), { noRefs: true }));
116
+ await fs.writeFile(admissionSVCPath, dumpYaml(service(this.name), { noRefs: true }));
117
+ await fs.writeFile(tlsSecretPath, dumpYaml(tlsSecret(this.name, this.tls), { noRefs: true }));
118
+ await fs.writeFile(apiTokenSecretPath, dumpYaml(apiTokenSecret(this.name, this.apiToken), { noRefs: true }));
119
+ await fs.writeFile(moduleSecretPath, dumpYaml(moduleSecret(this.name, code, this.hash), { noRefs: true }));
120
+ await fs.writeFile(storeRolePath, dumpYaml(storeRole(this.name), { noRefs: true }));
121
+ await fs.writeFile(storeRoleBindingPath, dumpYaml(storeRoleBinding(this.name), { noRefs: true }));
122
+ await fs.writeFile(
123
+ clusterRolePath,
124
+ dumpYaml(clusterRole(this.name, this.capabilities, "rbac"), { noRefs: true }),
125
+ );
126
+ await fs.writeFile(clusterRoleBindingPath, dumpYaml(clusterRoleBinding(this.name), { noRefs: true }));
127
+ await fs.writeFile(serviceAccountPath, dumpYaml(serviceAccount(this.name), { noRefs: true }));
128
+
129
+ const mutateWebhook = await webhookConfig(this, "mutate", this.config.webhookTimeout);
130
+ const validateWebhook = await webhookConfig(this, "validate", this.config.webhookTimeout);
131
+ const watchDeployment = watcher(this, this.hash, this.buildTimestamp);
132
+
133
+ if (validateWebhook || mutateWebhook) {
134
+ await fs.writeFile(admissionDeployPath, dedent(admissionDeployTemplate(this.buildTimestamp)));
135
+ }
136
+
137
+ if (mutateWebhook) {
138
+ const yamlMutateWebhook = dumpYaml(mutateWebhook, { noRefs: true });
139
+ const mutateWebhookTemplate = replaceString(
140
+ replaceString(
141
+ replaceString(yamlMutateWebhook, this.name, "{{ .Values.uuid }}"),
142
+ this.config.onError === "reject" ? "Fail" : "Ignore",
143
+ "{{ .Values.admission.failurePolicy }}",
144
+ ),
145
+ `${this.config.webhookTimeout}` || "10",
146
+ "{{ .Values.admission.webhookTimeout }}",
147
+ );
148
+ await fs.writeFile(mutationWebhookPath, mutateWebhookTemplate);
149
+ }
150
+
151
+ if (validateWebhook) {
152
+ const yamlValidateWebhook = dumpYaml(validateWebhook, { noRefs: true });
153
+ const validateWebhookTemplate = replaceString(
154
+ replaceString(
155
+ replaceString(yamlValidateWebhook, this.name, "{{ .Values.uuid }}"),
156
+ this.config.onError === "reject" ? "Fail" : "Ignore",
157
+ "{{ .Values.admission.failurePolicy }}",
158
+ ),
159
+ `${this.config.webhookTimeout}` || "10",
160
+ "{{ .Values.admission.webhookTimeout }}",
161
+ );
162
+ await fs.writeFile(validationWebhookPath, validateWebhookTemplate);
163
+ }
164
+
165
+ if (watchDeployment) {
166
+ await fs.writeFile(watcherDeployPath, dedent(watcherDeployTemplate(this.buildTimestamp)));
167
+ }
168
+ } catch (err) {
169
+ console.error(`Error generating helm chart: ${err.message}`);
170
+ process.exit(1);
171
+ }
172
+ };
56
173
  }
@@ -11,17 +11,27 @@ import { Binding } from "../types";
11
11
 
12
12
  /** Generate the pepr-system namespace */
13
13
  export function namespace(namespaceLabels?: Record<string, string>) {
14
- return {
15
- apiVersion: "v1",
16
- kind: "Namespace",
17
- metadata: {
18
- name: "pepr-system",
19
- labels: namespaceLabels ?? {},
20
- },
21
- };
14
+ if (namespaceLabels) {
15
+ return {
16
+ apiVersion: "v1",
17
+ kind: "Namespace",
18
+ metadata: {
19
+ name: "pepr-system",
20
+ labels: namespaceLabels ?? {},
21
+ },
22
+ };
23
+ } else {
24
+ return {
25
+ apiVersion: "v1",
26
+ kind: "Namespace",
27
+ metadata: {
28
+ name: "pepr-system",
29
+ },
30
+ };
31
+ }
22
32
  }
23
33
 
24
- export function watcher(assets: Assets, hash: string) {
34
+ export function watcher(assets: Assets, hash: string, buildTimestamp: string) {
25
35
  const { name, image, capabilities, config } = assets;
26
36
 
27
37
  let hasSchedule = false;
@@ -73,7 +83,7 @@ export function watcher(assets: Assets, hash: string) {
73
83
  template: {
74
84
  metadata: {
75
85
  annotations: {
76
- buildTimestamp: `${Date.now()}`,
86
+ buildTimestamp: `${buildTimestamp}`,
77
87
  },
78
88
  labels: {
79
89
  app,
@@ -167,7 +177,7 @@ export function watcher(assets: Assets, hash: string) {
167
177
  };
168
178
  }
169
179
 
170
- export function deployment(assets: Assets, hash: string): kind.Deployment {
180
+ export function deployment(assets: Assets, hash: string, buildTimestamp: string): kind.Deployment {
171
181
  const { name, image, config } = assets;
172
182
  const app = name;
173
183
 
@@ -197,7 +207,7 @@ export function deployment(assets: Assets, hash: string): kind.Deployment {
197
207
  template: {
198
208
  metadata: {
199
209
  annotations: {
200
- buildTimestamp: `${Date.now()}`,
210
+ buildTimestamp: `${buildTimestamp}`,
201
211
  },
202
212
  labels: {
203
213
  app,
@@ -11,6 +11,118 @@ import { deployment, moduleSecret, namespace, watcher } from "./pods";
11
11
  import { clusterRole, clusterRoleBinding, serviceAccount, storeRole, storeRoleBinding } from "./rbac";
12
12
  import { webhookConfig } from "./webhooks";
13
13
 
14
+ // Helm Chart overrides file (values.yaml) generated from assets
15
+ export async function overridesFile({ hash, name, image, config, apiToken }: Assets, path: string) {
16
+ const overrides = {
17
+ secrets: {
18
+ apiToken: Buffer.from(apiToken).toString("base64"),
19
+ },
20
+ hash,
21
+ namespace: {
22
+ annotations: {},
23
+ labels: {
24
+ "pepr.dev": "",
25
+ },
26
+ },
27
+ uuid: name,
28
+ admission: {
29
+ failurePolicy: config.onError === "reject" ? "Fail" : "Ignore",
30
+ webhookTimeout: config.webhookTimeout,
31
+ env: [
32
+ { name: "PEPR_WATCH_MODE", value: "false" },
33
+ { name: "PEPR_PRETTY_LOG", value: "false" },
34
+ { name: "LOG_LEVEL", value: "debug" },
35
+ process.env.PEPR_MODE === "dev" && { name: "MY_CUSTOM_VAR", value: "example-value" },
36
+ process.env.PEPR_MODE === "dev" && { name: "ZARF_VAR", value: "###ZARF_VAR_THING###" },
37
+ ],
38
+ image,
39
+ annotations: {
40
+ "pepr.dev/description": `${config.description}` || "",
41
+ },
42
+ labels: {
43
+ app: name,
44
+ "pepr.dev/controller": "admission",
45
+ "pepr.dev/uuid": config.uuid,
46
+ },
47
+ securityContext: {
48
+ runAsUser: 65532,
49
+ runAsGroup: 65532,
50
+ runAsNonRoot: true,
51
+ fsGroup: 65532,
52
+ },
53
+ resources: {
54
+ requests: {
55
+ memory: "64Mi",
56
+ cpu: "100m",
57
+ },
58
+ limits: {
59
+ memory: "256Mi",
60
+ cpu: "500m",
61
+ },
62
+ },
63
+ containerSecurityContext: {
64
+ runAsUser: 65532,
65
+ runAsGroup: 65532,
66
+ runAsNonRoot: true,
67
+ allowPrivilegeEscalation: false,
68
+ capabilities: {
69
+ drop: ["ALL"],
70
+ },
71
+ },
72
+ nodeSelector: {},
73
+ tolerations: [],
74
+ affinity: {},
75
+ },
76
+ watcher: {
77
+ env: [
78
+ { name: "PEPR_WATCH_MODE", value: "true" },
79
+ { name: "PEPR_PRETTY_LOG", value: "false" },
80
+ { name: "LOG_LEVEL", value: "debug" },
81
+ process.env.PEPR_MODE === "dev" && { name: "MY_CUSTOM_VAR", value: "example-value" },
82
+ process.env.PEPR_MODE === "dev" && { name: "ZARF_VAR", value: "###ZARF_VAR_THING###" },
83
+ ],
84
+ image,
85
+ annotations: {
86
+ "pepr.dev/description": `${config.description}` || "",
87
+ },
88
+ labels: {
89
+ app: `${name}-watcher`,
90
+ "pepr.dev/controller": "watcher",
91
+ "pepr.dev/uuid": config.uuid,
92
+ },
93
+ securityContext: {
94
+ runAsUser: 65532,
95
+ runAsGroup: 65532,
96
+ runAsNonRoot: true,
97
+ fsGroup: 65532,
98
+ },
99
+ resources: {
100
+ requests: {
101
+ memory: "64Mi",
102
+ cpu: "100m",
103
+ },
104
+ limits: {
105
+ memory: "256Mi",
106
+ cpu: "500m",
107
+ },
108
+ },
109
+ containerSecurityContext: {
110
+ runAsUser: 65532,
111
+ runAsGroup: 65532,
112
+ runAsNonRoot: true,
113
+ allowPrivilegeEscalation: false,
114
+ capabilities: {
115
+ drop: ["ALL"],
116
+ },
117
+ },
118
+ nodeSelector: {},
119
+ tolerations: [],
120
+ affinity: {},
121
+ },
122
+ };
123
+
124
+ await fs.writeFile(path, dumpYaml(overrides, { noRefs: true, forceQuotes: true }));
125
+ }
14
126
  export function zarfYaml({ name, image, config }: Assets, path: string) {
15
127
  const zarfCfg = {
16
128
  kind: "ZarfPackageConfig",
@@ -45,11 +157,11 @@ export async function allYaml(assets: Assets, rbacMode: string) {
45
157
  const code = await fs.readFile(path);
46
158
 
47
159
  // Generate a hash of the code
48
- const hash = crypto.createHash("sha256").update(code).digest("hex");
160
+ assets.hash = crypto.createHash("sha256").update(code).digest("hex");
49
161
 
50
162
  const mutateWebhook = await webhookConfig(assets, "mutate", assets.config.webhookTimeout);
51
163
  const validateWebhook = await webhookConfig(assets, "validate", assets.config.webhookTimeout);
52
- const watchDeployment = watcher(assets, hash);
164
+ const watchDeployment = watcher(assets, assets.hash, assets.buildTimestamp);
53
165
 
54
166
  const resources = [
55
167
  namespace(assets.config.customLabels?.namespace),
@@ -58,10 +170,10 @@ export async function allYaml(assets: Assets, rbacMode: string) {
58
170
  serviceAccount(name),
59
171
  apiTokenSecret(name, apiToken),
60
172
  tlsSecret(name, tls),
61
- deployment(assets, hash),
173
+ deployment(assets, assets.hash, assets.buildTimestamp),
62
174
  service(name),
63
175
  watcherService(name),
64
- moduleSecret(name, code, hash),
176
+ moduleSecret(name, code, assets.hash),
65
177
  storeRole(name),
66
178
  storeRoleBinding(name),
67
179
  ];
package/src/lib/filter.ts CHANGED
@@ -47,7 +47,10 @@ export function shouldSkipRequest(binding: Binding, req: AdmissionRequest, capab
47
47
  }
48
48
 
49
49
  // Test for matching namespaces
50
- if (combinedNamespaces.length && !combinedNamespaces.includes(req.namespace || "")) {
50
+ if (
51
+ (combinedNamespaces.length && !combinedNamespaces.includes(req.namespace || "")) ||
52
+ (!namespaces.includes(req.namespace || "") && capabilityNamespaces.length !== 0 && namespaces.length !== 0)
53
+ ) {
51
54
  logger.debug("Namespace does not match");
52
55
  return true;
53
56
  }