Skip to content

Verify official Resend Go SDK compatibility - #55

Draft
yhay81 wants to merge 32 commits into
mainfrom
agent/go-sdk-compat
Draft

Verify official Resend Go SDK compatibility#55
yhay81 wants to merge 32 commits into
mainfrom
agent/go-sdk-compat

Conversation

@yhay81

@yhay81 yhay81 commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add a pinned black-box compatibility program for the official resend-go v3.11.0 SDK
  • verify send, idempotent replay, retrieve, list, batch, and batch replay behavior against a local HayaSend server
  • add an independent go-sdk CI job with a fail-closed loopback endpoint guard
  • document the supported Go SDK setup and update compatibility, roadmap, changelog, and website claims

Why

Go adopters previously had no executable compatibility evidence for the official Resend SDK. That made the documented drop-in migration story weaker than the Node and Python paths and left SDK regressions undetected.

Impact

Go users can point the official SDK at HayaSend without maintaining a fork, and maintainers now get a pinned CI signal when the compatibility contract changes. The guard prevents this black-box test from sending to a non-loopback endpoint.

Validation

  • official resend-go v3.11.0 black-box run: send/get/list/batch and single/batch idempotent replay passed
  • production-endpoint guard rejected a non-loopback URL
  • go mod verify
  • go vet ./...
  • go test ./...
  • npm run check
  • npm test (146 tests)
  • npm run build
  • official Resend Python SDK black-box gate
  • Docker build and runtime health check
  • cfn-lint, Redocly OpenAPI validation, Lambda esbuild checks
  • npm audit --omit=dev --audit-level=high (0 vulnerabilities)
  • npm pack --dry-run
  • actionlint
  • git diff --check
  • Gitleaks staged scan (0 leaks)

Closes #54

yhay81 added 30 commits July 26, 2026 05:38
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
## What changed

- centralize bounded error classification for application, provider,
network, timeout, and invalid-data failures
- replace raw exception text in API, worker, inbound, SES-event, and
local queue logs with stable categories
- sanitize retained email and webhook failure fields while preserving
retry behavior
- generate API request IDs server-side and stop logging
caller-controlled paths or correlation headers
- remove addresses and subjects from local acceptance logs and suppress
non-JSON CLI response bodies
- expose the new application-failure metrics on the operations dashboard
and document the privacy/diagnostic contract

## Why

Provider, network, parser, and queue exception strings are untrusted.
They can include recipient data, webhook endpoints, response fragments,
or credentials. Copying them into CloudWatch or long-lived failure
fields conflicts with HayaSend's privacy boundary and makes public
support workflows harder to operate safely.

## Impact

Operators now correlate failures with server-generated request IDs,
opaque email or queue IDs, allowlisted job/HTTP metadata, and stable
error categories. Detailed provider diagnostics remain available from
the originating AWS service under controlled access. `Email.error` and
`WebhookDelivery.last_error` intentionally no longer reproduce external
exception strings.

Retry, partial-batch failure, DLQ, and alarm behavior is preserved.
SES-event and inbound Lambda rethrows are sanitized so the Lambda
runtime cannot emit the original exception text.

## Validation

- `npm run check`
- `npm test` — 21 files, 141 tests
- `npm run build`
- `cfn-lint==1.53.2 template.yaml`
- `npx @redocly/cli@2.12.5 lint openapi.yaml`
- Lambda entry-point bundling with esbuild
- `actionlint .github/workflows/*.yml`
- `gitleaks detect --source . --redact`
- `npm audit --omit=dev --audit-level=high`
- `npm pack --dry-run`
- Dockerfile check, image build, and read-only/capability-dropped
container smoke test with adversarial metadata; no injected sender,
recipient, subject, body, credential token, URL, or request ID appeared
in container logs

Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
## Outcome

Complete HayaSend's GitHub Community Profile and give contributors one
concise structure for explaining user impact, implementation tradeoffs,
compatibility, operations, and verification.

## Approach

- add a repository-wide pull request template rather than separate
overlapping templates
- lead with a private-vulnerability-reporting warning
- ask for exact validation and explicitly gated checks
- cover API/SDK compatibility, AWS/IAM/cost impact, migrations,
rollback, security, and privacy without forcing empty boilerplate
- include focused-change, test, documentation, sensitive-data, and DCO
checks

## Impact

New pull requests opened through GitHub receive the template
automatically after the release branch reaches the default branch. There
is no runtime, API, deployment, or dependency change.

## Verification

- `npm run check`
- `npm test` — 21 files, 141 tests
- `actionlint .github/workflows/*.yml`
- `gitleaks git --staged --redact`
- `git diff --cached --check`

Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
## Outcome

Reject malformed HayaSend scoped API keys as unauthorized before
consulting DynamoDB or the bootstrap-secret provider.

## Root cause

`ApiKeyService.authenticate` previously treated any value beginning with
`re_hs_` and containing a dot as a scoped key. The attacker-controlled
substring before the dot became a DynamoDB partition-key component
without first matching the format HayaSend actually issues.

API Gateway HTTP APIs accept up to 10,240 bytes across the request line
and headers, while a DynamoDB partition key is limited to 2,048 bytes. A
long malformed Bearer value could therefore turn an authentication
failure into a DynamoDB validation error, API 500, and `ApiErrors` alarm
instead of a bounded 401.

References:

-
https://docs.aws.amazon.com/apigateway/latest/developerguide/http-api-quotas.html
-
https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Constraints.html

## Approach

- accept only the exact issued shape: lowercase `key_<32 hex>` ID plus a
43-character base64url secret
- reject malformed `re_hs_*.*` values before Store or Secrets Manager
access
- preserve valid scoped-key lookup, revocation/expiry checks,
constant-time hash comparison, and existing bootstrap behavior
- move release-bound cost and telemetry entries from `Unreleased` into
the v0.1.0 section and record this fix there

## Impact

Valid keys and API responses are unchanged. Invalid scoped-looking
credentials now consistently return the existing 401 error without
consuming a DynamoDB read, surfacing a storage exception, or triggering
internal-error telemetry.

## Validation

- `npm run check`
- `npm test` — 21 files, 142 tests
- `npm run build`
- `cfn-lint==1.53.2 template.yaml`
- `npx @redocly/cli@2.12.5 lint openapi.yaml`
- Lambda entry-point bundling with esbuild
- `actionlint .github/workflows/*.yml`
- `npm audit --omit=dev --audit-level=high` — 0 vulnerabilities
- `gitleaks git --staged --redact`
- Dockerfile check, image build, and read-only/capability-dropped
container smoke test using a 2,048-character malformed key

Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
## What changed

- split email creation into side-effect-free preparation and commit
phases
- preflight every message in a strict batch before persisting or
queueing any sibling
- document strict-only batch validation and add service/API regression
coverage

## Why

`createBatch` previously called `create` for every message concurrently.
If one message referenced a missing or unpublished template, or an
invalid uploaded attachment, another valid message could already be
stored and queued even though the batch request returned an error. A
caller retry could then duplicate delivery.

The official Resend API uses strict batch validation by default, where
one invalid message prevents the batch from being sent. HayaSend now
matches that safety behavior for its service-level validation.

## Impact

Successful single-email and batch response shapes are unchanged. Invalid
batches now fail before any valid sibling is accepted. Permissive batch
mode and distributed transaction handling for infrastructure failures
remain out of scope.

## Validation

- `npm run check`
- `npm test` — 21 files, 144 tests
- `npm run build`
- `npm audit --omit=dev --audit-level=high` — 0 vulnerabilities
- `cfn-lint==1.53.2 template.yaml`
- Redocly 2.12.5 OpenAPI lint
- Lambda entry-point bundles
- `actionlint`
- `gitleaks git --staged`
- signed commit with DCO sign-off

Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
yhay81 added 2 commits July 26, 2026 13:38
## What changed

- pin AWS integration credentials to the exact API Gateway ID and Region
returned for the ephemeral CloudFormation stack
- remove response bodies, API key identifiers, and arbitrary error
messages from cleanup logs
- read bounded template files through one `O_NOFOLLOW` file descriptor
for both metadata checks and content reads
- add endpoint-confusion regression tests and release notes

## Why

CodeQL's first scan of the complete v0.1.0 pull request identified three
new flows: a dynamic integration-test destination, clear-text cleanup
logging, and a `stat(path)` / `readFile(path)` race. Even though the
integration destination originates from a dedicated test stack, it
carries a bootstrap credential and should fail closed if the URL differs
from that exact stack. The logging and file race findings are actionable
directly.

## Impact

The AWS integration workflow now independently reads the `HttpApi`
physical ID and the script accepts only its exact commercial API Gateway
HTTPS hostname. Cleanup diagnostics remain useful without retaining
response bodies or key identifiers. Template manifest behavior is
unchanged, but the size/type check and read now operate on the same
opened file.

## Validation

- `npm run check`
- `npm test` — 22 files, 146 tests
- `npm run build`
- endpoint-confusion and bootstrap-key output probes
- `npm audit --omit=dev --audit-level=high` — 0 vulnerabilities
- `cfn-lint==1.53.2 template.yaml`
- Redocly 2.12.5 OpenAPI lint
- `actionlint`
- `gitleaks git --staged`
- signed commit with DCO sign-off

Closes CodeQL findings #3, #4, and #5 on release PR #30.

Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
@yhay81 yhay81 added compatibility Official SDK and API behavioral compatibility enhancement New feature or request roadmap Accepted public roadmap work labels Jul 26, 2026 — with ChatGPT Codex Connector
Base automatically changed from release/v0.1.0 to main July 26, 2026 12:28
yhay81 added a commit that referenced this pull request Jul 26, 2026
## Outcome

Turn the accepted direction in #81 into a stage-gated implementation
plan: production semantics first, then a provider-neutral Cloudflare
proof, controlled FolioMCP dogfood, and only then agent-safe policy.

## What changed

- define ten non-negotiable customer-owned data-plane invariants
- document the current AWS gaps instead of treating aggregate status and
client-triggered dispatch repair as the final model
- specify canonical message, recipient, attempt, provider-event, and
transactional-outbox records
- define honest at-least-once boundaries and provider-acceptance
ambiguity
- require a versioned provider capability contract and common
conformance report
- add entry criteria, deliverables, exit evidence, and non-goals for
five gates
- ground the Cloudflare proof in current official Email Service, D1, R2,
and Queues behavior
- enumerate eleven focused implementation slices
- classify all 23 post-v0.1 drafts exactly once as rebase/review,
combine into the semantics series, or park
- align the public roadmap and commercial/support boundary with a
content-blind optional management plane

## Draft disposition

The plan preserves production-focused work, combines #49/#51/#53 into an
ordered semantics series, and parks #33/#55/#77/#82. Existing stacks
#59#61 and #73#75 remain ordered.

## Post-release refresh

- HayaSend v0.1.0 is fully released from protected `main`.
- The former stacked ancestry was replaced with one GPG-signed plan
commit on current `main`.
- The PR now changes only `README.md`, `ROADMAP.md`, `SUPPORT.md`,
`docs/commercial.md`, and the new `docs/execution-plan.md`.
- No feature draft is included or authorized for premature merge.

## Validation

- `npm ci`
- `npm run check`
- `npm test` — 22 files / 146 tests
- `npm run build`
- `npm audit --omit=dev --audit-level=high` — 0 vulnerabilities
- `npm outdated --depth=0 --json` — no direct updates
- Prettier check for all five changed Markdown files
- `git diff --check`
- signed commit with DCO sign-off

Closes #83
Relates to #81

Signed-off-by: Yusuke Hayashi <yusuke8h@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

compatibility Official SDK and API behavioral compatibility enhancement New feature or request roadmap Accepted public roadmap work

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant