Skip to content

Commit

Permalink
bump dependencies to alleviate secruity issue, switch out github acti…
Browse files Browse the repository at this point in the history
…on for creating env file to personally maintained one, update skills cron job to use node & proxycurl and run only once every 3 days.
  • Loading branch information
aasmal97 committed Jan 7, 2025
1 parent 57e8001 commit 2758a46
Show file tree
Hide file tree
Showing 12 changed files with 224 additions and 211 deletions.
28 changes: 4 additions & 24 deletions .github/workflows/deploy_to_production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,9 @@ jobs:
steps:
- uses: actions/checkout@v1
- name: Setup Node
uses: actions/setup-node@v2
uses: actions/setup-node@v4
with:
node-version: 18
# - name: Install AWS CDK
# shell: bash
# run: npm install -g aws-cdk
node-version: 20
- name: Install dependencies
shell: bash
run: npm install
Expand All @@ -30,26 +27,9 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_DEPLOY_SECRET_KEY }}
aws-region: us-east-1
- name: Create .env file
uses: ozaytsev86/create-env-file@v1
uses: aasmal97/create-env-file@v3.1.2
with:
ENV_AMAZON_REST_API_KEY: ${{ secrets.AMAZON_REST_API_KEY }}
ENV_GIT_HUB_PERSONAL_ACCESS_TOKEN: ${{ secrets.GIT_HUB_PERSONAL_ACCESS_TOKEN }}
ENV_GOOGLE_DRIVE_FOLDER_NAME: ${{ secrets.GOOGLE_DRIVE_FOLDER_NAME }}
ENV_GOOGLE_DRIVE_PARENT_FOLDER_NAME: ${{ secrets.GOOGLE_DRIVE_PARENT_FOLDER_NAME }}
ENV_GOOGLE_SERVICE_ACCOUNT_EMAIL: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_EMAIL }}
ENV_GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY: ${{ secrets.GOOGLE_SERVICE_ACCOUNT_PRIVATE_KEY }}
ENV_STACKOVERFLOW_API_ID: ${{ secrets.STACKOVERFLOW_API_ID }}
ENV_STACKOVERFLOW_API_KEY: ${{ secrets.STACKOVERFLOW_API_KEY }}
ENV_STACKOVERFLOW_API_SECRET: ${{ secrets.STACKOVERFLOW_API_SECRET }}
ENV_WEBHOOKS_API_KEY: ${{ secrets.WEBHOOKS_API_KEY }}
ENV_WEBHOOKS_API_TOKEN: ${{ secrets.WEBHOOKS_API_TOKEN }}
ENV_WEBHOOKS_API_TOKEN_SECRET: ${{ secrets.WEBHOOKS_API_TOKEN_SECRET }}
ENV_AZURE_COMPUTER_VISION_API_ENDPOINT: ${{secrets.AZURE_COMPUTER_VISION_API_ENDPOINT}}
ENV_AZURE_COMPUTER_VISION_API_KEY: ${{secrets.AZURE_COMPUTER_VISION_API_KEY}}
ENV_LINKED_IN_PASSWORD: ${{secrets.LINKED_IN_PASSWORD}}
ENV_SES_EMAIL_ADDRESS: ${{secrets.SES_EMAIL_ADDRESS}}
ENV_SNS_PHONE_NUMBER: ${{secrets.SNS_PHONE_NUMBER}}
ENV_SEND_IN_BLUE_API_KEY: ${{secrets.SEND_IN_BLUE_API_KEY}}
APP_SECRETS: ${{toJSON(secrets)}}
- name: Generate Cloud Template and Bootstrap
shell: bash
run: npm run bootstrap
Expand Down
26 changes: 2 additions & 24 deletions app/lib/restAPI/bundleApiFuncs.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
import restApiMap from "./restApiMap";
import createFuncLocationMap from "../../../utils/createResources/createFuncLocationMap";
import { execShellCommand } from "../../../utils/buildFuncs/execShellCommand";
import * as fs from "fs-extra";
import path = require("path");
async function copyDirectory(sourcePath: string, destPath: string) {
await fs.copy(sourcePath, destPath);
return `success, copied directory to ${destPath}`;
}
const outPath = "../../../build/app/lib/restAPI/resources";
const locationFuncMap = createFuncLocationMap(restApiMap({}));
const locationArr = Object.entries(locationFuncMap).map(([key, value]) => {
const newPath = value.location.relative + "/index.ts";
return newPath;
});
//add skills cron job to compile
locationArr.push("./resources/skills/cronJob/index.ts");
const command = locationArr.reduce((a, b) => a + " " + b);

//bundle node api functions
execShellCommand(
`esbuild ${command} --bundle --platform=node --outdir=${outPath}`,
Expand All @@ -24,20 +19,3 @@ execShellCommand(
.catch((err) => {
console.error(err);
});
//copy skill function to build folder
// Define the source and destination paths
const generalPath = path.join(__dirname, "./resources/skills/cronJob");
const skillSourcePath = generalPath;
const skillDestPath = generalPath
//for windows
.replace("\\app\\lib\\restAPI\\", "\\build\\app\\lib\\restAPI\\")
//for linux
.replace("/app/lib/restAPI/", "/build/app/lib/restAPI/");
console.log(skillSourcePath, skillDestPath, "paths");
copyDirectory(skillSourcePath, skillDestPath)
.then((e) => {
console.log(e);
})
.catch((err) => {
throw err;
});
190 changes: 190 additions & 0 deletions app/lib/restAPI/resources/skills/cronJob/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import {
DeleteItemCommand,
DynamoDBClient,
PutItemCommand,
QueryCommand,
QueryCommandInput,
UpdateItemCommand,
} from "@aws-sdk/client-dynamodb";
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";
import axios from "axios";
type SkillsType = {
recordType: string;
name: string;
date_created: number | string;
order: number | string;
};
type DataFuncsParams = Pick<SkillsType, "order"> & {
skillName: SkillsType["name"];
};
const tableName = process.env.AMAZON_DYNAMO_DB_TABLE_NAME;

const client = new DynamoDBClient({
region: "us-east-1",
});
const createSkill = async ({ skillName, order }: DataFuncsParams) => {
const currentTimestamp = Date.now();
const item = {
recordType: "skill",
name: skillName,
date_created: currentTimestamp.toString(),
order,
};
const putCommand = new PutItemCommand({
TableName: tableName,
Item: marshall(item, {
convertClassInstanceToMap: true,
removeUndefinedValues: true,
}),
});
return await client.send(putCommand);
};
const deleteSkill = async (skillName: string) => {
const deleteCommand = new DeleteItemCommand({
TableName: tableName,
Key: marshall(
{
recordType: "skill",
name: skillName,
},
{
convertClassInstanceToMap: true,
removeUndefinedValues: true,
}
),
});
return await client.send(deleteCommand);
};
const updateSkill = async ({ skillName, order }: DataFuncsParams) => {
const updateCommand = new UpdateItemCommand({
TableName: tableName,
Key: marshall(
{
recordType: "skill",
name: skillName,
},
{
convertClassInstanceToMap: true,
removeUndefinedValues: true,
}
),
UpdateExpression: "SET #order = :order",
ExpressionAttributeNames: {
"#order": "order",
},
ExpressionAttributeValues: marshall(
{
":order": order,
},
{
convertClassInstanceToMap: true,
removeUndefinedValues: true,
}
),
});
return await client.send(updateCommand);
};

const getSkillsInDynamoDbTable = async () => {
//create query command
const expValMap = {
":skill": "skill",
};
const expVal = marshall(expValMap, {
convertClassInstanceToMap: true,
removeUndefinedValues: true,
});
const query: QueryCommandInput = {
TableName: tableName,
KeyConditionExpression: "#rt = :skill",
ExpressionAttributeNames: {
"#rt": "recordType",
},
ExpressionAttributeValues: expVal,
};
//send command
const command = new QueryCommand(query);
const response = await client.send(command);
const items = response.Items;
if (!items) return [];
const newItems = items.map((i) => unmarshall(i)) as SkillsType[];
return newItems;
};
const getLinkedInSkills = async () => {
try {
const req = await axios({
method: "GET",
url: `https://nubela.co/proxycurl/api/v2/linkedin`,
headers: {
Authorization: `Bearer ${process.env.PROXYCURL_TOKEN}`,
},
params: {
url: "https://linkedin.com/in/arky-asmal/",
fallback_to_cache: "on-error",
use_cache: "if-present",
skills: "include",
},
});
const data = req.data || {};
if (!data.skills) return [];
const linkedInSkills = data.skills as string[];
return linkedInSkills;
} catch (err) {
return [];
}
};
const storeInDatabase = async (skills: string[]) => {
const skillsInDB = await getSkillsInDynamoDbTable();
const skillsInDBMap: Record<string, SkillsType> = Object.assign(
{},
...skillsInDB.map((val) => ({ [val.name]: val }))
);
const skillsInLinkedInMap: Record<
string,
Pick<SkillsType, "name" | "order">
> = Object.assign(
{},
...skills.map((val, idx) => ({
[val]: {
order: idx,
name: val,
},
}))
);
//loop through linkedin skills
const modifyPromiseArr = skills.map((val, idx) => {
//check if creation is needed
const skillName = val;
if (!(skillName in skillsInDBMap))
return createSkill({
skillName,
order: idx,
});
//check if update needed
const storedIdx = skillsInDBMap[skillName].order;
const parsedIdx =
typeof storedIdx === "string" ? parseInt(storedIdx) : storedIdx;
if (parsedIdx === idx) return null;
return updateSkill({
skillName,
order: idx,
});
});
//check if deletion is needed
//loop through skill in database already
const deletePromiseArr = skillsInDB.map((val) => {
const skillName = val.name;
if (!(skillName in skillsInLinkedInMap)) return deleteSkill(skillName);
return null;
});
const results = await Promise.all([...modifyPromiseArr, ...deletePromiseArr]);
return results;
};

export async function handler() {
const linkedInSkills = await getLinkedInSkills();
//this means failure, as LinkedIn skills will never be at zero
if (linkedInSkills.length <= 0) return;
const res = storeInDatabase(linkedInSkills);
return res;
}
105 changes: 0 additions & 105 deletions app/lib/restAPI/resources/skills/cronJob/main.py

This file was deleted.

3 changes: 0 additions & 3 deletions app/lib/restAPI/resources/skills/cronJob/requirements.txt

This file was deleted.

5 changes: 0 additions & 5 deletions app/lib/restAPI/resources/skills/cronJob/test.py

This file was deleted.

Loading

0 comments on commit 2758a46

Please sign in to comment.