Skip to content

feat: add AWS EventBridge destination - #1059

Open
pryzmatical wants to merge 1 commit into
hookdeck:mainfrom
pryzmatical:feat/aws-eventbridge-destination
Open

feat: add AWS EventBridge destination#1059
pryzmatical wants to merge 1 commit into
hookdeck:mainfrom
pryzmatical:feat/aws-eventbridge-destination

Conversation

@pryzmatical

Copy link
Copy Markdown

Closes #201.

Adds aws_eventbridge as a new destination type, following the existing aws_kinesis/aws_sqs provider pattern. Implements the shape discussed on #201 with @alexbouchardd:

  • config.event_bus_name (optional, name or ARN — empty uses the account's default bus) + config.region (required) + config.endpoint (optional, LocalStack/VPC endpoint override)
  • credentials.key/secret/session are all optional on the destination itself (not hard-required), so a future credential-less publishing mode can be added later without a breaking config change. Static credentials are still always passed to the AWS SDK explicitly, even when empty, rather than omitted — an empty NewStaticCredentialsProvider fails loudly with an auth error instead of the SDK silently falling back to its default credential chain (env vars, shared config, EC2/ECS/EKS instance role) and authenticating as whatever role the outpost process happens to be running under.
  • Source is a fixed, app-level setting (DESTINATIONS_EVENTBRIDGE_SOURCE server config, defaulting to outpost), not a per-destination field, matching how EventBridge rules commonly key off Source to identify the emitting application.
  • DetailType is the event's topic; Detail carries metadata+data in the same envelope shape as aws_kinesis's metadata-in-payload mode, since EventBridge has no side channel for metadata the way SQS message attributes do.

Batch/error handling

PutEvents is a batch API even for a single entry, and reports per-entry success/failure in the response body rather than solely via the returned Go error — a call can return err == nil with FailedEntryCount == 1 if that one entry was rejected. Publish() checks both the top-level error and the entry's own ErrorCode before calling a publish successful, rather than trusting a nil top-level error alone.

Error responses (both paths) are sanitized through a shared classifyErrorCode: AWS's own ErrorCode enum values are safe to pass through as-is, but the human-readable message is always authored here, never AWS's own ErrorMessage text, which can embed account IDs and ARNs in permission-denied style errors.

Tests

Unit coverage for Format() (envelope shape, Source/DetailType/EventBusName wiring) and the error-classification functions (including a test that explicitly asserts no AWS-authored message text, ARNs, or account IDs ever leak through) — all passing.

No LocalStack-based Publish() integration test is included. My local environment has no Docker available, so I couldn't write and verify one the way aws_sqs/aws_kinesis do — I'd rather flag that gap explicitly than submit integration test code I can't confirm actually passes. Every other AWS/queue destination's Publish() correctness is likewise only covered by its LocalStack suite rather than unit tests, so this matches existing project convention for the parts that are covered; happy to add the integration test in a follow-up once I can verify it, or if a maintainer would rather add it directly.

Docs

instructions.md + metadata.json for the new provider, a destinations/aws-eventbridge.mdoc page mirroring aws-kinesis.mdoc, nav.json/overview.mdoc/concepts.mdoc listing entries, and the DESTINATIONS_EVENTBRIDGE_SOURCE entry in docs/apis/openapi.yaml's managed config schema (hand-maintained alongside config.go, per #992's precedent).

🤖 Generated with Claude Code

https://claude.ai/code/session_01SNTzCmsH3jiGqgPqi4QMfj

Adds aws_eventbridge as a new destination type, following the existing
aws_kinesis/aws_sqs provider pattern (internal/destregistry/providers/
destawseventbridge). Implements the shape discussed on hookdeck#201:

- config.event_bus_name (optional, name or ARN) + config.region (required)
  + config.endpoint (optional, LocalStack/VPC endpoint override)
- credentials.key/secret/session are all optional on the destination itself,
  not hard-required, so a future credential-less publishing mode (the kind
  some AWS-partnered SaaS platforms use) can be added later without a
  breaking config change. Static credentials are still always passed to the
  AWS SDK explicitly, even when empty, rather than omitted -- an empty
  NewStaticCredentialsProvider fails loudly with an auth error instead of
  the SDK silently falling back to its default credential chain (env vars,
  shared config, EC2/ECS/EKS instance role) and authenticating as whatever
  role the outpost process happens to be running under.
- Source is a fixed, app-level setting (DESTINATIONS_EVENTBRIDGE_SOURCE
  server config, defaulting to "outpost"), not a per-destination field,
  matching how EventBridge rules commonly key off Source to identify the
  emitting application.
- DetailType is the event's topic; Detail carries metadata+data in the same
  envelope shape as aws_kinesis's metadata-in-payload mode, since EventBridge
  has no side channel for metadata the way SQS message attributes do.

PutEvents is a batch API even for a single entry, and reports per-entry
success/failure in the response body rather than solely via the returned Go
error -- a call can return err == nil with FailedEntryCount == 1 if that one
entry was rejected. Publish() checks both the top-level error and the
entry's own ErrorCode before calling a publish successful, rather than
trusting a nil top-level error alone.

Error responses (both the top-level and per-entry paths) are sanitized
through a shared classifyErrorCode: AWS's own ErrorCode enum values are safe
to pass through as-is, but the human-readable message is always authored
here, never AWS's own ErrorMessage text, which can embed account IDs and
ARNs in permission-denied style errors.

Tests: unit coverage for Format() (envelope shape, Source/DetailType/
EventBusName wiring) and the error-classification functions (verifying no
AWS-authored message text, including ARNs/account IDs, ever leaks through).
No LocalStack-based Publish() integration test is included -- this
environment has no Docker available to write and verify one against, and
submitting untested integration test code seemed worse than being explicit
about the gap. Every other AWS/queue destination's Publish() correctness is
likewise only covered by its LocalStack suite, not unit tests, so this
matches existing project convention for the parts that are covered.

Docs: instructions.md + metadata.json for the new provider, a
destinations/aws-eventbridge.mdoc page mirroring aws-kinesis.mdoc, nav.json/
overview.mdoc/concepts.mdoc listing entries, and the
DESTINATIONS_EVENTBRIDGE_SOURCE entry in docs/apis/openapi.yaml's managed
config schema (hand-maintained alongside config.go, per PR hookdeck#992's
precedent).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SNTzCmsH3jiGqgPqi4QMfj
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Destination - AWS EventBridge

1 participant