Skip to content

feat: Webhooks with Kronos - #365

Open
yuvrajjsingh0 wants to merge 1 commit into
mainfrom
webhooks-with-kronos
Open

yuvrajjsingh0 wants to merge 1 commit into
mainfrom
webhooks-with-kronos

Conversation

@yuvrajjsingh0

@yuvrajjsingh0 yuvrajjsingh0 commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Added webhook management in the dashboard, including create, edit, enable/disable, delete, test delivery, and delivery history views.
    • Added webhook event documentation and configuration guidance.
    • Added support for webhook delivery retries, signing, and retention settings.
  • Bug Fixes

    • Local environment setup now preserves existing settings and fills in any new missing values automatically.
    • Dev startup now prepares the environment file before launching services.

Screenshots:
Screenshot 2026-07-09 at 8 30 50 PM
Screenshot 2026-07-09 at 8 30 53 PM
Screenshot 2026-07-09 at 8 31 05 PM
Screenshot 2026-07-09 at 8 31 14 PM
Screenshot 2026-07-09 at 8 31 33 PM

@semanticdiff-com

semanticdiff-com Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review changes with  SemanticDiff

Changed Files
File Status
  airborne_dashboard/next.config.mjs  98% smaller
  airborne_dashboard/app/dashboard/[orgId]/layout.tsx  28% smaller
  airborne_server/src/utils/db/schema.rs  17% smaller
  airborne_server/src/main.rs  6% smaller
  airborne_server/src/utils/db/models.rs  3% smaller
  Cargo.lock Unsupported file format
  Makefile Unsupported file format
  airborne_authz_macros/src/lib.rs  0% smaller
  airborne_dashboard/app/dashboard/[orgId]/[appId]/webhooks/[webhookId]/deliveries/page.tsx  0% smaller
  airborne_dashboard/app/dashboard/[orgId]/[appId]/webhooks/page.tsx  0% smaller
  airborne_dashboard/app/dashboard/[orgId]/webhooks/[webhookId]/deliveries/page.tsx  0% smaller
  airborne_dashboard/app/dashboard/[orgId]/webhooks/page.tsx  0% smaller
  airborne_dashboard/components/shared-layout.tsx  0% smaller
  airborne_dashboard/components/webhooks/deliveries-view.tsx  0% smaller
  airborne_dashboard/components/webhooks/webhooks-view.tsx  0% smaller
  airborne_docs/docs/dashboard/webhooks.mdx Unsupported file format
  airborne_docs/docs/guides/webhooks.mdx Unsupported file format
  airborne_docs/docs/server/configuration.md Unsupported file format
  airborne_docs/docs/server/running-locally.md Unsupported file format
  airborne_docs/sidebars.ts  0% smaller
  airborne_docs/static/docs_static/img/screenshots/dark/webhook-create-dialog.png Unsupported file format
  airborne_docs/static/docs_static/img/screenshots/dark/webhook-deliveries.png Unsupported file format
  airborne_docs/static/docs_static/img/screenshots/dark/webhook-delivery-detail.png Unsupported file format
  airborne_docs/static/docs_static/img/screenshots/dark/webhook-get-caution.png Unsupported file format
  airborne_docs/static/docs_static/img/screenshots/dark/webhooks-app-list.png Unsupported file format
  airborne_docs/static/docs_static/img/screenshots/dark/webhooks-org-list.png Unsupported file format
  airborne_docs/static/docs_static/img/screenshots/light/webhook-create-dialog.png Unsupported file format
  airborne_docs/static/docs_static/img/screenshots/light/webhook-deliveries.png Unsupported file format
  airborne_docs/static/docs_static/img/screenshots/light/webhook-delivery-detail.png Unsupported file format
  airborne_docs/static/docs_static/img/screenshots/light/webhook-get-caution.png Unsupported file format
  airborne_docs/static/docs_static/img/screenshots/light/webhooks-app-list.png Unsupported file format
  airborne_docs/static/docs_static/img/screenshots/light/webhooks-org-list.png Unsupported file format
  airborne_server/.env.example Unsupported file format
  airborne_server/Cargo.toml Unsupported file format
  airborne_server/migrations/2026-07-08-120000_add_webhooks/down.sql Unsupported file format
  airborne_server/migrations/2026-07-08-120000_add_webhooks/up.sql Unsupported file format
  airborne_server/src/config.rs Unsupported file format
  airborne_server/src/release.rs  0% smaller
  airborne_server/src/types.rs  0% smaller
  airborne_server/src/utils.rs  0% smaller
  airborne_server/src/utils/kronos.rs  0% smaller
  airborne_server/src/webhook.rs  0% smaller
  airborne_server/src/webhook/dispatch.rs  0% smaller
  airborne_server/src/webhook/emit.rs  0% smaller
  airborne_server/src/webhook/maintenance.rs  0% smaller
  airborne_server/src/webhook/mw.rs  0% smaller
  airborne_server/src/webhook/sign.rs  0% smaller
  airborne_server/src/webhook/store.rs  0% smaller
  airborne_server/src/webhook/types.rs  0% smaller

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5e245b72-77ea-4666-85b7-1f8b15d83fd4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

This PR adds a Kronos-backed webhooks subsystem to Airborne: new database tables and models, expanded server config/startup wiring, a Kronos client utility, signing/SSRF-protected dispatch and maintenance workers, HTTP API endpoints, dashboard management/delivery UI, and documentation. Separately, the Makefile's env-file target is restructured to backfill missing keys.

Changes

Webhooks Feature

Layer / File(s) Summary
Database schema & Diesel models
airborne_server/migrations/2026-07-08-120000_add_webhooks/*, airborne_server/src/utils/db/schema.rs, airborne_server/src/utils/db/models.rs, airborne_server/Cargo.toml
Adds webhooks/webhook_deliveries tables with indexes, corresponding Diesel schema/model structs, and hmac/kronos dependencies.
Config, environment & startup wiring
airborne_server/src/config.rs, airborne_server/src/types.rs, airborne_server/src/utils.rs, airborne_server/src/main.rs, airborne_server/.env.example
Adds Kronos/webhook config fields, changes AppConfig::build to return a master encryption key, and wires Kronos client init, route mounting, and shutdown into startup.
Kronos client utility
airborne_server/src/utils/kronos.rs
Adds embedded/remote client construction and async wrappers for provisioning, secrets, endpoint registration, and job creation.
Webhook types & signing/SSRF security
airborne_server/src/webhook/types.rs, airborne_server/src/webhook/sign.rs
Defines request/response and envelope types plus secret generation/encryption, HMAC signing, and SSRF-guarded URL validation with tests.
Storage operations
airborne_server/src/webhook/store.rs
Implements CRUD/query/pagination functions for webhook configs and deliveries.
Dispatch, emission & maintenance workers
airborne_server/src/webhook/dispatch.rs, airborne_server/src/webhook/emit.rs, airborne_server/src/webhook/maintenance.rs
Implements outbound delivery attempts, internal dispatch/maintenance handlers, event emission scheduling, and delivery retention cleanup.
API endpoints, middleware & event hooks
airborne_server/src/webhook.rs, airborne_server/src/webhook/mw.rs, airborne_authz_macros/src/lib.rs, airborne_server/src/release.rs
Implements authz-protected CRUD/test/resend endpoints, route registration, task-local event middleware, and the release.conclude emission hook.
Dashboard UI
airborne_dashboard/app/dashboard/.../webhooks/*, airborne_dashboard/components/shared-layout.tsx, airborne_dashboard/next.config.mjs
Adds webhook management and delivery-history pages, sidebar navigation, and API rewrite for /api/webhooks.
Documentation
airborne_docs/docs/guides/webhooks.mdx, airborne_docs/docs/server/configuration.md, airborne_docs/sidebars.ts
Adds a webhooks guide, server config reference, and sidebar entry.

Local Dev Env-file Tooling

Layer / File(s) Summary
Env-file backfill and run prerequisite
Makefile, airborne_docs/docs/server/running-locally.md
Restructures env-file to backfill missing keys into an existing .env, adds env-file as a run prerequisite, and updates docs to match.

Estimated code review effort: 4 (Complex) | ~75 minutes

Suggested reviewers: JamesGeorg

Sequence Diagram(s)

sequenceDiagram
  participant ReleaseHandler
  participant EmitEvent
  participant KronosClient
  participant DispatchHandler
  participant CustomerURL
  ReleaseHandler->>EmitEvent: emit_event("release.conclude", delay)
  EmitEvent->>EmitEvent: insert delivery row (scheduled)
  EmitEvent->>KronosClient: submit_webhook_job
  KronosClient->>DispatchHandler: POST /internal/webhooks/dispatch
  DispatchHandler->>CustomerURL: signed HTTP POST
  CustomerURL-->>DispatchHandler: response / error
  DispatchHandler->>DispatchHandler: record_attempt, update delivery status
Loading

Poem

A rabbit hops with signed delight,
Webhooks fire deep into the night 🐇
Kronos schedules, retries chime,
Deliveries tracked one at a time.
.env backfilled, no keys forgot —
Hooray, this burrow ships a lot! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title is concise and accurately summarizes the main change: adding webhooks powered by Kronos.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch webhooks-with-kronos

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (1)
airborne_server/src/webhook/store.rs (1)

84-112: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Consider SQL-level JSONB filtering for list_subscribed_webhooks.

This function loads all enabled webhooks for an org/app into memory and filters by event in Rust. For typical workloads (tens of webhooks per app) this is fine, but at scale it becomes inefficient. A SQL-level JSONB containment check (e.g., events @> '["event.key"]' in PostgreSQL via Diesel) would push the filter to the database and avoid loading non-matching rows.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@airborne_server/src/webhook/store.rs` around lines 84 - 112,
`list_subscribed_webhooks` is filtering `events` in Rust after loading all
enabled rows, which is inefficient at scale. Move the event match into the
Diesel query on `webhooks::table` using a PostgreSQL JSONB containment filter
against `webhooks::events`, so only matching webhook rows are returned from the
database. Keep the existing `org_id`, `app_id`, and `enabled` filters in the
query and remove the in-memory
`serde_json::from_value`/`into_iter().filter(...)` pass.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@airborne_docs/docs/guides/webhooks.mdx`:
- Around line 73-79: The webhook signature verifier in the example can crash
when `parts["v1"]` is missing or malformed because `crypto.timingSafeEqual` is
called with buffers of different lengths. Update the verification logic around
the `expected`/`ok` check to first validate that the provided signature exists
and has the same byte length as the computed digest before calling
`timingSafeEqual`, so the function safely returns false instead of throwing.

In `@airborne_server/src/config.rs`:
- Around line 311-314: The `webhook_internal_secret` config currently falls back
to a hardcoded default in `Config::from_env` via `get_env`, which makes
`/internal/webhooks/dispatch` insecure when `KRONOS_ENABLED=true`. Update the
config loading logic so this secret is required in Kronos mode, or at minimum
detect the default `"airborne-internal-dev-secret"` and emit a clear startup
warning from the `config.rs` initialization path. Use the
`webhook_internal_secret` field and the surrounding `get_env` call to locate the
change.

In `@airborne_server/src/utils/kronos.rs`:
- Around line 54-65: The remote Kronos branch in kronos.rs is silently
defaulting `cfg.kronos_api_key` to `"dev-api-key"` inside the
`KronosHttpClient::new` setup, which should not happen when `cfg.kronos_url` is
present. Update the `if let Some(url) = &cfg.kronos_url` path to require
`kronos_api_key` explicitly and fail startup (or at minimum emit a clear
warning) instead of using the fallback, so the `KronosClient` is only created
with an intentional remote API key.

In `@airborne_server/src/webhook/dispatch.rs`:
- Around line 362-367: The webhook response handling in dispatch logic reads the
entire body with r.text().await before applying truncate, which can exhaust
memory on large responses. Update the response processing in the match arm for
Ok(r) to cap the body size while reading, such as by checking content_length()
first and/or streaming chunks up to the limit, and then pass only the bounded
text into truncate and logging.
- Around line 444-452: The truncate helper can panic when MAX_RESPONSE_BODY
lands in the middle of a multi-byte UTF-8 character. Update truncate in
dispatch.rs to avoid direct byte slicing of s[..MAX_RESPONSE_BODY]; instead,
snap the cutoff to a valid char boundary before building the truncated String
and appending the marker. Keep the behavior the same for short bodies, and
ensure the change is applied in the truncate function used by the webhook
delivery/test response path.

---

Nitpick comments:
In `@airborne_server/src/webhook/store.rs`:
- Around line 84-112: `list_subscribed_webhooks` is filtering `events` in Rust
after loading all enabled rows, which is inefficient at scale. Move the event
match into the Diesel query on `webhooks::table` using a PostgreSQL JSONB
containment filter against `webhooks::events`, so only matching webhook rows are
returned from the database. Keep the existing `org_id`, `app_id`, and `enabled`
filters in the query and remove the in-memory
`serde_json::from_value`/`into_iter().filter(...)` pass.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b2ef9dc2-ce22-4a87-b3b5-18ec783590b2

📥 Commits

Reviewing files that changed from the base of the PR and between 622f926 and ce2f0d7.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (30)
  • Makefile
  • airborne_authz_macros/src/lib.rs
  • airborne_dashboard/app/dashboard/[orgId]/[appId]/webhooks/[webhookId]/deliveries/page.tsx
  • airborne_dashboard/app/dashboard/[orgId]/[appId]/webhooks/page.tsx
  • airborne_dashboard/components/shared-layout.tsx
  • airborne_dashboard/next.config.mjs
  • airborne_docs/docs/guides/webhooks.mdx
  • airborne_docs/docs/server/configuration.md
  • airborne_docs/docs/server/running-locally.md
  • airborne_docs/sidebars.ts
  • airborne_server/.env.example
  • airborne_server/Cargo.toml
  • airborne_server/migrations/2026-07-08-120000_add_webhooks/down.sql
  • airborne_server/migrations/2026-07-08-120000_add_webhooks/up.sql
  • airborne_server/src/config.rs
  • airborne_server/src/main.rs
  • airborne_server/src/release.rs
  • airborne_server/src/types.rs
  • airborne_server/src/utils.rs
  • airborne_server/src/utils/db/models.rs
  • airborne_server/src/utils/db/schema.rs
  • airborne_server/src/utils/kronos.rs
  • airborne_server/src/webhook.rs
  • airborne_server/src/webhook/dispatch.rs
  • airborne_server/src/webhook/emit.rs
  • airborne_server/src/webhook/maintenance.rs
  • airborne_server/src/webhook/mw.rs
  • airborne_server/src/webhook/sign.rs
  • airborne_server/src/webhook/store.rs
  • airborne_server/src/webhook/types.rs

Comment thread airborne_docs/docs/guides/webhooks.mdx
Comment thread airborne_server/src/config.rs
Comment thread airborne_server/src/utils/kronos.rs
Comment thread airborne_server/src/webhook/dispatch.rs
Comment thread airborne_server/src/webhook/dispatch.rs
@yuvrajjsingh0
yuvrajjsingh0 force-pushed the webhooks-with-kronos branch 4 times, most recently from a349f07 to 158939f Compare July 16, 2026 11:25
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.

1 participant