Add FEP-7aa9 consent endpoint for featured collections#3277
Open
pfefferle wants to merge 20 commits into
Open
Conversation
…ape. Adds explicit assertions for the gts:interactingObject and gts:interactionTarget mappings in the JSON-LD context test, and a docblock note explaining the deliberately minimal context.
- Replace inline namespace reference with a use import. - Add explicit queue_reject coverage (visibility, recipient, key trim). - Cover the snake_case 'feature_request' alias accepted by handle_blocked_request.
Without this guard the router's actor-username lookup runs first on ?actor=ID&stamp=ID URLs and returns 404 for any user whose username isn't a number, breaking FeatureAuthorization stamp verification end to end. The guard tells the router to leave the request alone when a stamp is also requested so content negotiation can resolve the stamp.
- Merge with parent in Actor::get_interaction_policy so future canQuote / canReply additions on actors do not get dropped silently. - Rename the feature-policy "Just me" option to "No one" since for featured-collection consent the deny choice is operationally "nobody at all", not "self-service". - Drop the Phase 2 FeaturedCollection / FeaturedItem / featuredObject / featuredObjectType / featureAuthorization terms from the global Base_Object context. They are sender-side vocabulary that is not used in this phase, and including them bloated every JSON-LD document the plugin emits. They will be re-added in Phase 2 when the plugin actually emits FeaturedCollection objects.
- Document the router stamp guard inline so a future maintainer doesn't accidentally remove it. - Cover the unresolvable target user path with an explicit Reject test. - Strengthen the blog actor canFeature test with a value assertion (default-deny shape). - Add an end-to-end stamp resolution test that goes through go_to() and template_redirect() so the layers can never silently disagree again.
There was a problem hiding this comment.
Pull request overview
Implements the receive-side consent flow for FEP-7aa9 Featured Collections (Starter Packs): the plugin can now handle incoming FeatureRequest activities, reply with Accept (including a dereferenceable FeatureAuthorization stamp) or Reject based on a new site policy, and advertise interactionPolicy.canFeature on actor documents.
Changes:
- Added
FeatureRequestinbox handler with policy-controlled accept/reject behavior and actor-scoped stamp storage in user meta. - Added
FeatureAuthorizationextended object plus routing/query support to dereference stamps via?actor=ID&stamp=UMETA_ID. - Added admin setting + option registration for
activitypub_default_feature_policy, and comprehensive PHPUnit coverage for policy output and stamp lifecycle.
Reviewed changes
Copilot reviewed 16 out of 17 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/phpunit/tests/includes/model/class-test-interaction-policy.php | Verifies actor-level interactionPolicy.canFeature output for user/blog actors under each policy. |
| tests/phpunit/tests/includes/handler/class-test-feature-request.php | Tests validation, blocked-request handling, policy branching, accept/reject queuing, and idempotent stamp creation. |
| tests/phpunit/tests/includes/class-test-router.php | Adds coverage to ensure stamp URLs aren’t 404’d by the actor branch in template_redirect. |
| tests/phpunit/tests/includes/class-test-query-feature-stamp.php | Tests Query resolution for actor-scoped stamps, including cross-actor rejection and end-to-end routing. |
| tests/phpunit/tests/includes/activity/extended-object/class-test-feature-authorization.php | Verifies Feature_Authorization type and JSON-LD context mappings. |
| includes/wp-admin/class-settings-fields.php | Adds “Featured collection requests” dropdown to ActivityPub settings UI. |
| includes/handler/class-feature-request.php | New inbox handler for FeatureRequest, including policy enforcement and stamp issuance. |
| includes/class-router.php | Adds guard to avoid actor-username 404 path for stamp URLs. |
| includes/class-query.php | Extends stamp resolution to support actor-scoped FeatureAuthorization stamps. |
| includes/class-options.php | Registers the new activitypub_default_feature_policy option with sanitization and default. |
| includes/class-handler.php | Registers the new FeatureRequest handler during handler initialization. |
| includes/activity/extended-object/class-feature-authorization.php | Introduces Feature_Authorization extended object and its JSON-LD context. |
| includes/activity/class-base-object.php | Adds canFeature term to base JSON-LD context. |
| includes/activity/class-actor.php | Emits actor-level interactionPolicy.canFeature derived from the site policy. |
| includes/activity/class-activity.php | Adds FeatureRequest to Activity JSON-LD context and allowed activity types. |
| .gitignore | Ignores docs/superpowers/. |
| .github/changelog/feature-collections-consent | Adds changelogger entry documenting the new opt-in consent setting. |
- Move canFeature out of Base_Object's JSON-LD context. The term is only emitted by the actor (via Actor::get_interaction_policy), so carrying it on every Note / Article / Activity bloated their @context and silently broke Test_Outbox::test_add by altering the snapshot every Outbox object renders. - Add interactionPolicy, canFeature, automaticApproval, and the gts: prefix to Actor::JSON_LD_CONTEXT so actor JSON now actually defines the terms it emits, rather than hand-waving them through inheritance. - Tighten the router stamp guard so it only bypasses the actor branch when actor is numeric (the stamp pattern). Non-numeric actors still get the regular Mastodon-style profile lookup.
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.
Proposed changes:
Phase 1 of FEP-7aa9 (Featured Collections, also known as Mastodon Starter Packs). This PR implements the receive-side consent layer only. The plugin can now respond to incoming
FeatureRequestactivities from remote servers withAccept(issuing a verifiableFeatureAuthorizationstamp) orReject, governed by a new opt-in site policy.Architecturally a near-mirror of the existing FEP-044f quote-request layer (
Quote_Request,Quote_Authorization,activitypub_default_quote_policy), with three deliberate differences: actor-scoped storage instead of post-scoped, defaultme(deny) instead ofanyoneper the FEP "absence of policy = no consent" rule, andinteractionPolicy.canFeatureadvertised on the actor rather than per-post.Activitypub\Handler\Feature_Request— auto-accepts/rejects per policy, emits anAcceptwith aresultURL pointing to the stamp, or aReject.Activitypub\Activity\Extended_Object\Feature_Authorization— the JSON-LD stamp document served when remote servers verify a featured item.activitypub_default_feature_policy(anyone/followers/me, defaultme).interactionPolicy.canFeatureon everyUser,Blog, andApplicationactor (single override on the sharedActorbase class)._activitypub_featured_byuser_meta. The umeta_id doubles as the stamp identifier; ownership enforced by cross-checking the row'suser_idagainst the queried actor on dereference.?actor=USER_ID&stamp=UMETA_ID. Resolved by an extension toActivitypub\Query::maybe_get_stamp()that handles the actor-scoped variant alongside the existing post-scoped quote stamps. Includes a guard inRouter::template_redirectso stamp URLs are not 404'd by the actor-username lookup.Out of scope (deferred):
FeaturedCollections — separate, larger feature.DeleteforFeatureAuthorizationon revocation.Other information:
27 new test cases / 87 assertions across
Test_Feature_Authorization,Test_Feature_Request,Test_Interaction_Policy,Test_Query_Feature_Stamp, plus router-guard and end-to-end coverage inTest_RouterandTest_Query_Feature_Stamp::test_stamp_url_routes_and_resolves_end_to_end.Testing instructions:
curl -H 'Accept: application/activity+json' https://example.com/?author=1. Confirm the response includes:automaticApprovalshould now be["https://www.w3.org/ns/activitystreams#Public"].FeatureRequestactivity to the actor inbox while the policy is Anyone. Confirm anAcceptis emitted to the outbox and theresultURL dereferences to aFeatureAuthorizationJSON document withinteractingObjectset to the requester's collection URI.Rejectis emitted and no usermeta row is created.FeatureRequesttwice. Confirm only one usermeta row exists (idempotency).?actor=2&stamp=<umeta_id_belonging_to_user_1>. Confirm a 404 — cross-actor stamps are rejected.Changelog entry
Already added at
.github/changelog/feature-collections-consent(significance: minor, type: added). No auto-create needed.