Skip to content

Commit

Permalink
chore: webhook timer coverage in mutate-processor test (#1897)
Browse files Browse the repository at this point in the history
## Description

This is very hard to test because the Capability does not have actual
bindings. Because of that the test stops
[here](https://github.com/defenseunicorns/pepr/blob/4e8549a43bb911072bd0316f7dace7172e5eb1a0/src/lib/processors/mutate-processor.ts#L197)
and returns early. The only meaningful tests I could do was to ensure
the timer start and stop were called.

There is already too much mocking in this file I cannot get any
assertions to pass for base64 calls here.

**UPDATE**: was able to validate the first decodeData was called by
shuffling files around and mocking the call in `mutate-process.test.ts`.
The rest of the test is untestable due to no bindings in the
capabilities

Needs #1895 to pass.

## Related Issue

Fixes #1892 
<!-- or -->
Relates to #

## 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
- [ ] 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
- [ ] [Contributor Guide
Steps](https://docs.pepr.dev/main/contribute/#submitting-a-pull-request)
followed

---------

Signed-off-by: Case Wylie <[email protected]>
  • Loading branch information
cmwylie19 authored Mar 6, 2025
1 parent aa0e4a1 commit 666bdb2
Show file tree
Hide file tree
Showing 5 changed files with 262 additions and 128 deletions.
19 changes: 18 additions & 1 deletion src/lib/assets/defaultTestObjects.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
import { GenericClass } from "kubernetes-fluent-client";
import { GenericClass, GroupVersionKind } from "kubernetes-fluent-client";
import { Event } from "../enums";
import { Binding, CapabilityExport } from "../types";
import { defaultFilters } from "../filter/adjudicators/defaultTestObjects";
import { V1PolicyRule as PolicyRule } from "@kubernetes/client-node";
import { AdmissionRequest, GroupVersionResource } from "../types";
import { Operation } from "../enums";

export const createMockAdmissionRequest = (
kind: GroupVersionKind = { kind: "kind", group: "group", version: "version" },
resource: GroupVersionResource = { group: "group", version: "version", resource: "resource" },
object: { metadata: { name: string } } = { metadata: { name: "create-me" } },
operation: Operation = Operation.CREATE,
): AdmissionRequest => ({
uid: "uid",
kind,
resource,
name: "",
object,
operation,
userInfo: {},
});

export const createMockRbacRule = (
apiGroups: string[] = ["pepr.dev"],
Expand Down
101 changes: 101 additions & 0 deletions src/lib/processors/decode-utils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { beforeEach, describe, expect, it, jest } from "@jest/globals";
import { convertFromBase64Map, convertToBase64Map } from "../utils";
import { PeprMutateRequest } from "../mutate-request";
import { decodeData, reencodeData } from "./decode-utils";
import { createMockAdmissionRequest } from "../assets/defaultTestObjects";

jest.mock("../utils");

const defaultAdmissionRequest = createMockAdmissionRequest();

const defaultPeprMutateRequest = (admissionRequest = defaultAdmissionRequest) =>
new PeprMutateRequest(admissionRequest);

const mockConvertToBase64Map = jest.mocked(convertToBase64Map);
const mockConvertFromBase64Map = jest.mocked(convertFromBase64Map);

describe("decodeData", () => {
const skips = ["convert", "From", "Base64", "Map"];

beforeEach(() => {
mockConvertFromBase64Map.mockClear();
mockConvertFromBase64Map.mockImplementation(() => skips);
});

it("returns skips if required & given a Secret", () => {
const testAdmissionRequest = {
...defaultAdmissionRequest,
kind: {
kind: "Secret",
version: "v1",
group: "",
},
};
const testPeprMutateRequest = defaultPeprMutateRequest(testAdmissionRequest);

const { skipped, wrapped } = decodeData(testPeprMutateRequest);

expect(mockConvertFromBase64Map.mock.calls.length).toBe(1);
expect(mockConvertFromBase64Map.mock.calls[0].at(0)).toBe(testPeprMutateRequest.Raw);
expect(skipped).toBe(skips);
expect(wrapped).toBe(testPeprMutateRequest);
});

it("returns no skips when given a non-Secret", () => {
const testAdmissionRequest = {
...defaultAdmissionRequest,
kind: {
kind: "NotASecret",
version: "v1",
group: "",
},
};
const testPeprMutateRequest = defaultPeprMutateRequest(testAdmissionRequest);

const { skipped, wrapped } = decodeData(testPeprMutateRequest);

expect(mockConvertFromBase64Map.mock.calls.length).toBe(0);
expect(skipped).toEqual([]);
expect(wrapped).toBe(testPeprMutateRequest);
});
});

describe("reencodeData", () => {
it("returns unchanged content when given non-secret", () => {
const skipped = ["convert", "To", "Base64", "Map"];
const testAdmissionRequest = {
...defaultAdmissionRequest,
kind: {
kind: "NotASecret",
version: "v1",
group: "",
},
};
const testPeprMutateRequest = defaultPeprMutateRequest(testAdmissionRequest);

const transformed = reencodeData(testPeprMutateRequest, skipped);

expect(mockConvertToBase64Map.mock.calls.length).toBe(0);
expect(transformed).toEqual(testAdmissionRequest.object);
});

it("returns modified content when given a secret and skips", () => {
const skipped = ["convert", "To", "Base64", "Map"];
const testAdmissionRequest = {
...defaultAdmissionRequest,
kind: {
kind: "Secret",
version: "v1",
group: "",
},
};
const testPeprMutateRequest = defaultPeprMutateRequest(testAdmissionRequest);

const transformed = reencodeData(testPeprMutateRequest, skipped);

expect(mockConvertToBase64Map.mock.calls.length).toBe(1);
expect(mockConvertToBase64Map.mock.calls[0].at(0)).toEqual(testPeprMutateRequest.Raw);
expect(mockConvertToBase64Map.mock.calls[0].at(1)).toBe(skipped);
expect(transformed).toEqual(testPeprMutateRequest.Raw);
});
});
31 changes: 31 additions & 0 deletions src/lib/processors/decode-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { convertFromBase64Map, convertToBase64Map } from "../utils";
import { kind, KubernetesObject } from "kubernetes-fluent-client";
import { PeprMutateRequest } from "../mutate-request";
import { clone } from "ramda";

export function decodeData(wrapped: PeprMutateRequest<KubernetesObject>): {
skipped: string[];
wrapped: PeprMutateRequest<KubernetesObject>;
} {
let skipped: string[] = [];

const isSecret = wrapped.Request.kind.version === "v1" && wrapped.Request.kind.kind === "Secret";
if (isSecret) {
// convertFromBase64Map modifies it's arg rather than returing a mod'ed copy (ye olde side-effect special, blerg)
skipped = convertFromBase64Map(wrapped.Raw as unknown as kind.Secret);
}

return { skipped, wrapped };
}

export function reencodeData(wrapped: PeprMutateRequest<KubernetesObject>, skipped: string[]): KubernetesObject {
const transformed = clone(wrapped.Raw);

const isSecret = wrapped.Request.kind.version === "v1" && wrapped.Request.kind.kind === "Secret";
if (isSecret) {
// convertToBase64Map modifies it's arg rather than returing a mod'ed copy (ye olde side-effect special, blerg)
convertToBase64Map(transformed as unknown as kind.Secret, skipped);
}

return transformed;
}
Loading

0 comments on commit 666bdb2

Please sign in to comment.