accumulated fixes and improvements from neodb#44
Merged
alphatownsman merged 2 commits intoJul 25, 2026
Conversation
alphatownsman
force-pushed
the
contribute-to-incarnator
branch
from
May 23, 2026 16:37
abdec60 to
2cd26de
Compare
Aggregated, NeoDB-agnostic changes accumulated on neodb-social/neodb-incarnator
since upstream/main diverged. Reviewable as a single squash; happy to split per
maintainer preference.
ActivityPub compatibility
- accept list-form attributedTo (WriteFreely blog Articles)
- follow Link rel=alternate to resolve AP Article URLs
- only accept URL-shaped quote values (validate scheme and length)
- give identity Update/Delete/Move activities unique IDs (deduplication)
- serve QuoteAuthorization at a dereferenceable URL (FEP-044f):
new QuoteAuthorization model + view + migration
- treat image-only Notes as Posts instead of Interactions
- skip emoji tag ingestion when author has no domain
- handle vote-type in PostInteraction undo to prevent ValueError
- validate URI scheme before fetching posts and replies
- return 400 (VerificationFormatError) for unparseable HTTP signatures
- use ActivityPubError subtypes for invalid inbound activities
(ActorMismatchError / ActivityPubFormatError instead of ValueError)
- coalesce list-typed poll option name to string (pl.fediverse.pl)
- expose federation.enabled in nodeinfo metadata (FEP-0151)
Security
- add SSRF protection to all outbound HTTP requests
(core.files.check_url_safety + SSRFAttemptError, attached via httpx
event_hooks so redirect hops are also checked)
- enforce CSRF verification for session-authenticated API requests
- harden OAuth token exchange against error leak and timing attack
(constant-time compare for client_id/secret, single-shot code lookup)
- use safer URL-redirection sanitizers (_safe_remote_redirect) so CodeQL
recognises the sanitiser pattern
- treat DNS resolution failures as httpx.ConnectError instead of
SSRFAttemptError so logs are less noisy
Performance
- partial index on TimelineEvent(identity, -id) WHERE NOT dismissed; bell
follows matched by target_id, not Follow id; avoid OR-subquery in
notification queries
- collapse Hashtag stator stats into 2 queries
- use timestamp ranges in Hashtag stat filters (avoid per-row
AT TIME ZONE / EXTRACT casts)
Robustness
- translate ClearTimeline deadlocks to TryAgainLater so Stator silently
reschedules instead of logging OperationalError
- bump sentry-sdk
Article rendering
- preserve full AS Article on inbound by storing type_data = {"object": data}
so name/summary/source survive (the old ArticleData parse with
extra="ignore" dropped them)
- add templates/activities/_type_article.html so Article posts render as
title + body instead of falling through to the unknown-type path
Tests
- QuoteAuthorization, list-form attributedTo, search URL with
Link rel=alternate fallback, Article type_data shape, ClearTimeline
deadlock translation, json edge cases, identity RSS feed (with quote link)
alphatownsman
force-pushed
the
contribute-to-incarnator
branch
from
May 23, 2026 16:44
2cd26de to
3068808
Compare
Brings across the NeoDB-agnostic work that accumulated in neodb-social/neodb's vendored takahe fork since it was de-submoduled (590c9e7, 2026-05-21) up to main @ 53011a71 (2026-07-24), then moves the project to Python 3.14. Features - Polls (Question), full support: a new question_open post state that federates throttled tally Updates and closes the poll at expiry; closed/hide_totals/effective_end_time on QuestionData; vote validation (own-poll, out-of-range, additive multiple-choice, row locking); poll create/edit through the client API with Mastodon's limits; /api/v1/polls visibility plus stale-tally refetch; end-of-poll notifications; interactive voting on the server-rendered post page. - Converted ActivityStreams object types: Page, Image, Audio, Video and Event become ordinary statuses while the complete AS object is retained in type_data, with the object icon exposed as a preview card. - Federation content spread and Lemmy interop: LD-signed fan-out for public posts, FanOut.forward plus inbox raw_document capture for AP 7.1.2 reply forwarding, group-announced Create/Update/Delete resolved against the origin server, refresh_from_origin, idempotent boosts. - JSON-LD list-valued "type" handled for actors, inbox routing, search and posts (get_first_concrete_type). - Article web view: cover image and linked hashtags. Fixes - OAuth: authorization codes are single-use under concurrency, redirect params are urlencoded (state could inject query parameters), a missing redirect_uri returns 400, and non-ASCII client credentials now fail as access_denied instead of raising TypeError out of compare_digest. - Application redirect_uri/uris are shaped correctly; verify_credentials previously raised a validation error for every app. - Follow counts track follow state, and a 4xx on Follow delivery is classified instead of retried for a day. - Bare mentions resolve deterministically. - Identity handle search no longer raises FieldError on a bare domain. - Empty profile metadata values no longer drop the remaining fields. - Reply counts are recalculated when a reply is deleted. - Preview card fetches stream with a byte cap and clamp to column widths. - Media proxy regains the SSRF-safe client and image Content-Type allowlist it had lost, streams with a byte cap, and falls back to the default avatar instead of surfacing a broken image. - The default avatar is served from a path this project actually publishes: resolved via static() rather than the /s/ prefix, which is an alias in NeoDB's nginx and 404s here. It is also federated now, so the wrong URL would have been advertised fediverse-wide. - refresh_question_from_remote only accepts the document that lives at the requested URI; without that check a host we hold a poll from could return another server's object id and rewrite our copy of that post. - A Question whose type_data is missing or the wrong shape no longer raises out of the poll template tag, which would 500 every page the post appears on. Performance - bulk_create fan-outs, skip_locked task claiming, case-insensitive functional indexes for local handle lookups, and a stale config_identity cache is dropped after a write. Python 3.14 - requires-python >=3.14, .python-version, Dockerfile base image, CI matrix and pre-commit default_language_version all move to 3.14. - blurhash-python (no wheels past cp312) is replaced by blurhash-rs; cryptography, pillow and psycopg floors raised for cp314 wheels. uv.lock re-resolved without --upgrade, so only those change. - ruff applies PEP 758 unparenthesized except groups across 18 files. Tests - Ports the upstream suite for the new behaviour (poll lifecycle, announced activities, inbox forwarding, converted types, fan-out signing, poll voting, OAuth, notifications, media proxy) and adds regression tests for the two locally-found bugs above. - tests/conftest.py: @pytest.mark.django_db on a fixture does nothing; the fixtures now take the db fixture, and the warning filter that hid this is removed. - tests/api/notifications.py was never collected; renamed to test_notifications.py. 470 tests pass on 3.14.3, pre-commit is clean, migrations apply from scratch and makemigrations --check reports no drift. NeoDB-specific code (ext_neodb, takahe.neodb, NEODB_MQ wiring, Sentry instrumentation) is deliberately excluded.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Main fix is QuoteAuthorization which was incomplete in previous implementation.
ActivityPub compatibility
Security
Performance
Robustness
Python 3.14