Connect inbox POST handling to feder-core for supported Follow activities#37
Conversation
Move the hardcoded single-user demo into examples/single-user-server and leave feder-runtime-server as reusable Axum/Tokio integration. Expose the router/config building blocks, remove default local demo config from the library, and test the reusable routes directly. Assisted-by: Codex:gpt-5.5
Covers invalid inbox targets, unsupported content types, malformed JSON, unsupported activities, and oversized request bodies. Assisted-by: Codex:gpt-5.5
Reject unsigned inbox requests before core handling when signed inbox auth is required, while keeping explicit insecure dev mode for tests and the single-user example. Assisted-by: Codex:gpt-5.5
…ding the runtime inbox auth policy. Assisted-by: Codex:gpt-5.5
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughAdds an ActivityPub inbox handler with configurable auth policy, updates runtime configuration and router wiring around owned config, removes the note-backed server path and standalone binary, and adds a single-user example crate with updated tests and docs. ChangesRuntime server inbox feature
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Client
participant InboxHandler
participant FederCore
Client->>InboxHandler: POST /users/{username}/inbox (Follow JSON)
InboxHandler->>InboxHandler: verify_inbox_request(policy)
InboxHandler->>InboxHandler: parse JSON as Follow
InboxHandler->>InboxHandler: accept_id_for_follow(follow)
InboxHandler->>FederCore: Input::received_follow(follow, accept_id)
FederCore-->>InboxHandler: state updated
InboxHandler-->>Client: 202 Accepted
Possibly related issues
Possibly related PRs
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
feder-core for supported Follow activities
There was a problem hiding this comment.
Actionable comments posted: 5
🤖 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 `@crates/feder-runtime-server/README.md`:
- Around line 19-38: The README example using RuntimeConfig is missing the
required inbox_auth_policy field, so it does not compile as written. Update the
build_router example to include inbox_auth_policy in the RuntimeConfig literal,
matching the current RuntimeConfig definition in config.rs, and keep the example
aligned with the actual set of required fields.
- Around line 12-13: The README still says ActivityPub inbox handling is
deferred, but this PR now implements it via inbox.rs and wiring in build_router.
Update the documentation text in the README to remove inbox handling from the
list of deferred items, and make sure the remaining wording only mentions the
parts that are still actually postponed.
In `@crates/feder-runtime-server/src/config.rs`:
- Around line 20-24: InboxAuthPolicy::RequireSigned is currently treated as an
unconditional reject in verify_inbox_request, so legitimate signed deliveries
are still denied. Update verify_inbox_request to perform real signature
validation when RequireSigned is selected, using the existing request/auth
helpers in the inbox request path, and only return UNAUTHORIZED when the
signature check fails; if that plumbing does not exist yet, remove or disable
RequireSigned from InboxAuthPolicy until it is implemented.
In `@crates/feder-runtime-server/src/inbox.rs`:
- Around line 108-110: The inbox handler is ignoring the HandleResult from
core.handle(input), so any actions it contains, including SendActivity(Accept),
are never dispatched to the follower’s inbox. Update the handler around
core.handle(input) to execute or forward the returned actions before returning
StatusCode::ACCEPTED, using the existing HandleResult/action handling path in
this module; if delivery is intentionally deferred, add an explicit TODO near
the discarded result instead of silently dropping it.
- Around line 52-57: The verify_inbox_request function currently treats
InboxAuthPolicy::RequireSigned as an enforced signature check, but it always
returns UNAUTHORIZED without inspecting InboxRequest. Update the policy handling
in verify_inbox_request (and any related InboxAuthPolicy naming or docs) so
RequireSigned is clearly marked as a placeholder or renamed to reflect that
signature verification is not implemented yet, rather than implying actual
enforcement.
🪄 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: defaults
Review profile: CHILL
Plan: Pro
Run ID: bbb20537-6a51-471a-9660-376dee22e578
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (15)
Cargo.tomlcrates/feder-core/src/lib.rscrates/feder-runtime-server/Cargo.tomlcrates/feder-runtime-server/README.mdcrates/feder-runtime-server/src/actor.rscrates/feder-runtime-server/src/app.rscrates/feder-runtime-server/src/config.rscrates/feder-runtime-server/src/inbox.rscrates/feder-runtime-server/src/lib.rscrates/feder-runtime-server/src/main.rscrates/feder-runtime-server/src/note.rscrates/feder-runtime-server/src/webfinger.rsexamples/single-user-server/Cargo.tomlexamples/single-user-server/README.mdexamples/single-user-server/src/main.rs
💤 Files with no reviewable changes (2)
- crates/feder-runtime-server/src/main.rs
- crates/feder-runtime-server/src/note.rs
| let _result = core.handle(input); | ||
|
|
||
| Ok(StatusCode::ACCEPTED.into_response()) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect what core.handle returns and how actions are meant to be consumed.
fd -e rs -a . crates/feder-core/src | head
ast-grep run --pattern 'pub fn handle($$$) { $$$ }' --lang rust crates/feder-core/src/lib.rs
rg -nP 'fn handle\s*\(' crates/feder-core/src/lib.rs -A20Repository: fedify-dev/feder
Length of output: 886
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the inbox handler and how handle results/actions are consumed elsewhere.
ast-grep outline crates/feder-runtime-server/src/inbox.rs --view expanded
printf '\n--- inbox.rs excerpt ---\n'
sed -n '1,220p' crates/feder-runtime-server/src/inbox.rs
printf '\n--- HandleResult / action consumption search ---\n'
rg -n "HandleResult|handle\\(input\\)|delivery_targets\\(|followers\\(|actions" crates -g '*.rs' -A4 -B4
printf '\n--- feder-core lib excerpt ---\n'
sed -n '1,140p' crates/feder-core/src/lib.rsRepository: fedify-dev/feder
Length of output: 40687
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- search for action execution / HandleResult consumption ---'
rg -n "HandleResult|result\.actions|actions\.iter|Action::SendActivity|Action::StoreFollower|Action::StoreDeliveryTarget|Action::StoreObject|SendActivity" crates -g '*.rs' -A3 -B3
printf '\n%s\n' '--- list runtime server files ---'
fd -e rs -a crates/feder-runtime-server/src
printf '\n%s\n' '--- search for any dispatch/executor helpers ---'
rg -n "execute|dispatch|apply.*Action|perform.*Action|deliver|outbound|send activity" crates -g '*.rs' -A2 -B2Repository: fedify-dev/feder
Length of output: 15349
Dispatch the Accept action from core.handle
core.handle(input) returns a HandleResult whose actions include SendActivity(Accept) for a valid follow, but this handler drops the result and returns 202 Accepted immediately. The follow is recorded in memory, but the Accept is never sent to the follower’s inbox, so the handshake can’t complete over the wire. The test only covers in-memory state; wire up action execution here or add a TODO if delivery is meant to be deferred.
🤖 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 `@crates/feder-runtime-server/src/inbox.rs` around lines 108 - 110, The inbox
handler is ignoring the HandleResult from core.handle(input), so any actions it
contains, including SendActivity(Accept), are never dispatched to the follower’s
inbox. Update the handler around core.handle(input) to execute or forward the
returned actions before returning StatusCode::ACCEPTED, using the existing
HandleResult/action handling path in this module; if delivery is intentionally
deferred, add an explicit TODO near the discarded result instead of silently
dropping it.
There was a problem hiding this comment.
Pull request overview
This PR wires an Axum-based inbox POST endpoint into the feder-core boundary for supported ActivityPub Follow activities, adds a runnable single-user example binary, and refactors feder-runtime-server into a reusable library-oriented integration crate.
Changes:
- Added
/users/{username}/inboxPOST handler that parsesFollowand forwards it toFederCore::handle, with basic content-type/auth-policy checks and a router body-size limit. - Introduced
InboxAuthPolicyand adjusted runtime config/router construction to be consumer-provided (plus updated/added tests). - Added
examples/single-user-serveras the runnable demo and removed the oldfeder-runtime-serverbinary + seeded note endpoint.
Reviewed changes
Copilot reviewed 15 out of 16 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| examples/single-user-server/src/main.rs | New demo binary wiring RuntimeConfig into build_router and starting an Axum server. |
| examples/single-user-server/README.md | Run instructions for the new single-user demo. |
| examples/single-user-server/Cargo.toml | Declares the new example crate and its runtime dependencies. |
| crates/feder-runtime-server/src/webfinger.rs | Updates tests to use the new test_config() + build_router(config) API. |
| crates/feder-runtime-server/src/note.rs | Removes the seeded note endpoint and its tests. |
| crates/feder-runtime-server/src/main.rs | Removes the old runnable binary entrypoint (now replaced by the example). |
| crates/feder-runtime-server/src/lib.rs | Exposes the new inbox module and re-exports build_router, RuntimeConfig, and Error. |
| crates/feder-runtime-server/src/inbox.rs | Implements inbox POST handling and adds request/behavior tests. |
| crates/feder-runtime-server/src/config.rs | Adds InboxAuthPolicy and introduces test_config() for crate tests. |
| crates/feder-runtime-server/src/app.rs | Routes the new inbox endpoint, applies body-size limits, and refactors config ownership. |
| crates/feder-runtime-server/src/actor.rs | Updates tests to match router/config refactor. |
| crates/feder-runtime-server/README.md | Updates crate docs to describe library usage and point to the new demo. |
| crates/feder-runtime-server/Cargo.toml | Adjusts dependencies for the new inbox logic (serde_json, percent-encoding) and dev-only tokio. |
| crates/feder-core/src/lib.rs | Adds Input::received_follow constructor helper. |
| Cargo.toml | Adds examples/single-user-server to the workspace members. |
| Cargo.lock | Records new dependencies and the new example crate package. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
dahlia
left a comment
There was a problem hiding this comment.
One longer-term API thought, not a request to change this PR:
build_router(config) is a good simple shape for this vertical slice and the single-user example, but as the runtime grows we may eventually want Feder's Axum integration to be exposed as more composable pieces rather than a router builder that owns the route layout and middleware choices.
For example, it might be useful to expose the actor/webfinger/inbox handlers or route fragments separately, and let embedding applications decide where to mount them and which Axum layers to apply. That would also make things like the inbox body limit easier to configure at the application boundary instead of baking it into build_router.
I don't think this needs to block the current PR. It just seems worth keeping in mind before the feder-runtime-server API becomes more established.
Thanks for sharing. I'll keep that in my mind :) |
Closes #24
Adds
/users/{username}/inboxPOST handlingValidates inbox target, content type, body size, JSON shape, and auth policy
Parses supported
Followactivities intofeder-vocabConverts
Followintofeder_core::Inputand callsFederCore::handleAdds tests for valid
Follow, malformed/unsupported/oversized requests, andunsigned auth rejection
Keeps storage/delivery execution and real HTTP Signature verification out of
scope
Codex 5.5 is used for only refactoring and adding tests
Summary by CodeRabbit
New Features
Bug Fixes
Documentation