feat: Step Function + hardning

This commit is contained in:
Zakaria
2026-09-27 23:26:00 -04:00
parent ce8400757c
commit 0d613ae256
11 changed files with 672 additions and 1 deletions
+38
View File
@@ -729,6 +729,44 @@ export function createCloudRoutes(injectedService?: CloudProxyService) {
})
})
app.post('/:cloud/services/workflows/resources/:id/executions', async (c) => {
if (c.req.param('cloud') !== 'aws') return c.json({error: 'Unknown cloud or service'}, 404)
return withRuntime(c, async () => {
const body = await jsonBody<{input?: unknown; name?: unknown}>(c)
if (typeof body.input !== 'string') throw new ValidationError('input must be a JSON string')
try {
JSON.parse(body.input)
} catch {
throw new ValidationError('input must be valid JSON')
}
if (body.name !== undefined && (typeof body.name !== 'string' || !body.name.trim())) throw new ValidationError('name must be a non-empty string')
return c.json(await svc(c).startWorkflowExecution('aws', c.req.param('id'), {input: body.input, ...(typeof body.name === 'string' ? {name: body.name} : {})}), 201)
})
})
app.get('/:cloud/services/workflows/resources/:id/executions', async (c) => {
if (c.req.param('cloud') !== 'aws') return c.json({error: 'Unknown cloud or service'}, 404)
return withRuntime(c, async () => c.json(await svc(c).listWorkflowExecutions('aws', c.req.param('id'))))
})
app.get('/:cloud/services/workflows/resources/:id/executions/:executionArn', async (c) => {
if (c.req.param('cloud') !== 'aws') return c.json({error: 'Unknown cloud or service'}, 404)
return withRuntime(c, async () => c.json(await svc(c).describeWorkflowExecution('aws', c.req.param('executionArn'))))
})
app.get('/:cloud/services/workflows/resources/:id/executions/:executionArn/history', async (c) => {
if (c.req.param('cloud') !== 'aws') return c.json({error: 'Unknown cloud or service'}, 404)
return withRuntime(c, async () => c.json(await svc(c).getWorkflowExecutionHistory('aws', c.req.param('executionArn'), c.req.query('nextToken'))))
})
app.post('/:cloud/services/workflows/resources/:id/executions/:executionArn/stop', async (c) => {
if (c.req.param('cloud') !== 'aws') return c.json({error: 'Unknown cloud or service'}, 404)
return withRuntime(c, async () => {
await svc(c).stopWorkflowExecution('aws', c.req.param('executionArn'))
return c.json({ok: true})
})
})
app.get('/:cloud/services/serverless/resources/:id/sqs-event-source-mappings', async (c) => {
const cloud = c.req.param('cloud') as CloudProvider
if (cloud !== 'aws') return c.json({error: 'Unknown cloud or service'}, 404)
@@ -0,0 +1,59 @@
import {describe, expect, test} from 'bun:test'
import {createCloudRoutes} from './clouds'
import type {CloudProxyService} from '../service/CloudProxyService'
const machineArn = 'arn:aws:states:us-east-1:000000000000:stateMachine:orders'
const executionArn = 'arn:aws:states:us-east-1:000000000000:execution:orders:run-1'
describe('workflow execution routes', () => {
test('routes execution debugging through the AWS workflow contract', async () => {
const calls: Array<[string, ...unknown[]]> = []
const service = {
async startWorkflowExecution(...args: unknown[]) {
calls.push(['start', ...args])
return {executionArn, startDate: new Date('2026-07-28T10:01:00.000Z')}
},
async listWorkflowExecutions(...args: unknown[]) {
calls.push(['list', ...args])
return [{executionArn, name: 'run-1', status: 'RUNNING', startDate: new Date('2026-07-28T10:01:00.000Z')}]
},
async describeWorkflowExecution(...args: unknown[]) {
calls.push(['describe', ...args])
return {executionArn, name: 'run-1', status: 'RUNNING', startDate: new Date(), stateMachineArn: machineArn, input: '{}'}
},
async getWorkflowExecutionHistory(...args: unknown[]) {
calls.push(['history', ...args])
return {events: [{id: 1, type: 'ExecutionStarted'}], nextToken: 'next'}
},
async stopWorkflowExecution(...args: unknown[]) {
calls.push(['stop', ...args])
},
} as unknown as CloudProxyService
const app = createCloudRoutes(service)
const resource = encodeURIComponent(machineArn)
const execution = encodeURIComponent(executionArn)
const started = await app.request(`/aws/services/workflows/resources/${resource}/executions`, {method: 'POST', body: JSON.stringify({input: '{}', name: 'run-1'}), headers: {'content-type': 'application/json'}})
const listed = await app.request(`/aws/services/workflows/resources/${resource}/executions`)
const described = await app.request(`/aws/services/workflows/resources/${resource}/executions/${execution}`)
const history = await app.request(`/aws/services/workflows/resources/${resource}/executions/${execution}/history?nextToken=previous`)
const stopped = await app.request(`/aws/services/workflows/resources/${resource}/executions/${execution}/stop`, {method: 'POST'})
expect([started.status, listed.status, described.status, history.status, stopped.status]).toEqual([201, 200, 200, 200, 200])
expect(calls).toEqual([
['start', 'aws', machineArn, {input: '{}', name: 'run-1'}],
['list', 'aws', machineArn],
['describe', 'aws', executionArn],
['history', 'aws', executionArn, 'previous'],
['stop', 'aws', executionArn],
])
})
test('rejects invalid execution input before calling the adapter', async () => {
const app = createCloudRoutes({} as CloudProxyService)
const response = await app.request(`/aws/services/workflows/resources/${encodeURIComponent(machineArn)}/executions`, {method: 'POST', body: JSON.stringify({input: 'not json'}), headers: {'content-type': 'application/json'}})
expect(response.status).toBe(400)
await expect(response.json()).resolves.toMatchObject({error: 'input must be valid JSON'})
})
})