CI/CD - CodeBuild + CodeDeploy + CodePipeline

This commit is contained in:
Zakaria
2026-10-01 09:18:04 -04:00
parent aa02cdb7f6
commit 7f0d707578
41 changed files with 1817 additions and 78 deletions
@@ -8,8 +8,12 @@ import {
DescribeOrderableDBInstanceOptionsCommand,
ListTagsForResourceCommand,
ModifyDBInstanceCommand,
RebootDBInstanceCommand,
StartDBInstanceCommand,
StopDBInstanceCommand,
type RDSClient,
} from '@aws-sdk/client-rds'
import {ExecuteStatementCommand, type RDSDataClient} from '@aws-sdk/client-rds-data'
import {ConflictError, ValidationError} from '../cloud-spi/errors'
import {createRdsService} from '../services/rds'
import {mapAwsSdkError} from './awsErrors'
@@ -24,6 +28,9 @@ type RdsCommand =
| DescribeOrderableDBInstanceOptionsCommand
| ListTagsForResourceCommand
| ModifyDBInstanceCommand
| RebootDBInstanceCommand
| StartDBInstanceCommand
| StopDBInstanceCommand
type Responder = (command: RdsCommand) => unknown | Promise<unknown>
@@ -47,6 +54,17 @@ function adapterWith(responder: Responder) {
}
}
function recordingRdsData(responder: (command: ExecuteStatementCommand) => unknown | Promise<unknown>) {
const commands: ExecuteStatementCommand[] = []
const client = {
async send(command: ExecuteStatementCommand) {
commands.push(command)
return responder(command)
},
} as unknown as RDSDataClient
return {client, commands}
}
function instanceResponse(command: CreateDBInstanceCommand) {
return {
DBInstance: {
@@ -69,6 +87,47 @@ const validCreateValues = {
}
describe('AwsDatabaseAdapter', () => {
test('explores PostgreSQL databases through the RDS Data API without console credentials', async () => {
const {client, commands} = recordingRdsData((command) => {
expect(command.input.resourceArn).toBe('arn:aws:rds:us-east-1:000000000000:db:orders-db')
expect(command.input.database).toBe('orders')
expect(command.input.sql).toContain('FROM pg_database')
return {
columnMetadata: [{name: 'name', typeName: 'varchar'}, {name: 'state', typeName: 'varchar'}, {name: 'isSystem', typeName: 'bool'}],
records: [[{stringValue: 'orders'}, {stringValue: 'ONLINE'}, {booleanValue: false}]],
}
})
const {client: rds, commands: rdsCommands} = recordingRds((command) => {
expect(command).toBeInstanceOf(DescribeDBInstancesCommand)
return {DBInstances: [{
DBInstanceIdentifier: 'orders-db',
DBInstanceArn: 'arn:aws:rds:us-east-1:000000000000:db:orders-db',
Engine: 'postgres',
DBName: 'orders',
VpcSecurityGroups: [],
}]}
})
const adapter = new AwsDatabaseAdapter(createRdsService(rds), rds, client)
await expect(adapter.listSqlDatabases('orders-db', {username: '', password: ''})).resolves.toEqual([{
name: 'orders', state: 'ONLINE', createdAt: null, isSystem: false,
}])
expect(rdsCommands).toHaveLength(1)
expect(commands).toHaveLength(1)
expect(commands[0].input.secretArn).toContain('floci-ui-rds-data')
})
test('rejects SQL exploration for unsupported RDS engines', async () => {
const {client: rds} = recordingRds(() => ({DBInstances: [{
DBInstanceIdentifier: 'maria-db', Engine: 'mariadb', VpcSecurityGroups: [],
}]}))
const {client} = recordingRdsData(() => ({}))
const adapter = new AwsDatabaseAdapter(createRdsService(rds), rds, client)
await expect(adapter.querySql('maria-db', {username: '', password: '', database: 'app'}, 'SELECT 1'))
.rejects.toBeInstanceOf(ValidationError)
})
test('keeps list search behavior intact', async () => {
const {adapter} = adapterWith(async (command) => {
expect(command).toBeInstanceOf(DescribeDBInstancesCommand)
@@ -285,6 +344,25 @@ describe('AwsDatabaseAdapter', () => {
})
})
test('sends RDS lifecycle commands for an instance', async () => {
const {adapter, commands} = adapterWith(async () => ({}))
await adapter.start('orders-db')
await adapter.stop('orders-db')
await adapter.reboot('orders-db')
expect(commands.map((command) => command.constructor)).toEqual([
StartDBInstanceCommand,
StopDBInstanceCommand,
RebootDBInstanceCommand,
])
expect(commands.map((command) => command.input)).toEqual([
{DBInstanceIdentifier: 'orders-db'},
{DBInstanceIdentifier: 'orders-db'},
{DBInstanceIdentifier: 'orders-db'},
])
})
test('lists and normalizes database snapshots', async () => {
const {adapter, commands} = adapterWith(async (command) => {
expect(command).toBeInstanceOf(DescribeDBSnapshotsCommand)