Skip to content

Commit

Permalink
Updates from feedback
Browse files Browse the repository at this point in the history
- Remove CORS related code
- Minor refactoring
- Updating comments

Removing 'dom' from tsconfig.json produces error during tsc build
during github action Run Tests.
- required to workaround aws/aws-sdk-js-v3#2896

Ticket: AT-7050
  • Loading branch information
juliusfitzhugh-ccpo committed Mar 15, 2022
1 parent 1c358ed commit fe51d0d
Show file tree
Hide file tree
Showing 15 changed files with 59 additions and 88 deletions.
4 changes: 1 addition & 3 deletions api/provision/sample-fn.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
import { Context } from "aws-lambda";

/**
* Sample lambda used as a placeholder prior to implementation of other lambdas
*
* @param stateInput - input to the state task that is processed
*/
export async function handler(stateInput: any, context?: Context): Promise<unknown> {
export async function handler(stateInput: any): Promise<any> {
console.log("STATE INPUT: " + JSON.stringify(stateInput));

// A mock function that is used as a placeholder for each state and returns the input
Expand Down
16 changes: 8 additions & 8 deletions api/provision/start-provision-job.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ const provisioningBodyNoPayload = {
targetNetwork: Network.NETWORK_1,
};

export const requestContext = { identity: { sourceIp: "9.9.9.9" } };

describe("Successful provisioning operations", () => {
it("should add a new portfolio", async () => {
const request = {
Expand All @@ -40,10 +42,10 @@ describe("Successful provisioning operations", () => {
operators,
},
},
requestContext: { identity: { sourceIp: "9.9.9.9" } },
requestContext,
} as any;
const response = await handler(request, {} as Context, () => null);
console.log(response);
console.log("TROUBLESHOOTING: ", response);
expect(response).toBeInstanceOf(ApiSuccessResponse);
});
it("should add a funding source to existing portfolio", async () => {
Expand All @@ -63,10 +65,9 @@ describe("Successful provisioning operations", () => {
],
},
},
requestContext: { identity: { sourceIp: "9.9.9.9" } },
requestContext,
} as any;
const response = await handler(request, {} as Context, () => null);
console.log(response);
expect(response).toBeInstanceOf(ApiSuccessResponse);
});
it("should add operators to existing portfolio", async () => {
Expand All @@ -78,10 +79,9 @@ describe("Successful provisioning operations", () => {
operators: [...operators, "[email protected]"],
},
},
requestContext: { identity: { sourceIp: "9.9.9.9" } },
requestContext,
} as any;
const response = await handler(request, {} as Context, () => null);
console.log(response);
expect(response).toBeInstanceOf(ApiSuccessResponse);
});
});
Expand All @@ -96,7 +96,7 @@ describe("Failed provision operations", () => {
operators,
},
},
requestContext: { identity: { sourceIp: "9.9.9.9" } },
requestContext,
} as any;
const response = await handler(request, {} as Context, () => null);
expect(response).toBeInstanceOf(ValidationErrorResponse);
Expand All @@ -110,7 +110,7 @@ describe("Failed provision operations", () => {
operators,
},
},
requestContext: { identity: { sourceIp: "9.9.9.9" } },
requestContext,
} as any;
const response = await handler(request, {} as Context, () => null);
const responseBody = JSON.parse(response?.body ?? "");
Expand Down
13 changes: 5 additions & 8 deletions api/provision/start-provision-job.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { sfnClient } from "../../utils/aws-sdk/step-functions";
import { APIGatewayProxyEvent, APIGatewayProxyResult, Context } from "aws-lambda";
import { APIGatewayProxyResult } from "aws-lambda";
import { ApiSuccessResponse, ErrorStatusCode, OtherErrorResponse, SuccessStatusCode } from "../../utils/response";
import {
CspInvocation,
ILambdaEvent,
ProvisionRequest,
provisionRequestSchema,
ProvisionRequestType,
Expand All @@ -13,12 +14,10 @@ import middy from "@middy/core";
import validator from "@middy/validator";
import jsonBodyParser from "@middy/http-json-body-parser";
import JSONErrorHandlerMiddleware from "middy-middleware-json-error-handler";
import cors from "@middy/http-cors";
import xssSanitizer from "../../utils/middleware/xss-sanitizer";
import { IpCheckerMiddleware } from "../../utils/middleware/ip-logging";
import { CloudServiceProvider } from "../../models/cloud-service-providers";
import { HttpMethod } from "../../lib/http";
import { CORS_CONFIGURATION, MIDDY_CORS_CONFIGURATION } from "../../utils/cors-config";
import { REQUEST_BODY_INVALID } from "../../utils/errors";
import { cspPortfolioIdChecker } from "../../utils/middleware/check-csp-portfolio-id";

Expand All @@ -29,9 +28,9 @@ const SFN_ARN = process.env.SFN_ARN ?? "";
*
* @param event - POST request from API Gateway with provisioning job properties
*/
export async function baseHandler(event: APIGatewayProxyEvent, context: Context): Promise<APIGatewayProxyResult> {
export async function baseHandler(event: ILambdaEvent): Promise<APIGatewayProxyResult> {
try {
const cspInvocationJob = transformProvisionJob(event.body as any);
const cspInvocationJob = transformProvisionJob(event.body);
console.log("SentToSfn: " + JSON.stringify(cspInvocationJob));

// starting the execution
Expand Down Expand Up @@ -60,7 +59,6 @@ function transformProvisionJob(request: ProvisionRequest): CspInvocation {

const headers = {
"Content-Type": "application/json",
...CORS_CONFIGURATION,
};

switch (operationType) {
Expand Down Expand Up @@ -97,5 +95,4 @@ export const handler = middy(baseHandler)
.use(cspPortfolioIdChecker())
.use(validator({ inputSchema: wrapSchema(provisionRequestSchema) }))
.use(errorHandlingMiddleware())
.use(JSONErrorHandlerMiddleware())
.use(cors(MIDDY_CORS_CONFIGURATION));
.use(JSONErrorHandlerMiddleware());
6 changes: 3 additions & 3 deletions lib/atat-web-api-stack.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,15 @@ export class AtatWebApiStack extends cdk.Stack {
logGroup: provisioningSfn.logGroup,
}).stateMachine;

// Provisioning lambda that translate and invokes the state machine
// Provisioning lambda that translates and invokes the state machine
const provisioningJob = new ApiSfnFunction(this, "ProvisioningJobRequest", {
method: HttpMethod.POST,
handlerPath: "api/provision/start-provision-job.ts",
stateMachine: this.provisioningStateMachine,
});

// APIGW Provisioning Job Resource
const provisioningJobsResource = apigw.restApi.root.addResource("provisioning-job");
provisioningJobsResource.addMethod(provisioningJob.method, new LambdaIntegration(provisioningJob.fn));
const provisioningJobResource = apigw.restApi.root.addResource("provisioning-job");
provisioningJobResource.addMethod(provisioningJob.method, new LambdaIntegration(provisioningJob.fn));
}
}
8 changes: 4 additions & 4 deletions lib/constructs/provisioning-sfn-workflow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import { Construct } from "constructs";
import { mapTasks, TasksMap } from "./sfn-lambda-invoke-task";

/**
* Successful condition check used when status code is 200
* Successful condition check
*/
export const successResponse = sfn.Condition.numberEquals("$.cspResponse.Payload.statusCodeFn", 200);

/**
* Client error condition check used when the status code is 400, 402, or 404
* Client error condition check
*/
export const clientErrorResponse = sfn.Condition.or(
sfn.Condition.numberEquals("$.cspResponse.statusCode", 400),
Expand All @@ -19,12 +19,12 @@ export const clientErrorResponse = sfn.Condition.or(
);

/**
* Internal error condition check used when the status code is 500
* Internal error condition check
*/
export const internalErrorResponse = sfn.Condition.numberGreaterThanEquals("$.cspResponse.statusCode", 500);

/**
* Retry condition check when the status code is 500, with a max retry of 6
* Retry condition check
*/
export const maxRetries = sfn.Condition.and(
sfn.Condition.numberGreaterThan("$.cspResponsePass.retryCount", 6),
Expand Down
6 changes: 3 additions & 3 deletions models/cloud-service-providers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ export enum Network {
NETWORK_3 = "NETWORK_3",
}
export interface ICloudServiceProvider {
name: string;
uri: string;
networks: Array<Network>;
readonly name: string;
readonly uri: string;
readonly networks: Array<Network>;
}
export class CloudServiceProvider implements ICloudServiceProvider {
readonly name: string;
Expand Down
4 changes: 4 additions & 0 deletions models/provisioning-jobs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ export interface CspInvocation {
endpoint: string;
payload: NewPortfolioPayload | FundingSourcePayload | OperatorPayload;
}
export interface ILambdaEvent {
body: ProvisionRequest;
requestContext: { identity: { sourceIp: string } };
}

// temporary schema to use for validating /provision-job request
export const provisionRequestSchema = {
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"module": "commonjs",
"lib": [
"es2018",
// Required to workaround aws/aws-sdk-js-v3#2896
"dom"
],
"declaration": true,
Expand Down
26 changes: 0 additions & 26 deletions utils/cors-config.ts

This file was deleted.

7 changes: 4 additions & 3 deletions utils/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@ export const INTERNAL_SERVER_ERROR = new OtherErrorResponse("Server error", Erro
/**
* To be used when a request body exists but is invalid
* Could be invalid because:
* - request body is not of the expected Content-Type (for example, application/json, or application/pdf)
* - is not valid JSON / PDF
* - when JSON, is not of the expected type (for example, doesn't look like PortfolioStep/FundingStep/ApplicationStep)
* - request body is not of the expected Content-Type (for example, application/json)
* - is not valid JSON
* - when JSON, is not of the expected type (for example, doesn't look like Portfolio
* provisioning request)
*/
export const REQUEST_BODY_INVALID = new OtherErrorResponse(
"A valid request body must be provided",
Expand Down
18 changes: 7 additions & 11 deletions utils/middleware/check-csp-portfolio-id.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import middy from "@middy/core";
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";
import { ProvisionRequestType } from "../../models/provisioning-jobs";
import { APIGatewayProxyResult } from "aws-lambda";
import { ILambdaEvent, ProvisionRequestType } from "../../models/provisioning-jobs";
import createError from "http-errors";

export const cspPortfolioIdChecker = (): middy.MiddlewareObj<APIGatewayProxyEvent, APIGatewayProxyResult> => {
const before: middy.MiddlewareFn<APIGatewayProxyEvent, APIGatewayProxyResult> = async (request): Promise<void> => {
const { portfolioId, operationType } = request.event.body as any;

if (
(operationType === ProvisionRequestType.ADD_FUNDING_SOURCE ||
operationType === ProvisionRequestType.ADD_OPERATORS) &&
!portfolioId
) {
export const cspPortfolioIdChecker = (): middy.MiddlewareObj<ILambdaEvent, APIGatewayProxyResult> => {
const before: middy.MiddlewareFn<ILambdaEvent, APIGatewayProxyResult> = async (request): Promise<void> => {
const { portfolioId, operationType } = request.event.body;
const requiresPortfolioId = [ProvisionRequestType.ADD_FUNDING_SOURCE, ProvisionRequestType.ADD_OPERATORS];
if (requiresPortfolioId.includes(operationType) && !portfolioId) {
throw createError(400, "CSP portfolio ID required.");
}
};
Expand Down
21 changes: 10 additions & 11 deletions utils/middleware/error-handling-middleware.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
import middy from "@middy/core";
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";
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";

export const errorHandlingMiddleware = (): middy.MiddlewareObj<APIGatewayProxyEvent, APIGatewayProxyResult> => {
const onError: middy.MiddlewareFn<APIGatewayProxyEvent, APIGatewayProxyResult> = async (
export const errorHandlingMiddleware = (): middy.MiddlewareObj<ILambdaEvent, APIGatewayProxyResult> => {
const onError: middy.MiddlewareFn<ILambdaEvent, APIGatewayProxyResult> = async (
request
): Promise<ValidationErrorResponse | void> => {
const error = serializeError(request.error)!;
const errorMessage = error?.message as string;

if (errorMessage === "CSP portfolio ID required.") {
return new ValidationErrorResponse("Request failed validation", {
issue: errorMessage,
name: error.name,
});
}
const errorMessage = error.message;

switch (errorMessage) {
case "CSP portfolio ID required.":
return new ValidationErrorResponse("Request failed validation", {
issue: errorMessage,
name: error.name,
});
case "Event object failed validation":
return new ValidationErrorResponse("Request failed validation", error.details as Record<string, unknown>);
case "Business rules validation failed":
Expand Down
7 changes: 4 additions & 3 deletions utils/middleware/ip-logging.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import middy from "@middy/core";
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";
import { APIGatewayProxyResult } from "aws-lambda";
import { ILambdaEvent } from "../../models/provisioning-jobs";

// Create the middleware and export it
export const IpCheckerMiddleware = (): middy.MiddlewareObj<APIGatewayProxyEvent, APIGatewayProxyResult> => {
export const IpCheckerMiddleware = (): middy.MiddlewareObj<ILambdaEvent, APIGatewayProxyResult> => {
// Set up a before check, this will run before the handler
const before: middy.MiddlewareFn<APIGatewayProxyEvent, APIGatewayProxyResult> = async (request): Promise<void> => {
const before: middy.MiddlewareFn<ILambdaEvent, APIGatewayProxyResult> = async (request): Promise<void> => {
// log the sourceIp
console.log("Client IP address: " + request.event.requestContext.identity.sourceIp);
};
Expand Down
7 changes: 4 additions & 3 deletions utils/middleware/xss-sanitizer.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import middy from "@middy/core";
import xss from "xss";
import { APIGatewayProxyEvent, APIGatewayProxyResult } from "aws-lambda";
import { APIGatewayProxyResult } from "aws-lambda";
import { ILambdaEvent } 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<APIGatewayProxyEvent, APIGatewayProxyResult> => {
const before: middy.MiddlewareFn<APIGatewayProxyEvent, APIGatewayProxyResult> = async (request): Promise<void> => {
const xssSanitizer = (): middy.MiddlewareObj<ILambdaEvent, APIGatewayProxyResult> => {
const before: middy.MiddlewareFn<ILambdaEvent, APIGatewayProxyResult> = async (request): Promise<void> => {
request.event.body = JSON.parse(xss(JSON.stringify(request.event.body ?? {}), xssOptions));
};
return {
Expand Down
3 changes: 1 addition & 2 deletions utils/response.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
/* eslint-disable max-len */
import { APIGatewayProxyResult } from "aws-lambda";
import { CORS_CONFIGURATION } from "./cors-config";

type Headers = { [header: string]: string | number | boolean } | undefined;
type MultiValueHeaders = { [header: string]: (string | number | boolean)[] } | undefined;
Expand Down Expand Up @@ -86,7 +85,7 @@ abstract class Response implements APIGatewayProxyResult {
multiValueHeaders?: MultiValueHeaders,
isBase64Encoded?: boolean
) {
headers = { ...headers, ...CORS_CONFIGURATION };
headers = { ...headers };

this.body = body;
this.statusCode = statusCode;
Expand Down

0 comments on commit fe51d0d

Please sign in to comment.