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 #11529

Merged
merged 4 commits into from
Dec 6, 2023
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
4 changes: 2 additions & 2 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ jobs:
env:
SLS_DEPRECATION_DISABLE: "*" # Turn off deprecation warnings in the pipeline
steps:
- name: set branch_name
- name: set branch_name # Some integrations (Dependabot & Snyk) build very long branch names. This is a switch to make long branch names shorter.
run: |
if [[ "$GITHUB_REF" =~ ^refs/heads/dependabot/.* ]]; then # Dependabot builds very long branch names. This is a switch to make it shorter.
if [[ "$GITHUB_REF" =~ ^refs/heads/dependabot/.* ]] || [[ "$GITHUB_REF" =~ ^refs/remotes/origin/snyk-upgrade-* ]] || [[ "$GITHUB_REF" =~ ^refs/remotes/origin/snyk-fix-* ]]; then
echo "branch_name=`echo ${GITHUB_REF#refs/heads/} | md5sum | head -c 10 | sed 's/^/x/'`" >> $GITHUB_ENV
else
echo "branch_name=${GITHUB_REF#refs/heads/}" >> $GITHUB_ENV
Expand Down
16 changes: 7 additions & 9 deletions .github/workflows/scan_security-hub-jira-integration.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Sync Security Hub findings and Jira issues
name: Scan and Open Jira Tickets (AWS Security Hub)

on:
workflow_dispatch: # for testing and manual runs
Expand All @@ -20,16 +20,14 @@ jobs:
with:
aws-region: ${{ secrets.AWS_DEFAULT_REGION }}
role-to-assume: ${{ secrets.PRODUCTION_SYNC_OIDC_ROLE }}

- name: Sync Security Hub and Jira
uses: Enterprise-CMCS/[email protected]
with:
jira-token: ${{ secrets.JIRA_SERVICE_USER_TOKEN }}
jira-username: ${{ secrets.JIRA_SERVICE_USERNAME }}
jira-host: qmacbis.atlassian.net
jira-project-key: MDCT
jira-epic-key: MDCT-2280
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_14154" : [{"id": "16958", "value": "MCR"}] }'
jira-custom-fields: '{ "customfield_10100": "CMDCT-2280", "customfield_26700" : [{"id": "40104", "value": "MCR"}] }'
aws-severities: CRITICAL, HIGH, MEDIUM
assign-jira-ticket-to: ${{ secrets.ACCOUNT_ID_REHMAN }}
assign-jira-ticket-to: "MWTW"
19 changes: 9 additions & 10 deletions .github/workflows/scan_snyk-jira-integration.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Snyk Scan and Report
name: Scan and Open Jira Tickets (Snyk)

on:
pull_request:
Expand All @@ -14,7 +14,6 @@ jobs:
name: Snyk Run (for PR and push)
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'

steps:
- name: Check out repository
uses: actions/checkout@v3
Expand Down Expand Up @@ -42,17 +41,17 @@ jobs:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}

- name: use the custom github action to parse Snyk output
uses: Enterprise-CMCS/[email protected].0
uses: Enterprise-CMCS/[email protected].4
with:
jira-username: ${{ secrets.JIRA_SERVICE_USERNAME }}
jira-token: ${{ secrets.JIRA_SERVICE_USER_TOKEN }}
jira-host: "qmacbis.atlassian.net"
jira-project-key: "MDCT"
jira-username: "mdct_github_service_account"
jira-token: ${{ secrets.JIRA_ENT_USER_TOKEN }}
jira-host: "jiraent.cms.gov"
jira-project-key: "CMDCT"
jira-issue-type: "Task"
jira-custom-field-key-value: '{ "customfield_10007" : "MDCT-2280", "customfield_14154" : [{"id": "16958", "value": "MCR"}] }'
jira-custom-field-key-value: '{ "customfield_10100": "CMDCT-2280", "customfield_26700" : [{"id": "40104", "value": "MCR"}] }'
jira-labels: "MCR,snyk"
jira-title-prefix: "[MCR] - Snyk :"
is_jira_enterprise: false
assign-jira-ticket-to: ${{ secrets.ACCOUNT_ID_REHMAN }}
is_jira_enterprise: true
assign-jira-ticket-to: "MWTW"
scan-output-path: "snyk_output.txt"
scan-type: "snyk"
29 changes: 29 additions & 0 deletions .github/workflows/snyk-auto-merge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Adapted from https://docs.github.com/en/code-security/dependabot/working-with-dependabot/automating-dependabot-with-github-actions
name: Snyk auto-merge
on:
pull_request:
workflow_dispatch:

permissions:
pull-requests: write
contents: write

jobs:
dependabot:
runs-on: ubuntu-latest
if: ${{ github.actor == 'mdct-github-service-account' }}
steps:
- name: Snyk Gather Metadata
id: metadata
uses: dependabot/fetch-metadata@v1
- name: Approve a PR
run: gh pr review --approve "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Enable auto-merge for Snyk PRs
if: ${{ steps.metadata.outputs.update-type != 'version-update:semver-major'}}
run: gh pr merge --auto --merge "$PR_URL"
env:
PR_URL: ${{github.event.pull_request.html_url}}
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
3 changes: 2 additions & 1 deletion services/ui-src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@
"react-scripts": "^5.0.0",
"react-uuid": "^1.0.3",
"sass": "^1.37.5",
"yup": "^0.32.11"
"yup": "^0.32.11",
"zustand": "^4.4.6"
},
"devDependencies": {
"@aws-sdk/types": "^3.38.0",
Expand Down
6 changes: 4 additions & 2 deletions services/ui-src/src/components/accordions/FaqAccordion.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
// components
import { Accordion, Box, Text } from "@chakra-ui/react";
import { AccordionItem } from "components";
// utils
// types
import { AnyObject } from "types";
// utils
import { parseCustomHtml } from "utils";

export const FaqAccordion = ({ accordionItems, ...props }: Props) => {
return (
<Accordion allowToggle={true} allowMultiple={true} {...props}>
{accordionItems.map((item: AnyObject, index: number) => (
<AccordionItem key={index} label={item.question} sx={sx.item}>
<Box sx={sx.answerBox}>
<Text>{item.answer}</Text>
<Text>{parseCustomHtml(item.answer)}</Text>
</Box>
</AccordionItem>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { act } from "react-dom/test-utils";
// components
import { AdminBannerContext, AdminBannerProvider } from "./AdminBannerProvider";
// utils
import { useStore } from "utils";
import { mockBannerData } from "utils/testing/setupJest";
import { bannerErrors } from "verbiage/errors";

Expand All @@ -27,7 +28,6 @@ const TestComponent = () => {
<button onClick={() => context.deleteAdminBanner(mockBannerData.key)}>
Delete
</button>
{context.errorMessage && <p>{context.errorMessage}</p>}
</div>
);
};
Expand Down Expand Up @@ -70,7 +70,9 @@ describe("Test AdminBannerProvider fetchAdminBanner method", () => {
await act(async () => {
await render(testComponent);
});
expect(screen.queryByText(bannerErrors.GET_BANNER_FAILED)).toBeVisible();
expect(useStore.getState().bannerErrorMessage).toBe(
bannerErrors.GET_BANNER_FAILED
);
});
});

Expand All @@ -89,7 +91,9 @@ describe("Test AdminBannerProvider deleteAdminBanner method", () => {
});
expect(mockAPI.deleteBanner).toHaveBeenCalledTimes(1);
expect(mockAPI.deleteBanner).toHaveBeenCalledWith(mockBannerData.key);
await waitFor(() => expect(mockAPI.getBanner).toHaveBeenCalledTimes(1));

// 1 call on render + 1 call on button click
await waitFor(() => expect(mockAPI.getBanner).toHaveBeenCalledTimes(2));
});
});

Expand Down
100 changes: 76 additions & 24 deletions services/ui-src/src/components/banners/AdminBannerProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,66 +1,118 @@
import { useState, createContext, ReactNode, useMemo, useEffect } from "react";
import { createContext, ReactNode, useMemo, useEffect } from "react";
// utils
import { AdminBannerData, AdminBannerShape } from "types/banners";
import { AdminBannerData, AdminBannerMethods } from "types/banners";
import { bannerId } from "../../constants";
import { bannerErrors } from "verbiage/errors";
// api
import { deleteBanner, getBanner, writeBanner } from "utils";
import {
deleteBanner,
getBanner,
writeBanner,
useStore,
checkDateRangeStatus,
} from "utils";

const ADMIN_BANNER_ID = bannerId;

export const AdminBannerContext = createContext<AdminBannerShape>({
bannerData: undefined as AdminBannerData | undefined,
export const AdminBannerContext = createContext<AdminBannerMethods>({
fetchAdminBanner: Function,
writeAdminBanner: Function,
deleteAdminBanner: Function,
isLoading: false as boolean,
errorMessage: undefined,
});

export const AdminBannerProvider = ({ children }: Props) => {
const [bannerData, setBannerData] = useState<AdminBannerData | undefined>(
undefined
);
const [isLoading, setIsLoading] = useState<boolean>(false);
const [error, setError] = useState<string>();
// state management
const {
bannerData,
setBannerData,
bannerActive,
setBannerActive,
bannerLoading,
setBannerLoading,
bannerErrorMessage,
setBannerErrorMessage,
bannerDeleting,
setBannerDeleting,
} = useStore();

const fetchAdminBanner = async () => {
setIsLoading(true);
setBannerLoading(true);
try {
const currentBanner = await getBanner(ADMIN_BANNER_ID);
const newBannerData = currentBanner?.Item || {};
setBannerData(newBannerData);
} catch (e: any) {
setIsLoading(false);
setError(bannerErrors.GET_BANNER_FAILED);
setBannerErrorMessage("");
} catch (error: any) {
setBannerLoading(false);
setBannerErrorMessage(bannerErrors.GET_BANNER_FAILED);
}
setIsLoading(false);
setBannerLoading(false);
};

const deleteAdminBanner = async () => {
await deleteBanner(ADMIN_BANNER_ID);
setBannerData(undefined);
setBannerDeleting(true);
try {
await deleteBanner(ADMIN_BANNER_ID);
await fetchAdminBanner();
} catch (error: any) {
setBannerErrorMessage(bannerErrors.DELETE_BANNER_FAILED);
}
setBannerDeleting(false);
};

const writeAdminBanner = async (newBannerData: AdminBannerData) => {
await writeBanner(newBannerData);
setBannerData(newBannerData);
try {
await writeBanner(newBannerData);
} catch (error: any) {
setBannerErrorMessage(bannerErrors.CREATE_BANNER_FAILED);
}
await fetchAdminBanner();
};

useEffect(() => {
let bannerActivity = false;
if (bannerData) {
bannerActivity = checkDateRangeStatus(
bannerData.startDate,
bannerData.endDate
);
}
setBannerActive(bannerActivity);
}, [bannerData]);

useEffect(() => {
fetchAdminBanner();
}, []);

const providerValue = useMemo(
() => ({
// banner data
bannerData,
setBannerData,
// banner is showing
bannerActive,
setBannerActive,
// banner is loading
bannerLoading,
setBannerLoading,
// banner error state
bannerErrorMessage,
setBannerErrorMessage,
// banner deleting state
bannerDeleting,
setBannerDeleting,
// banner API calls
fetchAdminBanner,
writeAdminBanner,
deleteAdminBanner,
isLoading: isLoading,
errorMessage: error,
}),
[bannerData, isLoading, error]
[
bannerData,
bannerActive,
bannerLoading,
bannerErrorMessage,
bannerDeleting,
]
);

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Box, Image, Td, Text, Tr } from "@chakra-ui/react";
// types
import { EntityShape, ModalOverlayReportPageShape, ReportType } from "types";
// utils
import { assertExhaustive, getEntityDetailsMLR, renderHtml } from "utils";
import { assertExhaustive, getEntityDetailsMLR } from "utils";
// verbiage
import mcparVerbiage from "../../verbiage/pages/mcpar/mcpar-export";
import mlrVerbiage from "../../verbiage/pages/mlr/mlr-export";
Expand Down Expand Up @@ -86,7 +86,7 @@ export function renderModalOverlayTableBody(
<Text sx={sx.entityList}>
{entity.report_planName ?? "Not entered"} <br />
{report_programName} <br />
{renderHtml(mlrEligibilityGroup)} <br />
{mlrEligibilityGroup} <br />
{reportingPeriod}
</Text>
</Td>
Expand Down
Loading