-
Notifications
You must be signed in to change notification settings - Fork 0
Modernize testlead Lambda: Node 24, SDK v3, osls deploy (sc-112520) #15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
ddead0f
Add characterization test suite
johnrb2 a3a9986
Replace aws-sdk v2 with @aws-sdk/client-s3 v3
johnrb2 f21c595
Replace request with @activeprospect/request-capture/request
johnrb2 fb8969d
Replace faker with @faker-js/faker
johnrb2 a56133c
Remove moment in favor of native Date
johnrb2 cfd7fed
Add serverless.yml and CI workflows for osls deployment
johnrb2 26f5401
Update release workflow to Node 24 and add engines field
johnrb2 637ced1
Keep lambda handler synchronous to avoid freezing in-flight posts
johnrb2 7c25f54
Use faker.person.jobTitle for the title field
johnrb2 107326f
Make lead and feedback submission fully async
johnrb2 cce7903
Address Bugbot review findings
johnrb2 4805db0
Document osls deployment and one-time cutover
johnrb2 0ec2e0c
Replace submitLead callback with a resolved body
johnrb2 74a9b78
Address Copilot review feedback
johnrb2 b30c0e0
Add ESLint (semistandard) and reformat repo
johnrb2 db37707
Resolve demo keys from env/file/SSM instead of bundled keys.json
johnrb2 6e4a08e
Deploy via GitHub OIDC and drop the keys.json CI placeholder
johnrb2 81ef4a2
Remove deploy.sh and document the SSM/OIDC model
johnrb2 2b6afd3
Redact API key in submitfeedback verbose logging
johnrb2 a7d110b
Address Copilot review feedback
johnrb2 6d6519b
Keep API key out of CodeQL-tracked data flow in verbose log
johnrb2 75c5a21
Handle submitLead rejection in the testlead CLI
johnrb2 634f376
Resolve demo keys from Secrets Manager at runtime instead of SSM
johnrb2 7872af2
Document the Secrets Manager runtime keys model
johnrb2 0323a45
Exclude demoConfig from the deploy artifact
johnrb2 f2a4679
Stop logging env-derived values in demo key resolver
johnrb2 fd8a60d
Harden feedback response parsing and secret payload check
johnrb2 93b56c8
Fix misleading CLI usage strings
johnrb2 5575a14
Point demo keys at the Doppler-synced Secrets Manager secret
johnrb2 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| node_modules/ | ||
| .serverless/ |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,16 @@ | ||
| module.exports = { | ||
| env: { | ||
| es2022: true, | ||
| node: true, | ||
| mocha: true | ||
| }, | ||
| extends: [ | ||
| 'eslint:recommended', | ||
| 'semistandard' | ||
| ], | ||
| rules: { | ||
| complexity: ['error', 10], | ||
| 'no-useless-return': 'error', | ||
| 'prefer-const': 'error' | ||
| } | ||
| }; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| name: Deploy test-sales-and-dev-leads to Staging AWS Account | ||
|
|
||
| on: workflow_dispatch | ||
|
|
||
| permissions: | ||
| id-token: write | ||
| contents: read | ||
|
|
||
| jobs: | ||
| deploy: | ||
| name: deploy | ||
| runs-on: ubuntu-latest | ||
| env: | ||
| NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
|
|
||
| - name: setup node.js | ||
| uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 | ||
| with: | ||
| always-auth: true | ||
| node-version: "24" | ||
| registry-url: https://registry.npmjs.org | ||
| scope: "@activeprospect" | ||
| cache: 'npm' | ||
|
|
||
| - name: Install dependencies | ||
| run: npm ci --ignore-scripts | ||
|
|
||
| # Assume the dedicated least-privilege deploy role via GitHub OIDC. No | ||
| # long-lived AWS keys are stored as secrets. The role only creates/updates | ||
| # the stack; no secret is resolved at deploy time (the Lambda reads the | ||
| # demo keys from Secrets Manager at runtime via its own function role). | ||
| - name: Configure AWS Credentials Action For GitHub Actions | ||
| uses: aws-actions/configure-aws-credentials@8df5847569e6427dd6c4fb1cf565c83acfa8afa7 # v6.0.0 | ||
| with: | ||
| aws-region: us-east-1 | ||
| role-to-assume: arn:aws:iam::371005981288:role/testlead-deployer | ||
| role-session-name: testlead-deploy-github | ||
|
|
||
| - name: install osls deploy framework | ||
| run: npm i -g osls@3.70.0 --ignore-scripts | ||
|
|
||
| - name: osls deploy | ||
| run: osls deploy --stage staging |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| name: test | ||
|
|
||
| on: | ||
| push: | ||
| branches: [master] | ||
| pull_request: | ||
| branches: [master] | ||
|
|
||
| jobs: | ||
| test: | ||
| name: test | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 | ||
| with: | ||
| always-auth: true | ||
| node-version: '24' | ||
| registry-url: https://registry.npmjs.org | ||
| scope: "@activeprospect" | ||
| cache: 'npm' | ||
| - run: npm ci | ||
| env: | ||
| NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | ||
| - run: npm run lint | ||
| - run: npm test | ||
|
|
||
| validate-serverless-template: | ||
| name: validate serverless template | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | ||
| - uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0 | ||
| with: | ||
| always-auth: true | ||
| node-version: '24' | ||
| registry-url: https://registry.npmjs.org | ||
| scope: "@activeprospect" | ||
| cache: 'npm' | ||
| - run: npm ci | ||
| env: | ||
| NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | ||
| - run: npm i -g osls@3.70.0 | ||
| # serverless.yml no longer resolves any deploy-time variable (the secret | ||
| # is fetched at runtime via Secrets Manager), so packaging needs no AWS | ||
| # credentials. | ||
| - run: serverless package --stage staging | ||
| env: | ||
| AWS_REGION: 'us-east-1' |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,3 +3,4 @@ node_modules | |
| .DS_Store | ||
| keys.json | ||
| demoConfig | ||
| .serverless | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,59 +1,83 @@ | ||
| const { submitLead } = require('./lib/submitlead'); | ||
| const { submitFeedback } = require('./lib/submitfeedback'); | ||
| const AWS = require('aws-sdk'); | ||
| const { getDemoKeys } = require('./lib/demokeys'); | ||
| const { S3Client, GetObjectCommand } = require('@aws-sdk/client-s3'); | ||
|
|
||
| AWS.config.update({region: 'us-west-1'}); | ||
| s3 = new AWS.S3({apiVersion: '2006-03-01'}); | ||
| const s3 = new S3Client({}); | ||
|
|
||
| function demoLeads(config) { | ||
| config.forEach(lead => { | ||
| if(!lead.fields) lead.fields = [ "first_name", "last_name", "email", "phone_1", "address_1", "city", "state", "postal_code", "company.name" ]; | ||
| function demoLeads (config) { | ||
| return Promise.all(config.map(lead => { | ||
| if (!lead.fields) lead.fields = ['first_name', 'last_name', 'email', 'phone_1', 'address_1', 'city', 'state', 'postal_code', 'company.name']; | ||
| console.log(`Processing lead for ${lead.description} (${lead.probability}%)...`); | ||
| submitLead(lead); | ||
| }); | ||
| return submitLead(lead); | ||
| })); | ||
| } | ||
|
|
||
| function demoFeedbacks(config) { | ||
| const keys = require('./demoConfig/keys.json'); | ||
| config.forEach(feedback => { | ||
| async function demoFeedbacks (config) { | ||
| const keys = await getDemoKeys(); | ||
| return Promise.all(config.map(feedback => { | ||
| feedback.apiKey = keys[feedback.accountname]; | ||
| console.log(`Processing feedback for ${feedback.description} (${feedback.probability}%)...`) | ||
| submitFeedback(feedback); | ||
| }); | ||
| if (!feedback.apiKey) { | ||
| // Fail fast rather than firing an unauthenticated request that would just | ||
| // return a confusing 401/403. | ||
| console.log(`Skipping feedback for ${feedback.description}: no API key for account '${feedback.accountname}'`); | ||
| return Promise.resolve(); | ||
| } | ||
| console.log(`Processing feedback for ${feedback.description} (${feedback.probability}%)...`); | ||
| return submitFeedback(feedback); | ||
| })); | ||
|
johnrb2 marked this conversation as resolved.
|
||
| } | ||
|
|
||
| function lambda() { | ||
| function getConfig (bucket, key) { | ||
| return s3.send(new GetObjectCommand({ Bucket: bucket, Key: key })) | ||
| .then((response) => response.Body.transformToString('utf-8')) | ||
| .then((body) => JSON.parse(body)); | ||
| } | ||
|
|
||
| // Async handler: awaits both the S3 reads and every downstream post so the | ||
| // promise only settles once all work is done. This is important on Lambda, | ||
| // where an async handler freezes the execution environment as soon as its | ||
| // promise resolves (the event loop is not drained), so any unawaited HTTP | ||
| // would otherwise be cut off mid-flight. | ||
| async function lambda () { | ||
| const bucket = 'sales-and-dev-leads-config'; | ||
| const leadConfig = 'leadSubmissions.json'; | ||
| const feedbackConfig = 'feedbackSubmissions.json'; | ||
|
|
||
| // The config-load and submission phases are kept in separate try/catch blocks | ||
| // so a failed S3 read is reported distinctly from a failure while processing | ||
| // the (successfully fetched) config. | ||
| let leadCfg; | ||
| try { | ||
| s3.getObject({Bucket: bucket, Key: leadConfig}, function(err, data) { | ||
| if (err) { | ||
| console.log(`Error from s3.getObject (${bucket}/${leadConfig})`, err); | ||
| } else { | ||
| demoLeads(JSON.parse(data.Body.toString('utf-8'))); | ||
| } | ||
| }); | ||
| leadCfg = await getConfig(bucket, leadConfig); | ||
| } catch (e) { | ||
| console.log(`Unable to load lead submission configuration from S3 (${bucket}/${leadConfig})`, e); | ||
| console.log(`Error loading lead submission configuration from S3 (${bucket}/${leadConfig})`, e); | ||
| } | ||
| if (leadCfg) { | ||
| try { | ||
| await demoLeads(leadCfg); | ||
| } catch (e) { | ||
| console.log('Error processing lead submissions', e); | ||
| } | ||
| } | ||
|
|
||
| let feedbackCfg; | ||
| try { | ||
| s3.getObject({Bucket: bucket, Key: feedbackConfig}, function(err, data) { | ||
| if (err) { | ||
| console.log(`Error from s3.getObject (${bucket}/${feedbackConfig})`, err); | ||
| } else { | ||
| demoFeedbacks(JSON.parse(data.Body.toString('utf-8'))); | ||
| } | ||
| }); | ||
| feedbackCfg = await getConfig(bucket, feedbackConfig); | ||
| } catch (e) { | ||
| console.log(`Unable to load lead submission configuration from S3 (${bucket}/${feedbackConfig})`, e); | ||
| console.log(`Error loading feedback submission configuration from S3 (${bucket}/${feedbackConfig})`, e); | ||
| } | ||
| if (feedbackCfg) { | ||
| try { | ||
| await demoFeedbacks(feedbackCfg); | ||
| } catch (e) { | ||
| console.log('Error processing feedback submissions', e); | ||
|
github-advanced-security[bot] marked this conversation as resolved.
Fixed
|
||
| } | ||
| } | ||
| } | ||
|
|
||
| module.exports = { | ||
| lambda, | ||
| demoLeads, | ||
| demoFeedbacks | ||
| } | ||
| }; | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.