Skip to content

feat(messages): allow authorized services to send - #6

Merged
realmroot[bot] merged 3 commits into
mainfrom
feat/service-message-sender
Sep 3, 2026
Merged

realmroot[bot] merged 3 commits into
mainfrom
feat/service-message-sender

Conversation

@realmroot

@realmroot realmroot Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • accept Realmroot machine Application Bearer tokens with messages:create on POST /api/messages
  • persist service sender identity and per-client idempotency records
  • deliver normal message.created notifications for service messages
  • document the OpenAPI security alternative and add migration, auth, idempotency, concurrency, and notification coverage

Verification

  • pnpm check
  • 4 test files, 20 tests passed

Review path

  1. Apply D1 migration 0004_service_message_sender.sql.
  2. Grant a machine Application direct messages:create authority for the Inbox resource.
  3. Obtain its client-credentials Bearer token and POST an idempotent message to /api/messages with an agent:<uuidv7> recipient.
  4. Verify the response reports sender.kind = service, the recipient Agent lists it as inbound, notification subscribers receive one event, and replaying the same client/key/payload returns HTTP 200 with the same Message.

🤖 Created by Jarvis via Realmroot

@realmroot realmroot Bot left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review result: no blocking findings; this is mergeable.

Non-blocking follow-ups:

  1. createServiceMessage resolves and may provision recipient mailboxes before the idempotency reservation is won (server/repository.ts:245-257). Under two concurrent requests with the same client/key but different recipients, the 409 loser can still leave an empty mailbox behind. Reserving the key before recipient provisioning, or explicitly covering/accepting this side effect, would make the idempotency boundary stricter.

  2. service_idempotency_record.message_id has no foreign key (migrations/0004_service_message_sender.sql:13), unlike the existing agent idempotency table. There is no current service-message deletion path, so this does not block the feature, but a future deletion/retention path could leave a replay record pointing at a missing Message.

Evidence: pnpm check passed (typecheck; 4 test files, 20 tests), including migration preservation, authentication, conflicting and identical concurrent idempotency, recipient visibility, and notification creation.


🤖 Created by Jarvis via Realmroot

@realmroot

realmroot Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Auth architecture follow-up pushed in 4631aec:

  • removed the endpoint-specific authenticateMessages dispatcher
  • removed the duplicate authorizeService and authorizeMessage middleware
  • normalized authentication into a discriminated AgentPrincipal | ServicePrincipal
  • centralized operation scope, allowed principal kinds, and Agency client restrictions in the authorization policy
  • all protected routes now use one authorize middleware
  • added policy coverage proving Message creation accepts Agent and Service principals while mailbox Message reads remain Agent-only

Verification: pnpm check passes; 4 test files and 21 tests.


🤖 Created by Jarvis via Realmroot

@realmroot
realmroot Bot merged commit 9c4faaf into main Sep 3, 2026
1 check passed
@realmroot
realmroot Bot deleted the feat/service-message-sender branch September 3, 2026 23:03
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.

0 participants