Skip to content

Commit

Permalink
Merge pull request #90 from rtjord/dev
Browse files Browse the repository at this point in the history
Fixed logs and GetCost can handle circular dependencies
  • Loading branch information
rtjord authored Dec 5, 2024
2 parents c6dc578 + d68bd6b commit 7c6ef20
Show file tree
Hide file tree
Showing 25 changed files with 238 additions and 22 deletions.
1 change: 1 addition & 0 deletions backend/src/handlers/CreateAuthToken/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export const handler = async (_event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
const message = "This system does not support authentication.";
console.log(message);
return {
statusCode: 501,
headers: {
Expand Down
3 changes: 3 additions & 0 deletions backend/src/handlers/CreateIndex/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const handler = async (event: LambdaEvent, context: Context) => {
let exists = await checkIndexExists(domainEndpoint, indexName);

if (!exists) {
console.log(`Index '${indexName}' does not exist. Creating...`);
await createIndex(domainEndpoint, indexName);
} else {
console.log(`Index '${indexName}' already exists. Skipping creation.`);
Expand All @@ -54,6 +55,7 @@ export const handler = async (event: LambdaEvent, context: Context) => {
exists = await checkIndexExists(domainEndpoint, indexName);

if (!exists) {
console.log(`Index '${indexName}' does not exist. Creating...`);
await createIndex(domainEndpoint, indexName);
} else {
console.log(`Index '${indexName}' already exists. Skipping creation.`);
Expand All @@ -73,6 +75,7 @@ export const handler = async (event: LambdaEvent, context: Context) => {

// Send response to CloudFormation
await sendCloudFormationResponse(event.ResponseURL, response);
console.log("Create index operation complete.");
};

interface CloudFormationResponse {
Expand Down
2 changes: 1 addition & 1 deletion backend/src/handlers/GetCost/event.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"pathParameters": {
"id": "HQr6s53GdhTKyF9hF0zx"
"id": "C5p7p5HW-qfT9VQPF_2A"
},
"queryStringParameters": {
"dependency": "true"
Expand Down
15 changes: 14 additions & 1 deletion backend/src/handlers/GetCost/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayPr
}

console.log("Cost calculation complete.");
console.log("Response:", response);
return {
statusCode: 200,
body: JSON.stringify(response),
Expand All @@ -64,7 +65,7 @@ export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayPr
};
} catch (error) {
console.error("Error:", error);
return createErrorResponse(500, "The package rating system choked on at least one of the metrics.");
return createErrorResponse(500, "Error while calculating the cost.");
}
};

Expand All @@ -77,6 +78,18 @@ export async function calculateCost(packageId: string, costMap: PackageCost): Pr
console.log(`Package does not exist in our registry.`);
return 0;
}

// If the package is already in the cost map
if (costMap[packageId]) {
// If the total cost has already been calculated, return it
if (costMap[packageId].totalCost !== undefined) {
return costMap[packageId].totalCost;
}
// Otherwise, return 0 to avoid infinite recursion
console.log(`Circular dependency detected for ${packageRow.PackageName}@${packageRow.Version}. Skipping further calculation.`);
return 0;
}

// Get the package.json content from OpenSearch
console.log(`Retrieving package.json for ${packageRow.PackageName}@${packageRow.Version}...`);
const { content: packageJsonContent } = await retrieveFromOpenSearch(getEnvVariable('DOMAIN_ENDPOINT'), 'packagejsons', packageId);
Expand Down
2 changes: 2 additions & 0 deletions backend/src/handlers/GetTracks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const { createErrorResponse } = require(`${path}/utils`);
export const handler = async (_event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => {
try {
const plannedTracks: string[] = ["ML inside track"];
console.log("Retrieved the student's track information.");
return {
statusCode: 200,
headers: {
Expand All @@ -14,6 +15,7 @@ export const handler = async (_event: APIGatewayProxyEvent): Promise<APIGatewayP
body: JSON.stringify({ plannedTracks })
};
} catch {
console.error("An error occurred while retrieving the student's track information.");
return createErrorResponse(500, "The system encountered an error while retrieving the student's track information.");
}
};
Expand Down
1 change: 1 addition & 0 deletions backend/src/handlers/PackageByNameGet/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export const handler = async (event: APIGatewayEvent): Promise<APIGatewayProxyRe
const dynamoDBClient = DynamoDBDocumentClient.from(new DynamoDBClient());

const name = event.pathParameters?.name;
console.log('Fetching history for package:', name);

if (!name) {
console.error('Package name is required.');
Expand Down
2 changes: 1 addition & 1 deletion backend/src/handlers/PackageByRegEx/event.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"body": "{\"RegEx\": \"test-package$\"}",
"body": "{\"RegEx\": \"as.*dflkj\"}",
"httpMethod": "POST",
"headers": {
"Content-Type": "application/json"
Expand Down
37 changes: 31 additions & 6 deletions backend/src/handlers/PackageByRegEx/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayPr
}
const regEx: string = parsedBody.RegEx; // Extract the RegEx field from the request body

// console.log('Checking for ReDoS vulnerability in the provided regex:', regEx);
// if (!detector.isSafePattern(regEx).safe) {
// console.error('The provided regex is vulnerable to ReDoS attacks.');
// return createErrorResponse(400, 'The provided regex is vulnerable to ReDoS attacks.');
// }
console.log('Checking for ReDoS vulnerability in the provided regex:', regEx);
if (quantifierIsTooLarge(regEx)) {
console.error('The provided regex has a quantifier that is too large.');
return createErrorResponse(400, 'The provided regex has a quantifier that is too large.');
}

// Search over package names and readmes
console.log('Searching for packages matching the regular expression:', regEx);
const domainEndpoint = getEnvVariable('DOMAIN_ENDPOINT');
// const domainEndpoint = "https://search-package-readmes-wnvohkp2wydo2ymgjsxmmslu6u.us-east-2.es.amazonaws.com";
const matches = await searchReadmes(domainEndpoint, 'readmes', regEx);
console.log('Matching packages:', matches);

// If there are no matching packages, return a 404 response
if (matches.length === 0) {
Expand Down Expand Up @@ -60,6 +60,31 @@ function isValidRegEx(RegEx: string): boolean {
}
}

/**
* Checks if a regex contains large quantifier ranges.
* @param {string} regexStr - The regex pattern as a string.
* @returns {boolean} - Returns true if the regex is unsafe, false otherwise.
*/
function quantifierIsTooLarge(regexStr: string): boolean {
// Pattern to match quantifiers {min,max}
const quantifierPattern = /\{(\d+),(\d+)\}/g;
let match;

// Iterate over all quantifiers in the regex
while ((match = quantifierPattern.exec(regexStr)) !== null) {
const min = parseInt(match[1], 10);
const max = parseInt(match[2], 10);

// Check if max exceeds the safe threshold
if (max > 1000) {
console.error(`Unsafe quantifier range detected: {${min},${max}}`);
return true;
}
}

return false; // Regex is safe
}

async function searchReadmes(
domainEndpoint: string,
indexName: string,
Expand Down
20 changes: 20 additions & 0 deletions backend/src/handlers/PackageCreate/circular1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"body": {
"Name": "circular1",
"Content": "UEsDBBQAAAAAAG9whVkAAAAAAAAAAAAAAAAQACAAY2lyY3VsYXIxLTEuMC4wL1VUDQAHAvlRZ875UWfi+FFndXgLAAEEAAAAAAQAAAAAUEsDBBQACAAIAJdwhVkAAAAAAAAAACQBAAAcACAAY2lyY3VsYXIxLTEuMC4wL3BhY2thZ2UuanNvblVUDQAHTvlRZ075UWcC+VFndXgLAAEEAAAAAAQAAAAATY8xD4IwEIV3Ev7DpQOTIeDIZoyDs44sTTnlFNqmLYbE8N9tS0XHe9+9u/feeQbAJB+RNcAEGTEN3NRsF/UXGktKBlSXVVkluUMrDGmX0BWtA83Fk98xbYycIiLZ4Vw+bJJXm/Uk/vWK896wiKJX0LKTMco0IBUEAFajoBth1zIoCsCZHNQsWJf1IJ9cr8wW4rCOKxtIoLSx1/ly3KJr9JmkIPyP8S2+/1WNX/JsybMPUEsHCAuoi1+xAAAAJAEAAFBLAwQUAAgACAB5cIVZAAAAAAAAAAAzAAAAGQAgAGNpcmN1bGFyMS0xLjAuMC9SRUFETUUubWRVVA0ABxb5UWcW+VFnAvlRZ3V4CwABBAAAAAAEAAAAAAtydXTxdVVIy8xJVUjLL1JIzixKLs1JLFJISS1IzUtJzUuuVDBSKEstKs7Mz1Mw1DPQMwAAUEsHCF/kfYg1AAAAMwAAAFBLAQIUAxQAAAAAAG9whVkAAAAAAAAAAAAAAAAQACAAAAAAAAAAAAD/QQAAAABjaXJjdWxhcjEtMS4wLjAvVVQNAAcC+VFnzvlRZ+L4UWd1eAsAAQQAAAAABAAAAABQSwECFAMUAAgACACXcIVZC6iLX7EAAAAkAQAAHAAgAAAAAAAAAAAAtoFOAAAAY2lyY3VsYXIxLTEuMC4wL3BhY2thZ2UuanNvblVUDQAHTvlRZ075UWcC+VFndXgLAAEEAAAAAAQAAAAAUEsBAhQDFAAIAAgAeXCFWV/kfYg1AAAAMwAAABkAIAAAAAAAAAAAALaBaQEAAGNpcmN1bGFyMS0xLjAuMC9SRUFETUUubWRVVA0ABxb5UWcW+VFnAvlRZ3V4CwABBAAAAAAEAAAAAFBLBQYAAAAAAwADAC8BAAAFAgAAAAA=",
"JSProgram": "if (process.argv.length === 7) { console.log('Success'); process.exit(0); } else { console.log('Failed'); process.exit(1); }",
"debloat": true
},
"httpMethod": "POST",
"headers": {
"Content-Type": "application/json"
},
"pathParameters": null,
"queryStringParameters": null,
"requestContext": {
"requestId": "test-request-id",
"httpMethod": "POST",
"resourcePath": "/package"
}
}

20 changes: 20 additions & 0 deletions backend/src/handlers/PackageCreate/circular2.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"body": {
"Name": "circular2",
"Content": "UEsDBBQAAAAAAG5whVkAAAAAAAAAAAAAAAAQACAAY2lyY3VsYXIyLTEuMC4wL1VUDQAHAflRZ9j5UWf4+FFndXgLAAEEAAAAAAQAAAAAUEsDBBQACAAIAJtwhVkAAAAAAAAAACQBAAAcACAAY2lyY3VsYXIyLTEuMC4wL3BhY2thZ2UuanNvblVUDQAHVvlRZ1b5UWcB+VFndXgLAAEEAAAAAAQAAAAATY8xD4IwEIV3Ev7DpQOTIeDIZoyDs44sTTnlFNqmLYbE8N9tS0XHe9+9u/feeQbAJB+RNcAEGTEN3OzZLuovNJaUDKguq7JKcodWGNIuoStaB5qLJ79j2hg5RUSyw7l82CSvNutJ/OsV571hEUWvoGUnY5RpQCoIAKxGQTfCrmVQFIAzOahZsC7rQT65XpktxGEdVzaQQGljr/PluEXX6DNJQfgf41u8/lWNX/JsybMPUEsHCG+FnauxAAAAJAEAAFBLAwQUAAgACAB0cIVZAAAAAAAAAAAzAAAAGQAgAGNpcmN1bGFyMi0xLjAuMC9SRUFETUUubWRVVA0ABw35UWcO+VFnAflRZ3V4CwABBAAAAAAEAAAAAAtydXTxdVVIy8xJVUjLL1JIzixKLs1JLFJISS1IzUtJzUuuVDBUKEstKs7Mz1Mw1DPQMwAAUEsHCCaOAJk1AAAAMwAAAFBLAQIUAxQAAAAAAG5whVkAAAAAAAAAAAAAAAAQACAAAAAAAAAAAAD/QQAAAABjaXJjdWxhcjItMS4wLjAvVVQNAAcB+VFn2PlRZ/j4UWd1eAsAAQQAAAAABAAAAABQSwECFAMUAAgACACbcIVZb4Wdq7EAAAAkAQAAHAAgAAAAAAAAAAAAtoFOAAAAY2lyY3VsYXIyLTEuMC4wL3BhY2thZ2UuanNvblVUDQAHVvlRZ1b5UWcB+VFndXgLAAEEAAAAAAQAAAAAUEsBAhQDFAAIAAgAdHCFWSaOAJk1AAAAMwAAABkAIAAAAAAAAAAAALaBaQEAAGNpcmN1bGFyMi0xLjAuMC9SRUFETUUubWRVVA0ABw35UWcO+VFnAflRZ3V4CwABBAAAAAAEAAAAAFBLBQYAAAAAAwADAC8BAAAFAgAAAAA=",
"JSProgram": "if (process.argv.length === 7) { console.log('Success'); process.exit(0); } else { console.log('Failed'); process.exit(1); }",
"debloat": true
},
"httpMethod": "POST",
"headers": {
"Content-Type": "application/json"
},
"pathParameters": null,
"queryStringParameters": null,
"requestContext": {
"requestId": "test-request-id",
"httpMethod": "POST",
"resourcePath": "/package"
}
}

4 changes: 4 additions & 0 deletions backend/src/handlers/PackageDelete/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,15 @@ export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayPr
return createErrorResponse(404, `Package with ID ${id} not found.`);
}

console.log(`Deleting package with ID: ${id}`);
await deletePackageFromDynamoDB(dynamoDBClient, id);
console.log(`Deleted package metadata for ID: ${id}`);

await deletePackageFromS3(s3Client, existingPackage.s3Key);
console.log(`Deleted package file from S3 with key: ${existingPackage.s3Key}`);

await deleteDocumentById(getEnvVariable('DOMAIN_ENDPOINT'), 'readmes', id);
console.log(`Deleted document with ID: ${id} from OpenSearch index.`);

return createSuccessResponse(existingPackage.PackageName, existingPackage.Version);
} catch (error) {
Expand Down
5 changes: 5 additions & 0 deletions backend/src/handlers/PackageRetrieve/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,14 @@ export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayPr
// Extract and validate the package ID
const id = event.pathParameters?.id;
if (!id) {
console.error('Missing ID in path parameters.');
return createErrorResponse(400, "Missing ID in path parameters.");
}

// Fetch package details from DynamoDB
const existingPackage: PackageTableRow | null = await getPackageById(dynamoDBClient, id);
if (!existingPackage) {
console.error(`Package with ID ${id} not found.`);
return createErrorResponse(404, 'Package not found.');
}

Expand All @@ -58,6 +60,7 @@ export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayPr
user,
"DOWNLOAD"
);
console.log(`Updated package history for ${packageName}@${version}`);

// Prepare the response
const responseBody: Package = {
Expand All @@ -74,6 +77,8 @@ export const handler = async (event: APIGatewayProxyEvent): Promise<APIGatewayPr
},
};

console.log('Response:', responseBody);

return {
statusCode: 200,
headers: { 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json' },
Expand Down
Loading

0 comments on commit 7c6ef20

Please sign in to comment.