aws-samples / aws-samples/sample-autonomous-cloud-coding-agents

Add Slack-button approvals for Cedar HITL approval gates

Open
#112 2 comments 0 reactions 0 assignees View on GitHub
adapters security
Dominant language
TypeScript
Stars
143
Forks
46
Avg merge
3d 9h
Merged PRs (30d)
20

Description

> **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:

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.