From 54cd26ef1b026d5db62d096b9541dd403ea121fe Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Fri, 17 Jan 2025 07:46:25 -0600 Subject: [PATCH 1/7] wip: saving progress --- integration/cli/build.configequality.test.ts | 80 ++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 integration/cli/build.configequality.test.ts diff --git a/integration/cli/build.configequality.test.ts b/integration/cli/build.configequality.test.ts new file mode 100644 index 000000000..a7b7e9d26 --- /dev/null +++ b/integration/cli/build.configequality.test.ts @@ -0,0 +1,80 @@ +// SPDX-License-Identifier: Apache-2.0 +// SPDX-FileCopyrightText: 2023-Present The Pepr Authors + +import { beforeAll, describe, expect, it } from "@jest/globals"; +import * as path from "node:path"; +import * as fs from "node:fs/promises"; +import { Workdir } from "../helpers/workdir"; +import * as time from "../helpers/time"; +import * as pepr from "../helpers/pepr"; +// import { ModuleConfig } from "../../src/lib/core/module" + +const FILE = path.basename(__filename); +const HERE = __dirname; + +describe("build", () => { + const workdir = new Workdir(`${FILE}`, `${HERE}/../testroot/cli`); + + beforeAll(async () => { + await workdir.recreate(); + }); + + describe("builds a module", () => { + const id = FILE.split(".").at(1); + const testModule = `${workdir.path()}/${id}`; + + beforeAll(async () => { + await fs.rm(testModule, { recursive: true, force: true }); + const argz = [ + `--name ${id}`, + `--description ${id}`, + `--errorBehavior reject`, + "--confirm", + "--skip-post-init", + ].join(" "); + await pepr.cli(workdir.path(), { cmd: `pepr init ${argz}` }); + await pepr.tgzifyModule(testModule); + await pepr.cli(testModule, { cmd: `npm install` }); + }, time.toMs("2m")); + + describe("using every config option in package.json", () => { + beforeAll(async () => { + const build = await pepr.cli(testModule, { cmd: `pepr build` }); + expect(build.exitcode).toBe(0); + expect(build.stderr.join("").trim()).toBe(""); + expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); + }, time.toMs("1m")); + + it("configures both raw manifest and helm chart appropriately", async () => { + // /** Global configuration for the Pepr runtime. */ + // export type ModuleConfig = { + // /** The Pepr version this module uses */ + // peprVersion?: string; + // /** The user-defined version of the module */ + // appVersion?: string; + // /** A unique identifier for this Pepr module. This is automatically generated by Pepr. */ + // uuid: string; + // /** A description of the Pepr module and what it does. */ + // description?: string; + // /** The webhookTimeout */ + // webhookTimeout?: number; + // /** Reject K8s resource AdmissionRequests on error. */ + // onError?: string; + // /** Configure global exclusions that will never be processed by Pepr. */ + // alwaysIgnore: WebhookIgnore; + // /** Define the log level for the in-cluster controllers */ + // logLevel?: string; + // /** Propagate env variables to in-cluster controllers */ + // env?: Record; + // /** Custom Labels for Kubernetes Objects */ + // customLabels?: CustomLabels; + // /** Custom RBAC rules */ + // rbac?: PolicyRule[]; + // /** The RBAC mode; if "scoped", generates scoped rules, otherwise uses wildcard rules. */ + // rbacMode?: string; + // }; + // TODO: can we (somehow) introspect the type to know which / how many props to match? + }); + }); + }); +}); From 0a225b58925cd2c162da0eb3b7ffb559a02de4fc Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Wed, 22 Jan 2025 17:34:29 -0600 Subject: [PATCH 2/7] wip: saving progress --- integration/cli/build.configequality.test.ts | 211 ++++++++++++++++++- 1 file changed, 202 insertions(+), 9 deletions(-) diff --git a/integration/cli/build.configequality.test.ts b/integration/cli/build.configequality.test.ts index a7b7e9d26..40b3af073 100644 --- a/integration/cli/build.configequality.test.ts +++ b/integration/cli/build.configequality.test.ts @@ -4,10 +4,12 @@ import { beforeAll, describe, expect, it } from "@jest/globals"; import * as path from "node:path"; import * as fs from "node:fs/promises"; +import { kind } from "kubernetes-fluent-client"; import { Workdir } from "../helpers/workdir"; import * as time from "../helpers/time"; import * as pepr from "../helpers/pepr"; -// import { ModuleConfig } from "../../src/lib/core/module" +import * as resource from "../helpers/resource"; +import { ModuleConfig } from "../../src/lib/core/module"; const FILE = path.basename(__filename); const HERE = __dirname; @@ -17,11 +19,12 @@ describe("build", () => { beforeAll(async () => { await workdir.recreate(); - }); + }, time.toMs("1m")); describe("builds a module", () => { const id = FILE.split(".").at(1); const testModule = `${workdir.path()}/${id}`; + const packageJson = `${testModule}/package.json`; beforeAll(async () => { await fs.rm(testModule, { recursive: true, force: true }); @@ -37,21 +40,210 @@ describe("build", () => { await pepr.cli(testModule, { cmd: `npm install` }); }, time.toMs("2m")); - describe("using every config option in package.json", () => { + describe("using every config option in package.json > pepr", () => { + let moduleConfig: Required; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let peprResources: any; + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + let helmResources: any; + beforeAll(async () => { + // set configuration in package.json + const config = await resource.fromFile(packageJson); + config.pepr = { + ...config.pepr, + peprVersion: "1.2.3", + }; + await fs.writeFile(packageJson, JSON.stringify(config, null, 2)); + moduleConfig = config.pepr; + moduleConfig.appVersion = config.version; + + // build module const build = await pepr.cli(testModule, { cmd: `pepr build` }); expect(build.exitcode).toBe(0); expect(build.stderr.join("").trim()).toBe(""); expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); - }, time.toMs("1m")); - it("configures both raw manifest and helm chart appropriately", async () => { + // load helm manifests + const uuid = moduleConfig.uuid; + const chartDir = `${testModule}/dist/${uuid}-chart`; + const helm = await pepr.cli(chartDir, { cmd: `helm template .` }); + expect(build.exitcode).toBe(0); + expect(build.stderr.join("").trim()).toBe(""); + expect(build.stdout.join("").trim()).not.toBe(""); + + const helmManifest = `${chartDir}/reified.yaml`; + await fs.writeFile(helmManifest, helm.stdout.join("\n")); + helmResources = await resource.fromFile(helmManifest); + + // load pepr manifests + const peprManifest = `${testModule}/dist/pepr-module-${uuid}.yaml`; + peprResources = await resource.fromFile(peprManifest); + }, time.toMs("2m")); + + it("configures both raw manifest and helm chart manifests appropriately", // eslint-disable-next-line max-statements, complexity + async () => { + const peprStringified = JSON.stringify(peprResources); + const helmStringified = JSON.stringify(helmResources); + + // peprVersion + expect(peprStringified.includes(moduleConfig.peprVersion)).toBe(false); + expect(helmStringified.includes(moduleConfig.peprVersion)).toBe(false); + + // appVersion + expect(peprStringified.includes(moduleConfig.appVersion)).toBe(false); + expect(helmStringified.includes(moduleConfig.appVersion)).toBe(false); + + // uuid + const peprUuid = `pepr-${moduleConfig.uuid}`; + + for (const clusterRole of [ + resource.select(peprResources, kind.ClusterRole, peprUuid), + resource.select(helmResources, kind.ClusterRole, peprUuid), + ]) { + expect(clusterRole).toBeDefined(); + } + + for (const clusterRoleBinding of [ + resource.select(peprResources, kind.ClusterRoleBinding, peprUuid), + resource.select(helmResources, kind.ClusterRoleBinding, peprUuid), + ]) { + expect(clusterRoleBinding).toBeDefined(); + expect(clusterRoleBinding.roleRef.name).toBe(peprUuid); + expect(clusterRoleBinding!.subjects!.at(0)!.name).toBe(peprUuid); + } + + for (const serviceAccount of [ + resource.select(peprResources, kind.ServiceAccount, peprUuid), + resource.select(helmResources, kind.ServiceAccount, peprUuid), + ]) { + expect(serviceAccount).toBeDefined(); + } + + for (const secretApiToken of [ + resource.select(peprResources, kind.Secret, `${peprUuid}-api-token`), + resource.select(helmResources, kind.Secret, `${peprUuid}-api-token`), + ]) { + expect(secretApiToken).toBeDefined(); + } + + for (const secretTls of [ + resource.select(peprResources, kind.Secret, `${peprUuid}-tls`), + resource.select(helmResources, kind.Secret, `${peprUuid}-tls`), + ]) { + expect(secretTls).toBeDefined(); + } + + for (const deployAdmission of [ + resource.select(peprResources, kind.Deployment, peprUuid), + resource.select(helmResources, kind.Deployment, peprUuid), + ]) { + expect(deployAdmission).toBeDefined(); + expect(deployAdmission.metadata!.labels!.app).toBe(peprUuid); + expect(deployAdmission.metadata!.labels!["pepr.dev/uuid"]).toBe(moduleConfig.uuid); + expect(deployAdmission.spec!.selector!.matchLabels!.app).toBe(peprUuid); + expect(deployAdmission.spec!.template!.metadata!.labels!.app).toBe(peprUuid); + expect(deployAdmission.spec!.template!.spec!.serviceAccountName).toBe(peprUuid); + expect( + deployAdmission + .spec!.template!.spec!.volumes!.filter(vol => vol.name === "tls-certs") + .at(0)!.secret!.secretName, + ).toBe(`${peprUuid}-tls`); + expect( + deployAdmission + .spec!.template!.spec!.volumes!.filter(vol => vol.name === "api-token") + .at(0)!.secret!.secretName, + ).toBe(`${peprUuid}-api-token`); + expect( + deployAdmission + .spec!.template!.spec!.volumes!.filter(vol => vol.name === "module") + .at(0)!.secret!.secretName, + ).toBe(`${peprUuid}-module`); + } + + for (const serviceAdmission of [ + resource.select(peprResources, kind.Service, peprUuid), + resource.select(helmResources, kind.Service, peprUuid), + ]) { + expect(serviceAdmission).toBeDefined(); + expect(serviceAdmission.spec!.selector!.app).toBe(peprUuid); + } + + for (const serviceWatcher of [ + resource.select(peprResources, kind.Service, `${peprUuid}-watcher`), + resource.select(helmResources, kind.Service, `${peprUuid}-watcher`), + ]) { + expect(serviceWatcher).toBeDefined(); + expect(serviceWatcher.spec!.selector!.app).toBe(`${peprUuid}-watcher`); + } + + for (const secretModule of [ + resource.select(peprResources, kind.Secret, `${peprUuid}-module`), + resource.select(helmResources, kind.Secret, `${peprUuid}-module`), + ]) { + expect(secretModule).toBeDefined(); + } + + for (const roleStore of [ + resource.select(peprResources, kind.Role, `${peprUuid}-store`), + resource.select(helmResources, kind.Role, `${peprUuid}-store`), + ]) { + expect(roleStore).toBeDefined(); + } + + for (const roleBindingStore of [ + resource.select(peprResources, kind.RoleBinding, `${peprUuid}-store`), + resource.select(helmResources, kind.RoleBinding, `${peprUuid}-store`), + ]) { + expect(roleBindingStore).toBeDefined(); + expect(roleBindingStore.roleRef.name).toBe(`${peprUuid}-store`); + expect(roleBindingStore!.subjects!.at(0)!.name).toBe(`${peprUuid}-store`); + } + + for (const mwc of [ + resource.select(peprResources, kind.MutatingWebhookConfiguration, peprUuid), + resource.select(helmResources, kind.MutatingWebhookConfiguration, peprUuid), + ]) { + expect(mwc).toBeDefined(); + expect(mwc.webhooks!.at(0)!.name).toBe(`${peprUuid}.pepr.dev`); + expect(mwc.webhooks!.at(0)!.clientConfig.service!.name).toBe(peprUuid); + } + + for (const vwc of [ + resource.select(peprResources, kind.ValidatingWebhookConfiguration, peprUuid), + resource.select(helmResources, kind.ValidatingWebhookConfiguration, peprUuid), + ]) { + expect(vwc).toBeDefined(); + expect(vwc.webhooks!.at(0)!.name).toBe(`${peprUuid}.pepr.dev`); + expect(vwc.webhooks!.at(0)!.clientConfig.service!.name).toBe(peprUuid); + } + + for (const deployWatcher of [ + resource.select(peprResources, kind.Deployment, `${peprUuid}-watcher`), + resource.select(helmResources, kind.Deployment, `${peprUuid}-watcher`), + ]) { + expect(deployWatcher).toBeDefined(); + expect(deployWatcher.metadata!.labels!.app).toBe(`${peprUuid}-watcher`); + expect(deployWatcher.metadata!.labels!["pepr.dev/uuid"]).toBe(moduleConfig.uuid); + expect(deployWatcher.spec!.selector!.matchLabels!.app).toBe(`${peprUuid}-watcher`); + expect(deployWatcher.spec!.template!.metadata!.labels!.app).toBe(`${peprUuid}-watcher`); + expect(deployWatcher.spec!.template!.spec!.serviceAccountName).toBe(peprUuid); + expect( + deployWatcher + .spec!.template!.spec!.volumes!.filter(vol => vol.name === "tls-certs") + .at(0)!.secret!.secretName, + ).toBe(`${peprUuid}-tls`); + expect( + deployWatcher.spec!.template!.spec!.volumes!.filter(vol => vol.name === "module").at(0)! + .secret!.secretName, + ).toBe(`${peprUuid}-module`); + } + // /** Global configuration for the Pepr runtime. */ // export type ModuleConfig = { - // /** The Pepr version this module uses */ - // peprVersion?: string; - // /** The user-defined version of the module */ - // appVersion?: string; + // /** A unique identifier for this Pepr module. This is automatically generated by Pepr. */ // uuid: string; // /** A description of the Pepr module and what it does. */ @@ -74,6 +266,7 @@ describe("build", () => { // rbacMode?: string; // }; // TODO: can we (somehow) introspect the type to know which / how many props to match? + // - need to be able to have the test suite flag when "a change that needs testing" has happened }); }); }); From 06ff8d6161143b27024eddca7de0acc5a1cc2571 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Wed, 22 Jan 2025 17:35:57 -0600 Subject: [PATCH 3/7] wip: saving progress --- integration/cli/build.configequality.test.ts | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/integration/cli/build.configequality.test.ts b/integration/cli/build.configequality.test.ts index 40b3af073..385992df1 100644 --- a/integration/cli/build.configequality.test.ts +++ b/integration/cli/build.configequality.test.ts @@ -42,12 +42,8 @@ describe("build", () => { describe("using every config option in package.json > pepr", () => { let moduleConfig: Required; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let peprResources: any; - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - let helmResources: any; + let peprResources: any; // eslint-disable-line @typescript-eslint/no-explicit-any + let helmResources: any; // eslint-disable-line @typescript-eslint/no-explicit-any beforeAll(async () => { // set configuration in package.json @@ -83,8 +79,8 @@ describe("build", () => { peprResources = await resource.fromFile(peprManifest); }, time.toMs("2m")); - it("configures both raw manifest and helm chart manifests appropriately", // eslint-disable-next-line max-statements, complexity - async () => { + it("configures both raw manifest and helm chart manifests appropriately", async () => { + // eslint-disable-line max-statements, complexity const peprStringified = JSON.stringify(peprResources); const helmStringified = JSON.stringify(helmResources); From 98da1efffa6915452b92997b9b73a76cc8c63e4b Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Wed, 22 Jan 2025 17:36:18 -0600 Subject: [PATCH 4/7] wip: saving progress --- integration/cli/build.configequality.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration/cli/build.configequality.test.ts b/integration/cli/build.configequality.test.ts index 385992df1..dfa6fdf6c 100644 --- a/integration/cli/build.configequality.test.ts +++ b/integration/cli/build.configequality.test.ts @@ -79,8 +79,8 @@ describe("build", () => { peprResources = await resource.fromFile(peprManifest); }, time.toMs("2m")); + // eslint-disable-next-line max-statements, complexity it("configures both raw manifest and helm chart manifests appropriately", async () => { - // eslint-disable-line max-statements, complexity const peprStringified = JSON.stringify(peprResources); const helmStringified = JSON.stringify(helmResources); From 35e47614ddb0e5705c574bcda8281e01cccf6474 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Thu, 23 Jan 2025 10:04:20 -0600 Subject: [PATCH 5/7] wip: saving progress --- integration/cli/build.configequality.test.ts | 221 +++++++++++++++---- 1 file changed, 184 insertions(+), 37 deletions(-) diff --git a/integration/cli/build.configequality.test.ts b/integration/cli/build.configequality.test.ts index dfa6fdf6c..5c02ae62d 100644 --- a/integration/cli/build.configequality.test.ts +++ b/integration/cli/build.configequality.test.ts @@ -40,21 +40,43 @@ describe("build", () => { await pepr.cli(testModule, { cmd: `npm install` }); }, time.toMs("2m")); - describe("using every config option in package.json > pepr", () => { + describe("maps config options from package.json into pepr + helm manifests", () => { let moduleConfig: Required; let peprResources: any; // eslint-disable-line @typescript-eslint/no-explicit-any let helmResources: any; // eslint-disable-line @typescript-eslint/no-explicit-any + let peprUuid: string; + // eslint-disable-next-line max-statements beforeAll(async () => { // set configuration in package.json const config = await resource.fromFile(packageJson); + config.description = "testdesc"; config.pepr = { ...config.pepr, peprVersion: "1.2.3", + webhookTimeout: 11, + onError: "reject", + alwaysIgnore: { + namespaces: ["garbage"], + }, + logLevel: "warning", + env: { + TEST: "env", + }, + customLabels: { + namespace: { + test: "test", + value: "value", + }, + }, }; await fs.writeFile(packageJson, JSON.stringify(config, null, 2)); + + // translate package.json values into ModuleConfig + peprUuid = `pepr-${config.pepr.uuid}`; moduleConfig = config.pepr; moduleConfig.appVersion = config.version; + moduleConfig.description = config.description; // build module const build = await pepr.cli(testModule, { cmd: `pepr build` }); @@ -63,8 +85,7 @@ describe("build", () => { expect(build.stdout.join("").trim()).toContain("K8s resource for the module saved"); // load helm manifests - const uuid = moduleConfig.uuid; - const chartDir = `${testModule}/dist/${uuid}-chart`; + const chartDir = `${testModule}/dist/${moduleConfig.uuid}-chart`; const helm = await pepr.cli(chartDir, { cmd: `helm template .` }); expect(build.exitcode).toBe(0); expect(build.stderr.join("").trim()).toBe(""); @@ -75,26 +96,28 @@ describe("build", () => { helmResources = await resource.fromFile(helmManifest); // load pepr manifests - const peprManifest = `${testModule}/dist/pepr-module-${uuid}.yaml`; + const peprManifest = `${testModule}/dist/pepr-module-${moduleConfig.uuid}.yaml`; peprResources = await resource.fromFile(peprManifest); }, time.toMs("2m")); - // eslint-disable-next-line max-statements, complexity - it("configures both raw manifest and helm chart manifests appropriately", async () => { + it("peprVersion", async () => { const peprStringified = JSON.stringify(peprResources); const helmStringified = JSON.stringify(helmResources); - // peprVersion expect(peprStringified.includes(moduleConfig.peprVersion)).toBe(false); expect(helmStringified.includes(moduleConfig.peprVersion)).toBe(false); + }); + + it("appVersion", async () => { + const peprStringified = JSON.stringify(peprResources); + const helmStringified = JSON.stringify(helmResources); - // appVersion expect(peprStringified.includes(moduleConfig.appVersion)).toBe(false); expect(helmStringified.includes(moduleConfig.appVersion)).toBe(false); + }); - // uuid - const peprUuid = `pepr-${moduleConfig.uuid}`; - + // eslint-disable-next-line max-statements, complexity + it("uuid", async () => { for (const clusterRole of [ resource.select(peprResources, kind.ClusterRole, peprUuid), resource.select(helmResources, kind.ClusterRole, peprUuid), @@ -236,34 +259,158 @@ describe("build", () => { .secret!.secretName, ).toBe(`${peprUuid}-module`); } + }); + + it("description", async () => { + for (const deployAdmission of [ + resource.select(peprResources, kind.Deployment, peprUuid), + resource.select(helmResources, kind.Deployment, peprUuid), + ]) { + expect(deployAdmission.metadata!.annotations!["pepr.dev/description"]).toBe( + moduleConfig.description, + ); + } + + for (const deployWatcher of [ + resource.select(peprResources, kind.Deployment, `${peprUuid}-watcher`), + resource.select(helmResources, kind.Deployment, `${peprUuid}-watcher`), + ]) { + expect(deployWatcher.metadata!.annotations!["pepr.dev/description"]).toBe( + moduleConfig.description, + ); + } + }); + + it("webhookTimeout", async () => { + for (const mwc of [ + resource.select(peprResources, kind.MutatingWebhookConfiguration, peprUuid), + resource.select(helmResources, kind.MutatingWebhookConfiguration, peprUuid), + ]) { + expect(mwc.webhooks!.at(0)!.timeoutSeconds).toBe(moduleConfig.webhookTimeout); + } + + for (const vwc of [ + resource.select(peprResources, kind.ValidatingWebhookConfiguration, peprUuid), + resource.select(helmResources, kind.ValidatingWebhookConfiguration, peprUuid), + ]) { + expect(vwc.webhooks!.at(0)!.timeoutSeconds).toBe(moduleConfig.webhookTimeout); + } + }); + + it("onError", async () => { + const policy = moduleConfig.onError === "reject" ? "Fail" : "Ignore"; + + for (const mwc of [ + resource.select(peprResources, kind.MutatingWebhookConfiguration, peprUuid), + resource.select(helmResources, kind.MutatingWebhookConfiguration, peprUuid), + ]) { + expect(mwc.webhooks!.at(0)!.failurePolicy).toBe(policy); + } - // /** Global configuration for the Pepr runtime. */ - // export type ModuleConfig = { - - // /** A unique identifier for this Pepr module. This is automatically generated by Pepr. */ - // uuid: string; - // /** A description of the Pepr module and what it does. */ - // description?: string; - // /** The webhookTimeout */ - // webhookTimeout?: number; - // /** Reject K8s resource AdmissionRequests on error. */ - // onError?: string; - // /** Configure global exclusions that will never be processed by Pepr. */ - // alwaysIgnore: WebhookIgnore; - // /** Define the log level for the in-cluster controllers */ - // logLevel?: string; - // /** Propagate env variables to in-cluster controllers */ - // env?: Record; - // /** Custom Labels for Kubernetes Objects */ - // customLabels?: CustomLabels; - // /** Custom RBAC rules */ - // rbac?: PolicyRule[]; - // /** The RBAC mode; if "scoped", generates scoped rules, otherwise uses wildcard rules. */ - // rbacMode?: string; - // }; - // TODO: can we (somehow) introspect the type to know which / how many props to match? - // - need to be able to have the test suite flag when "a change that needs testing" has happened + for (const vwc of [ + resource.select(peprResources, kind.ValidatingWebhookConfiguration, peprUuid), + resource.select(helmResources, kind.ValidatingWebhookConfiguration, peprUuid), + ]) { + expect(vwc.webhooks!.at(0)!.failurePolicy).toBe(policy); + } }); + + it("alwaysIgnore.namespaces", async () => { + for (const mwc of [ + resource.select(peprResources, kind.MutatingWebhookConfiguration, peprUuid), + resource.select(helmResources, kind.MutatingWebhookConfiguration, peprUuid), + ]) { + expect(mwc.webhooks!.at(0)!.namespaceSelector!.matchExpressions!.at(0)!.values).toEqual( + expect.arrayContaining(moduleConfig.alwaysIgnore.namespaces!), + ); + } + + for (const vwc of [ + resource.select(peprResources, kind.ValidatingWebhookConfiguration, peprUuid), + resource.select(helmResources, kind.ValidatingWebhookConfiguration, peprUuid), + ]) { + expect(vwc.webhooks!.at(0)!.namespaceSelector!.matchExpressions!.at(0)!.values).toEqual( + expect.arrayContaining(moduleConfig.alwaysIgnore.namespaces!), + ); + } + }); + + it("logLevel", async () => { + for (const deployAdmission of [ + resource.select(peprResources, kind.Deployment, peprUuid), + resource.select(helmResources, kind.Deployment, peprUuid), + ]) { + expect(deployAdmission.spec!.template.spec!.containers.at(0)!.env).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "LOG_LEVEL", value: moduleConfig.logLevel }), + ]), + ); + } + + for (const deployWatcher of [ + resource.select(peprResources, kind.Deployment, `${peprUuid}-watcher`), + resource.select(helmResources, kind.Deployment, `${peprUuid}-watcher`), + ]) { + expect(deployWatcher.spec!.template.spec!.containers.at(0)!.env).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "LOG_LEVEL", value: moduleConfig.logLevel }), + ]), + ); + } + }); + + it("env", async () => { + for (const deployAdmission of [ + resource.select(peprResources, kind.Deployment, peprUuid), + resource.select(helmResources, kind.Deployment, peprUuid), + ]) { + expect(deployAdmission.spec!.template.spec!.containers.at(0)!.env).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "TEST", value: moduleConfig.env.TEST }), + ]), + ); + } + + for (const deployWatcher of [ + resource.select(peprResources, kind.Deployment, `${peprUuid}-watcher`), + resource.select(helmResources, kind.Deployment, `${peprUuid}-watcher`), + ]) { + expect(deployWatcher.spec!.template.spec!.containers.at(0)!.env).toEqual( + expect.arrayContaining([ + expect.objectContaining({ name: "TEST", value: moduleConfig.env.TEST }), + ]), + ); + } + }); + + it("customLabels.namespace", async () => { + for (const namespace of [ + resource.select(peprResources, kind.Namespace, "pepr-system"), + // resource.select(helmResources, kind.Namespace, "pepr-system"), // <-- desired behavior! + ]) { + expect(namespace.metadata!.labels!).toEqual( + expect.objectContaining(moduleConfig.customLabels.namespace!), + ); + } + + // incorrect behavior... + // Issue: https://github.com/defenseunicorns/pepr/issues/1713 + for (const namespace of [resource.select(helmResources, kind.Namespace, "pepr-system")]) { + expect(namespace.metadata!.labels!).toEqual(expect.objectContaining({ "pepr.dev": "" })); + } + // end incorrect behavior... + }); + + // /** Global configuration for the Pepr runtime. */ + // export type ModuleConfig = { + + // /** Custom RBAC rules */ + // rbac?: PolicyRule[]; + // /** The RBAC mode; if "scoped", generates scoped rules, otherwise uses wildcard rules. */ + // rbacMode?: string; + // }; + // TODO: can we (somehow) introspect the type to know which / how many props to match? + // - need to be able to have the test suite flag when "a change that needs testing" has happened }); }); }); From add6013d64736c0dea299050922095843dc186c5 Mon Sep 17 00:00:00 2001 From: Barrett LaFrance Date: Thu, 23 Jan 2025 10:45:42 -0600 Subject: [PATCH 6/7] wip: saving progress --- integration/cli/build.configequality.test.ts | 28 +++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/integration/cli/build.configequality.test.ts b/integration/cli/build.configequality.test.ts index 5c02ae62d..858a9bf85 100644 --- a/integration/cli/build.configequality.test.ts +++ b/integration/cli/build.configequality.test.ts @@ -69,6 +69,14 @@ describe("build", () => { value: "value", }, }, + rbacMode: "scoped", + rbac: [ + { + apiGroups: ["test"], + resources: ["tests"], + verbs: ["get", "list"], + }, + ], }; await fs.writeFile(packageJson, JSON.stringify(config, null, 2)); @@ -401,16 +409,16 @@ describe("build", () => { // end incorrect behavior... }); - // /** Global configuration for the Pepr runtime. */ - // export type ModuleConfig = { - - // /** Custom RBAC rules */ - // rbac?: PolicyRule[]; - // /** The RBAC mode; if "scoped", generates scoped rules, otherwise uses wildcard rules. */ - // rbacMode?: string; - // }; - // TODO: can we (somehow) introspect the type to know which / how many props to match? - // - need to be able to have the test suite flag when "a change that needs testing" has happened + it("rbacMode: scoped + rbac: [...]", async () => { + for (const clusterRole of [ + resource.select(peprResources, kind.ClusterRole, peprUuid), + resource.select(helmResources, kind.ClusterRole, peprUuid), + ]) { + moduleConfig.rbac.forEach(policyRule => { + expect(clusterRole.rules).toContainEqual(policyRule); + }); + } + }); }); }); }); From 097aa275f145bdf91948e7d4f03ba98a5f246066 Mon Sep 17 00:00:00 2001 From: Sam Mayer Date: Mon, 27 Jan 2025 09:21:22 -0600 Subject: [PATCH 7/7] Update integration/cli/build.configequality.test.ts --- integration/cli/build.configequality.test.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/integration/cli/build.configequality.test.ts b/integration/cli/build.configequality.test.ts index 858a9bf85..b6bfe82d6 100644 --- a/integration/cli/build.configequality.test.ts +++ b/integration/cli/build.configequality.test.ts @@ -124,7 +124,6 @@ describe("build", () => { expect(helmStringified.includes(moduleConfig.appVersion)).toBe(false); }); - // eslint-disable-next-line max-statements, complexity it("uuid", async () => { for (const clusterRole of [ resource.select(peprResources, kind.ClusterRole, peprUuid),