From 1d210a2590501e4a5e17cc059945c08ebcfc724b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Feb 2025 08:16:41 -0500 Subject: [PATCH 1/6] chore: bump trufflesecurity/trufflehog from 3.88.12 to 3.88.13 (#1876) Bumps [trufflesecurity/trufflehog](https://github.com/trufflesecurity/trufflehog) from 3.88.12 to 3.88.13.
Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=trufflesecurity/trufflehog&package-manager=github_actions&previous-version=3.88.12&new-version=3.88.13)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/secret-scan.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/secret-scan.yml b/.github/workflows/secret-scan.yml index 341096ba..3760238f 100644 --- a/.github/workflows/secret-scan.yml +++ b/.github/workflows/secret-scan.yml @@ -23,6 +23,6 @@ jobs: with: fetch-depth: 0 - name: Default Secret Scanning - uses: trufflesecurity/trufflehog@a2a17cd73d74376209d6323c80a9a55b424e25b0 # main + uses: trufflesecurity/trufflehog@03e8af1075a7f7410664de9f6a1101268c9c8c92 # main with: extra_args: --debug --no-verification # Warn on potential violations From 261274d3d7d55bb05b8709a4741c1e2c31933489 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Feb 2025 08:17:08 -0500 Subject: [PATCH 2/6] chore: bump slsa-framework/slsa-github-generator from 2.0.0 to 2.1.0 (#1875) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [slsa-framework/slsa-github-generator](https://github.com/slsa-framework/slsa-github-generator) from 2.0.0 to 2.1.0.
Release notes

Sourced from slsa-framework/slsa-github-generator's releases.

v2.1.0

This is an un-finalized release.

See the CHANGELOG for details.

What's Changed

... (truncated)

Commits

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=slsa-framework/slsa-github-generator&package-manager=github_actions&previous-version=2.0.0&new-version=2.1.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/release.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 79fde786..e47a6036 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -63,7 +63,7 @@ jobs: id-token: write contents: read actions: read - uses: slsa-framework/slsa-github-generator/.github/workflows/builder_nodejs_slsa3.yml@v2.0.0 + uses: slsa-framework/slsa-github-generator/.github/workflows/builder_nodejs_slsa3.yml@v2.1.0 with: run-scripts: "set:version, ci, build" @@ -82,7 +82,7 @@ jobs: registry-url: "https://registry.npmjs.org" - name: Publish package id: publish - uses: slsa-framework/slsa-github-generator/actions/nodejs/publish@5a775b367a56d5bd118a224a811bba288150a563 # v2.0.0 + uses: slsa-framework/slsa-github-generator/actions/nodejs/publish@9103ac683d00ceecdb1c21507a9c7a9983ef46f4 # v2.0.0 with: access: public node-auth-token: ${{ secrets.NPM_TOKEN }} From 42cd8de3a9825f3dc51c27b38e1da48f35687d9c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 25 Feb 2025 13:18:20 +0000 Subject: [PATCH 3/6] chore: bump ts-jest from 29.2.5 to 29.2.6 in the development-dependencies group (#1874) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps the development-dependencies group with 1 update: [ts-jest](https://github.com/kulshekhar/ts-jest). Updates `ts-jest` from 29.2.5 to 29.2.6
Release notes

Sourced from ts-jest's releases.

v29.2.6

Please refer to CHANGELOG.md for details.

Changelog

Sourced from ts-jest's changelog.

29.2.6 (2025-02-22)

Bug Fixes

  • fix: escape dot for JS_TRANSFORM_PATTERN regex (8c91c60)
  • fix: escape dot for TS_JS_TRANSFORM_PATTERN regex (3eea850)
  • fix: escape dot for TS_TRANSFORM_PATTERN regex (80d3e4d), closes #4579
Commits
  • 6a38767 chore(release): 29.2.6
  • 36e50e4 docs: update transform regex
  • 8c91c60 fix: escape dot for JS_TRANSFORM_PATTERN regex
  • 3eea850 fix: escape dot for TS_JS_TRANSFORM_PATTERN regex
  • 80d3e4d fix: escape dot for TS_TRANSFORM_PATTERN regex
  • 4811d42 build(deps): Update JamesIves/github-pages-deploy-action action to v4.7.3
  • 82d1116 build(deps): Update babel monorepo to ^7.26.9
  • ab058a9 build(deps): Update dependency @​types/node to v20.17.19
  • 399e918 build(deps): Update dependency @​formatjs/ts-transformer to ^3.13.32
  • 54181f1 build(deps): Update dependency @​vitejs/plugin-react-swc to ^3.8.0
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=ts-jest&package-manager=npm_and_yarn&previous-version=29.2.5&new-version=29.2.6)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore ` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore ` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore ` will remove the ignore condition of the specified dependency and ignore conditions
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 16 ++++++++-------- package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/package-lock.json b/package-lock.json index d7f44c0f..5b1faa47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -42,7 +42,7 @@ "jest": "29.7.0", "js-yaml": "^4.1.0", "shellcheck": "^3.0.0", - "ts-jest": "29.2.5", + "ts-jest": "29.2.6", "undici": "^7.0.1" }, "engines": { @@ -9525,9 +9525,9 @@ "license": "MIT" }, "node_modules/semver": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.0.tgz", - "integrity": "sha512-DrfFnPzblFmNrIZzg5RzHegbiRWg7KMR7btwi2yjHwx06zsUbO5g613sVwEV7FTwmzJu+Io0lJe2GJ3LxqpvBQ==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -10355,9 +10355,9 @@ } }, "node_modules/ts-jest": { - "version": "29.2.5", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.5.tgz", - "integrity": "sha512-KD8zB2aAZrcKIdGk4OwpJggeLcH1FgrICqDSROWqlnJXGCXK4Mn6FcdK2B6670Xr73lHMG1kHw8R87A0ecZ+vA==", + "version": "29.2.6", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.2.6.tgz", + "integrity": "sha512-yTNZVZqc8lSixm+QGVFcPe6+yj7+TWZwIesuOWvfcn4B9bz5x4NDzVCQQjOs7Hfouu36aEqfEbo9Qpo+gq8dDg==", "dev": true, "license": "MIT", "dependencies": { @@ -10368,7 +10368,7 @@ "json5": "^2.2.3", "lodash.memoize": "^4.1.2", "make-error": "^1.3.6", - "semver": "^7.6.3", + "semver": "^7.7.1", "yargs-parser": "^21.1.1" }, "bin": { diff --git a/package.json b/package.json index 9d1dfdd7..3794a3c7 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,7 @@ "jest": "29.7.0", "js-yaml": "^4.1.0", "shellcheck": "^3.0.0", - "ts-jest": "29.2.5", + "ts-jest": "29.2.6", "undici": "^7.0.1" }, "overrides": { From 00b120b1b530b70156532c48b006ecc0d9815f35 Mon Sep 17 00:00:00 2001 From: Tamir Azrab Date: Tue, 25 Feb 2025 22:27:04 +0500 Subject: [PATCH 4/6] chore: remove usage of regex matches in filter test condition (#1869) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit …#1779) ## Description ... End to End Test: (See [Pepr Excellent Examples](https://github.com/defenseunicorns/pepr-excellent-examples)) ## Related Issue Fixes #1779 ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [x] Other (security config, docs update, etc) ## Checklist before merging - [x] Unit, [Journey](https://github.com/defenseunicorns/pepr/tree/main/journey), [E2E Tests](https://github.com/defenseunicorns/pepr-excellent-examples), [docs](https://github.com/defenseunicorns/pepr/tree/main/docs), [adr](https://github.com/defenseunicorns/pepr/tree/main/adr) added or updated as needed - [x] [Contributor Guide Steps](https://docs.pepr.dev/main/contribute/#submitting-a-pull-request) followed Co-authored-by: Case Wylie --- src/lib/filter/filter.test.ts | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/lib/filter/filter.test.ts b/src/lib/filter/filter.test.ts index 4d4d7601..ed1d3afa 100644 --- a/src/lib/filter/filter.test.ts +++ b/src/lib/filter/filter.test.ts @@ -137,8 +137,9 @@ describe("shouldSkipRequest", () => { }); const pod = AdmissionRequestCreatePod(); + expect(shouldSkipRequest(binding, pod, [])).toMatch( - /Ignoring Admission Callback: Binding defines name regex '.*' but Object carries '.*'./, + /Ignoring Admission Callback: Binding defines name regex '\^default\$' but Object carries 'cool-name-podinfo-66bbff7cf4-fwhl2'./, ); }); @@ -160,7 +161,7 @@ describe("shouldSkipRequest", () => { const pod = AdmissionRequestDeletePod(); expect(shouldSkipRequest(binding, pod, [])).toMatch( - /Ignoring Admission Callback: Binding defines name regex '.*' but Object carries '.*'./, + /Ignoring Admission Callback: Binding defines name regex '\^default\$' but Object carries 'cool-name-podinfo-66bbff7cf4-fwhl2'./, ); }); @@ -192,7 +193,7 @@ describe("shouldSkipRequest", () => { const pod = AdmissionRequestCreatePod(); expect(shouldSkipRequest(binding, pod, [])).toMatch( - /Ignoring Admission Callback: Binding defines namespace regexes '.*' but Object carries '.*'./, + /Ignoring Admission Callback: Binding defines namespace regexes '\["\^argo"\]' but Object carries 'helm-releasename'./, ); }); @@ -204,7 +205,7 @@ describe("shouldSkipRequest", () => { const pod = AdmissionRequestDeletePod(); expect(shouldSkipRequest(binding, pod, [])).toMatch( - /Ignoring Admission Callback: Binding defines namespace regexes '.*' but Object carries '.*'./, + /Ignoring Admission Callback: Binding defines namespace regexes '\["\^argo"\]' but Object carries 'helm-releasename'./, ); }); @@ -226,7 +227,7 @@ describe("shouldSkipRequest", () => { const pod = AdmissionRequestDeletePod(); expect(shouldSkipRequest(binding, pod, [])).toMatch( - /Ignoring Admission Callback: Binding defines name '.*' but Object carries '.*'./, + /Ignoring Admission Callback: Binding defines name 'bleh' but Object carries 'cool-name-podinfo-66bbff7cf4-fwhl2'./, ); }); @@ -239,7 +240,7 @@ describe("shouldSkipRequest", () => { const pod = AdmissionRequestCreatePod(); expect(shouldSkipRequest(binding, pod, [])).toMatch( - /Ignoring Admission Callback: Binding defines kind '.*' but Request declares '.*'./, + /Ignoring Admission Callback: Binding defines kind 'Nope' but Request declares 'Pod'./, ); }); @@ -252,7 +253,7 @@ describe("shouldSkipRequest", () => { const pod = AdmissionRequestCreatePod(); expect(shouldSkipRequest(binding, pod, [])).toMatch( - /Ignoring Admission Callback: Binding defines group '.*' but Request declares '.*'./, + /Ignoring Admission Callback: Binding defines group 'Nope' but Request declares ''./, ); }); @@ -265,7 +266,7 @@ describe("shouldSkipRequest", () => { const pod = AdmissionRequestCreatePod(); expect(shouldSkipRequest(binding, pod, [])).toMatch( - /Ignoring Admission Callback: Binding defines version '.*' but Request declares '.*'./, + /Ignoring Admission Callback: Binding defines version 'Nope' but Request declares 'v1'./, ); }); @@ -298,7 +299,7 @@ describe("shouldSkipRequest", () => { const pod = AdmissionRequestCreatePod(); expect(shouldSkipRequest(binding, pod, ["bleh", "bleh2"])).toMatch( - /Ignoring Admission Callback: Object carries namespace '.*' but namespaces allowed by Capability are '.*'./, + /Ignoring Admission Callback: Object carries namespace 'helm-releasename' but namespaces allowed by Capability are '\["bleh","bleh2"\]'\./, ); }); @@ -311,7 +312,7 @@ describe("shouldSkipRequest", () => { const pod = AdmissionRequestCreatePod(); expect(shouldSkipRequest(binding, pod, [])).toMatch( - /Ignoring Admission Callback: Binding defines namespaces '.*' but Object carries '.*'./, + /Ignoring Admission Callback: Binding defines namespaces '\["bleh"\]' but Object carries 'helm-releasename'./, ); }); @@ -339,7 +340,7 @@ describe("shouldSkipRequest", () => { const pod = AdmissionRequestCreatePod(); expect(shouldSkipRequest(binding, pod, [])).toMatch( - /Ignoring Admission Callback: Binding defines labels '.*' but Object carries '.*'./, + /Ignoring Admission Callback: Binding defines labels '\{"foo":"bar"\}' but Object carries '\{"app\.kubernetes\.io\/name":"cool-name-podinfo","pod-template-hash":"66bbff7cf4","zarf-agent":"patched","test-op":"create"\}'.*/, ); }); @@ -378,7 +379,7 @@ describe("shouldSkipRequest", () => { const pod = AdmissionRequestCreatePod(); expect(shouldSkipRequest(binding, pod, [])).toMatch( - /Ignoring Admission Callback: Binding defines annotations '.*' but Object carries '.*'./, + /Ignoring Admission Callback: Binding defines annotations '\{"foo":"bar"\}' but Object carries '\{"prometheus\.io\/port":"9898","prometheus\.io\/scrape":"true"\}'./, ); }); From 1f9492bac69eda5b729cd1f96ac0308079522650 Mon Sep 17 00:00:00 2001 From: Tamir Azrab Date: Tue, 25 Feb 2025 23:14:00 +0500 Subject: [PATCH 5/6] chore(test): enforce ordering for callback processing (#1867) ## Description Add missing test case to definedCallback() ... End to End Test: (See [Pepr Excellent Examples](https://github.com/defenseunicorns/pepr-excellent-examples)) ## Related Issue Fixes #1859 ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [x] Other (security config, docs update, etc) ## Checklist before merging - [x] Unit, [Journey](https://github.com/defenseunicorns/pepr/tree/main/journey), [E2E Tests](https://github.com/defenseunicorns/pepr-excellent-examples), [docs](https://github.com/defenseunicorns/pepr/tree/main/docs), [adr](https://github.com/defenseunicorns/pepr/tree/main/adr) added or updated as needed - [x] [Contributor Guide Steps](https://docs.pepr.dev/main/contribute/#submitting-a-pull-request) followed --------- Co-authored-by: Sam Mayer Co-authored-by: Case Wylie --- .../adjudicators/bindingAdjudicators.test.ts | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/src/lib/filter/adjudicators/bindingAdjudicators.test.ts b/src/lib/filter/adjudicators/bindingAdjudicators.test.ts index e04043b0..48e02dc2 100644 --- a/src/lib/filter/adjudicators/bindingAdjudicators.test.ts +++ b/src/lib/filter/adjudicators/bindingAdjudicators.test.ts @@ -662,6 +662,41 @@ describe("definedCallback", () => { [{ isMutate: true, mutateCallback }, mutateCallback], [{ isWatch: true, watchCallback }, watchCallback], [{ isFinalize: true, finalizeCallback }, finalizeCallback], + [{ isFinalize: true, isValidate: true, finalizeCallback, validateCallback }, finalizeCallback], // Finalize > Validate + [{ isFinalize: true, isWatch: true, finalizeCallback, watchCallback }, finalizeCallback], // Finalize > Watch + [ + { isFinalize: true, isMutate: true, isWatch: true, finalizeCallback, mutateCallback, watchCallback }, + finalizeCallback, + ], // Finalize > Mutate > Watch + [{ isValidate: true, isMutate: true, validateCallback, mutateCallback }, mutateCallback], // Mutate > Validate + [{ isWatch: true, isMutate: true, watchCallback, mutateCallback }, watchCallback], // Watch > Mutate + [{ isMutate: true, isFinalize: true, mutateCallback, finalizeCallback }, finalizeCallback], // Finalize > Mutate + [ + { isMutate: true, isWatch: true, isFinalize: true, mutateCallback, watchCallback, finalizeCallback }, + finalizeCallback, + ], // Finalize > Watch > Mutate + [ + { isValidate: true, isMutate: true, isFinalize: true, validateCallback, mutateCallback, finalizeCallback }, + finalizeCallback, + ], // Finalize > Mutate > Validate + [ + { isValidate: true, isMutate: true, isWatch: true, validateCallback, mutateCallback, watchCallback }, + watchCallback, + ], // Watch > Mutate > Validate + [{ isValidate: true, isWatch: true, validateCallback, watchCallback }, watchCallback], // Watch > Validate + [ + { + isValidate: true, + isMutate: true, + isWatch: true, + isFinalize: true, + validateCallback, + mutateCallback, + watchCallback, + finalizeCallback, + }, + finalizeCallback, + ], // Finalize > Watch > Mutate > Validate ])("given %j, returns %s", (given, expected) => { const binding: Binding = { ...defaultBinding, From 2c6eeaead3158a8b9456286e286ff55c9345a176 Mon Sep 17 00:00:00 2001 From: Sam Mayer Date: Tue, 25 Feb 2025 13:38:28 -0600 Subject: [PATCH 6/6] chore(test): extract test data generation for RBAC tests (#1878) ## Description This PR works on improving our test data generation strategy for RBAC tests. It moves static test data to a separate file without making other changes to support a follow-on PR. End to End Test: (See [Pepr Excellent Examples](https://github.com/defenseunicorns/pepr-excellent-examples)) ## Related Issue Relates to #1329 ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change which adds functionality) - [x] Other (security config, docs update, etc) ## Checklist before merging - [x] Unit, [Journey](https://github.com/defenseunicorns/pepr/tree/main/journey), [E2E Tests](https://github.com/defenseunicorns/pepr-excellent-examples), [docs](https://github.com/defenseunicorns/pepr/tree/main/docs), [adr](https://github.com/defenseunicorns/pepr/tree/main/adr) added or updated as needed - [x] [Contributor Guide Steps](https://docs.pepr.dev/main/contribute/#submitting-a-pull-request) followed Co-authored-by: Case Wylie --- src/lib/assets/defaultTestObjects.ts | 533 +++++++++++++++++++++++++++ src/lib/assets/rbac.test.ts | 532 +------------------------- 2 files changed, 534 insertions(+), 531 deletions(-) create mode 100644 src/lib/assets/defaultTestObjects.ts diff --git a/src/lib/assets/defaultTestObjects.ts b/src/lib/assets/defaultTestObjects.ts new file mode 100644 index 00000000..28814a98 --- /dev/null +++ b/src/lib/assets/defaultTestObjects.ts @@ -0,0 +1,533 @@ +import { GenericClass } from "kubernetes-fluent-client"; +import { Event } from "../enums"; +import { CapabilityExport } from "../types"; +import { describe, beforeEach, jest, it, expect } from "@jest/globals"; +import { V1PolicyRule as PolicyRule } from "@kubernetes/client-node"; +import fs from "fs"; +import { clusterRole } from "./rbac"; +import * as helpers from "../helpers"; + +export const mockCapabilities: CapabilityExport[] = [ + { + rbac: [ + { + apiGroups: ["pepr.dev"], + resources: ["peprstores"], + verbs: ["create", "get", "patch", "watch"], + }, + ], + bindings: [ + { + kind: { group: "pepr.dev", version: "v1", kind: "peprstore", plural: "peprstores" }, + isWatch: false, + event: Event.CREATE, + model: {} as GenericClass, + filters: { + name: "", + regexName: "", + namespaces: [], + regexNamespaces: [], + labels: {}, + annotations: {}, + deletionTimestamp: false, + }, + }, + ], + hasSchedule: false, + name: "", + description: "", + }, + { + rbac: [ + { + apiGroups: ["apiextensions.k8s.io"], + resources: ["customresourcedefinitions"], + verbs: ["patch", "create"], + }, + ], + bindings: [ + { + kind: { + group: "apiextensions.k8s.io", + version: "v1", + kind: "customresourcedefinition", + plural: "customresourcedefinitions", + }, + isWatch: false, + isFinalize: false, + event: Event.CREATE, + model: {} as GenericClass, + filters: { + name: "", + regexName: "", + namespaces: [], + regexNamespaces: [], + labels: {}, + annotations: {}, + deletionTimestamp: false, + }, + }, + ], + hasSchedule: false, + name: "", + description: "", + }, + { + rbac: [ + { + apiGroups: [""], + resources: ["namespaces"], + verbs: ["watch"], + }, + ], + bindings: [ + { + kind: { group: "", version: "v1", kind: "namespace", plural: "namespaces" }, + isWatch: true, + isFinalize: false, + event: Event.CREATE, + model: {} as GenericClass, + filters: { + name: "", + regexName: "", + namespaces: [], + regexNamespaces: [], + labels: {}, + annotations: {}, + deletionTimestamp: false, + }, + }, + ], + hasSchedule: false, + name: "", + description: "", + }, + { + rbac: [ + { + apiGroups: [""], + resources: ["configmaps"], + verbs: ["watch"], + }, + ], + bindings: [ + { + kind: { group: "", version: "v1", kind: "configmap", plural: "configmaps" }, + isWatch: true, + isFinalize: false, + event: Event.CREATE, + model: {} as GenericClass, + filters: { + name: "", + regexName: "", + namespaces: [], + regexNamespaces: [], + labels: {}, + annotations: {}, + deletionTimestamp: false, + }, + }, + ], + hasSchedule: false, + name: "", + description: "", + }, +]; +describe("RBAC generation", () => { + beforeEach(() => { + jest.clearAllMocks(); + const mockPackageJsonRBAC = {}; + + jest.spyOn(fs, "readFileSync").mockImplementation((path: unknown) => { + if (typeof path === "string" && path.includes("package.json")) { + return JSON.stringify({ rbac: mockPackageJsonRBAC }); + } + return "{}"; + }); + }); + + it("should generate correct ClusterRole rules in scoped mode", () => { + const result = clusterRole("test-role", mockCapabilities, "scoped", []); + + expect(result.rules).toEqual([ + { + apiGroups: ["pepr.dev"], + resources: ["peprstores"], + verbs: ["create", "get", "patch", "watch"], + }, + { + apiGroups: ["apiextensions.k8s.io"], + resources: ["customresourcedefinitions"], + verbs: ["patch", "create"], + }, + { + apiGroups: [""], + resources: ["namespaces"], + verbs: ["watch"], + }, + { + apiGroups: [""], + resources: ["configmaps"], + verbs: ["watch"], + }, + ]); + }); + + it("should generate a ClusterRole with wildcard rules when not in scoped mode", () => { + const expectedWildcardRules = [ + { + apiGroups: ["*"], + resources: ["*"], + verbs: ["create", "delete", "get", "list", "patch", "update", "watch"], + }, + ]; + + const result = clusterRole("test-role", mockCapabilities, "admin", []); + + expect(result.rules).toEqual(expectedWildcardRules); + }); + + it("should return an empty rules array when capabilities are empty in scoped mode", () => { + const result = clusterRole("test-role", [], "scoped", []); + + expect(result.rules).toEqual([]); + }); + + it("should include finalize verbs if isFinalize is true in scoped mode", () => { + const capabilitiesWithFinalize: CapabilityExport[] = [ + { + rbac: [ + { + apiGroups: ["pepr.dev"], + resources: ["peprstores"], + verbs: ["patch"], + }, + ], + bindings: [ + { + kind: { group: "pepr.dev", version: "v1", kind: "peprstore", plural: "peprstores" }, + isWatch: false, + isFinalize: true, + event: Event.CREATE, + model: {} as GenericClass, + filters: { + name: "", + regexName: "", + namespaces: [], + regexNamespaces: [], + labels: {}, + annotations: {}, + deletionTimestamp: false, + }, + }, + ], + hasSchedule: false, + name: "", + description: "", + }, + ]; + + const result = clusterRole( + "test-role", + capabilitiesWithFinalize, + "scoped", + capabilitiesWithFinalize.flatMap(c => c.rbac).filter((rule): rule is PolicyRule => rule !== undefined), + ); + + expect(result.rules).toEqual([ + { + apiGroups: ["pepr.dev"], + resources: ["peprstores"], + verbs: ["patch"], + }, + { + apiGroups: ["apiextensions.k8s.io"], + resources: ["customresourcedefinitions"], + verbs: ["patch", "create"], + }, + ]); + }); + + it("should deduplicate verbs and resources in rules", () => { + const capabilitiesWithDuplicates: CapabilityExport[] = [ + { + rbac: [ + { + apiGroups: ["pepr.dev"], + resources: ["peprstores"], + verbs: ["create", "get"], + }, + ], + bindings: [ + { + kind: { group: "pepr.dev", version: "v1", kind: "peprlog", plural: "peprlogs" }, + isWatch: false, + event: Event.CREATE, + model: {} as GenericClass, + filters: { + name: "", + regexName: "", + namespaces: [], + regexNamespaces: [], + labels: {}, + annotations: {}, + deletionTimestamp: false, + }, + }, + ], + hasSchedule: false, + name: "", + description: "", + }, + { + rbac: [ + { + apiGroups: ["pepr.dev"], + resources: ["peprstores"], + verbs: ["get", "patch"], + }, + ], + bindings: [ + { + kind: { group: "pepr.dev", version: "v1", kind: "peprlog", plural: "peprlogs" }, + isWatch: false, + event: Event.CREATE, + model: {} as GenericClass, + filters: { + name: "", + regexName: "", + namespaces: [], + regexNamespaces: [], + labels: {}, + annotations: {}, + deletionTimestamp: false, + }, + }, + ], + hasSchedule: false, + name: "", + description: "", + }, + ]; + + const result = clusterRole( + "test-role", + capabilitiesWithDuplicates, + "scoped", + capabilitiesWithDuplicates.flatMap(c => c.rbac).filter((rule): rule is PolicyRule => rule !== undefined), + ); + + // Filter out only the rules for 'pepr.dev' and 'peprstores' + const filteredRules = result.rules?.filter( + rule => rule.apiGroups?.includes("pepr.dev") && rule.resources?.includes("peprstores"), + ); + + expect(filteredRules).toEqual([ + { + apiGroups: ["pepr.dev"], + resources: ["peprstores"], + verbs: ["create", "get", "patch", "watch"], + }, + ]); + }); +}); +describe("clusterRole", () => { + // Mocking the readRBACFromPackageJson function to return null + jest.mock("./rbac", () => ({ + ...(jest.requireActual("./rbac") as object), + readRBACFromPackageJson: jest.fn(() => null), + })); + + // Mocking createRBACMap to isolate the behavior of clusterRole function + jest.mock("../helpers", () => ({ + ...(jest.requireActual("../helpers") as object), + createRBACMap: jest.fn(), + })); + + beforeEach(() => { + jest.clearAllMocks(); + jest.restoreAllMocks(); + }); + + it("should handle keys with less than 3 segments and set group to an empty string", () => { + jest.spyOn(helpers, "createRBACMap").mockReturnValue({ + nodes: { + plural: "nodes", + verbs: ["get"], + }, + }); + + const capabilitiesWithShortKey: CapabilityExport[] = [ + { + rbac: [ + { + apiGroups: [""], + resources: ["nodes"], + verbs: ["get"], + }, + ], + bindings: [ + { + kind: { group: "", version: "v1", kind: "node", plural: "nodes" }, + isWatch: false, + event: Event.CREATE, + model: {} as GenericClass, + filters: { + name: "", + regexName: "", + namespaces: [], + regexNamespaces: [], + labels: {}, + annotations: {}, + deletionTimestamp: false, + }, + }, + ], + hasSchedule: false, + name: "", + description: "", + }, + ]; + + const result = clusterRole( + "test-role", + capabilitiesWithShortKey, + "scoped", + capabilitiesWithShortKey.flatMap(c => c.rbac).filter((rule): rule is PolicyRule => rule !== undefined), + ); + + expect(result.rules).toEqual([ + { + apiGroups: [""], + resources: ["nodes"], + verbs: ["get"], + }, + ]); + }); + + it("should handle keys with 3 or more segments and set group correctly", () => { + jest.spyOn(helpers, "createRBACMap").mockReturnValue({ + "apps/v1/deployments": { + plural: "deployments", + verbs: ["create"], + }, + }); + + const capabilitiesWithLongKey: CapabilityExport[] = [ + { + rbac: [ + { + apiGroups: ["apps"], + resources: ["deployments"], + verbs: ["create"], + }, + ], + bindings: [ + { + kind: { group: "apps", version: "v1", kind: "deployment", plural: "deployments" }, + isWatch: false, + event: Event.CREATE, + model: {} as GenericClass, + filters: { + name: "", + regexName: "", + namespaces: [], + regexNamespaces: [], + labels: {}, + annotations: {}, + deletionTimestamp: false, + }, + }, + ], + hasSchedule: false, + name: "", + description: "", + }, + ]; + + const result = clusterRole( + "test-role", + capabilitiesWithLongKey, + "scoped", + capabilitiesWithLongKey.flatMap(c => c.rbac).filter((rule): rule is PolicyRule => rule !== undefined), + ); + + expect(result.rules).toEqual([ + { + apiGroups: ["apps"], + resources: ["deployments"], + verbs: ["create"], + }, + ]); + }); + + it("should handle non-array custom RBAC by defaulting to an empty array", () => { + // Mock readRBACFromPackageJson to return a non-array value + jest.spyOn(fs, "readFileSync").mockImplementation(() => { + return JSON.stringify({ + pepr: { + rbac: "not-an-array", // Simulate invalid RBAC structure + }, + }); + }); + + const result = clusterRole( + "test-role", + mockCapabilities, + "scoped", + mockCapabilities.flatMap(c => c.rbac).filter((rule): rule is PolicyRule => rule !== undefined), + ); + + // The result should only contain rules from the capabilities, not from the invalid custom RBAC + expect(result.rules).toEqual([ + { + apiGroups: ["pepr.dev"], + resources: ["peprstores"], + verbs: ["create", "get", "patch", "watch"], + }, + { + apiGroups: ["apiextensions.k8s.io"], + resources: ["customresourcedefinitions"], + verbs: ["patch", "create"], + }, + { + apiGroups: [""], + resources: ["namespaces"], + verbs: ["watch"], + }, + { + apiGroups: [""], + resources: ["configmaps"], + verbs: ["watch"], + }, + ]); + }); + + it("should default to an empty verbs array if rule.verbs is undefined", () => { + // Simulate a custom RBAC rule with empty verbs + const customRbacWithNoVerbs: PolicyRule[] = [ + { + apiGroups: ["pepr.dev"], + resources: ["customresources"], + verbs: [], // Set verbs to an empty array to satisfy the V1PolicyRule type + }, + ]; + + jest.spyOn(fs, "readFileSync").mockImplementation(() => { + return JSON.stringify({ + pepr: { + rbac: customRbacWithNoVerbs, + }, + }); + }); + + const result = clusterRole("test-role", mockCapabilities, "scoped", customRbacWithNoVerbs); + + // Check that the verbs array is empty for the custom RBAC rule + expect(result.rules).toContainEqual({ + apiGroups: ["pepr.dev"], + resources: ["customresources"], + verbs: [], + }); + }); +}); diff --git a/src/lib/assets/rbac.test.ts b/src/lib/assets/rbac.test.ts index 9a630b84..d465f4fc 100644 --- a/src/lib/assets/rbac.test.ts +++ b/src/lib/assets/rbac.test.ts @@ -1,339 +1,10 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2023-Present The Pepr Authors import { clusterRole, clusterRoleBinding, storeRole, serviceAccount, storeRoleBinding } from "./rbac"; -import { CapabilityExport } from "../types"; import { it, describe, expect, beforeEach, jest } from "@jest/globals"; -import { GenericClass } from "kubernetes-fluent-client"; import { V1PolicyRule as PolicyRule } from "@kubernetes/client-node"; -import { Event } from "../enums"; import fs from "fs"; -import * as helpers from "../helpers"; - -const mockCapabilities: CapabilityExport[] = [ - { - rbac: [ - { - apiGroups: ["pepr.dev"], - resources: ["peprstores"], - verbs: ["create", "get", "patch", "watch"], - }, - ], - bindings: [ - { - kind: { group: "pepr.dev", version: "v1", kind: "peprstore", plural: "peprstores" }, - isWatch: false, - event: Event.CREATE, - model: {} as GenericClass, - filters: { - name: "", - regexName: "", - namespaces: [], - regexNamespaces: [], - labels: {}, - annotations: {}, - deletionTimestamp: false, - }, - }, - ], - hasSchedule: false, - name: "", - description: "", - }, - { - rbac: [ - { - apiGroups: ["apiextensions.k8s.io"], - resources: ["customresourcedefinitions"], - verbs: ["patch", "create"], - }, - ], - bindings: [ - { - kind: { - group: "apiextensions.k8s.io", - version: "v1", - kind: "customresourcedefinition", - plural: "customresourcedefinitions", - }, - isWatch: false, - isFinalize: false, - event: Event.CREATE, - model: {} as GenericClass, - filters: { - name: "", - regexName: "", - namespaces: [], - regexNamespaces: [], - labels: {}, - annotations: {}, - deletionTimestamp: false, - }, - }, - ], - hasSchedule: false, - name: "", - description: "", - }, - { - rbac: [ - { - apiGroups: [""], - resources: ["namespaces"], - verbs: ["watch"], - }, - ], - bindings: [ - { - kind: { group: "", version: "v1", kind: "namespace", plural: "namespaces" }, - isWatch: true, - isFinalize: false, - event: Event.CREATE, - model: {} as GenericClass, - filters: { - name: "", - regexName: "", - namespaces: [], - regexNamespaces: [], - labels: {}, - annotations: {}, - deletionTimestamp: false, - }, - }, - ], - hasSchedule: false, - name: "", - description: "", - }, - { - rbac: [ - { - apiGroups: [""], - resources: ["configmaps"], - verbs: ["watch"], - }, - ], - bindings: [ - { - kind: { group: "", version: "v1", kind: "configmap", plural: "configmaps" }, - isWatch: true, - isFinalize: false, - event: Event.CREATE, - model: {} as GenericClass, - filters: { - name: "", - regexName: "", - namespaces: [], - regexNamespaces: [], - labels: {}, - annotations: {}, - deletionTimestamp: false, - }, - }, - ], - hasSchedule: false, - name: "", - description: "", - }, -]; - -describe("RBAC generation", () => { - beforeEach(() => { - jest.clearAllMocks(); - const mockPackageJsonRBAC = {}; - - jest.spyOn(fs, "readFileSync").mockImplementation((path: unknown) => { - if (typeof path === "string" && path.includes("package.json")) { - return JSON.stringify({ rbac: mockPackageJsonRBAC }); - } - return "{}"; - }); - }); - - it("should generate correct ClusterRole rules in scoped mode", () => { - const result = clusterRole("test-role", mockCapabilities, "scoped", []); - - expect(result.rules).toEqual([ - { - apiGroups: ["pepr.dev"], - resources: ["peprstores"], - verbs: ["create", "get", "patch", "watch"], - }, - { - apiGroups: ["apiextensions.k8s.io"], - resources: ["customresourcedefinitions"], - verbs: ["patch", "create"], - }, - { - apiGroups: [""], - resources: ["namespaces"], - verbs: ["watch"], - }, - { - apiGroups: [""], - resources: ["configmaps"], - verbs: ["watch"], - }, - ]); - }); - - it("should generate a ClusterRole with wildcard rules when not in scoped mode", () => { - const expectedWildcardRules = [ - { - apiGroups: ["*"], - resources: ["*"], - verbs: ["create", "delete", "get", "list", "patch", "update", "watch"], - }, - ]; - - const result = clusterRole("test-role", mockCapabilities, "admin", []); - - expect(result.rules).toEqual(expectedWildcardRules); - }); - - it("should return an empty rules array when capabilities are empty in scoped mode", () => { - const result = clusterRole("test-role", [], "scoped", []); - - expect(result.rules).toEqual([]); - }); - - it("should include finalize verbs if isFinalize is true in scoped mode", () => { - const capabilitiesWithFinalize: CapabilityExport[] = [ - { - rbac: [ - { - apiGroups: ["pepr.dev"], - resources: ["peprstores"], - verbs: ["patch"], - }, - ], - bindings: [ - { - kind: { group: "pepr.dev", version: "v1", kind: "peprstore", plural: "peprstores" }, - isWatch: false, - isFinalize: true, - event: Event.CREATE, - model: {} as GenericClass, - filters: { - name: "", - regexName: "", - namespaces: [], - regexNamespaces: [], - labels: {}, - annotations: {}, - deletionTimestamp: false, - }, - }, - ], - hasSchedule: false, - name: "", - description: "", - }, - ]; - - const result = clusterRole( - "test-role", - capabilitiesWithFinalize, - "scoped", - capabilitiesWithFinalize.flatMap(c => c.rbac).filter((rule): rule is PolicyRule => rule !== undefined), - ); - - expect(result.rules).toEqual([ - { - apiGroups: ["pepr.dev"], - resources: ["peprstores"], - verbs: ["patch"], - }, - { - apiGroups: ["apiextensions.k8s.io"], - resources: ["customresourcedefinitions"], - verbs: ["patch", "create"], - }, - ]); - }); - - it("should deduplicate verbs and resources in rules", () => { - const capabilitiesWithDuplicates: CapabilityExport[] = [ - { - rbac: [ - { - apiGroups: ["pepr.dev"], - resources: ["peprstores"], - verbs: ["create", "get"], - }, - ], - bindings: [ - { - kind: { group: "pepr.dev", version: "v1", kind: "peprlog", plural: "peprlogs" }, - isWatch: false, - event: Event.CREATE, - model: {} as GenericClass, - filters: { - name: "", - regexName: "", - namespaces: [], - regexNamespaces: [], - labels: {}, - annotations: {}, - deletionTimestamp: false, - }, - }, - ], - hasSchedule: false, - name: "", - description: "", - }, - { - rbac: [ - { - apiGroups: ["pepr.dev"], - resources: ["peprstores"], - verbs: ["get", "patch"], - }, - ], - bindings: [ - { - kind: { group: "pepr.dev", version: "v1", kind: "peprlog", plural: "peprlogs" }, - isWatch: false, - event: Event.CREATE, - model: {} as GenericClass, - filters: { - name: "", - regexName: "", - namespaces: [], - regexNamespaces: [], - labels: {}, - annotations: {}, - deletionTimestamp: false, - }, - }, - ], - hasSchedule: false, - name: "", - description: "", - }, - ]; - - const result = clusterRole( - "test-role", - capabilitiesWithDuplicates, - "scoped", - capabilitiesWithDuplicates.flatMap(c => c.rbac).filter((rule): rule is PolicyRule => rule !== undefined), - ); - - // Filter out only the rules for 'pepr.dev' and 'peprstores' - const filteredRules = result.rules?.filter( - rule => rule.apiGroups?.includes("pepr.dev") && rule.resources?.includes("peprstores"), - ); - - expect(filteredRules).toEqual([ - { - apiGroups: ["pepr.dev"], - resources: ["peprstores"], - verbs: ["create", "get", "patch", "watch"], - }, - ]); - }); -}); +import { mockCapabilities } from "./defaultTestObjects"; describe("RBAC generation with mocked package.json", () => { beforeEach(() => { @@ -486,204 +157,3 @@ describe("storeRoleBinding", () => { expect(result).toEqual(expectedRoleBinding); }); }); - -describe("clusterRole", () => { - // Mocking the readRBACFromPackageJson function to return null - jest.mock("./rbac", () => ({ - ...(jest.requireActual("./rbac") as object), - readRBACFromPackageJson: jest.fn(() => null), - })); - - // Mocking createRBACMap to isolate the behavior of clusterRole function - jest.mock("../helpers", () => ({ - ...(jest.requireActual("../helpers") as object), - createRBACMap: jest.fn(), - })); - - beforeEach(() => { - jest.clearAllMocks(); - jest.restoreAllMocks(); - }); - - it("should handle keys with less than 3 segments and set group to an empty string", () => { - jest.spyOn(helpers, "createRBACMap").mockReturnValue({ - nodes: { - plural: "nodes", - verbs: ["get"], - }, - }); - - const capabilitiesWithShortKey: CapabilityExport[] = [ - { - rbac: [ - { - apiGroups: [""], - resources: ["nodes"], - verbs: ["get"], - }, - ], - bindings: [ - { - kind: { group: "", version: "v1", kind: "node", plural: "nodes" }, - isWatch: false, - event: Event.CREATE, - model: {} as GenericClass, - filters: { - name: "", - regexName: "", - namespaces: [], - regexNamespaces: [], - labels: {}, - annotations: {}, - deletionTimestamp: false, - }, - }, - ], - hasSchedule: false, - name: "", - description: "", - }, - ]; - - const result = clusterRole( - "test-role", - capabilitiesWithShortKey, - "scoped", - capabilitiesWithShortKey.flatMap(c => c.rbac).filter((rule): rule is PolicyRule => rule !== undefined), - ); - - expect(result.rules).toEqual([ - { - apiGroups: [""], - resources: ["nodes"], - verbs: ["get"], - }, - ]); - }); - - it("should handle keys with 3 or more segments and set group correctly", () => { - jest.spyOn(helpers, "createRBACMap").mockReturnValue({ - "apps/v1/deployments": { - plural: "deployments", - verbs: ["create"], - }, - }); - - const capabilitiesWithLongKey: CapabilityExport[] = [ - { - rbac: [ - { - apiGroups: ["apps"], - resources: ["deployments"], - verbs: ["create"], - }, - ], - bindings: [ - { - kind: { group: "apps", version: "v1", kind: "deployment", plural: "deployments" }, - isWatch: false, - event: Event.CREATE, - model: {} as GenericClass, - filters: { - name: "", - regexName: "", - namespaces: [], - regexNamespaces: [], - labels: {}, - annotations: {}, - deletionTimestamp: false, - }, - }, - ], - hasSchedule: false, - name: "", - description: "", - }, - ]; - - const result = clusterRole( - "test-role", - capabilitiesWithLongKey, - "scoped", - capabilitiesWithLongKey.flatMap(c => c.rbac).filter((rule): rule is PolicyRule => rule !== undefined), - ); - - expect(result.rules).toEqual([ - { - apiGroups: ["apps"], - resources: ["deployments"], - verbs: ["create"], - }, - ]); - }); - - it("should handle non-array custom RBAC by defaulting to an empty array", () => { - // Mock readRBACFromPackageJson to return a non-array value - jest.spyOn(fs, "readFileSync").mockImplementation(() => { - return JSON.stringify({ - pepr: { - rbac: "not-an-array", // Simulate invalid RBAC structure - }, - }); - }); - - const result = clusterRole( - "test-role", - mockCapabilities, - "scoped", - mockCapabilities.flatMap(c => c.rbac).filter((rule): rule is PolicyRule => rule !== undefined), - ); - - // The result should only contain rules from the capabilities, not from the invalid custom RBAC - expect(result.rules).toEqual([ - { - apiGroups: ["pepr.dev"], - resources: ["peprstores"], - verbs: ["create", "get", "patch", "watch"], - }, - { - apiGroups: ["apiextensions.k8s.io"], - resources: ["customresourcedefinitions"], - verbs: ["patch", "create"], - }, - { - apiGroups: [""], - resources: ["namespaces"], - verbs: ["watch"], - }, - { - apiGroups: [""], - resources: ["configmaps"], - verbs: ["watch"], - }, - ]); - }); - - it("should default to an empty verbs array if rule.verbs is undefined", () => { - // Simulate a custom RBAC rule with empty verbs - const customRbacWithNoVerbs: PolicyRule[] = [ - { - apiGroups: ["pepr.dev"], - resources: ["customresources"], - verbs: [], // Set verbs to an empty array to satisfy the V1PolicyRule type - }, - ]; - - jest.spyOn(fs, "readFileSync").mockImplementation(() => { - return JSON.stringify({ - pepr: { - rbac: customRbacWithNoVerbs, - }, - }); - }); - - const result = clusterRole("test-role", mockCapabilities, "scoped", customRbacWithNoVerbs); - - // Check that the verbs array is empty for the custom RBAC rule - expect(result.rules).toContainEqual({ - apiGroups: ["pepr.dev"], - resources: ["customresources"], - verbs: [], - }); - }); -});