From 1f14960be5c7ff70126d9abaa8ba22a96a77051e Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Thu, 19 Oct 2023 09:44:00 -0700 Subject: [PATCH 01/20] =?UTF-8?q?`aws-sdk/clients/dynamodb`=20=E2=86=92=20?= =?UTF-8?q?`@aws-lite/dynamodb`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintignore | 1 + .gitignore | 5 +- bin/binary-config.js | 3 +- package.json | 6 +- scripts/.npmrc | 1 + scripts/aws-lite-dynamodb.mjs | 4 + scripts/package.json | 5 + scripts/vendor.js | 8 + scripts/vendor.sh | 5 + src/sandbox/seed.js | 10 +- src/tables/_get-db-client.js | 65 ++--- src/tables/_init.js | 23 +- src/tables/create-table/_create-table.js | 56 ++--- .../_get-attribute-definitions.js | 3 +- src/tables/create-table/index.js | 41 ++-- test/integration/tables-test.js | 230 ++++++++---------- .../_get-attribute-definitions-test.js | 4 +- test/unit/src/sandbox-test.js | 2 + 18 files changed, 238 insertions(+), 234 deletions(-) create mode 100644 scripts/.npmrc create mode 100644 scripts/aws-lite-dynamodb.mjs create mode 100644 scripts/package.json create mode 100644 scripts/vendor.js create mode 100755 scripts/vendor.sh diff --git a/.eslintignore b/.eslintignore index 542b5b51..40b5bbe7 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,2 +1,3 @@ test/mock scratch/ +*-vendor.js diff --git a/.gitignore b/.gitignore index 73f66925..d19f4a52 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ -.DS_Store __pycache__ !test/mock/dep-warn/**/node_modules +.DS_Store .nyc_output/ +*-vendor.js bin/*.json bin/sandbox-binary* coverage/ @@ -9,8 +10,8 @@ node_modules/ package-lock.json scratch/ test/mock/*/.db -test/mock/*/src/*/*/vendor/ test/mock/*/*.test +test/mock/*/src/*/*/vendor/ test/mock/*/tmp test/mock/tmp diff --git a/bin/binary-config.js b/bin/binary-config.js index bc510666..460611a2 100644 --- a/bin/binary-config.js +++ b/bin/binary-config.js @@ -22,7 +22,8 @@ let config = { '../node_modules/**/@architect/inventory/**/*.js', ], assets: [ - '../src/invoke-lambda/exec/runtimes/*' + '../src/invoke-lambda/exec/runtimes/*', + '../src/tables/_aws-lite-dynamodb-vendor.js', ], targets: [], outputPath: 'bin' diff --git a/package.json b/package.json index fd5b5443..650f1467 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "coverage": "nyc --reporter=lcov --reporter=text npm run test:unit", "lint": "eslint . --fix", "rc": "npm version prerelease --preid RC", - "build": "node bin/binary-config.js && npx pkg bin" + "build": "node scripts/vendor.js && node bin/binary-config.js && npx pkg bin" }, "engines": { "node": ">=14" @@ -33,6 +33,8 @@ "@architect/hydrate": "~3.3.0", "@architect/inventory": "~3.6.1", "@architect/utils": "~3.1.9", + "@aws-lite/client": "~0.11.1", + "@aws-lite/dynamodb": "~0.2.2", "@aws-sdk/client-apigatewaymanagementapi": "^3.316.0", "@aws-sdk/client-dynamodb": "^3.316.0", "@aws-sdk/client-s3": "^3.316.0", @@ -66,6 +68,8 @@ "@architect/eslint-config": "~2.1.1", "@architect/functions": "~7.0.0", "@architect/req-res-fixtures": "git+https://github.com/architect/req-res-fixtures.git", + "@aws-lite/apigatewaymanagementapi": "~0.0.2", + "@aws-lite/ssm": "~0.1.1", "cross-env": "~7.0.3", "eslint": "~8.47.0", "fs-extra": "~11.1.1", diff --git a/scripts/.npmrc b/scripts/.npmrc new file mode 100644 index 00000000..43c97e71 --- /dev/null +++ b/scripts/.npmrc @@ -0,0 +1 @@ +package-lock=false diff --git a/scripts/aws-lite-dynamodb.mjs b/scripts/aws-lite-dynamodb.mjs new file mode 100644 index 00000000..38a8df3b --- /dev/null +++ b/scripts/aws-lite-dynamodb.mjs @@ -0,0 +1,4 @@ +import dynamo from '@aws-lite/dynamodb' +export const service = dynamo.service +export const property = dynamo.property +export const methods = dynamo.methods diff --git a/scripts/package.json b/scripts/package.json new file mode 100644 index 00000000..b57623f9 --- /dev/null +++ b/scripts/package.json @@ -0,0 +1,5 @@ +{ + "dependencies": { + "esbuild": "^0.19.5" + } +} diff --git a/scripts/vendor.js b/scripts/vendor.js new file mode 100644 index 00000000..23c2fb30 --- /dev/null +++ b/scripts/vendor.js @@ -0,0 +1,8 @@ +#! /usr/bin/env node + +let { execSync } = require('child_process') +let cwd = __dirname +let options = { cwd, stdio: 'inherit' } + +execSync('npm install --force --omit=dev', options) +execSync('npx esbuild ./aws-lite-dynamodb.mjs --bundle --platform=node --format=cjs --outfile=../src/tables/_aws-lite-dynamodb-vendor.js', options) diff --git a/scripts/vendor.sh b/scripts/vendor.sh new file mode 100755 index 00000000..bd32e841 --- /dev/null +++ b/scripts/vendor.sh @@ -0,0 +1,5 @@ +cd scripts + +npm install --force --omit=dev + +npx esbuild ./aws-lite-dynamodb.mjs --bundle --platform=node --format=cjs --outfile=../src/tables/_aws-lite-dynamodb-vendor.js diff --git a/src/sandbox/seed.js b/src/sandbox/seed.js index a07a7721..8da18221 100644 --- a/src/sandbox/seed.js +++ b/src/sandbox/seed.js @@ -47,13 +47,17 @@ module.exports = function startupSeedData (params, callback) { return } let TableName = `${app}-staging-${table}` - return rows.map(Item => callback => dynamo.put({ TableName, Item }, callback)) + return rows.map(Item => callback => { + dynamo.PutItem({ TableName, Item }) + .then(result => callback(null, result)) + .catch(callback) + }) }).filter(Boolean) - getDBClient(ports, (err, db, doc) => { + getDBClient(ports, (err, aws) => { if (err) callback(err) else { - dynamo = doc + dynamo = aws.DynamoDB let start = Date.now() series(seeds, (err) => { if (err) callback(err) diff --git a/src/tables/_get-db-client.js b/src/tables/_get-db-client.js index b3882b17..87dcbd4f 100644 --- a/src/tables/_get-db-client.js +++ b/src/tables/_get-db-client.js @@ -1,41 +1,48 @@ -// eslint-disable-next-line -try { require('aws-sdk/lib/maintenance_mode_message').suppress = true } -catch { /* Noop */ } -let aws = require('aws-sdk') +let { join } = require('path') +let awsLite = require('@aws-lite/client') module.exports = function initDynamoClient (ports, callback) { /** * Final DynamoDB credentials backstop - * - Creds are usually loaded for the process via banner's AWS initialization routines - * - Assumes that aws.config.credentials is present if aws-sdk successfully loaded valid credentials + * - Assumes credentials are loaded via aws-lite * - Populate AWS-specific env vars necessary to mock Lambda + make SDK calls if not already loaded * - Only AWS_SECRET_ACCESS_KEY + AWS_ACCESS_KEY_ID are technically required to mock Lambda */ - let creds = aws.config.credentials - - // Fail loudly and early if a creds file is present without a default profile - if (Array.isArray(creds) && !creds.length) { - let msg = `AWS credentials file found without a 'default' profile; you must add a default profile, specify a different profile, or remove your credentials file` - return callback(ReferenceError(msg)) - } - - if (!process.env.AWS_ACCESS_KEY_ID && creds?.accessKeyId) { - process.env.AWS_ACCESS_KEY_ID = creds.accessKeyId - } - if (!process.env.AWS_SECRET_ACCESS_KEY && creds?.secretAccessKey) { - process.env.AWS_SECRET_ACCESS_KEY = creds.secretAccessKey + let plugins = [] + // Binary dist mode + if (process.pkg) { + plugins.push(join(__dirname, '_aws-lite-dynamodb-vendor.js')) } - if (!creds) { - // These env vars *should* already be instantiated by utils >= 1.4.7 – but do it jic! - process.env.AWS_SECRET_ACCESS_KEY = 'xxx' - process.env.AWS_ACCESS_KEY_ID = 'xxx' - } - + else plugins.push('@aws-lite/dynamodb') let config = { - endpoint: `http://localhost:${ports.tables}`, + autoloadPlugins: false, + host: 'localhost', + plugins, + port: ports.tables, + protocol: 'http', region: process.env.AWS_REGION || 'us-west-2', } - let dynamo = new aws.DynamoDB(config) - let document = new aws.DynamoDB.DocumentClient(config) - callback(null, dynamo, document) + function go (aws) { + if (!process.env.AWS_ACCESS_KEY_ID) { + process.env.AWS_ACCESS_KEY_ID = aws.credentials.accessKeyId + } + if (!process.env.AWS_SECRET_ACCESS_KEY) { + process.env.AWS_SECRET_ACCESS_KEY = aws.credentials.secretAccessKey + } + callback(null, aws) + } + awsLite(config) + .then(go) + .catch(err => { + if (err.message.match(/You must supply AWS credentials/)) { + let dummy = 'xxx' + // These env vars *should* already be instantiated by utils >= 1.4.7 – but do it jic! + // TODO remove this junk after implementing aws-lite + process.env.AWS_SECRET_ACCESS_KEY = dummy + process.env.AWS_ACCESS_KEY_ID = dummy + config.accessKeyId = config.secretAccessKey = dummy + awsLite(config).then(go).catch(callback) + } + else callback(err) + }) } diff --git a/src/tables/_init.js b/src/tables/_init.js index b464bf04..b6016fad 100644 --- a/src/tables/_init.js +++ b/src/tables/_init.js @@ -1,23 +1,10 @@ -let createTable = require('./create-table') let getDBClient = require('./_get-db-client') -let series = require('run-series') +let createTables = require('./create-table') +// Just a thin passthrough to enable the abstraction of getDBClient (for testing) module.exports = function init ({ inventory, ports }, callback) { - getDBClient(ports, function _gotDBClient (err, dynamo) { - if (err) { - return callback(err) - } - - let { inv } = inventory - let app = inv.app - - // User tables (and their indexes) - let plans = inv.tables.map(table => { - return function (callback) { - createTable({ app, dynamo, inventory, ports, table }, callback) - } - }) - - series(plans, callback) + getDBClient(ports, (err, aws) => { + if (err) return callback(err) + createTables({ aws, inventory, ports }, callback) }) } diff --git a/src/tables/create-table/_create-table.js b/src/tables/create-table/_create-table.js index f2fa9bb9..4bbe0112 100644 --- a/src/tables/create-table/_create-table.js +++ b/src/tables/create-table/_create-table.js @@ -3,42 +3,42 @@ let getKeySchema = require('./_get-key-schema') let getGSI = require('./_get-global-secondary-index') module.exports = function _createTable (params, callback) { - let { name, TableName, dynamo, inventory, ports, table } = params + let { table, TableName, aws, inventory, ports } = params + let { name } = table - dynamo.listTables({}, function _tables (err, result) { - if (err) { + aws.DynamoDB.ListTables({}) + .then(result => { + let found = result.TableNames.find(tbl => tbl === TableName) + if (found) return callback() + + let creating = { + TableName, + AttributeDefinitions: getAttributeDefinitions(params), + KeySchema: getKeySchema(table), + ProvisionedThroughput: { + ReadCapacityUnits: 5, + WriteCapacityUnits: 5 + } + } + // Handle global secondary index stuff + let gsi = getGSI({ name, inventory }) + if (gsi) creating.GlobalSecondaryIndexes = gsi + + aws.DynamoDB.CreateTable(creating) + .then(result => callback(null, result)) + .catch(callback) + }) + .catch(err => { console.log(err) if (err.message === 'socket hang up' && err.name === 'TimeoutError') { let msg = `Sandbox was unable to instantiate database tables on port ${ports.tables} due to a timeout error\n` + - `This has been known to occur when system emulators (or tools that use them) attempt to use port ${ports.tables}\n` + - `Please ensure you are not running any such emulators or tools, or manually specify a different @tables port, and try starting Sandbox again` + `This has been known to occur when system emulators (or tools that use them) attempt to use port ${ports.tables}\n` + + `Please ensure you are not running any such emulators or tools, or manually specify a different @tables port, and try starting Sandbox again` console.log(msg) process.exit(1) } let msg = 'Unable to list DynamoDB tables' throw Error(msg) - } - else { - let found = result.TableNames.find(tbl => tbl === TableName) - if (found) callback() - else { - let creating = { - TableName, - AttributeDefinitions: getAttributeDefinitions(params), - KeySchema: getKeySchema(table), - ProvisionedThroughput: { - ReadCapacityUnits: 5, - WriteCapacityUnits: 5 - } - } - - // Handle global secondary index stuff - let gsi = getGSI({ name, inventory }) - if (gsi) creating.GlobalSecondaryIndexes = gsi - - dynamo.createTable(creating, callback) - } - } - }) + }) } diff --git a/src/tables/create-table/_get-attribute-definitions.js b/src/tables/create-table/_get-attribute-definitions.js index c1d8a430..3bfdee4f 100644 --- a/src/tables/create-table/_get-attribute-definitions.js +++ b/src/tables/create-table/_get-attribute-definitions.js @@ -1,5 +1,6 @@ module.exports = function getAttributeDefinitions (params) { - let { name, inventory, table, oob } = params + let { table, inventory, oob } = params + let { name } = table let { get } = inventory // oob is Sandbox default tables; otherwise it's userland diff --git a/src/tables/create-table/index.js b/src/tables/create-table/index.js index 3dc5cca5..ca36684a 100644 --- a/src/tables/create-table/index.js +++ b/src/tables/create-table/index.js @@ -1,3 +1,4 @@ +let series = require('run-series') let parallel = require('run-parallel') let create = require('./_create-table') @@ -6,24 +7,30 @@ let create = require('./_create-table') * @param params.app String * @param params.table Object */ -module.exports = function createTable (params, callback) { - let { app, table } = params - let { name } = table +module.exports = function createTables (params, callback) { + let { inventory } = params + let { inv } = inventory + let app = inv.app - parallel([ - function _createStaging (callback) { - create({ - name, - TableName: `${app}-staging-${name}`, - ...params - }, callback) - }, - function _createProduction (callback) { - create({ - name, - TableName: `${app}-production-${name}`, - ...params + // User tables (and their indexes) + let plans = inv.tables.map(table => { + return function (callback) { + parallel({ + staging: (callback) => { + create({ + TableName: `${app}-staging-${table.name}`, + table, ...params + }, callback) + }, + production: (callback) => { + create({ + TableName: `${app}-production-${table.name}`, + table, ...params + }, callback) + } }, callback) } - ], callback) + }) + + series(plans, callback) } diff --git a/test/integration/tables-test.js b/test/integration/tables-test.js index 16bc155a..5cf27c49 100644 --- a/test/integration/tables-test.js +++ b/test/integration/tables-test.js @@ -47,7 +47,7 @@ function runTests (runType, t) { t.plan(1) getDBClient(ports, function _gotDBClient (err, client) { if (err) console.log(err) // Yes, but actually no - dynamo = client + dynamo = client.DynamoDB t.ok(dynamo, 'Got Dynamo client') }) }) @@ -55,90 +55,81 @@ function runTests (runType, t) { t.test(`${mode} Can list tables`, t => { t.plan(1) setup(t) - dynamo.listTables({}, function done (err, result) { - if (err) t.end(err) - else { + dynamo.ListTables({}) + .then(result => { let { TableNames } = result t.ok(Array.isArray(TableNames), `Got tables back from the DB: ${TableNames}`) teardown(t) - } - }) + }) + .catch(t.end) }) t.test(`${mode} Can insert a row`, t => { t.plan(1) setup(t) - dynamo.putItem({ + dynamo.PutItem({ TableName, Item: { - accountID: { S: 'mock-account-id' }, - email: { S: 'person@email.lol' } + accountID: 'mock-account-id', + email: 'person@email.lol' } - }, - function _put (err, result) { - if (err) t.end(err) - else { + }) + .then(result => { t.ok(result, `Got result: ${str(result)}`) teardown(t) - } - }) + }) + .catch(t.end) }) t.test(`${mode} Can read index in Arc 6`, t => { t.plan(1) setup(t) - dynamo.describeTable({ + dynamo.DescribeTable({ TableName - }, - function _desc (err, result) { - if (err) t.end(err) - else { + }) + .then(result => { t.equal(result.Table.GlobalSecondaryIndexes[0].IndexName, 'email-index', 'Got index: email-index') teardown(t) - } - }) + }) + .catch(t.end) }) t.test(`${mode} Can read index in Arc 6`, t => { t.plan(3) setup(t) - dynamo.describeTable({ + dynamo.DescribeTable({ TableName: TableName2 - }, - function _desc (err, result) { - if (err) t.end(err) - else { + }) + .then(result => { let indexes = result.Table.GlobalSecondaryIndexes t.equal(indexes.length, 2, 'Got back two indexes') t.equal(indexes[0].IndexName, 'petID-index', 'Got index: petID-index') t.equal(indexes[1].IndexName, 'accountID-petID-index', 'Got index: accountID-petID-index') teardown(t) - } - }) + }) + .catch(t.end) }) t.test(`${mode} Can read the row`, t => { t.plan(1) setup(t) - dynamo.getItem({ + dynamo.GetItem({ TableName, Key: { - accountID: { S: 'fake-account-id' } + accountID: 'fake-account-id' } - }, - function _desc (err, result) { - if (err) t.end(err) - else { + }) + .then(result => { t.ok(result, `Got result: ${str(result)}`) teardown(t) - } - }) + }) + .catch(t.end) }) t.test(`${mode} Can query the index`, t => { t.plan(1) setup(t) - dynamo.query({ + dynamo.Query({ TableName, IndexName: 'email-index', KeyConditions: { @@ -147,14 +138,12 @@ function runTests (runType, t) { ComparisonOperator: 'EQ' } } - }, - function _desc (err, result) { - if (err) t.end(err) - else { + }) + .then(result => { t.ok(result, `Got result: ${str(result)}`) teardown(t) - } - }) + }) + .catch(t.end) }) t.test(`${mode} Shut down Sandbox`, t => { @@ -171,35 +160,28 @@ function runTests (runType, t) { t.test(`${mode} Scan seeded rows from first table`, t => { t.plan(3) setup(t) - dynamo.scan({ TableName: 'seed-data-staging-stuff' }, - function _desc (err, result) { - if (err) t.end(err) - else { - console.log(str(result)) - t.equal(result.Count, 2, 'Got two results') - t.equal(result.Items[0].id.S, 'fiz', `Got expected row`) - t.equal(result.Items[1].id.S, 'foo', `Got expected row`) - teardown(t) - } - } - ) + dynamo.Scan({ TableName: 'seed-data-staging-stuff' }) + .then(result => { + console.log(str(result)) + t.equal(result.Count, 2, 'Got two results') + t.equal(result.Items[0].id, 'fiz', `Got expected row`) + t.equal(result.Items[1].id, 'foo', `Got expected row`) + teardown(t) + }) + .catch(t.end) }) t.test(`${mode} Scan seeded rows from second table`, t => { t.plan(3) setup(t) - dynamo.scan({ TableName: 'seed-data-staging-things' }, - function _desc (err, result) { - if (err) t.end(err) - else { - console.log(str(result)) - t.equal(result.Count, 2, 'Got two results') - t.equal(result.Items[0].id.S, 'foo', `Got expected row`) - t.equal(result.Items[1].id.S, 'foo', `Got expected row`) - teardown(t) - } - } - ) + dynamo.Scan({ TableName: 'seed-data-staging-things' }) + .then(result => { + console.log(str(result)) + t.equal(result.Count, 2, 'Got two results') + t.equal(result.Items[0].id, 'foo', `Got expected row`) + t.equal(result.Items[1].id, 'foo', `Got expected row`) + teardown(t) + }) }) t.test(`${mode} Shut down Sandbox`, t => { @@ -213,35 +195,28 @@ function runTests (runType, t) { t.test(`${mode} Scan seeded rows from first table`, t => { t.plan(3) setup(t) - dynamo.scan({ TableName: 'seed-data-staging-stuff' }, - function _desc (err, result) { - if (err) t.end(err) - else { - console.log(str(result)) - t.equal(result.Count, 2, 'Got two results') - t.equal(result.Items[0].id.S, 'fiz', `Got expected row`) - t.equal(result.Items[1].id.S, 'foo', `Got expected row`) - teardown(t) - } - } - ) + dynamo.Scan({ TableName: 'seed-data-staging-stuff' }) + .then(result => { + console.log(str(result)) + t.equal(result.Count, 2, 'Got two results') + t.equal(result.Items[0].id, 'fiz', `Got expected row`) + t.equal(result.Items[1].id, 'foo', `Got expected row`) + teardown(t) + }) + .catch(t.end) }) t.test(`${mode} Scan seeded rows from second table`, t => { t.plan(3) setup(t) - dynamo.scan({ TableName: 'seed-data-staging-things' }, - function _desc (err, result) { - if (err) t.end(err) - else { - console.log(str(result)) - t.equal(result.Count, 2, 'Got two results') - t.equal(result.Items[0].id.S, 'foo', `Got expected row`) - t.equal(result.Items[1].id.S, 'foo', `Got expected row`) - teardown(t) - } - } - ) + dynamo.Scan({ TableName: 'seed-data-staging-things' }) + .then(result => { + console.log(str(result)) + t.equal(result.Count, 2, 'Got two results') + t.equal(result.Items[0].id, 'foo', `Got expected row`) + t.equal(result.Items[1].id, 'foo', `Got expected row`) + teardown(t) + }) }) t.test(`${mode} Shut down Sandbox`, t => { @@ -255,35 +230,29 @@ function runTests (runType, t) { t.test(`${mode} Scan seeded rows from first table`, t => { t.plan(3) setup(t) - dynamo.scan({ TableName: 'seed-data-staging-stuff' }, - function _desc (err, result) { - if (err) t.end(err) - else { - console.log(str(result)) - t.equal(result.Count, 2, 'Got two results') - t.equal(result.Items[0].id.S, 'fiz', `Got expected row`) - t.equal(result.Items[1].id.S, 'foo', `Got expected row`) - teardown(t) - } - } - ) + dynamo.Scan({ TableName: 'seed-data-staging-stuff' }) + .then(result => { + console.log(str(result)) + t.equal(result.Count, 2, 'Got two results') + t.equal(result.Items[0].id, 'fiz', `Got expected row`) + t.equal(result.Items[1].id, 'foo', `Got expected row`) + teardown(t) + }) + .catch(t.end) }) t.test(`${mode} Scan seeded rows from second table`, t => { t.plan(3) setup(t) - dynamo.scan({ TableName: 'seed-data-staging-things' }, - function _desc (err, result) { - if (err) t.end(err) - else { - console.log(str(result)) - t.equal(result.Count, 2, 'Got two results') - t.equal(result.Items[0].id.S, 'foo', `Got expected row`) - t.equal(result.Items[1].id.S, 'foo', `Got expected row`) - teardown(t) - } - } - ) + dynamo.Scan({ TableName: 'seed-data-staging-things' }) + .then(result => { + console.log(str(result)) + t.equal(result.Count, 2, 'Got two results') + t.equal(result.Items[0].id, 'foo', `Got expected row`) + t.equal(result.Items[1].id, 'foo', `Got expected row`) + teardown(t) + }) + .catch(t.end) }) t.test(`${mode} Shut down Sandbox`, t => { @@ -292,26 +261,24 @@ function runTests (runType, t) { t.test(`${mode} Start Sandbox`, t => { process.env.ARC_ENV = 'staging' + process.env.ARC_SANDBOX = '{}' // Force aws-lite to disable keepalive startup[runType](t, join('seed-data', 'js')) }) t.test(`${mode} Data is not seeded when in !testing env`, t => { t.plan(1) setup(t) - dynamo.scan({ TableName: 'seed-data-staging-stuff' }, - function _desc (err, result) { - if (err) t.end(err) - else { - console.log(str(result)) - t.equal(result.Count, 0, 'Got zero results') - teardown(t) - } - } - ) + dynamo.Scan({ TableName: 'seed-data-staging-stuff' }) + .then(result => { + console.log(str(result)) + t.equal(result.Count, 0, 'Got zero results') + teardown(t) + }) }) t.test(`${mode} Shut down Sandbox`, t => { delete process.env.ARC_ENV + delete process.env.ARC_SANDBOX shutdown[runType](t) }) @@ -338,7 +305,7 @@ function runTests (runType, t) { setup(t, externalDBPort) getDBClient({ tables: externalDBPort }, function _gotDBClient (err, client) { if (err) console.log(err) // Yes, but actually no - dynamo = client + dynamo = client.DynamoDB t.ok(dynamo, 'Got Dynamo client') teardown(t) }) @@ -347,14 +314,13 @@ function runTests (runType, t) { t.test(`${mode} Can list tables (external DB)`, t => { t.plan(1) setup(t, externalDBPort) - dynamo.listTables({}, function done (err, result) { - if (err) t.end(err) - else { + dynamo.ListTables({}) + .then(result => { let { TableNames } = result t.ok(Array.isArray(TableNames), `Got tables back from the DB: ${TableNames}`) teardown(t) - } - }) + }) + .catch(t.end) }) t.test(`${mode} Shut down Sandbox`, t => { diff --git a/test/unit/src/db/create-table/_get-attribute-definitions-test.js b/test/unit/src/db/create-table/_get-attribute-definitions-test.js index 85e01fce..0dc62c96 100644 --- a/test/unit/src/db/create-table/_get-attribute-definitions-test.js +++ b/test/unit/src/db/create-table/_get-attribute-definitions-test.js @@ -38,7 +38,7 @@ test('Get DynamoDB AttributeDefinitions (partition key only, manually injected)' test('Get DynamoDB AttributeDefinitions (partition key + GSI, user defined)', t => { t.plan(5) - let result = getDefns({ name: 'accounts', inventory }) + let result = getDefns({ table: { name: 'accounts' }, inventory }) t.equal(result.length, 2, 'Got back one attribute definition') t.equal(result[0].AttributeName, 'accountID', `Got back correct attribute name`) t.equal(result[0].AttributeType, 'S', `Got back correct attribute type`) @@ -60,7 +60,7 @@ test('Get DynamoDB AttributeDefinitions (partition key + multiple GSIs, user def // Note: the GSIs in this mock share key names // Thus, we demonstrate reduced properties; there aren't more attribues just because more GSIs t.plan(5) - let result = getDefns({ name: 'pets', inventory }) + let result = getDefns({ table: { name: 'pets' }, inventory }) t.equal(result.length, 2, 'Got back one attribute definition') t.equal(result[0].AttributeName, 'accountID', `Got back correct attribute name`) t.equal(result[0].AttributeType, 'S', `Got back correct attribute type`) diff --git a/test/unit/src/sandbox-test.js b/test/unit/src/sandbox-test.js index ada73e11..08ba6b31 100644 --- a/test/unit/src/sandbox-test.js +++ b/test/unit/src/sandbox-test.js @@ -88,6 +88,7 @@ let envVars = [ 'ARC_APP_NAME', 'ARC_AWS_CREDS', 'ARC_ENV', + 'ARC_SANDBOX', 'AWS_ACCESS_KEY_ID', 'AWS_PROFILE', 'AWS_REGION', @@ -118,6 +119,7 @@ test('Sandbox only minimally mutates env vars', async t => { // Architect 6+ (staging/prod) before = copy(process.env) process.env.ARC_ENV = 'staging' + process.env.ARC_SANDBOX = '{}' // Force aws-lite to disable keepalive await sandbox.start({ cwd: join(mock, 'normal'), port, quiet }) after = copy(process.env) envVars.forEach(v => delete after[v]) From 00f328026f7ad063f44eebf8382208fcd8668929 Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Thu, 19 Oct 2023 10:56:45 -0700 Subject: [PATCH 02/20] Update SSM integration tests to use `@aws-lite/ssm` --- package.json | 2 +- src/arc/_ssm/index.js | 1 + test/integration/arc/ssm-test.js | 229 +++++++++++++------------------ 3 files changed, 101 insertions(+), 131 deletions(-) diff --git a/package.json b/package.json index 650f1467..74c1c0c7 100644 --- a/package.json +++ b/package.json @@ -69,7 +69,7 @@ "@architect/functions": "~7.0.0", "@architect/req-res-fixtures": "git+https://github.com/architect/req-res-fixtures.git", "@aws-lite/apigatewaymanagementapi": "~0.0.2", - "@aws-lite/ssm": "~0.1.1", + "@aws-lite/ssm": "~0.2.0", "cross-env": "~7.0.3", "eslint": "~8.47.0", "fs-extra": "~11.1.1", diff --git a/src/arc/_ssm/index.js b/src/arc/_ssm/index.js index fb2c86bc..20b1563a 100644 --- a/src/arc/_ssm/index.js +++ b/src/arc/_ssm/index.js @@ -101,6 +101,7 @@ module.exports = function _ssm ({ body, services }, params, req, res) { update.verbose.warn(err) res.statusCode = 400 error = error || { __type: 'InternalServerError', message: 'Unknown Sandbox error: ' + err.stack } + res.setHeader('content-type', 'application/json') res.end(JSON.stringify(error)) return } diff --git a/test/integration/arc/ssm-test.js b/test/integration/arc/ssm-test.js index 54b13f75..e774043f 100644 --- a/test/integration/arc/ssm-test.js +++ b/test/integration/arc/ssm-test.js @@ -1,8 +1,6 @@ -require('aws-sdk/lib/maintenance_mode_message').suppress = true let { join } = require('path') let test = require('tape') -let aws = require('aws-sdk') -let http = require('http') +let awsLite = require('@aws-lite/client') let sut = join(process.cwd(), 'src') let sandbox = require(sut) let { credentials, run, startup, shutdown } = require('../../utils') @@ -10,11 +8,7 @@ let _arcPort = 2222 let app = 'MockappTesting' let tables = [ 'accounts', 'pets', 'places', 'data' ] - -// AWS services to test -let endpoint = new aws.Endpoint(`http://localhost:${_arcPort}/_arc/ssm`) -let httpOptions = { agent: new http.Agent() } -let ssm = new aws.SSM({ endpoint, region: 'us-west-2', httpOptions, credentials }) +let ssm function check ({ result, type, items, fallback, t }) { let internal = result.Parameters?.[0]?.Name?.includes('ARC_SANDBOX') ? 1 : 0 @@ -30,9 +24,19 @@ function check ({ result, type, items, fallback, t }) { }) } -test('Set up env', t => { - t.plan(1) +test('Set up env', async t => { + t.plan(2) t.ok(sandbox, 'Got Sandbox') + let aws = await awsLite({ + ...credentials, + endpointPrefix: '/_arc/ssm', + host: 'localhost', + port: _arcPort, + protocol: 'http', + region: 'us-west-2', + }) + ssm = aws.SSM + t.ok(ssm, 'Populated SSM client') }) test('Run internal Arc SSM service tests', t => { @@ -50,165 +54,134 @@ function runTests (runType, t) { /** * ssm.getParametersByPath() */ - t.test(`${mode} Get & check params (without specifying a type)`, t => { + t.test(`${mode} Get & check params (without specifying a type)`, async t => { t.plan(6) // Should get all tables params back - ssm.getParametersByPath({ Path: `/${app}` }, function (err, result) { - if (err) t.end(err) - else { - t.equal(result.Parameters.length, 5, 'Got back correct number of params') - check({ result, type: 'tables', items: tables, t }) - } - }) + let result = await ssm.GetParametersByPath({ Path: `/${app}` }) + t.equal(result.Parameters.length, 5, 'Got back correct number of params') + check({ result, type: 'tables', items: tables, t }) }) - t.test(`${mode} Get & check params (without specifying a type; Arc Functions bare module mode)`, t => { + t.test(`${mode} Get & check params (without specifying a type; Arc Functions bare module mode)`, async t => { t.plan(6) // Should get all tables params back - ssm.getParametersByPath({ Path: `/ArcAppTesting` }, function (err, result) { - if (err) t.end(err) - else { - t.equal(result.Parameters.length, 5, 'Got back correct number of params') - check({ result, type: 'tables', items: tables, fallback: true, t }) - } - }) + let result = await ssm.GetParametersByPath({ Path: `/ArcAppTesting` }) + t.equal(result.Parameters.length, 5, 'Got back correct number of params') + check({ result, type: 'tables', items: tables, fallback: true, t }) }) - t.test(`${mode} Get & check params (specifying a type)`, t => { + t.test(`${mode} Get & check params (specifying a type)`, async t => { t.plan(6) - ssm.getParametersByPath({ Path: `/${app}/tables` }, function (err, result) { - if (err) t.end(err) - else { - t.equal(result.Parameters.length, 4, 'Got back correct number of params') - check({ result, type: 'tables', items: tables, t }) - } - }) + let result = await ssm.GetParametersByPath({ Path: `/${app}/tables` }) + t.equal(result.Parameters.length, 4, 'Got back correct number of params') + check({ result, type: 'tables', items: tables, t }) }) - t.test(`${mode} Get & check params (specifying a type; Arc Functions bare module mode)`, t => { + t.test(`${mode} Get & check params (specifying a type; Arc Functions bare module mode)`, async t => { t.plan(6) - ssm.getParametersByPath({ Path: `/ArcAppTesting/tables` }, function (err, result) { - if (err) t.end(err) - else { - t.equal(result.Parameters.length, 4, 'Got back correct number of params') - check({ result, type: 'tables', items: tables, fallback: true, t }) - } - }) + let result = await ssm.GetParametersByPath({ Path: `/ArcAppTesting/tables` }) + check({ result, type: 'tables', items: tables, fallback: true, t }) + t.equal(result.Parameters.length, 4, 'Got back correct number of params') }) - t.test(`${mode} Get & check params (specifying an invalid or unknown service)`, t => { + t.test(`${mode} Get & check params (specifying an invalid or unknown service)`, async t => { t.plan(1) - ssm.getParametersByPath({ Path: `/${app}/idk` }, function (err, result) { - if (err) t.end(err) - else t.deepEqual(result.Parameters, [], 'No parameters returned') - }) + let result = await ssm.GetParametersByPath({ Path: `/${app}/idk` }) + t.deepEqual(result.Parameters, [], 'No parameters returned') }) - t.test(`${mode} Get & check params (specifying an invalid or unknown service; Arc Functions bare module mode)`, t => { + t.test(`${mode} Get & check params (specifying an invalid or unknown service; Arc Functions bare module mode)`, async t => { t.plan(1) - ssm.getParametersByPath({ Path: `/ArcAppTesting/idk` }, function (err, result) { - if (err) t.end(err) - else t.deepEqual(result.Parameters, [], 'No parameters returned') - }) + let result = await ssm.GetParametersByPath({ Path: `/ArcAppTesting/idk` }) + t.deepEqual(result.Parameters, [], 'No parameters returned') }) - t.test(`${mode} Get & check params (specifying an invalid or unknown app)`, t => { + t.test(`${mode} Get & check params (specifying an invalid or unknown app)`, async t => { t.plan(1) - ssm.getParametersByPath({ Path: `/idk` }, function (err, result) { - if (err) t.end(err) - else t.deepEqual(result.Parameters, [], 'No parameters returned') - }) + let result = await ssm.GetParametersByPath({ Path: `/idk` }) + t.deepEqual(result.Parameters, [], 'No parameters returned') }) - t.test(`${mode} Get & check params (specifying an unknown app + known service)`, t => { + t.test(`${mode} Get & check params (specifying an unknown app + known service)`, async t => { t.plan(1) - ssm.getParametersByPath({ Path: `/idk/tables` }, function (err, result) { - if (err) t.end(err) - else t.deepEqual(result.Parameters, [], 'No parameters returned') - }) + let result = await ssm.GetParametersByPath({ Path: `/idk/tables` }) + t.deepEqual(result.Parameters, [], 'No parameters returned') }) /** * ssm.getParameter() */ - t.test(`${mode} Get & check a param`, t => { + t.test(`${mode} Get & check a param`, async t => { t.plan(1) let key = `/${app}/tables/accounts` - ssm.getParameter({ Name: key }, function (err, result) { - if (err) t.end(err) - else { - let { Name, Value } = result.Parameter - if (Name === key && Value === `mockapp-staging-accounts`) { - t.pass(`Found param: ${key}`) - } - else t.end(`Could not find param: ${key}`) - } - }) + let result = await ssm.GetParameter({ Name: key }) + let { Name, Value } = result.Parameter + if (Name === key && Value === `mockapp-staging-accounts`) { + t.pass(`Found param: ${key}`) + } + else t.end(`Could not find param: ${key}`) }) - t.test(`${mode} Get & check a param (Arc Functions bare module mode)`, t => { + t.test(`${mode} Get & check a param (Arc Functions bare module mode)`, async t => { t.plan(1) let key = `/ArcAppTesting/tables/accounts` - ssm.getParameter({ Name: key }, function (err, result) { - if (err) t.end(err) - else { - let { Name, Value } = result.Parameter - if (Name === key && Value === `mockapp-staging-accounts`) { - t.pass(`Found param: ${key}`) - } - else t.end(`Could not find param: ${key}`) - } - }) + let result = await ssm.GetParameter({ Name: key }) + let { Name, Value } = result.Parameter + if (Name === key && Value === `mockapp-staging-accounts`) { + t.pass(`Found param: ${key}`) + } + else t.end(`Could not find param: ${key}`) }) - t.test(`${mode} Getting a param without specifying a service type should fail`, t => { - t.plan(2) + t.test(`${mode} Getting a param without specifying a service type should fail`, async t => { + t.plan(1) let key = `/${app}` - ssm.getParameter({ Name: key }, function (err) { - if (!err) t.fail('Expected error') - else { - t.match(err.name, /ParameterNotFound/, 'Got ParameterNotFound error') - t.equal(err.message, null, 'Returned null value') - } - }) + try { + await ssm.GetParameter({ Name: key }) + t.fail('Expected an error') + } + catch (err) { + t.match(err.__type, /ParameterNotFound/, 'Got ParameterNotFound error') + } }) - t.test(`${mode} Getting a param without specifying a param should fail`, t => { - t.plan(2) + t.test(`${mode} Getting a param without specifying a param should fail`, async t => { + t.plan(1) let key = `/${app}/tables/idk` - ssm.getParameter({ Name: key }, function (err) { - if (!err) t.fail('Expected error') - else { - t.match(err.name, /ParameterNotFound/, 'Got ParameterNotFound error') - t.equal(err.message, null, 'Returned null value') - } - }) + try { + await ssm.GetParameter({ Name: key }) + t.fail('Expected an error') + } + catch (err) { + t.match(err.__type, /ParameterNotFound/, 'Got ParameterNotFound error') + } }) - t.test(`${mode} Getting a param without specifying a param should fail (trailing slash)`, t => { + t.test(`${mode} Getting a param without specifying a param should fail (trailing slash)`, async t => { t.plan(2) let key = `/${app}/tables/` - ssm.getParameter({ Name: key }, function (err) { - if (!err) t.fail('Expected error') - else { - t.match(err.name, /ValidationException/, 'Got ValidationException error') - t.match(err.message, /Parameter cannot end in \'\/\'/, 'Errored on trailing slash') - } - }) + try { + await ssm.GetParameter({ Name: key }) + t.fail('Expected an error') + } + catch (err) { + t.match(err.__type, /ValidationException/, 'Got ValidationException error') + t.match(err.message, /Parameter cannot end in \'\/\'/, 'Errored on trailing slash') + } }) /** * Fail on unsupported ssm methods */ - t.test(`${mode} Get & check params (without specifying a type)`, t => { - t.plan(2) - ssm.getParameters({ Names: [ 'a', 'b' ] }, function (err) { - if (!err) t.fail('Expected error') - else { - t.match(err.name, /InternalServerError/, 'Got InternalServerError error') - t.match(err.message, /Unrecognized request, Sandbox only supports/, 'Tried to provide a helpful error') - } - }) + t.test(`${mode} Get & check params (without specifying a type)`, async t => { + t.plan(1) + try { + await ssm.GetParameters({ Names: [ 'a', 'b' ] }) + t.fail('Expected an error') + } + catch (err) { + t.match(err.message, /Unrecognized request, Sandbox only supports/, 'Tried to provide a helpful error') + } }) t.test(`${mode} Shut down Sandbox`, t => { @@ -219,19 +192,15 @@ function runTests (runType, t) { startup[runType](t, 'plugins-sync') }) - t.test(`${mode} Get & check params provided by plugin (without specifying a type)`, t => { + t.test(`${mode} Get & check params provided by plugin (without specifying a type)`, async t => { t.plan(5) // Should get all tables params back - ssm.getParametersByPath({ Path: '/PluginsSandboxTesting' }, function (err, result) { - if (err) t.end(err) - else { - t.equal(result.Parameters.length, 2, 'One parameter returned') - t.equal(result.Parameters[0].Name, '/PluginsSandboxTesting/ARC_SANDBOX/ports', 'Plugin parameter name correct') - t.match(result.Parameters[0].Value, /\"_arc\":/, 'Plugin parameter value correct') - t.equal(result.Parameters[1].Name, '/PluginsSandboxTesting/myplugin/varOne', 'Plugin parameter name correct') - t.equal(result.Parameters[1].Value, 'valueOne', 'Plugin parameter value correct') - } - }) + let result = await ssm.GetParametersByPath({ Path: '/PluginsSandboxTesting' }) + t.equal(result.Parameters.length, 2, 'One parameter returned') + t.equal(result.Parameters[0].Name, '/PluginsSandboxTesting/ARC_SANDBOX/ports', 'Plugin parameter name correct') + t.match(result.Parameters[0].Value, /\"_arc\":/, 'Plugin parameter value correct') + t.equal(result.Parameters[1].Name, '/PluginsSandboxTesting/myplugin/varOne', 'Plugin parameter name correct') + t.equal(result.Parameters[1].Value, 'valueOne', 'Plugin parameter value correct') }) t.test(`${mode} Shut down Sandbox`, t => { From a1260bcf89e6159233f90756a61eb9a47588afd8 Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Thu, 19 Oct 2023 10:59:20 -0700 Subject: [PATCH 03/20] Tidy up DynamoDB integration tests a bit --- test/integration/tables-test.js | 199 +++++++++++++------------------- 1 file changed, 80 insertions(+), 119 deletions(-) diff --git a/test/integration/tables-test.js b/test/integration/tables-test.js index 5cf27c49..9c279551 100644 --- a/test/integration/tables-test.js +++ b/test/integration/tables-test.js @@ -52,84 +52,69 @@ function runTests (runType, t) { }) }) - t.test(`${mode} Can list tables`, t => { + t.test(`${mode} Can list tables`, async t => { t.plan(1) setup(t) - dynamo.ListTables({}) - .then(result => { - let { TableNames } = result - t.ok(Array.isArray(TableNames), `Got tables back from the DB: ${TableNames}`) - teardown(t) - }) - .catch(t.end) + let result = await dynamo.ListTables({}) + let { TableNames } = result + t.ok(Array.isArray(TableNames), `Got tables back from the DB: ${TableNames}`) + teardown(t) }) - t.test(`${mode} Can insert a row`, t => { + t.test(`${mode} Can insert a row`, async t => { t.plan(1) setup(t) - dynamo.PutItem({ + let result = await dynamo.PutItem({ TableName, Item: { accountID: 'mock-account-id', email: 'person@email.lol' } }) - .then(result => { - t.ok(result, `Got result: ${str(result)}`) - teardown(t) - }) - .catch(t.end) + t.ok(result, `Got result: ${str(result)}`) + teardown(t) }) - t.test(`${mode} Can read index in Arc 6`, t => { + t.test(`${mode} Can read index in Arc 6`, async t => { t.plan(1) setup(t) - dynamo.DescribeTable({ + let result = await dynamo.DescribeTable({ TableName }) - .then(result => { - t.equal(result.Table.GlobalSecondaryIndexes[0].IndexName, 'email-index', 'Got index: email-index') - teardown(t) - }) - .catch(t.end) + t.equal(result.Table.GlobalSecondaryIndexes[0].IndexName, 'email-index', 'Got index: email-index') + teardown(t) }) - t.test(`${mode} Can read index in Arc 6`, t => { + t.test(`${mode} Can read index in Arc 6`, async t => { t.plan(3) setup(t) - dynamo.DescribeTable({ + let result = await dynamo.DescribeTable({ TableName: TableName2 }) - .then(result => { - let indexes = result.Table.GlobalSecondaryIndexes - t.equal(indexes.length, 2, 'Got back two indexes') - t.equal(indexes[0].IndexName, 'petID-index', 'Got index: petID-index') - t.equal(indexes[1].IndexName, 'accountID-petID-index', 'Got index: accountID-petID-index') - teardown(t) - }) - .catch(t.end) + let indexes = result.Table.GlobalSecondaryIndexes + t.equal(indexes.length, 2, 'Got back two indexes') + t.equal(indexes[0].IndexName, 'petID-index', 'Got index: petID-index') + t.equal(indexes[1].IndexName, 'accountID-petID-index', 'Got index: accountID-petID-index') + teardown(t) }) - t.test(`${mode} Can read the row`, t => { + t.test(`${mode} Can read the row`, async t => { t.plan(1) setup(t) - dynamo.GetItem({ + let result = await dynamo.GetItem({ TableName, Key: { accountID: 'fake-account-id' } }) - .then(result => { - t.ok(result, `Got result: ${str(result)}`) - teardown(t) - }) - .catch(t.end) + t.ok(result, `Got result: ${str(result)}`) + teardown(t) }) - t.test(`${mode} Can query the index`, t => { + t.test(`${mode} Can query the index`, async t => { t.plan(1) setup(t) - dynamo.Query({ + let result = await dynamo.Query({ TableName, IndexName: 'email-index', KeyConditions: { @@ -139,11 +124,8 @@ function runTests (runType, t) { } } }) - .then(result => { - t.ok(result, `Got result: ${str(result)}`) - teardown(t) - }) - .catch(t.end) + t.ok(result, `Got result: ${str(result)}`) + teardown(t) }) t.test(`${mode} Shut down Sandbox`, t => { @@ -157,31 +139,26 @@ function runTests (runType, t) { startup[runType](t, join('seed-data', 'js'), { confirmStarted }) }) - t.test(`${mode} Scan seeded rows from first table`, t => { + t.test(`${mode} Scan seeded rows from first table`, async t => { t.plan(3) setup(t) - dynamo.Scan({ TableName: 'seed-data-staging-stuff' }) - .then(result => { - console.log(str(result)) - t.equal(result.Count, 2, 'Got two results') - t.equal(result.Items[0].id, 'fiz', `Got expected row`) - t.equal(result.Items[1].id, 'foo', `Got expected row`) - teardown(t) - }) - .catch(t.end) + let result = await dynamo.Scan({ TableName: 'seed-data-staging-stuff' }) + console.log(str(result)) + t.equal(result.Count, 2, 'Got two results') + t.equal(result.Items[0].id, 'fiz', `Got expected row`) + t.equal(result.Items[1].id, 'foo', `Got expected row`) + teardown(t) }) - t.test(`${mode} Scan seeded rows from second table`, t => { + t.test(`${mode} Scan seeded rows from second table`, async t => { t.plan(3) setup(t) - dynamo.Scan({ TableName: 'seed-data-staging-things' }) - .then(result => { - console.log(str(result)) - t.equal(result.Count, 2, 'Got two results') - t.equal(result.Items[0].id, 'foo', `Got expected row`) - t.equal(result.Items[1].id, 'foo', `Got expected row`) - teardown(t) - }) + let result = await dynamo.Scan({ TableName: 'seed-data-staging-things' }) + console.log(str(result)) + t.equal(result.Count, 2, 'Got two results') + t.equal(result.Items[0].id, 'foo', `Got expected row`) + t.equal(result.Items[1].id, 'foo', `Got expected row`) + teardown(t) }) t.test(`${mode} Shut down Sandbox`, t => { @@ -192,31 +169,26 @@ function runTests (runType, t) { startup[runType](t, join('seed-data', 'json'), { confirmStarted }) }) - t.test(`${mode} Scan seeded rows from first table`, t => { + t.test(`${mode} Scan seeded rows from first table`, async t => { t.plan(3) setup(t) - dynamo.Scan({ TableName: 'seed-data-staging-stuff' }) - .then(result => { - console.log(str(result)) - t.equal(result.Count, 2, 'Got two results') - t.equal(result.Items[0].id, 'fiz', `Got expected row`) - t.equal(result.Items[1].id, 'foo', `Got expected row`) - teardown(t) - }) - .catch(t.end) + let result = await dynamo.Scan({ TableName: 'seed-data-staging-stuff' }) + console.log(str(result)) + t.equal(result.Count, 2, 'Got two results') + t.equal(result.Items[0].id, 'fiz', `Got expected row`) + t.equal(result.Items[1].id, 'foo', `Got expected row`) + teardown(t) }) - t.test(`${mode} Scan seeded rows from second table`, t => { + t.test(`${mode} Scan seeded rows from second table`, async t => { t.plan(3) setup(t) - dynamo.Scan({ TableName: 'seed-data-staging-things' }) - .then(result => { - console.log(str(result)) - t.equal(result.Count, 2, 'Got two results') - t.equal(result.Items[0].id, 'foo', `Got expected row`) - t.equal(result.Items[1].id, 'foo', `Got expected row`) - teardown(t) - }) + let result = await dynamo.Scan({ TableName: 'seed-data-staging-things' }) + console.log(str(result)) + t.equal(result.Count, 2, 'Got two results') + t.equal(result.Items[0].id, 'foo', `Got expected row`) + t.equal(result.Items[1].id, 'foo', `Got expected row`) + teardown(t) }) t.test(`${mode} Shut down Sandbox`, t => { @@ -227,32 +199,26 @@ function runTests (runType, t) { startup[runType](t, join('seed-data', 'custom'), { confirmStarted }) }) - t.test(`${mode} Scan seeded rows from first table`, t => { + t.test(`${mode} Scan seeded rows from first table`, async t => { t.plan(3) setup(t) - dynamo.Scan({ TableName: 'seed-data-staging-stuff' }) - .then(result => { - console.log(str(result)) - t.equal(result.Count, 2, 'Got two results') - t.equal(result.Items[0].id, 'fiz', `Got expected row`) - t.equal(result.Items[1].id, 'foo', `Got expected row`) - teardown(t) - }) - .catch(t.end) + let result = await dynamo.Scan({ TableName: 'seed-data-staging-stuff' }) + console.log(str(result)) + t.equal(result.Count, 2, 'Got two results') + t.equal(result.Items[0].id, 'fiz', `Got expected row`) + t.equal(result.Items[1].id, 'foo', `Got expected row`) + teardown(t) }) - t.test(`${mode} Scan seeded rows from second table`, t => { + t.test(`${mode} Scan seeded rows from second table`, async t => { t.plan(3) setup(t) - dynamo.Scan({ TableName: 'seed-data-staging-things' }) - .then(result => { - console.log(str(result)) - t.equal(result.Count, 2, 'Got two results') - t.equal(result.Items[0].id, 'foo', `Got expected row`) - t.equal(result.Items[1].id, 'foo', `Got expected row`) - teardown(t) - }) - .catch(t.end) + let result = await dynamo.Scan({ TableName: 'seed-data-staging-things' }) + console.log(str(result)) + t.equal(result.Count, 2, 'Got two results') + t.equal(result.Items[0].id, 'foo', `Got expected row`) + t.equal(result.Items[1].id, 'foo', `Got expected row`) + teardown(t) }) t.test(`${mode} Shut down Sandbox`, t => { @@ -265,15 +231,13 @@ function runTests (runType, t) { startup[runType](t, join('seed-data', 'js')) }) - t.test(`${mode} Data is not seeded when in !testing env`, t => { + t.test(`${mode} Data is not seeded when in !testing env`, async t => { t.plan(1) setup(t) - dynamo.Scan({ TableName: 'seed-data-staging-stuff' }) - .then(result => { - console.log(str(result)) - t.equal(result.Count, 0, 'Got zero results') - teardown(t) - }) + let result = await dynamo.Scan({ TableName: 'seed-data-staging-stuff' }) + console.log(str(result)) + t.equal(result.Count, 0, 'Got zero results') + teardown(t) }) t.test(`${mode} Shut down Sandbox`, t => { @@ -311,16 +275,13 @@ function runTests (runType, t) { }) }) - t.test(`${mode} Can list tables (external DB)`, t => { + t.test(`${mode} Can list tables (external DB)`, async t => { t.plan(1) setup(t, externalDBPort) - dynamo.ListTables({}) - .then(result => { - let { TableNames } = result - t.ok(Array.isArray(TableNames), `Got tables back from the DB: ${TableNames}`) - teardown(t) - }) - .catch(t.end) + let result = await dynamo.ListTables({}) + let { TableNames } = result + t.ok(Array.isArray(TableNames), `Got tables back from the DB: ${TableNames}`) + teardown(t) }) t.test(`${mode} Shut down Sandbox`, t => { From 2f078b8b7c929ccec084603afb281b2dc058bcdc Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Thu, 19 Oct 2023 11:17:22 -0700 Subject: [PATCH 04/20] Update WS integration tests to use `@aws-lite/apigatewaymanagementapi` --- test/integration/arc/ws-test.js | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/test/integration/arc/ws-test.js b/test/integration/arc/ws-test.js index e59fb385..597e7476 100644 --- a/test/integration/arc/ws-test.js +++ b/test/integration/arc/ws-test.js @@ -1,17 +1,21 @@ -require('aws-sdk/lib/maintenance_mode_message').suppress = true let { join } = require('path') let test = require('tape') -let aws = require('aws-sdk') -let http = require('http') +let awsLite = require('@aws-lite/client') let Websocket = require('ws') let sut = join(process.cwd(), 'src') let sandbox = require(sut) let { credentials, run, startup, shutdown, makeSideChannel, wsUrl } = require('../../utils') let _arcPort = 2222 +let ApiUrl = `http://localhost:${_arcPort}/_arc/ws` +let apiGatewayManagementApi + test('Set up env', async t => { - t.plan(1) + t.plan(2) t.ok(sandbox, 'Got Sandbox') + let aws = await awsLite({ ...credentials, region: 'us-west-2', keepAlive: false }) + apiGatewayManagementApi = aws.ApiGatewayManagementApi + t.ok(apiGatewayManagementApi, 'Populated ApiGatewayManagementApi client') }) test('Run internal Arc API Gateway Management service tests', t => { @@ -25,11 +29,6 @@ function runTests (runType, t) { let _ws let ConnectionId - // AWS services to test - let endpoint = new aws.Endpoint(`http://localhost:${_arcPort}/_arc/ws`) - let httpOptions = { agent: new http.Agent() } - let apiGatewayManagementApi = new aws.ApiGatewayManagementApi({ endpoint, region: 'us-west-2', httpOptions, credentials }) - let connectWebSocket = async () => { if (_ws) throw Error('Only one websocket can be connected at a time, test is not clean') _ws = new Websocket(wsUrl) @@ -72,7 +71,7 @@ function runTests (runType, t) { ConnectionId = connectionEvent.event.requestContext.connectionId t.ok(ConnectionId, `Got requestContext with connectionId: ${ConnectionId}`) - let connection = await apiGatewayManagementApi.getConnection({ ConnectionId }).promise() + let connection = await apiGatewayManagementApi.GetConnection({ ApiUrl, ConnectionId }) t.ok(new Date(Date.parse(connection.ConnectedAt)) <= new Date(), `Got back connectedAt string: ${connection.ConnectedAt}`) }) @@ -80,25 +79,23 @@ function runTests (runType, t) { t.plan(1) let Data = JSON.stringify({ message: 'hi' }) let messagePromise = new Promise(resolve => _ws.once('message', resolve)) - await apiGatewayManagementApi.postToConnection({ ConnectionId, Data }).promise() + await apiGatewayManagementApi.PostToConnection({ ApiUrl, ConnectionId, Data }) const message = (await messagePromise).toString() - // console.log({ message }) t.equals(message, Data, 'Got message') }) t.test(`${mode} Disconnect a socket`, async t => { - t.plan(3) + t.plan(2) let closePromise = new Promise(resolve => _ws.once('close', resolve)) - await apiGatewayManagementApi.deleteConnection({ ConnectionId }).promise() + await apiGatewayManagementApi.DeleteConnection({ ApiUrl, ConnectionId }) await closePromise t.notOk(_ws, 'WebSocket closed') try { - await apiGatewayManagementApi.getConnection({ ConnectionId }).promise() + await apiGatewayManagementApi.GetConnection({ ApiUrl, ConnectionId }) t.fail('getConnection should have thrown') } catch (error) { - t.equals(error.message, '410', 'Error message matches') - t.equals(error.code, 'GoneException', 'Error Code Matches') + t.equals(error.statusCode, 410, 'Error status matches') } }) From ae2772ef9106ded516b85bbfbd539df0c9126c72 Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Thu, 19 Oct 2023 19:04:59 -0700 Subject: [PATCH 05/20] Farewell, old friend! --- bin/binary-config.js | 2 ++ package.json | 11 +---------- src/cli/arc.js | 3 ++- src/invoke-lambda/env/index.js | 4 ++-- src/sandbox/index.js | 7 +------ src/tables/_get-db-client.js | 8 ++------ test/utils/_lib.js | 4 ++-- 7 files changed, 12 insertions(+), 27 deletions(-) diff --git a/bin/binary-config.js b/bin/binary-config.js index 460611a2..846272a2 100644 --- a/bin/binary-config.js +++ b/bin/binary-config.js @@ -17,6 +17,8 @@ let config = { // Don't manually include runtimes/deno.js in scripts, as it fails on pkg#997 scripts: [ '../node_modules/@architect/inventory/**/*.js', + // Utils now has a child process-executed script for checking credentials + '../node_modules/@architect/utils/**/*.js', '../node_modules/dynalite/**/*.js', // This line is only necessary when testing RC releases of Inventory, do NOT use it in production binary builds of Sandbox: '../node_modules/**/@architect/inventory/**/*.js', diff --git a/package.json b/package.json index 74c1c0c7..3a4d23ea 100644 --- a/package.json +++ b/package.json @@ -32,19 +32,10 @@ "@architect/create": "~4.2.3", "@architect/hydrate": "~3.3.0", "@architect/inventory": "~3.6.1", - "@architect/utils": "~3.1.9", + "@architect/utils": "~4.0.0-RC.0", "@aws-lite/client": "~0.11.1", "@aws-lite/dynamodb": "~0.2.2", - "@aws-sdk/client-apigatewaymanagementapi": "^3.316.0", - "@aws-sdk/client-dynamodb": "^3.316.0", - "@aws-sdk/client-s3": "^3.316.0", - "@aws-sdk/client-sns": "^3.316.0", - "@aws-sdk/client-sqs": "^3.316.0", - "@aws-sdk/client-ssm": "^3.316.0", - "@aws-sdk/lib-dynamodb": "^3.316.0", - "@aws-sdk/node-http-handler": "^3.360.0", "@begin/hashid": "~1.0.0", - "aws-sdk": "^2.1363.0", "chalk": "4.1.2", "chokidar": "~3.5.3", "depstatus": "~1.1.1", diff --git a/src/cli/arc.js b/src/cli/arc.js index 7baeb401..3b266ee5 100644 --- a/src/cli/arc.js +++ b/src/cli/arc.js @@ -6,10 +6,11 @@ let cli = require('./index.js') */ module.exports = function arcCalling ({ inventory }) { cli({ + checkCreds: false, disableBanner: true, + inventory, needsValidCreds: false, runtimeCheck: 'warn', - inventory, }, function _done (err) { if (err) { diff --git a/src/invoke-lambda/env/index.js b/src/invoke-lambda/env/index.js index aa09dfea..785b7f1f 100644 --- a/src/invoke-lambda/env/index.js +++ b/src/invoke-lambda/env/index.js @@ -23,7 +23,7 @@ module.exports = function getEnv (params, requestID) { // Runtime environment variables let env = { // AWS-specific - AWS_ACCESS_KEY_ID, + AWS_ACCESS_KEY_ID: AWS_ACCESS_KEY_ID || 'arc_dummy_access_key', AWS_LAMBDA_FUNCTION_MEMORY_SIZE: lambda.config.memory, AWS_LAMBDA_FUNCTION_NAME: `@${lambda.pragma} ${lambda.name}`, AWS_LAMBDA_FUNCTION_VERSION: '$latest', @@ -31,7 +31,7 @@ module.exports = function getEnv (params, requestID) { AWS_PROFILE, AWS_REGION, AWS_SDK_JS_SUPPRESS_MAINTENANCE_MODE_MESSAGE: true, // Sigh. - AWS_SECRET_ACCESS_KEY, + AWS_SECRET_ACCESS_KEY: AWS_SECRET_ACCESS_KEY || 'arc_dummy_secret_key', AWS_SESSION_TOKEN, LAMBDA_TASK_ROOT: src, TZ: 'UTC', diff --git a/src/sandbox/index.js b/src/sandbox/index.js index 1896fd8a..63217126 100644 --- a/src/sandbox/index.js +++ b/src/sandbox/index.js @@ -107,12 +107,7 @@ function _start (params, callback) { ], function (err) { if (err) callback(err) - else { - if (process.env.ARC_AWS_CREDS === 'dummy' && !restart) { - update.verbose.warn('Missing or invalid AWS credentials or credentials file, using dummy credentials (this is probably ok)') - } - callback(null, params.ports) - } + else callback(null, params.ports) }) } diff --git a/src/tables/_get-db-client.js b/src/tables/_get-db-client.js index 87dcbd4f..72cfd76e 100644 --- a/src/tables/_get-db-client.js +++ b/src/tables/_get-db-client.js @@ -35,12 +35,8 @@ module.exports = function initDynamoClient (ports, callback) { .then(go) .catch(err => { if (err.message.match(/You must supply AWS credentials/)) { - let dummy = 'xxx' - // These env vars *should* already be instantiated by utils >= 1.4.7 – but do it jic! - // TODO remove this junk after implementing aws-lite - process.env.AWS_SECRET_ACCESS_KEY = dummy - process.env.AWS_ACCESS_KEY_ID = dummy - config.accessKeyId = config.secretAccessKey = dummy + config.accessKeyId = 'arc_dummy_access_key' + config.secretAccessKey = 'arc_dummy_secret_key' awsLite(config).then(go).catch(callback) } else callback(err) diff --git a/test/utils/_lib.js b/test/utils/_lib.js index 51dbfbd6..4a021279 100644 --- a/test/utils/_lib.js +++ b/test/utils/_lib.js @@ -9,8 +9,8 @@ let copy = thing => JSON.parse(JSON.stringify(thing)) // Dummy AWS creds let credentials = { - accessKeyId: 'xxx', - secretAccessKey: 'xxx', + accessKeyId: 'arc_dummy_access_key', + secretAccessKey: 'arc_dummy_secret_key', } let data = { hi: 'there' } From 94a1b62c7ef344158457b6d5c13b908d65022f88 Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Wed, 25 Oct 2023 15:45:10 -0700 Subject: [PATCH 06/20] Load, backstop, and pass around AWS credentials the correct way: via `aws-lite` Stop populating credential-related process env vars: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN` No longer use Dynamo client init as a missing credential backstop --- bin/binary-config.js | 2 -- package.json | 2 +- src/cli/arc.js | 2 -- src/http/middleware/_fallback.js | 4 ++- src/invoke-lambda/env/index.js | 11 +++--- src/sandbox/creds.js | 25 ++++++++++++++ src/sandbox/index.js | 6 ++++ src/sandbox/seed.js | 4 +-- src/tables/_get-db-client.js | 41 ++++++----------------- src/tables/_init.js | 4 +-- test/integration/tables-test.js | 6 ++-- test/unit/src/invoke-lambda/index-test.js | 3 +- test/unit/src/sandbox-test.js | 2 +- 13 files changed, 61 insertions(+), 51 deletions(-) create mode 100644 src/sandbox/creds.js diff --git a/bin/binary-config.js b/bin/binary-config.js index 846272a2..460611a2 100644 --- a/bin/binary-config.js +++ b/bin/binary-config.js @@ -17,8 +17,6 @@ let config = { // Don't manually include runtimes/deno.js in scripts, as it fails on pkg#997 scripts: [ '../node_modules/@architect/inventory/**/*.js', - // Utils now has a child process-executed script for checking credentials - '../node_modules/@architect/utils/**/*.js', '../node_modules/dynalite/**/*.js', // This line is only necessary when testing RC releases of Inventory, do NOT use it in production binary builds of Sandbox: '../node_modules/**/@architect/inventory/**/*.js', diff --git a/package.json b/package.json index f663ec7f..88cf21f1 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "@architect/create": "~4.2.3", "@architect/hydrate": "~3.4.1", "@architect/inventory": "~3.6.2", - "@architect/utils": "~4.0.0-RC.0", + "@architect/utils": "~4.0.0-RC.1", "@aws-lite/client": "~0.11.1", "@aws-lite/dynamodb": "~0.2.2", "@begin/hashid": "~1.0.0", diff --git a/src/cli/arc.js b/src/cli/arc.js index 3b266ee5..d0e43861 100644 --- a/src/cli/arc.js +++ b/src/cli/arc.js @@ -6,10 +6,8 @@ let cli = require('./index.js') */ module.exports = function arcCalling ({ inventory }) { cli({ - checkCreds: false, disableBanner: true, inventory, - needsValidCreds: false, runtimeCheck: 'warn', }, function _done (err) { diff --git a/src/http/middleware/_fallback.js b/src/http/middleware/_fallback.js index 9bc39e5c..567f0919 100644 --- a/src/http/middleware/_fallback.js +++ b/src/http/middleware/_fallback.js @@ -12,7 +12,7 @@ let httpProxy = require('http-proxy') * - Error out */ module.exports = function fallback (args, req, res, next) { - let { apiType, cwd, inventory, ports, staticPath, update } = args + let { apiType, creds, cwd, inventory, ports, staticPath, update } = args let { inv, get } = inventory let httpAPI = apiType.startsWith('http') let method = req.method.toLowerCase() @@ -111,6 +111,7 @@ module.exports = function fallback (args, req, res, next) { let name = `${rootParam[0]} /${rootParam[1]}` let lambda = get.http(name) let exec = invoker({ + creds, cwd, lambda, apiType, @@ -144,6 +145,7 @@ module.exports = function fallback (args, req, res, next) { function invokeProxy (src, arcStaticAssetProxy) { let exec = invoker({ apiType, + creds, cwd, lambda: { name: 'get /*', diff --git a/src/invoke-lambda/env/index.js b/src/invoke-lambda/env/index.js index 785b7f1f..8cced7d7 100644 --- a/src/invoke-lambda/env/index.js +++ b/src/invoke-lambda/env/index.js @@ -5,10 +5,11 @@ let { version } = require('../../../package.json') // Assemble Lambda-specific execution environment variables module.exports = function getEnv (params, requestID) { - let { apiType, cwd, lambda, host, inventory, ports, staticPath } = params + let { apiType, creds, cwd, lambda, host, inventory, ports, staticPath } = params + let { accessKeyId, secretAccessKey, sessionToken } = creds let { config, src, build, handlerFile } = lambda let { inv } = inventory - let { AWS_ACCESS_KEY_ID, AWS_PROFILE, AWS_REGION, AWS_SECRET_ACCESS_KEY, AWS_SESSION_TOKEN, PATH } = process.env + let { AWS_PROFILE, AWS_REGION, PATH } = process.env let lambdaContext = getContext(params) let envVars = userEnvVars(params) @@ -23,7 +24,7 @@ module.exports = function getEnv (params, requestID) { // Runtime environment variables let env = { // AWS-specific - AWS_ACCESS_KEY_ID: AWS_ACCESS_KEY_ID || 'arc_dummy_access_key', + AWS_ACCESS_KEY_ID: accessKeyId, AWS_LAMBDA_FUNCTION_MEMORY_SIZE: lambda.config.memory, AWS_LAMBDA_FUNCTION_NAME: `@${lambda.pragma} ${lambda.name}`, AWS_LAMBDA_FUNCTION_VERSION: '$latest', @@ -31,8 +32,8 @@ module.exports = function getEnv (params, requestID) { AWS_PROFILE, AWS_REGION, AWS_SDK_JS_SUPPRESS_MAINTENANCE_MODE_MESSAGE: true, // Sigh. - AWS_SECRET_ACCESS_KEY: AWS_SECRET_ACCESS_KEY || 'arc_dummy_secret_key', - AWS_SESSION_TOKEN, + AWS_SECRET_ACCESS_KEY: secretAccessKey, + AWS_SESSION_TOKEN: sessionToken, LAMBDA_TASK_ROOT: src, TZ: 'UTC', // Internal for handler bootstrap diff --git a/src/sandbox/creds.js b/src/sandbox/creds.js new file mode 100644 index 00000000..1a4df1c0 --- /dev/null +++ b/src/sandbox/creds.js @@ -0,0 +1,25 @@ +let awsLite = require('@aws-lite/client') +module.exports = function loadCreds (params, callback) { + let { inventory } = params + awsLite({ + autoloadPlugins: false, + profile: inventory.inv?.aws?.profile, + region: 'us-west-1', + }) + .then(aws => { + params.creds = { + // secretAccessKey + sessionToken are non-enumerable, so we can't just ref or spread + accessKeyId: aws.credentials.accessKeyId, + secretAccessKey: aws.credentials.secretAccessKey, + sessionToken: aws.credentials.sessionToken, + } + callback() + }) + .catch(() => { + params.creds = { + accessKeyId: 'arc_dummy_access_key', + secretAccessKey: 'arc_dummy_secret_key', + } + callback() + }) +} diff --git a/src/sandbox/index.js b/src/sandbox/index.js index 63217126..d330b344 100644 --- a/src/sandbox/index.js +++ b/src/sandbox/index.js @@ -3,6 +3,7 @@ let series = require('run-series') let create = require('@architect/create') let env = require('./env') +let creds = require('./creds') let ports = require('./ports') let checkRuntimes = require('./check-runtimes') let maybeHydrate = require('./maybe-hydrate') @@ -27,6 +28,11 @@ function _start (params, callback) { env(params, callback) }, + // Load credentials + function (callback) { + creds(params, callback) + }, + // Get the ports for services function (callback) { ports(params, callback) diff --git a/src/sandbox/seed.js b/src/sandbox/seed.js index 8da18221..b5f2d8db 100644 --- a/src/sandbox/seed.js +++ b/src/sandbox/seed.js @@ -5,7 +5,7 @@ let getDBClient = require('../tables/_get-db-client') module.exports = function startupSeedData (params, callback) { let { ARC_ENV } = process.env - let { cwd, inventory, update, ports } = params + let { creds, cwd, inventory, update, ports } = params let { inv, get } = inventory let { app, tables } = inv if (!tables || ARC_ENV !== 'testing') return callback() @@ -54,7 +54,7 @@ module.exports = function startupSeedData (params, callback) { }) }).filter(Boolean) - getDBClient(ports, (err, aws) => { + getDBClient({ creds, ports }, (err, aws) => { if (err) callback(err) else { dynamo = aws.DynamoDB diff --git a/src/tables/_get-db-client.js b/src/tables/_get-db-client.js index 72cfd76e..0eafb7a1 100644 --- a/src/tables/_get-db-client.js +++ b/src/tables/_get-db-client.js @@ -1,19 +1,13 @@ let { join } = require('path') let awsLite = require('@aws-lite/client') -module.exports = function initDynamoClient (ports, callback) { - /** - * Final DynamoDB credentials backstop - * - Assumes credentials are loaded via aws-lite - * - Populate AWS-specific env vars necessary to mock Lambda + make SDK calls if not already loaded - * - Only AWS_SECRET_ACCESS_KEY + AWS_ACCESS_KEY_ID are technically required to mock Lambda - */ - let plugins = [] - // Binary dist mode - if (process.pkg) { - plugins.push(join(__dirname, '_aws-lite-dynamodb-vendor.js')) - } - else plugins.push('@aws-lite/dynamodb') +module.exports = function initDynamoClient ({ creds, ports }, callback) { + let plugins = [ + // Binary dist mode + process.pkg + ? join(__dirname, '_aws-lite-dynamodb-vendor.js') + : '@aws-lite/dynamodb' + ] let config = { autoloadPlugins: false, host: 'localhost', @@ -21,24 +15,9 @@ module.exports = function initDynamoClient (ports, callback) { port: ports.tables, protocol: 'http', region: process.env.AWS_REGION || 'us-west-2', - } - function go (aws) { - if (!process.env.AWS_ACCESS_KEY_ID) { - process.env.AWS_ACCESS_KEY_ID = aws.credentials.accessKeyId - } - if (!process.env.AWS_SECRET_ACCESS_KEY) { - process.env.AWS_SECRET_ACCESS_KEY = aws.credentials.secretAccessKey - } - callback(null, aws) + ...creds, } awsLite(config) - .then(go) - .catch(err => { - if (err.message.match(/You must supply AWS credentials/)) { - config.accessKeyId = 'arc_dummy_access_key' - config.secretAccessKey = 'arc_dummy_secret_key' - awsLite(config).then(go).catch(callback) - } - else callback(err) - }) + .then(client => callback(null, client)) + .catch(callback) } diff --git a/src/tables/_init.js b/src/tables/_init.js index b6016fad..a63d5843 100644 --- a/src/tables/_init.js +++ b/src/tables/_init.js @@ -2,8 +2,8 @@ let getDBClient = require('./_get-db-client') let createTables = require('./create-table') // Just a thin passthrough to enable the abstraction of getDBClient (for testing) -module.exports = function init ({ inventory, ports }, callback) { - getDBClient(ports, (err, aws) => { +module.exports = function init ({ creds, inventory, ports }, callback) { + getDBClient({ creds, ports }, (err, aws) => { if (err) return callback(err) createTables({ aws, inventory, ports }, callback) }) diff --git a/test/integration/tables-test.js b/test/integration/tables-test.js index 9c279551..732f246a 100644 --- a/test/integration/tables-test.js +++ b/test/integration/tables-test.js @@ -6,7 +6,7 @@ let getDBClient = require(join(process.cwd(), 'src', 'tables', '_get-db-client') let TableName = 'mockapp-production-accounts' let TableName2 = 'mockapp-production-pets' let mock = join(process.cwd(), 'test', 'mock') -let { run, startup, shutdown } = require('../utils') +let { credentials: creds, run, startup, shutdown } = require('../utils') let str = s => JSON.stringify(s, null, 2) let dynamo let tablesPort = 5555 @@ -45,7 +45,7 @@ function runTests (runType, t) { t.test(`${mode} Get client`, t => { t.plan(1) - getDBClient(ports, function _gotDBClient (err, client) { + getDBClient({ creds, ports }, function _gotDBClient (err, client) { if (err) console.log(err) // Yes, but actually no dynamo = client.DynamoDB t.ok(dynamo, 'Got Dynamo client') @@ -267,7 +267,7 @@ function runTests (runType, t) { t.test(`${mode} Get client (external DB)`, t => { t.plan(1) setup(t, externalDBPort) - getDBClient({ tables: externalDBPort }, function _gotDBClient (err, client) { + getDBClient({ creds, ports: { tables: externalDBPort } }, function _gotDBClient (err, client) { if (err) console.log(err) // Yes, but actually no dynamo = client.DynamoDB t.ok(dynamo, 'Got Dynamo client') diff --git a/test/unit/src/invoke-lambda/index-test.js b/test/unit/src/invoke-lambda/index-test.js index 642280e3..ea4cd1de 100644 --- a/test/unit/src/invoke-lambda/index-test.js +++ b/test/unit/src/invoke-lambda/index-test.js @@ -6,6 +6,7 @@ let update = require('@architect/utils').updater() let cwd = process.cwd() let mock = join(cwd, 'test', 'mock') let { invocations } = require(join(cwd, 'src', 'arc', '_runtime-api')) +let { credentials: creds } = require(join(cwd, 'test', 'utils')) let runtimes = { asap: 0, @@ -36,7 +37,7 @@ let event = { something: 'happened' } let inventory = { inv: { _project: { env: { local: { testing: null, staging: null, production: null } } }, app: 'hi' } } let ports = {} let userEnv = {} -let params = { event, inventory, update, userEnv, ports } +let params = { creds, event, inventory, update, userEnv, ports } let inv let get diff --git a/test/unit/src/sandbox-test.js b/test/unit/src/sandbox-test.js index 08ba6b31..0e2c2066 100644 --- a/test/unit/src/sandbox-test.js +++ b/test/unit/src/sandbox-test.js @@ -83,7 +83,7 @@ test('Sandbox uses continuation passing', t => { ]) }) -// Standard env vars that may be populated during a banner / AWS init +// Nothing should be mutating these, but reset them jic! let envVars = [ 'ARC_APP_NAME', 'ARC_AWS_CREDS', From 02824cd55ad39f12cc66e8165cf39f4cdb17b6e9 Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Tue, 12 Dec 2023 10:50:34 -0800 Subject: [PATCH 07/20] Update deps --- package.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 8a733efb..8304e621 100644 --- a/package.json +++ b/package.json @@ -28,13 +28,13 @@ "src/*" ], "dependencies": { - "@architect/asap": "~6.0.4", + "@architect/asap": "~6.1.0-RC.0", "@architect/create": "~4.2.4", "@architect/hydrate": "~3.5.1", - "@architect/inventory": "~3.6.3", + "@architect/inventory": "~3.6.5", "@architect/utils": "~4.0.0-RC.1", - "@aws-lite/client": "~0.11.1", - "@aws-lite/dynamodb": "~0.2.2", + "@aws-lite/client": "~0.12.2", + "@aws-lite/dynamodb": "~0.3.0", "@begin/hashid": "~1.0.0", "chalk": "4.1.2", "chokidar": "~3.5.3", @@ -53,17 +53,17 @@ "tmp": "~0.2.1", "tree-kill": "~1.2.2", "update-notifier-cjs": "~5.1.6", - "ws": "~8.14.2" + "ws": "~8.15.0" }, "devDependencies": { "@architect/eslint-config": "~2.1.2", "@architect/functions": "~7.0.0", "@architect/req-res-fixtures": "git+https://github.com/architect/req-res-fixtures.git", - "@aws-lite/apigatewaymanagementapi": "~0.0.2", - "@aws-lite/ssm": "~0.2.0", + "@aws-lite/apigatewaymanagementapi": "~0.0.5", + "@aws-lite/ssm": "~0.2.1", "cross-env": "~7.0.3", - "eslint": "~8.54.0", - "fs-extra": "~11.1.1", + "eslint": "~8.55.0", + "fs-extra": "~11.2.0", "nyc": "~15.1.0", "pkg": "~5.8.1", "proxyquire": "~2.1.3", From 6f63669963ba8a5b57f7b3ba69f34104c2f4e93b Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Tue, 9 Jan 2024 10:22:10 -0800 Subject: [PATCH 08/20] Test matrix update: add Node.js 20.x / remove 14.x Update unit tests to deal with latest runtimes and runtime deprecations Update deps and changelog --- .github/workflows/binary-build.yml | 4 +- .github/workflows/build.yml | 2 +- changelog.md | 12 +++++ package.json | 22 ++++---- test/integration/http/http-test.js | 53 +++++++++++-------- test/integration/http/httpv1-test.js | 44 ++++++++------- test/integration/http/rest-test.js | 43 ++++++++------- test/mock/multi-handler/app.arc | 2 +- .../no-index-fail/src/http/get-foo/config.arc | 2 +- .../no-index-pass/src/http/get-foo/config.arc | 2 +- test/mock/normal/app.arc | 6 +-- .../config.arc | 4 +- .../index.js | 2 +- .../config.arc | 2 +- .../normal/src/http/get-python3_11/index.py | 12 +++++ .../normal/src/http/get-python3_7/index.py | 10 ---- .../normal/src/http/get-python3_8/index.py | 11 ++-- .../{get-ruby2_7 => get-ruby3_2}/config.arc | 4 +- .../{get-ruby2_7 => get-ruby3_2}/index.rb | 2 +- .../src/http/get-index/config.arc | 2 +- .../src/http/get-000param-there/config.arc | 2 +- .../src/http/get-000param/config.arc | 2 +- test/unit/src/invoke-lambda/index-test.js | 34 ++++++------ .../check-runtimes/version-check-test.js | 20 +++---- 24 files changed, 167 insertions(+), 132 deletions(-) rename test/mock/normal/src/http/{get-nodejs14_x => get-nodejs20_x}/config.arc (53%) rename test/mock/normal/src/http/{get-nodejs14_x => get-nodejs20_x}/index.js (74%) rename test/mock/normal/src/http/{get-python3_7 => get-python3_11}/config.arc (70%) create mode 100644 test/mock/normal/src/http/get-python3_11/index.py delete mode 100644 test/mock/normal/src/http/get-python3_7/index.py rename test/mock/normal/src/http/{get-ruby2_7 => get-ruby3_2}/config.arc (56%) rename test/mock/normal/src/http/{get-ruby2_7 => get-ruby3_2}/index.rb (84%) diff --git a/.github/workflows/binary-build.yml b/.github/workflows/binary-build.yml index b86aa5c3..c1a8d8f7 100644 --- a/.github/workflows/binary-build.yml +++ b/.github/workflows/binary-build.yml @@ -15,7 +15,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - node-version: [ 14.x ] + node-version: [ 16.x ] os: [ windows-latest, ubuntu-latest, macOS-latest ] # Go @@ -37,7 +37,7 @@ jobs: - name: Set up Ruby uses: ruby/setup-ruby@v1 with: - ruby-version: '2.7' + ruby-version: '3.2' - name: Set up Deno uses: denolib/setup-deno@v2 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1196b92a..31321158 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - node-version: [ 14.x, 16.x, 18.x ] + node-version: [ 16.x, 18.x, 20.x ] os: [ windows-latest, ubuntu-latest, macOS-latest ] # Go diff --git a/changelog.md b/changelog.md index cc5da2e5..6efb3319 100644 --- a/changelog.md +++ b/changelog.md @@ -2,6 +2,18 @@ --- +## [6.0.0] 2024-01-09 + +### Changed + +- Transitioned from `aws-sdk` to [`aws-lite`](https://aws-lite.org) +- Breaking change: Sandbox no longer includes `aws-sdk` + `@aws-sdk/*` as dependencies; projects that rely on the AWS SDK should install those dependencies to their project directly +- Added Node.js 20.x to test matrix +- Breaking change: removed support for Node.js 14.x (now EOL, and no longer available to created in AWS Lambda) +- Updated dependencies + +--- + ## [5.9.4] 2023-11-20 ### Changed diff --git a/package.json b/package.json index 8304e621..7480d985 100644 --- a/package.json +++ b/package.json @@ -28,13 +28,13 @@ "src/*" ], "dependencies": { - "@architect/asap": "~6.1.0-RC.0", - "@architect/create": "~4.2.4", + "@architect/asap": "~7.0.0-RC.0", + "@architect/create": "~5.0.0-RC.0", "@architect/hydrate": "~3.5.1", - "@architect/inventory": "~3.6.5", - "@architect/utils": "~4.0.0-RC.1", - "@aws-lite/client": "~0.12.2", - "@aws-lite/dynamodb": "~0.3.0", + "@architect/inventory": "~4.0.0-RC.0", + "@architect/utils": "~4.0.0-RC.2", + "@aws-lite/client": "~0.13.4", + "@aws-lite/dynamodb": "~0.3.1", "@begin/hashid": "~1.0.0", "chalk": "4.1.2", "chokidar": "~3.5.3", @@ -43,7 +43,7 @@ "finalhandler": "~1.2.0", "glob": "~10.3.10", "http-proxy": "~1.18.1", - "lambda-runtimes": "~1.1.6", + "lambda-runtimes": "~1.1.7", "minimist": "~1.2.8", "router": "~1.3.8", "run-parallel": "~1.2.0", @@ -53,16 +53,16 @@ "tmp": "~0.2.1", "tree-kill": "~1.2.2", "update-notifier-cjs": "~5.1.6", - "ws": "~8.15.0" + "ws": "~8.16.0" }, "devDependencies": { "@architect/eslint-config": "~2.1.2", "@architect/functions": "~7.0.0", "@architect/req-res-fixtures": "git+https://github.com/architect/req-res-fixtures.git", - "@aws-lite/apigatewaymanagementapi": "~0.0.5", - "@aws-lite/ssm": "~0.2.1", + "@aws-lite/apigatewaymanagementapi": "~0.0.6", + "@aws-lite/ssm": "~0.2.2", "cross-env": "~7.0.3", - "eslint": "~8.55.0", + "eslint": "~8.56.0", "fs-extra": "~11.2.0", "nyc": "~15.1.0", "pkg": "~5.8.1", diff --git a/test/integration/http/http-test.js b/test/integration/http/http-test.js index 4dd4a8e5..2992e638 100644 --- a/test/integration/http/http-test.js +++ b/test/integration/http/http-test.js @@ -166,17 +166,17 @@ function runTests (runType, t) { }) }) - t.test(`${mode} get /nodejs18.x`, t => { + t.test(`${mode} get /nodejs20.x`, t => { t.plan(15) - let rawPath = '/nodejs18.x' + let rawPath = '/nodejs20.x' tiny.get({ url: url + rawPath }, function _got (err, result) { if (err) t.end(err) else { checkResult(t, result.body, { - message: 'Hello from get /nodejs18.x (running nodejs18.x)', - routeKey: 'GET /nodejs18.x', + message: 'Hello from get /nodejs20.x (running nodejs20.x)', + routeKey: 'GET /nodejs20.x', rawPath, pathParameters: undefined, cookies: undefined, @@ -190,17 +190,17 @@ function runTests (runType, t) { }) }) - t.test(`${mode} get /nodejs14.x`, t => { + t.test(`${mode} get /nodejs18.x`, t => { t.plan(15) - let rawPath = '/nodejs14.x' + let rawPath = '/nodejs18.x' tiny.get({ url: url + rawPath }, function _got (err, result) { if (err) t.end(err) else { checkResult(t, result.body, { - message: 'Hello from get /nodejs14.x (running nodejs14.x)', - routeKey: 'GET /nodejs14.x', + message: 'Hello from get /nodejs18.x (running nodejs18.x)', + routeKey: 'GET /nodejs18.x', rawPath, pathParameters: undefined, cookies: undefined, @@ -238,9 +238,9 @@ function runTests (runType, t) { }) }) - t.test(`${mode} get /python3.8`, t => { + t.test(`${mode} get /python3.11`, t => { t.plan(16) - let rawPath = '/python3.8' + let rawPath = '/python3.11' tiny.get({ url: url + rawPath }, function _got (err, result) { @@ -248,8 +248,8 @@ function runTests (runType, t) { else if (err) t.end(err) else { checkResult(t, result.body, { - message: 'Hello from get /python3.8 (running python3.8)', - routeKey: 'GET /python3.8', + message: 'Hello from get /python3.11 (running python3.11)', + routeKey: 'GET /python3.11', rawPath, pathParameters: undefined, cookies: undefined, @@ -260,7 +260,7 @@ function runTests (runType, t) { body: undefined, context: { aws_request_id: true, // Just check for presence - function_name: 'sandbox-get-python3_8', + function_name: 'sandbox-get-python3_11', function_version: '$LATEST', invoked_function_arn: 'sandbox', memory_limit_in_mb: 1152, @@ -270,9 +270,9 @@ function runTests (runType, t) { }) }) - t.test(`${mode} get /python3.7`, t => { - t.plan(15) - let rawPath = '/python3.7' + t.test(`${mode} get /python3.8`, t => { + t.plan(16) + let rawPath = '/python3.8' tiny.get({ url: url + rawPath }, function _got (err, result) { @@ -280,8 +280,8 @@ function runTests (runType, t) { else if (err) t.end(err) else { checkResult(t, result.body, { - message: 'Hello from get /python3.7 (running python3.7)', - routeKey: 'GET /python3.7', + message: 'Hello from get /python3.8 (running python3.8)', + routeKey: 'GET /python3.8', rawPath, pathParameters: undefined, cookies: undefined, @@ -290,22 +290,29 @@ function runTests (runType, t) { headers: '🤷🏽‍♀️', isBase64Encoded: false, body: undefined, + context: { + aws_request_id: true, // Just check for presence + function_name: 'sandbox-get-python3_8', + function_version: '$LATEST', + invoked_function_arn: 'sandbox', + memory_limit_in_mb: 1152, + } }) } }) }) - t.test(`${mode} get /ruby2.7`, t => { + t.test(`${mode} get /ruby3.2`, t => { t.plan(16) - let rawPath = '/ruby2.7' + let rawPath = '/ruby3.2' tiny.get({ url: url + rawPath }, function _got (err, result) { if (err) t.end(err) else { checkResult(t, result.body, { - message: 'Hello from get /ruby2.7 (running ruby2.7)', - routeKey: 'GET /ruby2.7', + message: 'Hello from get /ruby3.2 (running ruby3.2)', + routeKey: 'GET /ruby3.2', rawPath, pathParameters: undefined, cookies: undefined, @@ -316,7 +323,7 @@ function runTests (runType, t) { body: undefined, context: { aws_request_id: true, // Just check for presence - function_name: 'sandbox-get-ruby2_7', + function_name: 'sandbox-get-ruby3_2', function_version: '$LATEST', invoked_function_arn: 'sandbox', memory_limit_in_mb: 1152, diff --git a/test/integration/http/httpv1-test.js b/test/integration/http/httpv1-test.js index ac3a2eb5..36cf57f6 100644 --- a/test/integration/http/httpv1-test.js +++ b/test/integration/http/httpv1-test.js @@ -128,16 +128,16 @@ function runTests (runType, t) { }) }) - t.test(`${mode} get /nodejs18.x`, t => { + t.test(`${mode} get /nodejs20.x`, t => { t.plan(16) - let path = '/nodejs18.x' + let path = '/nodejs20.x' tiny.get({ url: url + path }, function _got (err, result) { if (err) t.end(err) else { checkResult(t, result.body, { - message: 'Hello from get /nodejs18.x (running nodejs18.x)', + message: 'Hello from get /nodejs20.x (running nodejs20.x)', resource: path, path, httpMethod: 'GET', @@ -153,16 +153,16 @@ function runTests (runType, t) { }) }) - t.test(`${mode} get /nodejs14.x`, t => { + t.test(`${mode} get /nodejs18.x`, t => { t.plan(16) - let path = '/nodejs14.x' + let path = '/nodejs18.x' tiny.get({ url: url + path }, function _got (err, result) { if (err) t.end(err) else { checkResult(t, result.body, { - message: 'Hello from get /nodejs14.x (running nodejs14.x)', + message: 'Hello from get /nodejs18.x (running nodejs18.x)', resource: path, path, httpMethod: 'GET', @@ -203,9 +203,9 @@ function runTests (runType, t) { }) }) - t.test(`${mode} get /python3.8`, t => { + t.test(`${mode} get /python3.11`, t => { t.plan(17) - let path = '/python3.8' + let path = '/python3.11' tiny.get({ url: url + path }, function _got (err, result) { @@ -213,7 +213,7 @@ function runTests (runType, t) { else if (err) t.end(err) else { checkResult(t, result.body, { - message: 'Hello from get /python3.8 (running python3.8)', + message: 'Hello from get /python3.11 (running python3.11)', resource: path, path, httpMethod: 'GET', @@ -226,7 +226,7 @@ function runTests (runType, t) { isBase64Encoded: false, context: { aws_request_id: true, // Just check for presence - function_name: 'sandbox-get-python3_8', + function_name: 'sandbox-get-python3_11', function_version: '$LATEST', invoked_function_arn: 'sandbox', memory_limit_in_mb: 1152, @@ -235,10 +235,9 @@ function runTests (runType, t) { } }) }) - - t.test(`${mode} get /python3.7`, t => { - t.plan(16) - let path = '/python3.7' + t.test(`${mode} get /python3.8`, t => { + t.plan(17) + let path = '/python3.8' tiny.get({ url: url + path }, function _got (err, result) { @@ -246,7 +245,7 @@ function runTests (runType, t) { else if (err) t.end(err) else { checkResult(t, result.body, { - message: 'Hello from get /python3.7 (running python3.7)', + message: 'Hello from get /python3.8 (running python3.8)', resource: path, path, httpMethod: 'GET', @@ -257,21 +256,28 @@ function runTests (runType, t) { pathParameters: null, body: null, isBase64Encoded: false, + context: { + aws_request_id: true, // Just check for presence + function_name: 'sandbox-get-python3_8', + function_version: '$LATEST', + invoked_function_arn: 'sandbox', + memory_limit_in_mb: 1152, + } }) } }) }) - t.test(`${mode} get /ruby2.7`, t => { + t.test(`${mode} get /ruby3.2`, t => { t.plan(17) - let path = '/ruby2.7' + let path = '/ruby3.2' tiny.get({ url: url + path }, function _got (err, result) { if (err) t.end(err) else { checkResult(t, result.body, { - message: 'Hello from get /ruby2.7 (running ruby2.7)', + message: 'Hello from get /ruby3.2 (running ruby3.2)', resource: path, path, httpMethod: 'GET', @@ -284,7 +290,7 @@ function runTests (runType, t) { isBase64Encoded: false, context: { aws_request_id: true, // Just check for presence - function_name: 'sandbox-get-ruby2_7', + function_name: 'sandbox-get-ruby3_2', function_version: '$LATEST', invoked_function_arn: 'sandbox', memory_limit_in_mb: 1152, diff --git a/test/integration/http/rest-test.js b/test/integration/http/rest-test.js index 747f0006..149bf9c6 100644 --- a/test/integration/http/rest-test.js +++ b/test/integration/http/rest-test.js @@ -128,16 +128,16 @@ function runTests (runType) { }) }) - test(`${mode} get /nodejs18.x`, t => { + test(`${mode} get /nodejs20.x`, t => { t.plan(16) - let path = '/nodejs18.x' + let path = '/nodejs20.x' tiny.get({ url: url + path }, function _got (err, result) { if (err) t.end(err) else { checkResult(t, result.body, { - message: 'Hello from get /nodejs18.x (running nodejs18.x)', + message: 'Hello from get /nodejs20.x (running nodejs20.x)', resource: path, path, httpMethod: 'GET', @@ -153,16 +153,16 @@ function runTests (runType) { }) }) - test(`${mode} get /nodejs14.x`, t => { + test(`${mode} get /nodejs18.x`, t => { t.plan(16) - let path = '/nodejs14.x' + let path = '/nodejs18.x' tiny.get({ url: url + path }, function _got (err, result) { if (err) t.end(err) else { checkResult(t, result.body, { - message: 'Hello from get /nodejs14.x (running nodejs14.x)', + message: 'Hello from get /nodejs18.x (running nodejs18.x)', resource: path, path, httpMethod: 'GET', @@ -178,9 +178,9 @@ function runTests (runType) { }) }) - test(`${mode} get /python3.8`, t => { + test(`${mode} get /python3.11`, t => { t.plan(17) - let path = '/python3.8' + let path = '/python3.11' tiny.get({ url: url + path }, function _got (err, result) { @@ -188,7 +188,7 @@ function runTests (runType) { else if (err) t.end(err) else { checkResult(t, result.body, { - message: 'Hello from get /python3.8 (running python3.8)', + message: 'Hello from get /python3.11 (running python3.11)', resource: path, path, httpMethod: 'GET', @@ -201,7 +201,7 @@ function runTests (runType) { isBase64Encoded: false, context: { aws_request_id: true, // Just check for presence - function_name: 'sandbox-get-python3_8', + function_name: 'sandbox-get-python3_11', function_version: '$LATEST', invoked_function_arn: 'sandbox', memory_limit_in_mb: 1152, @@ -211,9 +211,9 @@ function runTests (runType) { }) }) - test(`${mode} get /python3.7`, t => { - t.plan(16) - let path = '/python3.7' + test(`${mode} get /python3.8`, t => { + t.plan(17) + let path = '/python3.8' tiny.get({ url: url + path }, function _got (err, result) { @@ -221,7 +221,7 @@ function runTests (runType) { else if (err) t.end(err) else { checkResult(t, result.body, { - message: 'Hello from get /python3.7 (running python3.7)', + message: 'Hello from get /python3.8 (running python3.8)', resource: path, path, httpMethod: 'GET', @@ -232,21 +232,28 @@ function runTests (runType) { pathParameters: null, body: null, isBase64Encoded: false, + context: { + aws_request_id: true, // Just check for presence + function_name: 'sandbox-get-python3_8', + function_version: '$LATEST', + invoked_function_arn: 'sandbox', + memory_limit_in_mb: 1152, + } }) } }) }) - test(`${mode} get /ruby2.7`, t => { + test(`${mode} get /ruby3.2`, t => { t.plan(17) - let path = '/ruby2.7' + let path = '/ruby3.2' tiny.get({ url: url + path }, function _got (err, result) { if (err) t.end(err) else { checkResult(t, result.body, { - message: 'Hello from get /ruby2.7 (running ruby2.7)', + message: 'Hello from get /ruby3.2 (running ruby3.2)', resource: path, path, httpMethod: 'GET', @@ -259,7 +266,7 @@ function runTests (runType) { isBase64Encoded: false, context: { aws_request_id: true, // Just check for presence - function_name: 'sandbox-get-ruby2_7', + function_name: 'sandbox-get-ruby3_2', function_version: '$LATEST', invoked_function_arn: 'sandbox', memory_limit_in_mb: 1152, diff --git a/test/mock/multi-handler/app.arc b/test/mock/multi-handler/app.arc index bc0fc06f..11b9f157 100644 --- a/test/mock/multi-handler/app.arc +++ b/test/mock/multi-handler/app.arc @@ -17,4 +17,4 @@ get /node/esm/index.js get /node/esm/index.mjs @arc -runtime nodejs14.x # The Deno functions have config files +runtime nodejs20.x # The Deno functions have config files diff --git a/test/mock/no-index-fail/src/http/get-foo/config.arc b/test/mock/no-index-fail/src/http/get-foo/config.arc index daf73a48..d9c37445 100644 --- a/test/mock/no-index-fail/src/http/get-foo/config.arc +++ b/test/mock/no-index-fail/src/http/get-foo/config.arc @@ -1,5 +1,5 @@ @aws -runtime nodejs14.x +runtime nodejs18.x # timeout 30 # concurrency 1 # memory 1152 diff --git a/test/mock/no-index-pass/src/http/get-foo/config.arc b/test/mock/no-index-pass/src/http/get-foo/config.arc index daf73a48..d9c37445 100644 --- a/test/mock/no-index-pass/src/http/get-foo/config.arc +++ b/test/mock/no-index-pass/src/http/get-foo/config.arc @@ -1,5 +1,5 @@ @aws -runtime nodejs14.x +runtime nodejs18.x # timeout 30 # concurrency 1 # memory 1152 diff --git a/test/mock/normal/app.arc b/test/mock/normal/app.arc index 9e68b58e..f29f05ab 100644 --- a/test/mock/normal/app.arc +++ b/test/mock/normal/app.arc @@ -14,12 +14,12 @@ queue-custom @http get / # runs default # Runtimes +get /nodejs20.x get /nodejs18.x -get /nodejs14.x get /node-esm +get /python3.11 get /python3.8 -get /python3.7 -get /ruby2.7 +get /ruby3.2 get /deno # Path get /get-p-c/:param/* diff --git a/test/mock/normal/src/http/get-nodejs14_x/config.arc b/test/mock/normal/src/http/get-nodejs20_x/config.arc similarity index 53% rename from test/mock/normal/src/http/get-nodejs14_x/config.arc rename to test/mock/normal/src/http/get-nodejs20_x/config.arc index c0c1cc8a..14a23854 100644 --- a/test/mock/normal/src/http/get-nodejs14_x/config.arc +++ b/test/mock/normal/src/http/get-nodejs20_x/config.arc @@ -1,5 +1,5 @@ @aws -runtime nodejs14.x -timeout 14 +runtime nodejs20.x +timeout 20 # concurrency 1 # memory 1152 diff --git a/test/mock/normal/src/http/get-nodejs14_x/index.js b/test/mock/normal/src/http/get-nodejs20_x/index.js similarity index 74% rename from test/mock/normal/src/http/get-nodejs14_x/index.js rename to test/mock/normal/src/http/get-nodejs20_x/index.js index 4209ebbd..dcd01503 100644 --- a/test/mock/normal/src/http/get-nodejs14_x/index.js +++ b/test/mock/normal/src/http/get-nodejs20_x/index.js @@ -1,6 +1,6 @@ exports.handler = async (event) => { const body = event - body.message = 'Hello from get /nodejs14.x (running nodejs14.x)' + body.message = 'Hello from get /nodejs20.x (running nodejs20.x)' return { statusCode: 200, headers: { 'content-type': 'application/json' }, diff --git a/test/mock/normal/src/http/get-python3_7/config.arc b/test/mock/normal/src/http/get-python3_11/config.arc similarity index 70% rename from test/mock/normal/src/http/get-python3_7/config.arc rename to test/mock/normal/src/http/get-python3_11/config.arc index c327c640..74555153 100644 --- a/test/mock/normal/src/http/get-python3_7/config.arc +++ b/test/mock/normal/src/http/get-python3_11/config.arc @@ -1,5 +1,5 @@ @aws -runtime python3.7 +runtime python3.11 timeout 3 # concurrency 1 # memory 1152 diff --git a/test/mock/normal/src/http/get-python3_11/index.py b/test/mock/normal/src/http/get-python3_11/index.py new file mode 100644 index 00000000..46ddd552 --- /dev/null +++ b/test/mock/normal/src/http/get-python3_11/index.py @@ -0,0 +1,12 @@ +import json + + +def handler(event, context): + body = event + body["message"] = "Hello from get /python3.11 (running python3.11)" + body["context"] = context + return { + "statusCode": 200, + "headers": {"content-type": "application/json"}, + "body": json.dumps(body), + } diff --git a/test/mock/normal/src/http/get-python3_7/index.py b/test/mock/normal/src/http/get-python3_7/index.py deleted file mode 100644 index e8c771b9..00000000 --- a/test/mock/normal/src/http/get-python3_7/index.py +++ /dev/null @@ -1,10 +0,0 @@ -import json - -def handler(event, context): - body = event - body['message'] = 'Hello from get /python3.7 (running python3.7)' - return { - 'statusCode': 200, - 'headers': { 'content-type': 'application/json' }, - 'body': json.dumps(body) - } diff --git a/test/mock/normal/src/http/get-python3_8/index.py b/test/mock/normal/src/http/get-python3_8/index.py index e3a219cd..37a333e6 100644 --- a/test/mock/normal/src/http/get-python3_8/index.py +++ b/test/mock/normal/src/http/get-python3_8/index.py @@ -1,11 +1,12 @@ import json + def handler(event, context): body = event - body['message'] = 'Hello from get /python3.8 (running python3.8)' - body['context'] = context + body["message"] = "Hello from get /python3.8 (running python3.8)" + body["context"] = context return { - 'statusCode': 200, - 'headers': { 'content-type': 'application/json' }, - 'body': json.dumps(body) + "statusCode": 200, + "headers": {"content-type": "application/json"}, + "body": json.dumps(body), } diff --git a/test/mock/normal/src/http/get-ruby2_7/config.arc b/test/mock/normal/src/http/get-ruby3_2/config.arc similarity index 56% rename from test/mock/normal/src/http/get-ruby2_7/config.arc rename to test/mock/normal/src/http/get-ruby3_2/config.arc index da2f0742..8d915619 100644 --- a/test/mock/normal/src/http/get-ruby2_7/config.arc +++ b/test/mock/normal/src/http/get-ruby3_2/config.arc @@ -1,5 +1,5 @@ @aws -runtime ruby2.7 -timeout 25 +runtime ruby3.2 +timeout 32 # concurrency 1 # memory 1152 diff --git a/test/mock/normal/src/http/get-ruby2_7/index.rb b/test/mock/normal/src/http/get-ruby3_2/index.rb similarity index 84% rename from test/mock/normal/src/http/get-ruby2_7/index.rb rename to test/mock/normal/src/http/get-ruby3_2/index.rb index 951992be..49cd2bf5 100644 --- a/test/mock/normal/src/http/get-ruby2_7/index.rb +++ b/test/mock/normal/src/http/get-ruby3_2/index.rb @@ -4,7 +4,7 @@ def handler(event:, context:) body = event - body[:message] = 'Hello from get /ruby2.7 (running ruby2.7)' + body[:message] = 'Hello from get /ruby3.2 (running ruby3.2)' body[:context] = context { statusCode: 200, diff --git a/test/mock/root-handling/greedy-get-index/src/http/get-index/config.arc b/test/mock/root-handling/greedy-get-index/src/http/get-index/config.arc index 43b9c8df..164a9299 100644 --- a/test/mock/root-handling/greedy-get-index/src/http/get-index/config.arc +++ b/test/mock/root-handling/greedy-get-index/src/http/get-index/config.arc @@ -1,5 +1,5 @@ @aws -runtime nodejs14.x +runtime nodejs18.x timeout 10 # concurrency 1 # memory 1152 diff --git a/test/mock/root-handling/param-exact/src/http/get-000param-there/config.arc b/test/mock/root-handling/param-exact/src/http/get-000param-there/config.arc index 43b9c8df..164a9299 100644 --- a/test/mock/root-handling/param-exact/src/http/get-000param-there/config.arc +++ b/test/mock/root-handling/param-exact/src/http/get-000param-there/config.arc @@ -1,5 +1,5 @@ @aws -runtime nodejs14.x +runtime nodejs18.x timeout 10 # concurrency 1 # memory 1152 diff --git a/test/mock/root-handling/root-param/src/http/get-000param/config.arc b/test/mock/root-handling/root-param/src/http/get-000param/config.arc index 43b9c8df..164a9299 100644 --- a/test/mock/root-handling/root-param/src/http/get-000param/config.arc +++ b/test/mock/root-handling/root-param/src/http/get-000param/config.arc @@ -1,5 +1,5 @@ @aws -runtime nodejs14.x +runtime nodejs18.x timeout 10 # concurrency 1 # memory 1152 diff --git a/test/unit/src/invoke-lambda/index-test.js b/test/unit/src/invoke-lambda/index-test.js index ea4cd1de..5a88fbf5 100644 --- a/test/unit/src/invoke-lambda/index-test.js +++ b/test/unit/src/invoke-lambda/index-test.js @@ -72,6 +72,15 @@ test('Test runtime invocations', t => { t.deepEqual(result, event, 'Default runtime received event') }) + lambda = get.http('get /nodejs20.x') + invoke({ lambda, ...params }, (err, result) => { + if (err) t.end(err) + let { options, timeout } = execPassedParams + t.equals(options.cwd, lambda.src, 'nodejs20.x passed correct path') + t.equals(timeout, 20000, 'nodejs20.x ran with correct timeout') + t.deepEqual(result, event, 'nodejs20.x received event') + }) + lambda = get.http('get /nodejs18.x') invoke({ lambda, ...params }, (err, result) => { if (err) t.end(err) @@ -81,13 +90,13 @@ test('Test runtime invocations', t => { t.deepEqual(result, event, 'nodejs18.x received event') }) - lambda = get.http('get /nodejs14.x') + lambda = get.http('get /python3.11') invoke({ lambda, ...params }, (err, result) => { if (err) t.end(err) let { options, timeout } = execPassedParams - t.equals(options.cwd, lambda.src, 'nodejs14.x passed correct path') - t.equals(timeout, 14000, 'nodejs14.x ran with correct timeout') - t.deepEqual(result, event, 'nodejs14.x received event') + t.equals(options.cwd, lambda.src, 'python3.11 passed correct path') + t.equals(timeout, 3000, 'python3.11 ran with correct timeout') + t.deepEqual(result, event, 'python3.11 received event') }) lambda = get.http('get /python3.8') @@ -99,22 +108,13 @@ test('Test runtime invocations', t => { t.deepEqual(result, event, 'python3.8 received event') }) - lambda = get.http('get /python3.7') - invoke({ lambda, ...params }, (err, result) => { - if (err) t.end(err) - let { options, timeout } = execPassedParams - t.equals(options.cwd, lambda.src, 'python3.7 passed correct path') - t.equals(timeout, 3000, 'python3.7 ran with correct timeout') - t.deepEqual(result, event, 'python3.7 received event') - }) - - lambda = get.http('get /ruby2.7') + lambda = get.http('get /ruby3.2') invoke({ lambda, ...params }, (err, result) => { if (err) t.end(err) let { options, timeout } = execPassedParams - t.equals(options.cwd, lambda.src, 'ruby2.7 passed correct path') - t.equals(timeout, 25000, 'ruby2.7 ran with correct timeout') - t.deepEqual(result, event, 'ruby2.7 received event') + t.equals(options.cwd, lambda.src, 'ruby3.2 passed correct path') + t.equals(timeout, 32000, 'ruby3.2 ran with correct timeout') + t.deepEqual(result, event, 'ruby3.2 received event') }) lambda = get.http('get /deno') diff --git a/test/unit/src/sandbox/check-runtimes/version-check-test.js b/test/unit/src/sandbox/check-runtimes/version-check-test.js index f2953436..940652e3 100644 --- a/test/unit/src/sandbox/check-runtimes/version-check-test.js +++ b/test/unit/src/sandbox/check-runtimes/version-check-test.js @@ -86,7 +86,7 @@ test('Project global runtime config', async t => { t.ok(result[1].includes('aliased to ruby'), 'Reported issue with alias') // Minor - rawArc = basic + '\n@aws\nruntime ruby2.7' + rawArc = basic + '\n@aws\nruntime ruby3.2' inventory = await _inventory({ rawArc }) localRuntimes = { ruby: '2.6.0' } result = versionCheck({ cwd, inventory, localRuntimes }) @@ -94,7 +94,7 @@ test('Project global runtime config', async t => { t.ok(result[1].includes('Project global runtime'), 'Reported issue with project global runtime') // Major - rawArc = basic + '\n@aws\nruntime ruby2.7' + rawArc = basic + '\n@aws\nruntime ruby3.2' inventory = await _inventory({ rawArc }) localRuntimes = { ruby: '1.7.0' } result = versionCheck({ cwd, inventory, localRuntimes }) @@ -114,15 +114,15 @@ test('Per-Lambda runtime config', async t => { t.notOk(result, 'Control: no runtime configuration did not return any issues') inventory = await _inventory({ rawArc }) - inventory.inv.http[0].config.runtime = 'nodejs14.x' - localRuntimes = { node: '16.0.0' } + inventory.inv.http[0].config.runtime = 'nodejs18.x' + localRuntimes = { node: '20.0.0' } result = versionCheck({ cwd, inventory, localRuntimes }) t.notOk(result, 'Control: compatible runtime configuration did not return any issues') // Minor inventory = await _inventory({ rawArc }) - inventory.inv.http[0].config.runtime = 'nodejs14.x' - localRuntimes = { node: '14.1.0' } + inventory.inv.http[0].config.runtime = 'nodejs18.x' + localRuntimes = { node: '18.1.0' } result = versionCheck({ cwd, inventory, localRuntimes }) t.notOk(result, 'Compatible runtime configuration did not return any issues') @@ -152,17 +152,17 @@ test('Per-Lambda runtime config', async t => { // Minor inventory = await _inventory({ rawArc }) - inventory.inv.http[0].config.runtime = 'ruby2.7' + inventory.inv.http[0].config.runtime = 'ruby3.2' localRuntimes = { ruby: '2.6.0' } result = versionCheck({ cwd, inventory, localRuntimes }) console.log(result[1]) - t.ok(result[1].includes('ruby2.7'), 'Reported issue with Lambda runtime') + t.ok(result[1].includes('ruby3.2'), 'Reported issue with Lambda runtime') // Major inventory = await _inventory({ rawArc }) - inventory.inv.http[0].config.runtime = 'ruby2.7' + inventory.inv.http[0].config.runtime = 'ruby3.2' localRuntimes = { ruby: '1.7.0' } result = versionCheck({ cwd, inventory, localRuntimes }) console.log(result[1]) - t.ok(result[1].includes('ruby2.7'), 'Reported issue with Lambda runtime') + t.ok(result[1].includes('ruby3.2'), 'Reported issue with Lambda runtime') }) From 7e84da10ce112f81874fa8d6bf2b702b3d0af9a9 Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Tue, 9 Jan 2024 10:31:59 -0800 Subject: [PATCH 09/20] 6.0.0-RC.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 7480d985..77d1c104 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@architect/sandbox", - "version": "5.9.4", + "version": "6.0.0-RC.0", "description": "Architect dev server: run full Architect projects locally & offline", "main": "src/index.js", "scripts": { From 0975e433bc3475d663de61d36ff9e84043d3c913 Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Tue, 23 Jan 2024 18:46:22 -0800 Subject: [PATCH 10/20] Update CI --- .github/workflows/binary-build.yml | 2 +- .github/workflows/build.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/binary-build.yml b/.github/workflows/binary-build.yml index c1a8d8f7..0901f7e6 100644 --- a/.github/workflows/binary-build.yml +++ b/.github/workflows/binary-build.yml @@ -74,7 +74,7 @@ jobs: - name: Notify uses: sarisia/actions-status-discord@v1 # Only fire alert once - if: github.ref == 'refs/heads/main' && failure() && matrix.node-version == '14.x' && matrix.os == 'ubuntu-latest' + if: github.ref == 'refs/heads/main' && failure() && matrix.node-version == '20.x' && matrix.os == 'ubuntu-latest' with: webhook: ${{ secrets.DISCORD_WEBHOOK }} title: "build and test" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 31321158..ae357569 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -68,7 +68,7 @@ jobs: - name: Notify uses: sarisia/actions-status-discord@v1 # Only fire alert once - if: github.ref == 'refs/heads/main' && failure() && matrix.node-version == '14.x' && matrix.os == 'ubuntu-latest' + if: github.ref == 'refs/heads/main' && failure() && matrix.node-version == '20.x' && matrix.os == 'ubuntu-latest' with: webhook: ${{ secrets.DISCORD_WEBHOOK }} title: "build and test" @@ -92,7 +92,7 @@ jobs: - name: Set up Node.js uses: actions/setup-node@v3 with: - node-version: 16 + node-version: lts/* registry-url: https://registry.npmjs.org/ # Publish to npm From 9418f97f60bc0e53c4e1dd67597065a11b48b17b Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Wed, 24 Jan 2024 08:11:09 -0800 Subject: [PATCH 11/20] Update deps and changelog --- changelog.md | 3 ++- package.json | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/changelog.md b/changelog.md index 6efb3319..dd39341c 100644 --- a/changelog.md +++ b/changelog.md @@ -8,8 +8,9 @@ - Transitioned from `aws-sdk` to [`aws-lite`](https://aws-lite.org) - Breaking change: Sandbox no longer includes `aws-sdk` + `@aws-sdk/*` as dependencies; projects that rely on the AWS SDK should install those dependencies to their project directly -- Added Node.js 20.x to test matrix +- Breaking change: `nodejs20.x` and `python3.12` are now the default Node.js and Python Lambda runtimes, respectively - Breaking change: removed support for Node.js 14.x (now EOL, and no longer available to created in AWS Lambda) +- Added Node.js 20.x to test matrix - Updated dependencies --- diff --git a/package.json b/package.json index 77d1c104..876684c9 100644 --- a/package.json +++ b/package.json @@ -28,12 +28,12 @@ "src/*" ], "dependencies": { - "@architect/asap": "~7.0.0-RC.0", - "@architect/create": "~5.0.0-RC.0", - "@architect/hydrate": "~3.5.1", - "@architect/inventory": "~4.0.0-RC.0", - "@architect/utils": "~4.0.0-RC.2", - "@aws-lite/client": "~0.13.4", + "@architect/asap": "~7.0.0-RC.1", + "@architect/create": "~5.0.0-RC.1", + "@architect/hydrate": "~4.0.0-RC.1", + "@architect/inventory": "~4.0.0-RC.2", + "@architect/utils": "~4.0.0-RC.3", + "@aws-lite/client": "~0.14.2", "@aws-lite/dynamodb": "~0.3.1", "@begin/hashid": "~1.0.0", "chalk": "4.1.2", @@ -43,7 +43,7 @@ "finalhandler": "~1.2.0", "glob": "~10.3.10", "http-proxy": "~1.18.1", - "lambda-runtimes": "~1.1.7", + "lambda-runtimes": "~2.0.0", "minimist": "~1.2.8", "router": "~1.3.8", "run-parallel": "~1.2.0", @@ -68,7 +68,7 @@ "pkg": "~5.8.1", "proxyquire": "~2.1.3", "tap-arc": "~1.2.2", - "tape": "~5.7.2", + "tape": "~5.7.3", "tiny-json-http": "~7.5.1" }, "eslintConfig": { From 78f2f95eeebe2244b0d22ae59bc9ee80dcd948bf Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Wed, 24 Jan 2024 08:14:04 -0800 Subject: [PATCH 12/20] Update tests for `nodejs20.x` default --- test/unit/src/sandbox/check-runtimes/version-check-test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/unit/src/sandbox/check-runtimes/version-check-test.js b/test/unit/src/sandbox/check-runtimes/version-check-test.js index 940652e3..1354b429 100644 --- a/test/unit/src/sandbox/check-runtimes/version-check-test.js +++ b/test/unit/src/sandbox/check-runtimes/version-check-test.js @@ -17,13 +17,13 @@ test('Project global runtime config', async t => { rawArc = basic inventory = await _inventory({ rawArc }) - localRuntimes = { node: '16.0.0' } + localRuntimes = { node: '20.0.0' } result = versionCheck({ cwd, inventory, localRuntimes }) t.notOk(result, 'Control: no runtime configuration did not return any issues') rawArc = basic + '\n@aws\nruntime node' inventory = await _inventory({ rawArc }) - localRuntimes = { node: '16.0.0' } + localRuntimes = { node: '20.0.0' } result = versionCheck({ cwd, inventory, localRuntimes }) t.notOk(result, 'Control: compatible runtime configuration did not return any issues') @@ -109,7 +109,7 @@ test('Per-Lambda runtime config', async t => { rawArc = basic inventory = await _inventory({ rawArc }) - localRuntimes = { node: '16.0.0' } + localRuntimes = { node: '20.0.0' } result = versionCheck({ cwd, inventory, localRuntimes }) t.notOk(result, 'Control: no runtime configuration did not return any issues') From 69bdbc5823333831a945256f3db5ca564a9681b8 Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Wed, 24 Jan 2024 08:14:07 -0800 Subject: [PATCH 13/20] 6.0.0-RC.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 876684c9..d060bf74 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@architect/sandbox", - "version": "6.0.0-RC.0", + "version": "6.0.0-RC.1", "description": "Architect dev server: run full Architect projects locally & offline", "main": "src/index.js", "scripts": { From 470583dd28d3b37c65c171d5f1cd88eb80f16319 Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Mon, 29 Jan 2024 13:25:27 -0800 Subject: [PATCH 14/20] Move calls to new `aws-lite` `endpoint` param Update deps --- package.json | 8 ++++---- src/tables/_get-db-client.js | 4 +--- test/integration/arc/ssm-test.js | 5 +---- 3 files changed, 6 insertions(+), 11 deletions(-) diff --git a/package.json b/package.json index d060bf74..57095241 100644 --- a/package.json +++ b/package.json @@ -33,8 +33,8 @@ "@architect/hydrate": "~4.0.0-RC.1", "@architect/inventory": "~4.0.0-RC.2", "@architect/utils": "~4.0.0-RC.3", - "@aws-lite/client": "~0.14.2", - "@aws-lite/dynamodb": "~0.3.1", + "@aws-lite/client": "~0.15.0", + "@aws-lite/dynamodb": "~0.3.3", "@begin/hashid": "~1.0.0", "chalk": "4.1.2", "chokidar": "~3.5.3", @@ -59,7 +59,7 @@ "@architect/eslint-config": "~2.1.2", "@architect/functions": "~7.0.0", "@architect/req-res-fixtures": "git+https://github.com/architect/req-res-fixtures.git", - "@aws-lite/apigatewaymanagementapi": "~0.0.6", + "@aws-lite/apigatewaymanagementapi": "~0.0.7", "@aws-lite/ssm": "~0.2.2", "cross-env": "~7.0.3", "eslint": "~8.56.0", @@ -68,7 +68,7 @@ "pkg": "~5.8.1", "proxyquire": "~2.1.3", "tap-arc": "~1.2.2", - "tape": "~5.7.3", + "tape": "~5.7.4", "tiny-json-http": "~7.5.1" }, "eslintConfig": { diff --git a/src/tables/_get-db-client.js b/src/tables/_get-db-client.js index 0eafb7a1..8627da80 100644 --- a/src/tables/_get-db-client.js +++ b/src/tables/_get-db-client.js @@ -10,10 +10,8 @@ module.exports = function initDynamoClient ({ creds, ports }, callback) { ] let config = { autoloadPlugins: false, - host: 'localhost', + endpoint: `http://localhost:${ports.tables}`, plugins, - port: ports.tables, - protocol: 'http', region: process.env.AWS_REGION || 'us-west-2', ...creds, } diff --git a/test/integration/arc/ssm-test.js b/test/integration/arc/ssm-test.js index e774043f..d4301076 100644 --- a/test/integration/arc/ssm-test.js +++ b/test/integration/arc/ssm-test.js @@ -29,10 +29,7 @@ test('Set up env', async t => { t.ok(sandbox, 'Got Sandbox') let aws = await awsLite({ ...credentials, - endpointPrefix: '/_arc/ssm', - host: 'localhost', - port: _arcPort, - protocol: 'http', + endpoint: `http://localhost:${_arcPort}/_arc/ssm`, region: 'us-west-2', }) ssm = aws.SSM From 8f189c5e87a738e1e73efcbc5cbabf613370139c Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Mon, 29 Jan 2024 13:25:32 -0800 Subject: [PATCH 15/20] 6.0.0-RC.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 57095241..b2454cb5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@architect/sandbox", - "version": "6.0.0-RC.1", + "version": "6.0.0-RC.2", "description": "Architect dev server: run full Architect projects locally & offline", "main": "src/index.js", "scripts": { From 6d0399253f4acb858eaceede2957f08ef995d378 Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Wed, 31 Jan 2024 08:35:07 -0800 Subject: [PATCH 16/20] Update deps --- package.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index b2454cb5..ce274f82 100644 --- a/package.json +++ b/package.json @@ -28,13 +28,13 @@ "src/*" ], "dependencies": { - "@architect/asap": "~7.0.0-RC.1", - "@architect/create": "~5.0.0-RC.1", + "@architect/asap": "~7.0.0-RC.2", + "@architect/create": "~5.0.0-RC.2", "@architect/hydrate": "~4.0.0-RC.1", - "@architect/inventory": "~4.0.0-RC.2", - "@architect/utils": "~4.0.0-RC.3", - "@aws-lite/client": "~0.15.0", - "@aws-lite/dynamodb": "~0.3.3", + "@architect/inventory": "~4.0.0-RC.3", + "@architect/utils": "~4.0.0-RC.4", + "@aws-lite/client": "^0.15.1", + "@aws-lite/dynamodb": "^0.3.3", "@begin/hashid": "~1.0.0", "chalk": "4.1.2", "chokidar": "~3.5.3", From 231cd4b46199f682daf6891b3e661b5f7ab50fb7 Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Wed, 31 Jan 2024 08:35:46 -0800 Subject: [PATCH 17/20] 6.0.0-RC.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ce274f82..a3d0d4c2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@architect/sandbox", - "version": "6.0.0-RC.2", + "version": "6.0.0-RC.3", "description": "Architect dev server: run full Architect projects locally & offline", "main": "src/index.js", "scripts": { From 4516d01989720d0ab43fca9c01f90b3c1c8eb60b Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Thu, 1 Feb 2024 11:59:30 -0800 Subject: [PATCH 18/20] Fix aws-lite profile selection --- src/sandbox/creds.js | 2 +- src/sandbox/seed.js | 2 +- src/tables/_get-db-client.js | 5 +++-- src/tables/_init.js | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/sandbox/creds.js b/src/sandbox/creds.js index 1a4df1c0..2ffcf78e 100644 --- a/src/sandbox/creds.js +++ b/src/sandbox/creds.js @@ -4,7 +4,7 @@ module.exports = function loadCreds (params, callback) { awsLite({ autoloadPlugins: false, profile: inventory.inv?.aws?.profile, - region: 'us-west-1', + region: 'us-west-1', // Region doesn't matter, we just need to get creds }) .then(aws => { params.creds = { diff --git a/src/sandbox/seed.js b/src/sandbox/seed.js index b5f2d8db..770f9b59 100644 --- a/src/sandbox/seed.js +++ b/src/sandbox/seed.js @@ -54,7 +54,7 @@ module.exports = function startupSeedData (params, callback) { }) }).filter(Boolean) - getDBClient({ creds, ports }, (err, aws) => { + getDBClient({ creds, inventory, ports }, (err, aws) => { if (err) callback(err) else { dynamo = aws.DynamoDB diff --git a/src/tables/_get-db-client.js b/src/tables/_get-db-client.js index 8627da80..233b3ed0 100644 --- a/src/tables/_get-db-client.js +++ b/src/tables/_get-db-client.js @@ -1,7 +1,7 @@ let { join } = require('path') let awsLite = require('@aws-lite/client') -module.exports = function initDynamoClient ({ creds, ports }, callback) { +module.exports = function initDynamoClient ({ creds, inventory, ports }, callback) { let plugins = [ // Binary dist mode process.pkg @@ -12,7 +12,8 @@ module.exports = function initDynamoClient ({ creds, ports }, callback) { autoloadPlugins: false, endpoint: `http://localhost:${ports.tables}`, plugins, - region: process.env.AWS_REGION || 'us-west-2', + profile: inventory.inv?.aws?.profile, + region: inventory.inv?.aws?.region || process.env.AWS_REGION || 'us-west-2', ...creds, } awsLite(config) diff --git a/src/tables/_init.js b/src/tables/_init.js index a63d5843..11b5b263 100644 --- a/src/tables/_init.js +++ b/src/tables/_init.js @@ -3,7 +3,7 @@ let createTables = require('./create-table') // Just a thin passthrough to enable the abstraction of getDBClient (for testing) module.exports = function init ({ creds, inventory, ports }, callback) { - getDBClient({ creds, ports }, (err, aws) => { + getDBClient({ creds, inventory, ports }, (err, aws) => { if (err) return callback(err) createTables({ aws, inventory, ports }, callback) }) From 536a8c334363d341a0633d3296766c07237d6917 Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Thu, 1 Feb 2024 11:59:31 -0800 Subject: [PATCH 19/20] 6.0.0-RC.4 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a3d0d4c2..0476f4fd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@architect/sandbox", - "version": "6.0.0-RC.3", + "version": "6.0.0-RC.4", "description": "Architect dev server: run full Architect projects locally & offline", "main": "src/index.js", "scripts": { From 9f642028e50f44c94d5e31f63938a40c9c08ade3 Mon Sep 17 00:00:00 2001 From: Ryan Block Date: Thu, 1 Feb 2024 20:02:35 -0800 Subject: [PATCH 20/20] Update deps --- package.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index 0476f4fd..d4e89e82 100644 --- a/package.json +++ b/package.json @@ -28,12 +28,12 @@ "src/*" ], "dependencies": { - "@architect/asap": "~7.0.0-RC.2", - "@architect/create": "~5.0.0-RC.2", - "@architect/hydrate": "~4.0.0-RC.1", - "@architect/inventory": "~4.0.0-RC.3", - "@architect/utils": "~4.0.0-RC.4", - "@aws-lite/client": "^0.15.1", + "@architect/asap": "~7.0.0", + "@architect/create": "~5.0.0", + "@architect/hydrate": "~4.0.0", + "@architect/inventory": "~4.0.0", + "@architect/utils": "~4.0.0", + "@aws-lite/client": "^0.15.2", "@aws-lite/dynamodb": "^0.3.3", "@begin/hashid": "~1.0.0", "chalk": "4.1.2", @@ -43,7 +43,7 @@ "finalhandler": "~1.2.0", "glob": "~10.3.10", "http-proxy": "~1.18.1", - "lambda-runtimes": "~2.0.0", + "lambda-runtimes": "~2.0.1", "minimist": "~1.2.8", "router": "~1.3.8", "run-parallel": "~1.2.0", @@ -57,7 +57,7 @@ }, "devDependencies": { "@architect/eslint-config": "~2.1.2", - "@architect/functions": "~7.0.0", + "@architect/functions": "~8.0.0-RC.3", "@architect/req-res-fixtures": "git+https://github.com/architect/req-res-fixtures.git", "@aws-lite/apigatewaymanagementapi": "~0.0.7", "@aws-lite/ssm": "~0.2.2",