aws-samples / aws-samples/sample-autonomous-cloud-coding-agents
Add Slack-button approvals for Cedar HITL approval gates
- Lingua principale
- TypeScript
- Stelle
- 143
- Fork
- 46
- Merge medio
- 3g 9h
- PR unite (30g)
- 20
Descrizione
> **Follow-up from [PR #88](https://github.com/aws-samples/sample-autonomous-cloud-coding-agents/pull/88)** — Cedar HITL approvals work via CLI today; Slack interactivity is wired but not yet used for approvals.
## Functional description
PR #88 ships a complete Cedar HITL approval flow: when an agent attempts a sensitive operation (force push, write to .env, etc.), the task pauses in `AWAITING_APPROVAL` status and an operator must run `bgagent approve ` (or `deny`) to resume or fail it. The CLI works well for individual operators, but **for team workflows (CI bots, on-call rotations, mobile approvals) the natural surface is Slack**, not a terminal.
ABCA already has a working `SlackIntegration` construct (`cdk/src/constructs/slack-integration.ts`) with `InteractionsFn` handling `block_actions` callbacks, plus `SlackNotifyFn` posting task lifecycle events. The plumbing for "user clicks a button in a Slack message → Lambda processes the action → state update" already works for `link_account_action` and a few others. **Extending it with `approve_action:` / `deny_action:` block_actions would close the HITL loop end-to-end without any new infrastructure.**
**User-visible impact (what's missing today):**
- Operator on phone gets a Slack message: "Task abc-123 is awaiting approval (force push)." They have to switch to a terminal, run `bgagent login`, run `bgagent approve abc-123 req-456`. Friction is high enough that approvals stall.
- CI bots can't approve via Slack workflow steps (they could call the API directly, but the Slack-button surface would be the cleanest integration).
- Any team using the dashboard for visibility but the CLI for action lives in two contexts.
**With this issue resolved:**
- Slack message gains "✅ Approve" / "❌ Deny" buttons.
- Click triggers `block_actions` callback, Lambda extracts the user identity (already mapped via `SlackUserMappingTable`), calls the same `approve-task` / `deny-task` handlers the CLI uses.
- Operator never leaves Slack.
## Technical context
**Existing plumbing:**
- `cdk/src/handlers/slack-interactions.ts` — handles incoming `block_actions` payloads. Already validates Slack signatures, extracts the action_id, maps the Slack user to an ABCA user via `SlackUserMappingTable`. Adding new action_ids is a switch-case.
- `cdk/src/handlers/shared/slack-blocks.ts` — Block Kit template helpers. Has `taskCreated`, `taskCompleted`, etc.; needs an `approvalRequest` template that includes the buttons.
- `cdk/src/handlers/slack-notify.ts` — currently called by FanOutConsumer when an `approval_requested` event is dispatched. Today it posts plain text; would need to switch to the Block Kit template.
- `cdk/src/handlers/approve-task.ts` / `deny-task.ts` — the existing handlers. Their interfaces (`POST /tasks/{id}/approve` etc.) are reusable; the Slack interactions Lambda would call into the same shared business logic via `cdk/src/handlers/shared/approval-action.ts` (need to extract the core from the HTTP handler into a shared module).
**Net new code:**
- `slackApprovalRequestBlocks(taskId, requestId, ruleIds)` in `slack-blocks.ts` (~50 LOC).
- `handleApproveAction` / `handleDenyAction` in `slack-interactions.ts` (~80 LOC each).
- Refactor approve-task.ts / deny-task.ts to extract a `processApprovalDecision(...)` shared function that both the HTTP handler and the Slack handler call (~30 LOC refactor + tests).
- Wiring: `slack-notify.ts` switches to the Block Kit template when `event.event_type === 'approval_requested'`.
**Estimated effort:** ~1 day for a single dev including tests + E2E validation against the dev stack.
## Proposed options
**Recommended path:**
1. Refactor the approve/deny handler core into `cdk/src/handlers/shared/approval-decision.ts` (no behavior change; passes existing tests).
2. Add Block Kit template + new action_id branches in `slack-interactions.ts`.
3. Update `slack-notify.ts` to use the Block Kit template for `approval_requested` events.
4. Add CDK + agent-side E2E test that simulates the Slack interaction flow end-to-end (the existing pattern from `cdk/test/handlers/slack-interactions.test.ts` extends naturally).
**Alternative considered:** building a separate Slack approval handler that bypasses the HTTP path. **Rejected** because it would diverge the auth/audit trail — both surfaces should land in the same `ApprovalsTable` row with the same fields.
## Acceptance criteria
- [ ] Operator who is logged into Slack via the existing `link account` flow can approve / deny a pending task by clicking a button in the FanOut-dispatched Slack message
- [ ] Approval row in `TaskApprovalsTable` shows `decided_by_channel: "slack"` (new optional field — extends the existing schema additively)
- [ ] Slack button click is rejected (with a friendly Slack ephemeral message) if the clicker is not the task owner — same 403 logic as the HTTP handler
- [ ] CDK unit tests cover both new action_ids; CDK construct tests verify the FanOut config
- [ ] Updated user docs section in `docs/guides/USER_GUIDE.md` showing the Slack approval flow
## Out of scope
- iOS / Android push notifications.
- Mobile-friendly approval landing page (web-form fallback for users not on Slack).
- Reassigning a stuck approval to a different user (separate issue if needed).
- Bulk approve/deny.
## References
- `cdk/src/constructs/slack-integration.ts`
- `cdk/src/handlers/slack-interactions.ts` (existing block_actions handler)
- `cdk/src/handlers/shared/slack-blocks.ts` (Block Kit template helpers)
- `cdk/src/handlers/approve-task.ts` / `deny-task.ts` (existing approval handlers)
- `docs/design/CEDAR_HITL_GATES.md` §6.5 (approval flow design)
- Slack Block Kit reference:
Guida per i contributori
Apri la guida per i contributori
Direzione di ricerca
Inizia da cdk/src/handlers/slack-interactions.ts, shared/slack-blocks.ts, slack-notify.ts e approve-task.ts/deny-task.ts; esegui cdk/test/handlers/slack-interactions.test.ts per comprendere la copertura esistente di block_actions. Traccia il flusso di approvazione attuale e il comportamento condiviso di autorizzazione prima di aggiungere il percorso Slack. Il lavoro è completato quando sono coperti entrambi gli ID delle azioni, i blocchi di notifica Slack, l’attribuzione del canale, il rifiuto da parte del proprietario, la copertura del construct, la validazione E2E e la sezione di USER_GUIDE.md.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- aws, typescript
- Ambito
- api, backend, devops, documentation, testing
- Tipo di issue
- Funzionalità
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Stato di attività
- Tranquilla
- Chiarezza
- Specificata chiaramente
- Idoneità per principianti
- 48/100