Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into upgradeXstate
Browse files Browse the repository at this point in the history
  • Loading branch information
chohner committed Mar 1, 2024
2 parents 419e723 + f56b7d0 commit cb7346b
Show file tree
Hide file tree
Showing 21 changed files with 703 additions and 590 deletions.
8 changes: 8 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,12 @@ module.exports = {
},
],
},
overrides: [
{
files: ["**/*.test.ts"],
rules: {
"sonarjs/no-duplicate-string": "off",
},
},
],
};
4 changes: 2 additions & 2 deletions .github/workflows/ci-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,13 @@ jobs:
- run: ./docker.sh --build prod
- run: echo "PROD_IMAGE_TAG=$(./docker.sh --prodImageTag)" >> $GITHUB_ENV
- name: Generate cosign vulnerability scan record for PROD image
uses: aquasecurity/trivy-action@84384bd6e777ef152729993b8145ea352e9dd3ef
uses: aquasecurity/trivy-action@062f2592684a31eb3aa050cc61e7ca1451cecd3d
with:
image-ref: ${{ env.REGISTRY }}/${{ github.repository }}:${{ env.PROD_IMAGE_TAG }}
format: "cosign-vuln"
output: "vulnerabilities.json"
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@84384bd6e777ef152729993b8145ea352e9dd3ef
uses: aquasecurity/trivy-action@062f2592684a31eb3aa050cc61e7ca1451cecd3d
with:
image-ref: ${{ env.REGISTRY }}/${{ github.repository }}:${{ env.PROD_IMAGE_TAG }}
format: "sarif"
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Remove all caches and database of the trivy scanner
uses: aquasecurity/trivy-action@84384bd6e777ef152729993b8145ea352e9dd3ef
uses: aquasecurity/trivy-action@062f2592684a31eb3aa050cc61e7ca1451cecd3d
env:
TRIVY_RESET: true
TRIVY_DEBUG: true
with:
scan-type: "image"
- name: Download trivy vulnerabilities DB
uses: aquasecurity/trivy-action@84384bd6e777ef152729993b8145ea352e9dd3ef
uses: aquasecurity/trivy-action@062f2592684a31eb3aa050cc61e7ca1451cecd3d
env:
TRIVY_DEBUG: true
TRIVY_DOWNLOAD_DB_ONLY: true
Expand All @@ -42,7 +42,7 @@ jobs:
- name: Run Trivy vulnerability scanner
# Third-party action, pin to commit SHA!
# See https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions
uses: aquasecurity/trivy-action@84384bd6e777ef152729993b8145ea352e9dd3ef
uses: aquasecurity/trivy-action@062f2592684a31eb3aa050cc61e7ca1451cecd3d
env:
TRIVY_USERNAME: ${{ github.actor }}
TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -67,7 +67,7 @@ jobs:
- name: Generate cosign vulnerability scan record
# Third-party action, pin to commit SHA!
# See https://docs.github.com/en/actions/security-guides/security-hardening-for-github-actions
uses: aquasecurity/trivy-action@84384bd6e777ef152729993b8145ea352e9dd3ef
uses: aquasecurity/trivy-action@062f2592684a31eb3aa050cc61e7ca1451cecd3d
env:
TRIVY_USERNAME: ${{ github.actor }}
TRIVY_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
Expand Down
28 changes: 20 additions & 8 deletions app/components/MigrationDataOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,21 +10,33 @@ type MigrationDataProps = {
};

export default function MigrationDataOverview(props: MigrationDataProps) {
if (!props.migrationData || Object.keys(props.migrationData).length == 0)
if (!props.migrationData || Object.keys(props.migrationData).length === 0)
return null;
return (
<Background backgroundColor="white">
<Container>
<Box
content={{
markdown: Object.entries(props.migrationData)
.map(
([key, field]) =>
`**${lookupOrKey(key, props.translations)}:**\n\n${lookupOrKey(
field as string,
props.translations,
)}\n\n`,
)
.map(([key, value]) => {
const formattedKey = `**${lookupOrKey(key, props.translations)}:**\n\n`;

if (typeof value === "object" && value !== null) {
const objectProperties = Object.entries(value)
.map(
([subKey, subValue]) =>
`${lookupOrKey(
subValue as string,
props.translations,
)}`,
)
.join("\n\n");

return `${formattedKey}\n\n${objectProperties}\n\n`;
} else {
return `${formattedKey}${lookupOrKey(value as string, props.translations)}\n\n`;
}
})
.join(""),
}}
/>
Expand Down
2 changes: 1 addition & 1 deletion app/entry.server.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ function handleBrowserRequest(
const cspNonce = generateNonce();
responseHeaders.set(
"Content-Security-Policy",
`default-src 'self'; script-src 'self' 'nonce-${cspNonce}' https://eu.posthog.com/static/recorder-v2.js; style-src 'self' 'unsafe-inline'; connect-src ${
`default-src 'self'; script-src 'self' 'nonce-${cspNonce}' https://*.posthog.com; style-src 'self' 'unsafe-inline'; connect-src ${
configServer().TRUSTED_CSP_CONNECT_SOURCES
}; img-src 'self' localhost:* ${configServer().TRUSTED_IMAGE_SOURCES}`,
);
Expand Down
1 change: 0 additions & 1 deletion app/models/flows/contexts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ export type ObjectType = Record<
string,
BasicTypes | Record<string, BasicTypes | Record<string, BasicTypes>> // TODO: check whether GeldEinklagenFormularContext should be triple nested
>;
export type ArrayCollection = Record<string, ObjectType[]>;
export type Context = Record<
string,
BasicTypes | ObjectType | ObjectType[] | undefined
Expand Down
9 changes: 9 additions & 0 deletions app/models/flows/fluggastrechte/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,14 @@ export const fluggastBereichSchema = z.enum(
customRequiredErrorMessage,
);

export const zustaendigesAmtsgerichtSchema = z.array(
z.object({
bezeichnung: z.string(),
strasseMitHausnummer: z.string(),
plzUndStadt: z.string(),
}),
);

export const fluggastrechteVorabcheckContext = {
startAirport: airportSchema,
endAirport: airportSchema,
Expand All @@ -38,6 +46,7 @@ export const fluggastrechteVorabcheckContext = {
kostenlos: YesNoAnswer,
rabatt: YesNoAnswer,
buchung: YesNoAnswer,
zustaendigesAmtsgericht: zustaendigesAmtsgerichtSchema.optional(),
} as const;

const contextObject = z.object(fluggastrechteVorabcheckContext).partial();
Expand Down
2 changes: 2 additions & 0 deletions app/models/flows/fluggastrechteFormular/context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { inputRequiredSchema } from "~/services/validation/inputRequired";
import {
airlineSchema,
fluggastBereichSchema,
zustaendigesAmtsgerichtSchema,
} from "../fluggastrechte/context";
import {
checkedOptional,
Expand Down Expand Up @@ -73,6 +74,7 @@ export const fluggastrechtContext = {
doMigration: YesNoAnswer,
aenderungMitteilung: checkedRequired,
zahlungOptional: checkedOptional,
zustaendigesAmtsgericht: zustaendigesAmtsgerichtSchema.optional(),
} as const;

const contextObject = z.object(fluggastrechtContext).partial();
Expand Down
66 changes: 30 additions & 36 deletions app/routes/shared/formular.server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import type { ActionFunctionArgs, LoaderFunctionArgs } from "@remix-run/node";
import { json, redirectDocument } from "@remix-run/node";
import { validationError } from "remix-validated-form";
import { getSessionForContext, updateSession } from "~/services/session.server";
import {
getSessionData,
getSessionForContext,
updateSession,
} from "~/services/session.server";
import {
fetchCollectionEntry,
fetchMeta,
Expand All @@ -13,19 +17,14 @@ import type { Context } from "~/models/flows/contexts";
import { parsePathname } from "~/models/flows/contexts";
import { flows } from "~/models/flows/flows.server";
import { isStrapiSelectComponent } from "~/services/cms/models/StrapiSelect";
import {
createCSRFToken,
csrfSessionFromRequest,
validatedSession,
} from "~/services/security/csrf.server";
import { validatedSession } from "~/services/security/csrf.server";
import { throw404IfFeatureFlagEnabled } from "~/services/errorPages/throw404";
import { logError } from "~/services/logging";
import { lastStepKey } from "~/services/flow/constants";
import { getMigrationData } from "~/services/session.server/crossFlowMigration";
import { navItemsFromFlowSpecifics } from "~/services/flowNavigation.server";
import type { z } from "zod";
import type { CollectionSchemas } from "~/services/cms/schemas";
import { buttonProps } from "~/util/buttonProps";
import { getButtonNavigationProps } from "~/util/buttonProps";
import { sendCustomEvent } from "~/services/analytics/customEvent";
import { parentFromParams } from "~/services/params";
import { isStrapiArraySummary } from "~/services/cms/models/StrapiArraySummary";
Expand All @@ -37,6 +36,7 @@ import {
} from "~/services/session.server/arrayDeletion";
import { interpolateDeep } from "~/util/fillTemplate";
import { stepMeta } from "~/services/meta/formStepMeta";
import { updateSessionInHeader } from "~/services/session.server/updateSessionInHeader";

const structureCmsContent = (
formPageContent: z.infer<CollectionSchemas["form-flow-pages"]>,
Expand Down Expand Up @@ -88,10 +88,11 @@ export const loader = async ({
const { flowId, stepId, arrayIndex } = parsePathname(pathname);
const cookieId = request.headers.get("Cookie");

// get data from redis
const { data, id } = await getSessionForContext(flowId).getSession(cookieId);
const userDataFromRedis: Context = data; // Recast for now to get type safety
context.sessionId = getSessionForContext(flowId).getSessionId(id); // For showing in errors
const { userDataFromRedis, sessionId } = await getSessionData(
flowId,
cookieId,
);
context.sessionId = sessionId; // For showing in errors

// get flow controller
const currentFlow = flows[flowId];
Expand Down Expand Up @@ -149,7 +150,11 @@ export const loader = async ({

// filter user data for current step
const fieldNames = formPageContent.form.map((entry) => entry.name);
const stepData = stepDataFromFieldNames(fieldNames, data, arrayIndex);
const stepData = stepDataFromFieldNames(
fieldNames,
userDataFromRedis,
arrayIndex,
);

// get array data to display in ArraySummary -> Formular + Vorabcheck?
const arrayData = Object.fromEntries(
Expand All @@ -162,30 +167,19 @@ export const loader = async ({
}),
);

// update session with csrf
const csrf = createCSRFToken();
const session = await csrfSessionFromRequest(csrf, request);

// update session with last valid step
session.set(lastStepKey, { [flowId]: stepId });

// set session in header
const sessionContext = getSessionForContext("main");
const headers = { "Set-Cookie": await sessionContext.commitSession(session) };
const { headers, csrf } = await updateSessionInHeader({
request,
flowId,
stepId,
});

// get navigation destinations + labels
const buttonNavigationProps = {
next: flowController.isFinal(stepId)
? undefined
: buttonProps(
cmsContent.nextButtonLabel ??
defaultStrings["nextButtonDefaultLabel"],
),
back: buttonProps(
defaultStrings["backButtonDefaultLabel"],
returnTo ?? flowController.getPrevious(stepId),
),
};
const buttonNavigationProps = getButtonNavigationProps({
flowController,
stepId,
nextButtonLabel: cmsContent.nextButtonLabel,
defaultStrings,
returnTo,
});

// get navigation items -> Formular
const navItems = navItemsFromFlowSpecifics(
Expand Down
33 changes: 24 additions & 9 deletions app/routes/shared/result.server.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { ActionFunction, LoaderFunctionArgs } from "@remix-run/node";
import { json, redirect } from "@remix-run/node";
import { getSessionForContext } from "~/services/session.server";
import { getSessionForContext, updateSession } from "~/services/session.server";
import {
fetchCollectionEntry,
fetchMeta,
Expand All @@ -23,6 +23,7 @@ import {
partnerCourtAirports,
} from "~/models/flows/fluggastrechte";
import { findCourt } from "~/services/gerichtsfinder/amtsgerichtData.server";
import type { Jmtd14VTErwerberGerbeh } from "~/services/gerichtsfinder/types";

export const loader = async ({ request, context }: LoaderFunctionArgs) => {
await throw404IfFeatureFlagEnabled(request);
Expand All @@ -31,9 +32,29 @@ export const loader = async ({ request, context }: LoaderFunctionArgs) => {
const { pathname } = new URL(request.url);
const { flowId, stepId } = parsePathname(pathname);
const cookieId = request.headers.get("Cookie");
const { data, id } = await getSessionForContext(flowId).getSession(cookieId);
const flowSession = await getSessionForContext(flowId).getSession(cookieId);
const { data, id } = flowSession;
context.sessionId = getSessionForContext(flowId).getSessionId(id); // For showing in errors

const courts = [data.startAirport, data.endAirport]
.filter(isPartnerAirport)
.map((airport) => findCourt({ zipCode: partnerCourtAirports[airport] }))
.filter(Boolean) as Jmtd14VTErwerberGerbeh[];

// TODO: move logic that enriches user data out of the loader
const zustaendigesAmtsgericht = courts.map((court) => ({
bezeichnung: court.BEZEICHNUNG,
strasseMitHausnummer: court.STR_HNR,
plzUndStadt: `${court.PLZ_ZUSTELLBEZIRK} ${court.ORT}`,
}));

if (zustaendigesAmtsgericht.length > 0) {
updateSession(flowSession, {
zustaendigesAmtsgericht: zustaendigesAmtsgericht[0],
});
await getSessionForContext(flowId).commitSession(flowSession);
}

const { config, guards } = flows[flowId];
const flowController = buildFlowController({ config, data, guards });

Expand Down Expand Up @@ -87,13 +108,7 @@ export const loader = async ({ request, context }: LoaderFunctionArgs) => {
getFeedbackBannerState(userDataFromRedis, pathname) ??
BannerState.ShowRating,
amtsgerichtCommon,
courts:
cmsData.pageType === "success" &&
[data.startAirport, data.endAirport]
.filter(isPartnerAirport)
.map((airport) =>
findCourt({ zipCode: partnerCourtAirports[airport] }),
),
courts: cmsData.pageType === "success" && courts,
},
{ headers: { "Set-Cookie": await commitSession(userDataFromRedis) } },
);
Expand Down
Loading

0 comments on commit cb7346b

Please sign in to comment.