Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/core/utils/cui-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { HttpClient } from "../http/http-client";
import { FatalError, logger } from "./logger";
import { Context } from "../command/cli-context";

export const CUI_MARKING_FAILED_MESSAGE = "Could not resolve CUI marking. No file was written";

export interface CuiPdfCoverResponse {
coverPage?: { pdfContent: string; encoding: string };
}
Expand Down Expand Up @@ -39,6 +41,7 @@ export class CuiApi {
return { marking: CuiMarking.CLASSIFIED, cover: data as CuiPdfCoverResponse };
}

throw new FatalError("Problem fetching cui pdf cover");
logger.debug(`The CUI cover call answered with status ${status}`);
throw new FatalError(CUI_MARKING_FAILED_MESSAGE);
}
}
10 changes: 6 additions & 4 deletions src/core/utils/cui-file-service.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import * as path from "node:path";
import AdmZip = require("adm-zip");
import { Context } from "../command/cli-context";
import { CuiApi, CuiMarking, CuiPdfCoverResponse } from "./cui-api";
import { CUI_MARKING_FAILED_MESSAGE, CuiApi, CuiMarking, CuiPdfCoverResponse } from "./cui-api";
import { fileService } from "./file-service";
import { FileConstants } from "./file.constants";
import { FatalError } from "./logger";
import { FatalError, logger } from "./logger";

export class CuiFileService {
public static readonly COVER_SHEET_FILE_NAME = "CUI_Cover_Sheet.pdf";
Expand Down Expand Up @@ -96,10 +96,12 @@ export class CuiFileService {
private decodeCoverPage(cover: CuiPdfCoverResponse): Buffer {
const coverPage = cover.coverPage;
if (!coverPage?.pdfContent) {
throw new FatalError("CUI marking applies but the response contained no cover page.");
logger.debug("CUI marking applies but the response contained no cover page");
throw new FatalError(CUI_MARKING_FAILED_MESSAGE);
}
if (coverPage.encoding !== CuiFileService.BASE64_ENCODING) {
throw new FatalError(`Unsupported CUI cover page encoding: ${coverPage.encoding}`);
logger.debug(`Unsupported CUI cover page encoding: ${coverPage.encoding}`);
throw new FatalError(CUI_MARKING_FAILED_MESSAGE);
}

return Buffer.from(coverPage.pdfContent, CuiFileService.BASE64_ENCODING);
Expand Down
50 changes: 50 additions & 0 deletions tests/core/utils/cui-api.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { CUI_MARKING_FAILED_MESSAGE, CuiApi, CuiMarking } from "../../../src/core/utils/cui-api";
import { FatalError } from "../../../src/core/utils/logger";
import { testContext } from "../../utls/test-context";
import { mockAxiosGetWithStatus } from "../../utls/http-requests-mock";

describe("CuiApi", () => {
const COVER_URL = "https://myTeam.celonis.cloud/api/team/cui-settings/cui-pdf-cover";

const coverResponse = () => ({
coverPage: {
pdfContent: Buffer.from("%PDF-1.4 cover sheet").toString("base64"),
encoding: "base64",
},
});

let cuiApi: CuiApi;

beforeEach(() => {
cuiApi = new CuiApi(testContext);
});

it("Should report the content as classified and pass the cover response on", async () => {
const cover = coverResponse();
mockAxiosGetWithStatus(COVER_URL, 200, cover);

await expect(cuiApi.getCuiMarking()).resolves.toEqual({
marking: CuiMarking.CLASSIFIED,
cover,
});
});

it("Should report that marking does not apply when the feature flag is disabled", async () => {
mockAxiosGetWithStatus(COVER_URL, 403, "");

await expect(cuiApi.getCuiMarking()).resolves.toEqual({ marking: CuiMarking.DISABLED });
});

it("Should fail when the marking applies but the response body is empty", async () => {
mockAxiosGetWithStatus(COVER_URL, 200, "");

await expect(cuiApi.getCuiMarking()).rejects.toThrow(FatalError);
await expect(cuiApi.getCuiMarking()).rejects.toThrow(CUI_MARKING_FAILED_MESSAGE);
});

it("Should fail when the backend answers with an unexpected status", async () => {
mockAxiosGetWithStatus(COVER_URL, 204, "");

await expect(cuiApi.getCuiMarking()).rejects.toThrow(CUI_MARKING_FAILED_MESSAGE);
});
});
20 changes: 15 additions & 5 deletions tests/core/utils/cui-file-service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,15 @@ describe("CuiFileService", () => {
expect(filename).toEqual("report.json");
expect(readFile("report.json").toString()).toEqual(PAYLOAD);
});

it("Should keep the original filename when axios resolves the 403 instead of rejecting", async () => {
mockAxiosGetWithStatus(COVER_URL, 403, "");

const filename = await cuiFileService.writeToFileWithGivenName(PAYLOAD, "resolved-403.json");

expect(filename).toEqual("resolved-403.json");
expect(readFile("resolved-403.json").toString()).toEqual(PAYLOAD);
});
});

describe("when the cover response cannot be used", () => {
Expand All @@ -55,7 +64,8 @@ describe("CuiFileService", () => {
it("Should fail when the backend answers with no content", async () => {
mockAxiosGetWithStatus(COVER_URL, 204, "");

await expect(cuiFileService.writeToFileWithGivenName(PAYLOAD, "no-content.json")).rejects.toThrow(FatalError);
await expect(cuiFileService.writeToFileWithGivenName(PAYLOAD, "no-content.json"))
.rejects.toThrow("Could not resolve CUI marking. No file was written");
expect(() => accessSync(resolve(process.cwd(), "no-content.json"))).toThrow();
});
});
Expand All @@ -81,14 +91,14 @@ describe("CuiFileService", () => {
mockAxiosGetWithStatus(COVER_URL, 200, response);

await expect(cuiFileService.writeToFileWithGivenName(PAYLOAD, "packages.json"))
.rejects.toThrow("Unsupported CUI cover page encoding: hex");
.rejects.toThrow("Could not resolve CUI marking. No file was written");
});

it("Should fail when the marking applies but no cover page was returned", async () => {
mockAxiosGetWithStatus(COVER_URL, 200, { teamId: "team-1" });

await expect(cuiFileService.writeToFileWithGivenName(PAYLOAD, "packages.json"))
.rejects.toThrow("CUI marking applies but the response contained no cover page.");
.rejects.toThrow("Could not resolve CUI marking. No file was written");
});
});

Expand Down Expand Up @@ -134,7 +144,7 @@ describe("CuiFileService", () => {
mockAxiosGetWithStatus(COVER_URL, 200, { teamId: "team-1" });

await expect(cuiFileService.writeZipToFileWithGivenName(buildExportZip(), "export.zip"))
.rejects.toThrow("CUI marking applies but the response contained no cover page.");
.rejects.toThrow("Could not resolve CUI marking. No file was written");
});
});

Expand Down Expand Up @@ -174,7 +184,7 @@ describe("CuiFileService", () => {
mockAxiosGetWithStatus(COVER_URL, 200, { teamId: "team-1" });

await expect(cuiFileService.writeDirectoryWithGivenName(writeTree, "broken-export"))
.rejects.toThrow("CUI marking applies but the response contained no cover page.");
.rejects.toThrow("Could not resolve CUI marking. No file was written");
expect(exists("broken-export")).toBe(false);
expect(exists("CUI - broken-export")).toBe(false);
});
Expand Down
Loading