Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test → val (28 October 2024) #11899

Merged
merged 35 commits into from
Oct 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
f104540
[Snyk] Security upgrade vite from 5.3.5 to 5.3.6 (#11861)
mdct-github-service-account Sep 19, 2024
5d6d76a
update macfc security hub github action (#11862)
gmrabian Sep 20, 2024
e5127f3
fix scss deprecation warning (#11863)
gmrabian Sep 20, 2024
114b451
upgrade aws sdk versions (#11864)
gmrabian Sep 23, 2024
a3b85d0
[Snyk] Upgrade react-router-dom from 6.25.1 to 6.26.1 (#11866)
mdct-github-service-account Sep 24, 2024
b048444
refactor api response pattern (#11865)
gmrabian Sep 25, 2024
c4bf725
[Snyk] Upgrade @emotion/react from 11.11.4 to 11.13.3 (#11868)
mdct-github-service-account Sep 26, 2024
438d80f
[Snyk] Upgrade jsdom from 24.1.0 to 24.1.3 (#11869)
mdct-github-service-account Oct 2, 2024
32dd4a7
[Snyk] Upgrade react-hook-form from 7.52.1 to 7.53.0 (#11870)
mdct-github-service-account Oct 3, 2024
41a7cef
[Snyk] Upgrade react-router-dom from 6.26.1 to 6.26.2 (#11871)
mdct-github-service-account Oct 8, 2024
5b5647c
Cmdct 4026 - Prior Authorization Section B (#11872)
britt-mo Oct 8, 2024
8955a56
Cmdct 4027 - patient access section under nov macpar release flag (#1…
britt-mo Oct 9, 2024
2e145d7
Section b updates (#11875)
britt-mo Oct 16, 2024
31fc9f7
CMDCT-4028: Prior Authorization Section D (#11867)
karla-vm Oct 16, 2024
1c7f1d1
Upgrade amplify to v6 (#11876)
gmrabian Oct 17, 2024
198ebca
CMDCT-4050: Allow "NR" Values for Number Fields (#11877)
karla-vm Oct 18, 2024
68625a2
[Snyk] Upgrade @aws-sdk/client-dynamodb from 3.654.0 to 3.658.1 (#11879)
mdct-github-service-account Oct 21, 2024
61d7b5b
CMDCT-4051: Addressing MCPAR Design Feedback (#11878)
karla-vm Oct 21, 2024
6bb6266
[Snyk] Upgrade @aws-sdk/lib-dynamodb from 3.654.0 to 3.658.1 (#11882)
mdct-github-service-account Oct 22, 2024
ea82a29
[Snyk] Upgrade @aws-sdk/client-s3 from 3.654.0 to 3.658.1 (#11880)
mdct-github-service-account Oct 22, 2024
ab1644e
Console Cleanup (#11883)
karla-vm Oct 22, 2024
b97b954
Fixup amplify types and methods (#11886)
gmrabian Oct 23, 2024
715bbb9
Amplify: add implicit oauth grant to see if it fixes IDM login (#11887)
gmrabian Oct 23, 2024
53edd31
[Snyk] Upgrade sass from 1.77.7 to 1.79.4 (#11884)
mdct-github-service-account Oct 23, 2024
b51fdbe
[Snyk] Upgrade dompurify from 2.5.5 to 2.5.7 (#11885)
mdct-github-service-account Oct 23, 2024
7c9dfd8
Amplify: Add Package from CARTS (#11888)
karla-vm Oct 23, 2024
16ebc16
await auth and update types (#11892)
gmrabian Oct 24, 2024
921ee2f
[Snyk] Upgrade @aws-sdk/client-cognito-identity-provider from 3.654.0…
mdct-github-service-account Oct 24, 2024
3b4f17c
Log auth (#11894)
gmrabian Oct 24, 2024
609001b
revert to old redirect style (#11895)
gmrabian Oct 24, 2024
6643755
Bug Fix: Admin Dashboard Button Styling (#11893)
karla-vm Oct 24, 2024
9b42cf7
Add oauth listener import to app root (#11897)
gmrabian Oct 25, 2024
e3c74dc
MCR - Disabled button darker and text update (#11896)
rocio-desantiago Oct 25, 2024
882bc9d
move idm method back to amplify method (#11898)
gmrabian Oct 25, 2024
26e7fb4
Refactor amplify methods to single file (#11881)
bangbay-bluetiger Oct 28, 2024
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: 2 additions & 3 deletions .github/workflows/scan_security-hub-jira-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,12 @@ jobs:
aws-region: ${{ secrets.AWS_DEFAULT_REGION }}
role-to-assume: ${{ secrets.PRODUCTION_SYNC_OIDC_ROLE }}
- name: Sync Security Hub and Jira
uses: Enterprise-CMCS/mac-fc-security-hub-visibility@v1.0.7
uses: Enterprise-CMCS/mac-fc-security-hub-visibility@v2.0.9
with:
jira-username: "mdct_github_service_account"
jira-token: ${{ secrets.JIRA_ENT_USER_TOKEN }}
jira-host: jiraent.cms.gov
jira-project-key: CMDCT
jira-ignore-statuses: Done, Closed, Canceled
jira-custom-fields: '{ "customfield_10100": "CMDCT-2280", "customfield_26700" : [{"id": "40104", "value": "MCR"}] }'
aws-severities: CRITICAL, HIGH, MEDIUM
assign-jira-ticket-to: "MWTW"
jira-assignee: "MWTW"
502 changes: 446 additions & 56 deletions services/app-api/forms/mcpar.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions services/app-api/forms/mlr.json
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@
},
{
"type": "externalLink",
"content": "\"Managed Care Enrollment by Program and Plan\"",
"content": "Managed Care Enrollment by Program and Plan",
"props": {
"href": "https://www.medicaid.gov/medicaid/managed-care/enrollment-report/index.html",
"target": "_blank",
Expand Down Expand Up @@ -287,7 +287,7 @@
"hint": [
{
"type": "p",
"content": "Enter the eligibility group for this MLR report. Most states provide MLR reports for all populations. In this case, select \"All Populations.\" If the state is providing additional detail for specific eligibility groups, see below for instructions related to each group."
"content": "Enter the eligibility group for this MLR report. Most states provide MLR reports for all populations. In this case, select All Populations”. If the state is providing additional detail for specific eligibility groups, see below for instructions related to each group."
},
{
"type": "ol",
Expand All @@ -305,7 +305,7 @@
"children": [
{
"type": "html",
"content": "<i>For separate CHIP reporting:</i> States that intend to report MLRs for separate CHIP-only programs should select \"Standalone CHIP\". These separate child health assistance programs are defined in "
"content": "<i>For separate CHIP reporting:</i> States that intend to report MLRs for separate CHIP-only programs should select Standalone CHIP. These separate child health assistance programs are defined in "
},
{
"type": "externalLink",
Expand All @@ -330,7 +330,7 @@
"children": [
{
"type": "p",
"content": "<i>For SUPPORT Act reporting:</i> States that intend to qualify for the SUPPORT Act Section 4001 MLR provision must provide an MLR for the eligibility group described in section 1902(a)(10)(A)(i)(VIII) (referred to here as \"the Expansion Group\"). Select \"Group VIII Expansion Adult Only\"."
"content": "<i>For SUPPORT Act reporting:</i> States that intend to qualify for the SUPPORT Act Section 4001 MLR provision must provide an MLR for the eligibility group described in section 1902(a)(10)(A)(i)(VIII) (referred to here as the Expansion Group). Select Group VIII Expansion Adult Only."
}
]
},
Expand All @@ -344,7 +344,7 @@
"children": [
{
"type": "p",
"content": "For States that intend to report separate MLRs for elibility groups that are served under the same program, select \"Other, specify\"."
"content": "For States that intend to report separate MLRs for elibility groups that are served under the same program, select Other, specify."
}
]
}
Expand Down
36 changes: 23 additions & 13 deletions services/app-api/handlers/banners/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,18 @@ import { createBanner } from "./create";
import { DynamoDBDocumentClient, PutCommand } from "@aws-sdk/lib-dynamodb";
import { mockClient } from "aws-sdk-client-mock";
// types
import { APIGatewayProxyEvent, StatusCodes } from "../../utils/types";
import { APIGatewayProxyEvent } from "../../utils/types";
// utils
import { error } from "../../utils/constants/constants";
import { proxyEvent } from "../../utils/testing/proxyEvent";
import { StatusCodes } from "../../utils/responses/response-lib";
import { hasPermissions } from "../../utils/auth/authorization";

const dynamoClientMock = mockClient(DynamoDBDocumentClient);

jest.mock("../../utils/auth/authorization", () => ({
isAuthorized: jest.fn().mockReturnValue(true),
hasPermissions: jest.fn().mockReturnValueOnce(false).mockReturnValue(true),
isAuthenticated: jest.fn().mockReturnValue(true),
hasPermissions: jest.fn().mockReturnValue(true),
}));

const testEvent: APIGatewayProxyEvent = {
Expand All @@ -37,10 +39,14 @@ const consoleSpy: {
};

describe("Test createBanner API method", () => {
beforeEach(() => {
dynamoClientMock.reset();
});
test("Test unauthorized banner creation throws 403 error", async () => {
(hasPermissions as jest.Mock).mockReturnValueOnce(false);
const res = await createBanner(testEvent, null);
expect(consoleSpy.debug).toHaveBeenCalled();
expect(res.statusCode).toBe(403);
expect(res.statusCode).toBe(StatusCodes.Forbidden);
expect(res.body).toContain(error.UNAUTHORIZED);
});

Expand All @@ -49,37 +55,41 @@ describe("Test createBanner API method", () => {
dynamoClientMock.on(PutCommand).callsFake(mockPut);
const res = await createBanner(testEvent, null);
expect(consoleSpy.debug).toHaveBeenCalled();
expect(res.statusCode).toBe(StatusCodes.CREATED);
expect(res.statusCode).toBe(StatusCodes.Created);
expect(res.body).toContain("test banner");
expect(res.body).toContain("test description");
expect(mockPut).toHaveBeenCalled();
});

test("Test dynamo issue throws error", async () => {
dynamoClientMock.on(PutCommand).rejectsOnce("error with dynamo");
const res = await createBanner(testEvent, null);
expect(res.statusCode).toBe(StatusCodes.InternalServerError);
expect(res.body).toContain(error.DYNAMO_CREATION_ERROR);
});

test("Test invalid data causes failure", async () => {
const res = await createBanner(testEventWithInvalidData, null);
expect(consoleSpy.error).toHaveBeenCalled();
expect(res.statusCode).toBe(StatusCodes.SERVER_ERROR);
expect(res.statusCode).toBe(StatusCodes.BadRequest);
});

test("Test bannerKey not provided throws 500 error", async () => {
test("Test bannerKey not provided throws 400 error", async () => {
const noKeyEvent: APIGatewayProxyEvent = {
...testEvent,
pathParameters: {},
};
const res = await createBanner(noKeyEvent, null);
expect(consoleSpy.error).toHaveBeenCalled();
expect(res.statusCode).toBe(500);
expect(res.statusCode).toBe(StatusCodes.BadRequest);
expect(res.body).toContain(error.NO_KEY);
});

test("Test bannerKey empty throws 500 error", async () => {
test("Test bannerKey empty throws 400 error", async () => {
const noKeyEvent: APIGatewayProxyEvent = {
...testEvent,
pathParameters: { bannerId: "" },
};
const res = await createBanner(noKeyEvent, null);
expect(consoleSpy.error).toHaveBeenCalled();
expect(res.statusCode).toBe(500);
expect(res.statusCode).toBe(StatusCodes.BadRequest);
expect(res.body).toContain(error.NO_KEY);
});
});
88 changes: 49 additions & 39 deletions services/app-api/handlers/banners/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,51 +5,61 @@ import dynamoDb from "../../utils/dynamo/dynamodb-lib";
import { hasPermissions } from "../../utils/auth/authorization";
import { validateData } from "../../utils/validation/validation";
import { error } from "../../utils/constants/constants";
import {
badRequest,
created,
forbidden,
internalServerError,
} from "../../utils/responses/response-lib";
// types
import { StatusCodes, UserRoles } from "../../utils/types";
import { UserRoles } from "../../utils/types";

const validationSchema = yup.object().shape({
key: yup.string().required(),
title: yup.string().required(),
description: yup.string().required(),
link: yup.string().url().notRequired(),
startDate: yup.number().required(),
endDate: yup.number().required(),
});

export const createBanner = handler(async (event, _context) => {
if (!hasPermissions(event, [UserRoles.ADMIN])) {
return {
status: StatusCodes.UNAUTHORIZED,
body: error.UNAUTHORIZED,
};
} else if (!event?.pathParameters?.bannerId!) {
throw new Error(error.NO_KEY);
} else {
const unvalidatedPayload = JSON.parse(event!.body!);
return forbidden(error.UNAUTHORIZED);
}
if (!event?.pathParameters?.bannerId!) {
return badRequest(error.NO_KEY);
}
const unvalidatedPayload = JSON.parse(event.body!);

const validationSchema = yup.object().shape({
key: yup.string().required(),
title: yup.string().required(),
description: yup.string().required(),
link: yup.string().url().notRequired(),
startDate: yup.number().required(),
endDate: yup.number().required(),
});
let validatedPayload;
try {
validatedPayload = await validateData(validationSchema, unvalidatedPayload);
} catch {
return badRequest(error.INVALID_DATA);
}

const validatedPayload = await validateData(
validationSchema,
unvalidatedPayload
);
const { title, description, link, startDate, endDate } = validatedPayload;
const currentTime = Date.now();

if (validatedPayload) {
const params = {
TableName: process.env.BANNER_TABLE_NAME!,
Item: {
key: event.pathParameters.bannerId,
createdAt: Date.now(),
lastAltered: Date.now(),
lastAlteredBy: event?.headers["cognito-identity-id"],
title: validatedPayload.title,
description: validatedPayload.description,
link: validatedPayload.link,
startDate: validatedPayload.startDate,
endDate: validatedPayload.endDate,
},
};
await dynamoDb.put(params);
return { status: StatusCodes.CREATED, body: params };
}
const params = {
TableName: process.env.BANNER_TABLE_NAME!,
Item: {
key: event.pathParameters.bannerId,
createdAt: currentTime,
lastAltered: currentTime,
lastAlteredBy: event?.headers["cognito-identity-id"],
title,
description,
link,
startDate,
endDate,
},
};
try {
await dynamoDb.put(params);
} catch {
return internalServerError(error.DYNAMO_CREATION_ERROR);
}
return created(params);
});
24 changes: 12 additions & 12 deletions services/app-api/handlers/banners/delete.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import { mockClient } from "aws-sdk-client-mock";
// utils
import { proxyEvent } from "../../utils/testing/proxyEvent";
import { error } from "../../utils/constants/constants";
import { hasPermissions } from "../../utils/auth/authorization";
// types
import { APIGatewayProxyEvent, StatusCodes } from "../../utils/types";
import { APIGatewayProxyEvent } from "../../utils/types";
import { StatusCodes } from "../../utils/responses/response-lib";

const dynamoClientMock = mockClient(DynamoDBDocumentClient);

jest.mock("../../utils/auth/authorization", () => ({
isAuthorized: jest.fn().mockReturnValue(true),
hasPermissions: jest.fn().mockReturnValueOnce(false).mockReturnValue(true),
isAuthenticated: jest.fn().mockReturnValue(true),
hasPermissions: jest.fn().mockReturnValue(true),
}));

const testEvent: APIGatewayProxyEvent = {
Expand All @@ -30,10 +32,11 @@ const consoleSpy: {

describe("Test deleteBanner API method", () => {
test("Test not authorized to delete banner throws 403 error", async () => {
(hasPermissions as jest.Mock).mockReturnValueOnce(false);
const res = await deleteBanner(testEvent, null);

expect(consoleSpy.debug).toHaveBeenCalled();
expect(res.statusCode).toBe(403);
expect(res.statusCode).toBe(StatusCodes.Forbidden);
expect(res.body).toContain(error.UNAUTHORIZED);
});

Expand All @@ -43,32 +46,29 @@ describe("Test deleteBanner API method", () => {
const res = await deleteBanner(testEvent, null);

expect(consoleSpy.debug).toHaveBeenCalled();
expect(res.statusCode).toBe(StatusCodes.SUCCESS);
expect(res.body).toContain("testKey");
expect(res.statusCode).toBe(StatusCodes.Ok);
expect(mockDelete).toHaveBeenCalled();
});

test("Test bannerKey not provided throws 500 error", async () => {
test("Test bannerKey not provided throws 400 error", async () => {
const noKeyEvent: APIGatewayProxyEvent = {
...testEvent,
pathParameters: {},
};
const res = await deleteBanner(noKeyEvent, null);

expect(consoleSpy.error).toHaveBeenCalled();
expect(res.statusCode).toBe(500);
expect(res.statusCode).toBe(StatusCodes.BadRequest);
expect(res.body).toContain(error.NO_KEY);
});

test("Test bannerKey empty throws 500 error", async () => {
test("Test bannerKey empty throws 400 error", async () => {
const noKeyEvent: APIGatewayProxyEvent = {
...testEvent,
pathParameters: { bannerId: "" },
};
const res = await deleteBanner(noKeyEvent, null);

expect(consoleSpy.error).toHaveBeenCalled();
expect(res.statusCode).toBe(500);
expect(res.statusCode).toBe(StatusCodes.BadRequest);
expect(res.body).toContain(error.NO_KEY);
});
});
30 changes: 14 additions & 16 deletions services/app-api/handlers/banners/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,23 @@ import handler from "../handler-lib";
import dynamoDb from "../../utils/dynamo/dynamodb-lib";
import { hasPermissions } from "../../utils/auth/authorization";
import { error } from "../../utils/constants/constants";
import { badRequest, forbidden, ok } from "../../utils/responses/response-lib";
// types
import { StatusCodes, UserRoles } from "../../utils/types";
import { UserRoles } from "../../utils/types";

export const deleteBanner = handler(async (event, _context) => {
if (!hasPermissions(event, [UserRoles.ADMIN])) {
return {
status: StatusCodes.UNAUTHORIZED,
body: error.UNAUTHORIZED,
};
} else if (!event?.pathParameters?.bannerId!) {
throw new Error(error.NO_KEY);
} else {
const params = {
TableName: process.env.BANNER_TABLE_NAME!,
Key: {
key: event?.pathParameters?.bannerId!,
},
};
await dynamoDb.delete(params);
return { status: StatusCodes.SUCCESS, body: params };
return forbidden(error.UNAUTHORIZED);
}
if (!event?.pathParameters?.bannerId!) {
return badRequest(error.NO_KEY);
}
const params = {
TableName: process.env.BANNER_TABLE_NAME!,
Key: {
key: event.pathParameters.bannerId,
},
};
await dynamoDb.delete(params);
return ok();
});
Loading
Loading