Skip to content

Accept impolite quotes of public local posts - #660

Merged
dahlia merged 1 commit into
fedify-dev:mainfrom
dahlia:feat/accept-impolite-quotes
Oct 5, 2026
Merged

dahlia merged 1 commit into
fedify-dev:mainfrom
dahlia:feat/accept-impolite-quotes

Conversation

@dahlia

@dahlia dahlia commented Oct 5, 2026 •

Copy link
Copy Markdown
Member

A missing FEP-044f approval should not hide a quote that the local author's policy already permits. For public/unlisted local originals, Hollo checks the author's policy and blocks in both directions. It issues a local authorization when everyone may quote. Boost wrappers are excluded because the local account did not author the original.

Quote updates preserve revocation when the target is unchanged. Acceptance, quote counts, and new notifications are saved together before fetching media, so a failed fetch cannot lose the notification on retry.

Fixes #640.

Summary by CodeRabbit

  • New Features
    • Eligible quotes from remote accounts can be accepted automatically when the local post allows public quotes and is public or unlisted, provided neither account blocks the other.
    • Accepted quotes are reflected in quote counts and can trigger notifications.
  • Bug Fixes
    • Revoking a quote now remains effective when the quoted post is updated, preventing the quote from being accepted again.
    • Quote counts and notifications stay consistent when quote approvals or targets change.

Approve remote quotes of local public or unlisted originals when their
policy allows everyone and neither account blocks the other. Mint stable
local authorizations and preserve same-target revocation on updates.
Exclude local boost wrappers from this automatic approval path.

Persist local quote acceptance, counts and new notifications atomically
before media processing, so failed fetches and retries retain alerts.
Recount QuoteRequest targets and avoid overwriting concurrent revocation.
Add federation and API regressions for policy, wire formats, delivery
ordering, concurrent moderation, retries and authorization revocation.

Codex implemented the change with three Claude Code design reviews.
OpenCode with DeepSeek Flash, Codex and Claude Code reviewed the patch;
verified Codex and Claude findings were fixed and reviewed again.
Validation: mise run check and 920 tests passed, with one skipped.
Live Misskey/Mastodon interoperability remains untested.

Fixes fedify-dev#640

Assisted-by: Codex:gpt-6.1-sol
Assisted-by: Codex:gpt-6-astra
Assisted-by: Claude Code:claude-fable-5-1
@dahlia dahlia added this to the Hollo 0.10 milestone Oct 5, 2026
@dahlia dahlia self-assigned this Oct 5, 2026
@dahlia dahlia added the enhancement New feature or request label Oct 5, 2026
@coderabbitai

coderabbitai Bot commented Oct 5, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Navigate logical layers of code changes, visualize relationships, and explore their blast radius.

🧰 Additional context used
📚 Code guidelines (1)
AGENTS.md — auto-discovered

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 3ca8e2ef-2eb0-4c15-b1c7-3fe644a518d1
📥 Commits

Reviewing files that changed from the base of the PR and between 0b5fcc1 and c2b9e3c.

📒 Files selected for processing (6)
  • CHANGES.md
  • src/api/v1/statuses.test.ts
  • src/federation/inbox.test.ts
  • src/federation/inbox.ts
  • src/federation/post.test.ts
  • src/federation/post.ts

Included review availability: This review used your included allowance. Your plan provides up to 2 included reviews per hour; 1 remain after this review.


📝 Walkthrough

Walkthrough

Remote quotes that meet local target visibility, policy, origin, and block checks can be accepted without a verified authorization. Persistence creates local authorization for accepted quotes, updates quote counts and notifications, and retains revoked state across updates. Inbox handling also avoids processing revoked quotes as accepted requests.

Changes

Remote quote lifecycle

Layer / File(s) Summary
Quote policy and persistence
src/federation/post.ts, src/federation/post.test.ts, CHANGES.md
persistPost applies automatic acceptance checks to eligible quotes of local public or unlisted targets. It preserves revocations for the same target, maintains authorization across concurrent updates, refreshes quote counts, and notifies the local target owner when a quote becomes accepted. Tests cover quote policies, visibility, blocking, quote representations, target changes, and concurrent revocation.
Inbox quote requests and updates
src/federation/inbox.ts, src/federation/inbox.test.ts, src/api/v1/statuses.test.ts
onQuoteRequested skips revoked quotes and recalculates target statistics after a successful update. Tests cover Create and QuoteRequest delivery order, retries, updates, notifications, API exposure, authorization, and revocation.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix · Severity of issue fixed: Medium

Sequence Diagram(s)

sequenceDiagram
  participant RemoteActivity
  participant onPostCreated
  participant persistPost
  participant Database
  participant createNotification
  RemoteActivity->>onPostCreated: deliver remote Create
  onPostCreated->>persistPost: persist quoted post
  persistPost->>Database: store quote state and authorization
  persistPost->>createNotification: notify local target owner of accepted quote
Loading

Merge Risk: ⚪ Minimal · up to c2b9e

Remote quotes of public or unlisted local posts are now accepted automatically when the author allows everyone to quote and neither account blocks the other. Revoked quotes stay revoked when the quoted post is later updated. No concrete defect is evident, and tests cover the main lifecycle cases. Live testing against Misskey and Mastodon is still pending.

Security Architecture Review

Security architecture risk: 🔵 Low · up to c2b9e

Remote quotes gain a local approval path limited to permissive, publicly visible originals, with blocking and revocation protections. No introduced vulnerability was established, but the guarantee connecting an incoming activity to its claimed author remains unconfirmed.

Retained concerns
No architecture-level concerns identified.

Security review details

Security Blast Radius

  • inferred — The newly authorized outcome is acceptance of references to permissive public/unlisted local originals, affecting quote rows, target counts, author notifications, and locally served authorization documents. The fallback does not extend approval to private/direct originals.

Trust Boundaries and Controls

  • observed — Create handling passes the resolved object to persistence, which derives the quoting account from attribution and checks object/author origin equality for automatic acceptance. No activity-actor comparison is visible in that handler. Whether framework authentication and object resolution close this boundary remains unresolved; the lifecycle test calls the handler directly.
  • observed — Update processing requires matching activity-actor, object, and attribution origins. Local API revocation requires status ownership and write:statuses authority; federated authorization deletion requires the target author's actor identity.

Resilience and Maintainability Implications

  • observed — Conflict handling gives persisted same-target revocation precedence over incoming acceptance, and QuoteRequest updates cannot overwrite a revoked row. Added tests assert revocation survival during authorization verification and continued hiding of the quote and authorization after a remote Update; these tests were inspected, not executed.

Hardening Proposals

  • proposed — Establish the incoming actor-to-object authority guarantee explicitly for the Create acceptance path, either through a demonstrated framework contract or a local guard, before relying on object attribution for block-sensitive authorization decisions.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 5 files. (1 skipped: 1… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: accepting impolite quotes of public local posts.
Linked Issues check ✅ Passed Issue #640’s coding requirements are covered. persistPost() accepts an impolite quote only for an eligible local public or unlisted target with public or null quote policy, no block, and a remote qu…
Out of Scope Changes check ✅ Passed The changes are connected to issue #640. The post.ts and inbox.ts changes implement quote acceptance, authorization, revocation, request ordering, notifications, and count handling. The added test…
Full details: Docstring Coverage

Explanation

Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 14 functions across 5 files. (1 skipped: 1 unsupported.)

  • Fix all pre-merge checks with AI
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@dahlia
dahlia merged commit e28d73f into fedify-dev:main Oct 5, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Accept impolite quotes of publicly quotable local posts

1 participant