Skip to content

Commit

Permalink
Refactor types for sfn
Browse files Browse the repository at this point in the history
Refactor based on feedback from
- #638 (comment)

Ticket: AT-7055
  • Loading branch information
juliusfitzhugh-ccpo committed Mar 15, 2022
1 parent 831c422 commit b07061e
Show file tree
Hide file tree
Showing 9 changed files with 56 additions and 31 deletions.
12 changes: 7 additions & 5 deletions api/provision/mock-invocation-lambda.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe("Successful invocation of mock CSP function", () => {
operators,
},
}) as any;
const response = await handler(stateInput, {} as Context);
const response: any = await handler(stateInput, {} as Context);
console.log(response);
expect(response?.code).toBe(200);
});
Expand All @@ -51,7 +51,7 @@ describe("Failed invocation operations", () => {
operators,
},
}) as any;
const response = await handler(stateInput, {} as Context);
const response: any = await handler(stateInput, {} as Context);
console.log(response);
expect(response?.code).toBe(400);
});
Expand All @@ -65,7 +65,7 @@ describe("Failed invocation operations", () => {
operators,
},
} as any);
const response = await handler(stateInput, {} as Context);
const response: any = await handler(stateInput, {} as Context);
console.log(response);
expect(response).toBeInstanceOf(ValidationErrorResponse);
expect(response.statusCode).toBe(400);
Expand All @@ -80,10 +80,12 @@ describe("Failed invocation operations", () => {
operators,
},
}) as any;
expect(async () => await handler(stateInput, {} as Context)).rejects.toThrow(JSON.stringify({ code: 500, content: { some: "internal error"}, payload: stateInput}))
expect(async () => await handler(stateInput, {} as Context)).rejects.toThrow(
JSON.stringify({ code: 500, content: { some: "internal error" }, payload: stateInput })
);
});
it("should return a 400 when null", async () => {
const response = await handler(undefined, {} as Context, () => null);
const response: any = await handler(undefined as any, {} as Context, () => null);
console.log(response);
expect(response).toBeInstanceOf(OtherErrorResponse);
expect(response.statusCode).toBe(400);
Expand Down
11 changes: 5 additions & 6 deletions api/provision/mock-invocation-lambda.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import { Context } from "aws-lambda";
import { CspInvocation, cspInvocationSchema, CspResponse } from "../../models/provisioning-jobs";

import { errorHandlingMiddleware } from "../../utils/middleware/error-handling-middleware";
import middy from "@middy/core";
import validator from "@middy/validator";
import JSONErrorHandlerMiddleware from "middy-middleware-json-error-handler";
import { CloudServiceProvider } from "../../models/cloud-service-providers";
import { REQUEST_BODY_INVALID } from "../../utils/errors";
import { ValidationErrorResponse } from "../../utils/response";

/**
* Mock invocation of CSP and returns a CSP Response based on CSP
Expand All @@ -17,25 +16,25 @@ import { REQUEST_BODY_INVALID } from "../../utils/errors";
* @param stateInput - Csp Invocation request
* @return - CspResponse or throw error for 500 or above
*/
export async function baseHandler(stateInput: any, context: Context): Promise<any> {
export async function baseHandler(stateInput: CspInvocation): Promise<CspResponse | ValidationErrorResponse> {
console.log("STATE INPUT: ", JSON.stringify(stateInput));
if (!stateInput || !stateInput.endpoint) {
return REQUEST_BODY_INVALID;
}

const cspResponse = createCspResponse(stateInput);

// Throws a custom error identified by the state machine and the function retires 2
// Throws a custom error identified by the state machine and the function retires 2
// times before failing continuing through the remaining states
if (cspResponse.code >= 500) {
const error = new Error(JSON.stringify(cspResponse));
Object.defineProperty(error, "name", {
value: "MockCspApiError",
});
throw error
throw error;
}

return cspResponse
return cspResponse;
}

export function createCspResponse(request: CspInvocation): CspResponse {
Expand Down
1 change: 0 additions & 1 deletion api/provision/start-provision-job.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ describe("Successful provisioning operations", () => {
requestContext,
} as any;
const response = await handler(request, {} as Context, () => null);
console.log("TROUBLESHOOTING: ", response);
expect(response).toBeInstanceOf(ApiSuccessResponse);
});
it("should add a funding source to existing portfolio", async () => {
Expand Down
4 changes: 2 additions & 2 deletions api/provision/start-provision-job.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { APIGatewayProxyResult } from "aws-lambda";
import { ApiSuccessResponse, ErrorStatusCode, OtherErrorResponse, SuccessStatusCode } from "../../utils/response";
import {
CspInvocation,
ILambdaEvent,
StepFunctionRequestEvent,
ProvisionRequest,
provisionRequestSchema,
ProvisionRequestType,
Expand All @@ -28,7 +28,7 @@ const SFN_ARN = process.env.SFN_ARN ?? "";
*
* @param event - POST request from API Gateway with provisioning job properties
*/
export async function baseHandler(event: ILambdaEvent): Promise<APIGatewayProxyResult> {
export async function baseHandler(event: StepFunctionRequestEvent<ProvisionRequest>): Promise<APIGatewayProxyResult> {
try {
const cspInvocationJob = transformProvisionJob(event.body);
console.log("SentToSfn: " + JSON.stringify(cspInvocationJob));
Expand Down
8 changes: 5 additions & 3 deletions models/provisioning-jobs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { HttpMethod } from "../lib/http";
import { APIGatewayEventRequestContext } from "aws-lambda";
import { CloudServiceProvider, Network } from "./cloud-service-providers";

export enum ProvisionRequestType {
Expand Down Expand Up @@ -45,10 +46,11 @@ export interface CspInvocation {
endpoint: string;
payload: NewPortfolioPayload | FundingSourcePayload | OperatorPayload;
}
export interface ILambdaEvent {
body: ProvisionRequest;
requestContext: { identity: { sourceIp: string } };
export interface StepFunctionRequestEvent<T> {
body: T;
requestContext: APIGatewayEventRequestContext;
}
export type RequestBodyType = ProvisionRequest;

export interface CspResponse {
code: number;
Expand Down
18 changes: 15 additions & 3 deletions utils/middleware/check-csp-portfolio-id.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,22 @@
import middy from "@middy/core";
import { APIGatewayProxyResult } from "aws-lambda";
import { ILambdaEvent, ProvisionRequestType } from "../../models/provisioning-jobs";
import {
StepFunctionRequestEvent,
ProvisionRequestType,
RequestBodyType,
CspResponse,
} from "../../models/provisioning-jobs";
import createError from "http-errors";
import { ValidationErrorResponse } from "../response";

export const cspPortfolioIdChecker = (): middy.MiddlewareObj<ILambdaEvent, APIGatewayProxyResult> => {
const before: middy.MiddlewareFn<ILambdaEvent, APIGatewayProxyResult> = async (request): Promise<void> => {
export const cspPortfolioIdChecker = (): middy.MiddlewareObj<
StepFunctionRequestEvent<RequestBodyType>,
APIGatewayProxyResult | CspResponse | ValidationErrorResponse
> => {
const before: middy.MiddlewareFn<
StepFunctionRequestEvent<RequestBodyType>,
APIGatewayProxyResult | CspResponse | ValidationErrorResponse
> = async (request): Promise<void> => {
const { portfolioId, operationType } = request.event.body;
const requiresPortfolioId = [ProvisionRequestType.ADD_FUNDING_SOURCE, ProvisionRequestType.ADD_OPERATORS];
if (requiresPortfolioId.includes(operationType) && !portfolioId) {
Expand Down
14 changes: 9 additions & 5 deletions utils/middleware/error-handling-middleware.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,16 @@ import { APIGatewayProxyResult } from "aws-lambda";
import { serializeError } from "serialize-error";
import { ValidationErrorResponse } from "../response";
import { INTERNAL_SERVER_ERROR, REQUEST_BODY_INVALID } from "../errors";
import { ILambdaEvent } from "../../models/provisioning-jobs";
import { StepFunctionRequestEvent, RequestBodyType, CspInvocation, CspResponse } from "../../models/provisioning-jobs";

export const errorHandlingMiddleware = (): middy.MiddlewareObj<ILambdaEvent, APIGatewayProxyResult> => {
const onError: middy.MiddlewareFn<ILambdaEvent, APIGatewayProxyResult> = async (
request
): Promise<ValidationErrorResponse | void> => {
export const errorHandlingMiddleware = (): middy.MiddlewareObj<
StepFunctionRequestEvent<RequestBodyType> | CspInvocation,
APIGatewayProxyResult | CspResponse | ValidationErrorResponse
> => {
const onError: middy.MiddlewareFn<
StepFunctionRequestEvent<RequestBodyType> | CspInvocation,
APIGatewayProxyResult | CspResponse | ValidationErrorResponse
> = async (request): Promise<ValidationErrorResponse | void> => {
const error = serializeError(request.error!);
const errorMessage = error.message;

Expand Down
11 changes: 8 additions & 3 deletions utils/middleware/ip-logging.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import middy from "@middy/core";
import { APIGatewayProxyResult } from "aws-lambda";
import { ILambdaEvent } from "../../models/provisioning-jobs";
import { StepFunctionRequestEvent, RequestBodyType } from "../../models/provisioning-jobs";

// Create the middleware and export it
export const IpCheckerMiddleware = (): middy.MiddlewareObj<ILambdaEvent, APIGatewayProxyResult> => {
export const IpCheckerMiddleware = (): middy.MiddlewareObj<
StepFunctionRequestEvent<RequestBodyType>,
APIGatewayProxyResult
> => {
// Set up a before check, this will run before the handler
const before: middy.MiddlewareFn<ILambdaEvent, APIGatewayProxyResult> = async (request): Promise<void> => {
const before: middy.MiddlewareFn<StepFunctionRequestEvent<RequestBodyType>, APIGatewayProxyResult> = async (
request
): Promise<void> => {
// log the sourceIp
console.log("Client IP address: " + request.event.requestContext.identity.sourceIp);
};
Expand Down
8 changes: 5 additions & 3 deletions utils/middleware/xss-sanitizer.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import middy from "@middy/core";
import xss from "xss";
import { APIGatewayProxyResult } from "aws-lambda";
import { ILambdaEvent } from "../../models/provisioning-jobs";
import { StepFunctionRequestEvent, RequestBodyType } from "../../models/provisioning-jobs";

// keep plain text only
const xssOptions = {
whiteList: {}, // empty means remove all tags
stripIgnoreTag: true, // remove all tags not in whitelist
stripIgnoreTagBody: ["script"], // remove script tag content
};
const xssSanitizer = (): middy.MiddlewareObj<ILambdaEvent, APIGatewayProxyResult> => {
const before: middy.MiddlewareFn<ILambdaEvent, APIGatewayProxyResult> = async (request): Promise<void> => {
const xssSanitizer = (): middy.MiddlewareObj<StepFunctionRequestEvent<RequestBodyType>, APIGatewayProxyResult> => {
const before: middy.MiddlewareFn<StepFunctionRequestEvent<RequestBodyType>, APIGatewayProxyResult> = async (
request
): Promise<void> => {
request.event.body = JSON.parse(xss(JSON.stringify(request.event.body ?? {}), xssOptions));
};
return {
Expand Down

0 comments on commit b07061e

Please sign in to comment.