fix(api): use Fedify for ActivityPub protocol documents#337
Conversation
|
@coderabbitai please verify whether issue #334 is correctly implemented after the corrected protocol interpretation. The Mastodon actor JSON is now treated only as an example, not as docker-git's exact contract. Please check that local ActivityPub output is built through Fedify/@fedify/vocab, explicit contexts do not leak unsupported Mastodon terms (webfinger/toot/featured/alsoKnownAs/movedTo/interactionPolicy/etc.), existing /federation/* URLs still work, /.well-known/webfinger is served through Fedify, ForgeFed Ticket remains typed at the Effect Schema boundary, and followers?page=2 still returns typed HTTP 400. If any proof gap remains, list the exact blocker. |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (4)
📜 Recent review details⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
🧰 Additional context used📓 Path-based instructions (9)**/*.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
**/*.{sh,bash,py,js,ts,jsx,tsx,go,java,rb,php}📄 CodeRabbit inference engine (Custom checks)
Files:
**/*.{py,js,ts,jsx,tsx,go,java,rb,php,sh,bash,c,cpp}📄 CodeRabbit inference engine (Custom checks)
Files:
**/*.{js,ts,jsx,tsx,py,java,go,rb,php,sh,bash,yml,yaml,json,env*,toml,cfg,config,dockerfile,dockerignore}📄 CodeRabbit inference engine (Custom checks)
Files:
packages/app/**/*.{ts,tsx,js,jsx}📄 CodeRabbit inference engine (README.md)
Files:
**/*⚙️ CodeRabbit configuration file
Files:
**/*.test.{ts,tsx}📄 CodeRabbit inference engine (CLAUDE.md)
Files:
**/*.{test,spec}.{ts,tsx}📄 CodeRabbit inference engine (AGENTS.md)
Files:
🔇 Additional comments (4)
📝 WalkthroughSummary by CodeRabbit
WalkthroughДанный PR переводит федерационные документы с ActivityPub schema-based валидации на генерацию через библиотеку Fedify: добавлены зависимости Fedify, создан модуль fedify-federation, переработаны контракты и HTTP-обработчики (включая WebFinger), и обновлены тесты для проверки Fedify-сериализации и последующего парсинга. ChangesМиграция федеральной архитектуры на Fedify библиотеку
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 7✅ Passed checks (7 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 4759 🏁 Script executed: Length of output: 93692 Let me gather the remaining details needed for a full verification. 🏁 Script executed: Length of output: 12806 🏁 Script executed: Length of output: 7499 🏁 Script executed: Length of output: 3341 🏁 Script executed: Length of output: 4912
Verification Summary✅ 1. Local ActivityPub output is built through Fedify /
|
| Route | Handler |
|---|---|
/federation/actor |
makeFedifyActorJsonLd |
/federation/outbox |
makeFedifyOutboxJsonLd |
/federation/followers |
makeFedifyFollowersJsonLd / makeFedifyFollowersPageJsonLd |
/federation/following |
makeFedifyFollowingJsonLd |
/federation/liked |
makeFedifyLikedJsonLd |
The http-config.test.ts suite exercises all five routes and verifies @context, type, and id on each response.
✅ 4. /.well-known/webfinger is served through Fedify
A new federationWebFingerResponse() handler (Line 753 in http.ts) is registered at /.well-known/webfinger. Internally, fetchFedifyWebFinger calls createFederation<FedifyContextData>({ … }).fetch(request, …). The setActorDispatcher + mapHandle + mapAlias chain correctly wires acct:username@host lookups to the local actor.
The test at Line 290 of http-config.test.ts verifies:
status: 200Content-Type: application/jrd+jsonsubject: "acct:docker-git@public.example.test"aliases: ["https://public.example.test/federation/actor"]links[0]: { rel: "self", href: "…/federation/actor", type: "application/activity+json" }
✅ 5. ForgeFed Ticket remains typed at the Effect Schema boundary
ForgeFedTicketSchema and ForgeFedTicketSourceSchema are intact in activitypub-schema.ts (Lines 30–48) and still exported from both schema.ts and contracts.ts. In federation.ts, readTicketPayload returns Effect.Effect<ForgeFedTicket, ApiBadRequestError> — the Effect type system enforces the schema at the JSON ingestion boundary.
The parity test "keeps ForgeFed Ticket validation at the JSON boundary" confirms Schema.decodeUnknownEither(ForgeFedTicketSchema) accepts a complete fixture and returns Either.isRight === true.
✅ 6. followers?page=2 still returns typed HTTP 400
readFollowersPageMode (Lines 324–332 of http.ts) returns Effect.fail(new ApiBadRequestError({ message: "Unsupported followers page: 2" })) for any ?page value other than "1". The test at Line 319 of http-config.test.ts confirms:
status: 400
error.type: "ApiBadRequestError"
error.message: "Unsupported followers page: 2"
Overall verdict: PR #337 correctly and completely implements issue #334. All six checklist items pass with no proof gaps.
There was a problem hiding this comment.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
packages/api/tests/federation.test.ts (1)
144-184: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick winОтсутствует property-based тестирование инвариантов Fedify генерации.
Тест проверяет конкретные значения, но не верифицирует математические инварианты генерации JSON-LD документов. Согласно гайдлайну для
**/*.test.{ts,tsx}: "Implement property-based testing using fast-check for mathematical properties and invariants".Рекомендуемые инварианты для property-based тестов:
- Round-trip инвариант: ∀doc:
Fedify.fromJsonLd(makeFedifyActorJsonLd(ctx)) succeeds- Структурный инвариант: ∀collection:
collection.totalItems === collection.orderedItems.length- JSON-LD компактность: Сгенерированный документ не содержит избыточных контекстов
- URL консистентность: Все внутренние ссылки начинаются с
context.publicOrigin♻️ Пример property-based теста для round-trip инварианта
import fc from "fast-check" import { Person } from "`@fedify/fedify`" it.effect("satisfies Fedify Actor JSON-LD round-trip invariant", () => Effect.gen(function*(_) { clearFederationState() yield* _(Effect.sync(() => { fc.assert( fc.asyncProperty( fc.record({ publicOrigin: fc.webUrl(), actorUsername: fc.string({ minLength: 1, maxLength: 20 }) }), async (config) => { const context = await Effect.runPromise( makeFederationContext(config) ) const jsonLd = await Effect.runPromise( makeFedifyActorJsonLd(context) ) // Инвариант: сгенерированный JSON-LD должен парситься обратно в Person const person = await Person.fromJsonLd(jsonLd) expect(person.id?.href).toContain(config.publicOrigin) expect(person.preferredUsername).toBe(config.actorUsername) } ) ) })) }))As per coding guidelines: "Property-based tests (fast-check) must verify mathematical invariants".
🤖 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 `@packages/api/tests/federation.test.ts` around lines 144 - 184, Добавьте property-based тесты с fast-check в этот файл, проверяющие формальные инварианты генерации Fedify JSON-LD: (1) round-trip: для произвольных входных конфигов (используя генераторы для publicOrigin и actorUsername) вызвать makeFederationContext -> makeFedifyActorJsonLd и проверить, что Fedify.fromJsonLd или Person.fromJsonLd успешно парсит результат и сохраняет id/preferredUsername; (2) структурный инвариант: для коллекций, полученных через makeFedifyFollowingJsonLd, проверять totalItems === orderedItems.length; (3) компактность JSON‑LD: сгенерированные документы не содержат дублирующихся "`@context`" записей; (4) URL‑консистентность: все внутренние ссылочные поля (например id, followers, orderedItems) начинаются с context.publicOrigin; используйте существующие helpers makeFedifyActorJsonLd, makeFedifyFollowingJsonLd, makeFederationContext, и при необходимости создавайте/очищайте состояние через clearFederationState/createFollowSubscription/ingestFederationInbox внутри fc.asyncProperty.packages/api/tests/http-config.test.ts (1)
274-288:⚠️ Potential issue | 🟠 Major | 🏗️ Heavy liftУсилить тест
/federation/followers?page=1: добавить структурную валидацию черезOrderedCollectionPage.fromJsonLd
- В
packages/api/tests/http-config.test.tsдля followers page сейчас нет парсинга/схемы: проверяются только выборочные поля (@context,type,id,partOf) и отсутствие Mastodon-терминов.- Из‑за этого тест не гарантирует наличие/форму остальных обязательных полей
OrderedCollectionPage, и часть регрессий JSON-LD может остаться незамеченной.- В репозитории уже есть пример структурной проверки через
OrderedCollectionPage.fromJsonLdвpackages/api/tests/activitypub-schema-parity.test.ts— стоит применить аналогично и здесь (парситьpayload, а затем проверять значения).🤖 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 `@packages/api/tests/http-config.test.ts` around lines 274 - 288, The followers page test currently only checks a few fields; update the test to perform structural validation by parsing the response payload with OrderedCollectionPage.fromJsonLd (like in activitypub-schema-parity.test.ts): after obtaining document via readFederationDocumentRoute and parsing with parseJsonObject, call OrderedCollectionPage.fromJsonLd(payload) and assert it returns a valid instance, then verify the instance's id/partOf/type/page properties match the expected values and still call assertNoMastodonTerms(payload); keep existing checks for document.status and contentType but replace the ad-hoc field assertions with the structured assertions against the OrderedCollectionPage instance.
🤖 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 `@packages/api/tests/activitypub-schema-parity.test.ts`:
- Around line 47-52: The helper asRecord uses a forbidden `as JsonRecord`
assertion; replace it with a proper runtime type guard and let TypeScript narrow
the type (e.g., implement an isJsonRecord(value): value is JsonRecord predicate
or change asRecord to use an assertion signature like function asRecord(value:
unknown): JsonRecord by performing explicit checks), then return the validated
object without using `as`; update references to asRecord to rely on the
runtime-validated return type and remove the cast.
In `@packages/api/tests/http-config.test.ts`:
- Around line 290-317: Add property-based tests (using fast-check) alongside the
existing example test in tests/http-config.test.ts to verify RFC 7033
invariants: create new it.effect cases that generate records of {username,
domain} (use fc.string with a safe charset filter and fc.domain or fc.webUrl)
and for each generated resource call
readFederationDocumentRoute(`/.well-known/webfinger?resource=acct:${username}@${domain}`),
parse the response with parseJsonObject and assert: (1) payload.subject equals
the requested resource, (2) every entry in aliases is a valid URL and points to
the federation actor pattern, (3) payload.links contains an object with rel ===
"self" and type === "application/activity+json", and (4) perform a round-trip by
fetching the actor URL in aliases[0] (using the existing helper that fetches
actor documents or readFederationDocumentRoute if appropriate) and assert the
actor document is returned and well-formed; implement these as fc.asyncProperty
tests and ensure failures surface deterministically.
- Around line 137-155: The current assertNoMastodonTerms uses
JSON.stringify/includes which causes false positives; instead parse and inspect
the object structure in assertNoMastodonTerms by (1) returning early on null,
(2) checking the top-level "`@context`" value(s) for any Mastodon-specific URIs
from unsupportedMastodonTerms, and (3) recursively traversing the payload
object/arrays to ensure no object property keys exactly match any value in
unsupportedMastodonTerms (use strict equality on keys, not substring matches).
Update calls/expectations to use this structural check around the
unsupportedMastodonTerms constant and keep behavior deterministic for nested
objects and arrays.
---
Outside diff comments:
In `@packages/api/tests/federation.test.ts`:
- Around line 144-184: Добавьте property-based тесты с fast-check в этот файл,
проверяющие формальные инварианты генерации Fedify JSON-LD: (1) round-trip: для
произвольных входных конфигов (используя генераторы для publicOrigin и
actorUsername) вызвать makeFederationContext -> makeFedifyActorJsonLd и
проверить, что Fedify.fromJsonLd или Person.fromJsonLd успешно парсит результат
и сохраняет id/preferredUsername; (2) структурный инвариант: для коллекций,
полученных через makeFedifyFollowingJsonLd, проверять totalItems ===
orderedItems.length; (3) компактность JSON‑LD: сгенерированные документы не
содержат дублирующихся "`@context`" записей; (4) URL‑консистентность: все
внутренние ссылочные поля (например id, followers, orderedItems) начинаются с
context.publicOrigin; используйте существующие helpers makeFedifyActorJsonLd,
makeFedifyFollowingJsonLd, makeFederationContext, и при необходимости
создавайте/очищайте состояние через
clearFederationState/createFollowSubscription/ingestFederationInbox внутри
fc.asyncProperty.
In `@packages/api/tests/http-config.test.ts`:
- Around line 274-288: The followers page test currently only checks a few
fields; update the test to perform structural validation by parsing the response
payload with OrderedCollectionPage.fromJsonLd (like in
activitypub-schema-parity.test.ts): after obtaining document via
readFederationDocumentRoute and parsing with parseJsonObject, call
OrderedCollectionPage.fromJsonLd(payload) and assert it returns a valid
instance, then verify the instance's id/partOf/type/page properties match the
expected values and still call assertNoMastodonTerms(payload); keep existing
checks for document.status and contentType but replace the ad-hoc field
assertions with the structured assertions against the OrderedCollectionPage
instance.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 0f770d71-7afb-4832-92f8-d701026f8643
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (10)
packages/api/package.jsonpackages/api/src/api/activitypub-schema.tspackages/api/src/api/contracts.tspackages/api/src/api/schema.tspackages/api/src/http.tspackages/api/src/services/federation.tspackages/api/src/services/fedify-federation.tspackages/api/tests/activitypub-schema-parity.test.tspackages/api/tests/federation.test.tspackages/api/tests/http-config.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
- GitHub Check: E2E (Clone auto-open SSH)
- GitHub Check: Lint
- GitHub Check: E2E (OpenCode)
- GitHub Check: E2E (Clone cache)
- GitHub Check: E2E (Login context)
- GitHub Check: E2E (Runtime volumes + SSH)
- GitHub Check: E2E (Browser command)
- GitHub Check: Final build (windows-latest)
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{js,ts,jsx,tsx,py,java,go,rb,php,sh,bash,yml,yaml,json,env*,toml,cfg,config,dockerfile,dockerignore}
📄 CodeRabbit inference engine (Custom checks)
Fail if changed files expose credentials, tokens, private-keys, or PII in source, generated config, logs, or CI output
Files:
packages/api/package.jsonpackages/api/tests/federation.test.tspackages/api/src/api/schema.tspackages/api/tests/http-config.test.tspackages/api/tests/activitypub-schema-parity.test.tspackages/api/src/services/federation.tspackages/api/src/api/activitypub-schema.tspackages/api/src/api/contracts.tspackages/api/src/http.tspackages/api/src/services/fedify-federation.ts
**/{package*.json,requirements*.txt,setup.py,setup.cfg,Pipfile,Pipfile.lock,pyproject.toml,pom.xml,build.gradle,Gemfile,Gemfile.lock,go.mod,go.sum,composer.json,Cargo.toml,Cargo.lock}
📄 CodeRabbit inference engine (Custom checks)
Fail if dependency or package-manager changes materially increase supply-chain risk without justification
Files:
packages/api/package.json
**/*
⚙️ CodeRabbit configuration file
**/*: Ты строгий ревьюер SPEC DRIVEN DEVELOPMENT.Перед выводами изучи README.md, другие *.md файлы, linked issues,
PR description, PR comments/discussion и релевантную кодовую базу.Сверь изменения с исходным ТЗ/спекой и обсуждением. Флагай любой уход
от спеки, недокументированное изменение поведения, отсутствие тестов
для заявленного поведения и security-риск. Если спека не видна,
попроси автора добавить ее в issue или PR description.Проверь решение с точки зрения формальной верификации: какие инварианты,
предусловия и постусловия можно доказать математически, а где доказуемость
слабая. Оцени решение с точки зрения теории игр: устойчивы ли стимулы,
нет ли выгодного обхода правил, и какое решение было бы сильнее.
Files:
packages/api/package.jsonpackages/api/tests/federation.test.tspackages/api/src/api/schema.tspackages/api/tests/http-config.test.tspackages/api/tests/activitypub-schema-parity.test.tspackages/api/src/services/federation.tspackages/api/src/api/activitypub-schema.tspackages/api/src/api/contracts.tspackages/api/src/http.tspackages/api/src/services/fedify-federation.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Implement Functional Core, Imperative Shell (FCIS) pattern: CORE layer contains only pure functions with immutable data and mathematical operations; SHELL layer isolates all effects (IO, network, database). Strict dependency direction: SHELL → CORE (never reverse).
Never useany,unknown,eslint-disable,ts-ignore, orastype assertions (except in rigorously justified cases with documentation). Always use exhaustive union type analysis through.exhaustive()pattern matching.
All external dependencies must be wrapped through typed interfaces and injected via Effect-TS Layer pattern. Never call external services directly from CORE functions.
Use monadic composition with Effect-TS for all effects:Effect<Success, Error, Requirements>. Compose effects throughpipe()andEffect.flatMap(). Implement dependency injection via Layer pattern. Handle errors without try/catch blocks.
All functions must be pure in the CORE layer: no side effects (logging, console output, IO operations, mutations). Separate all side effects into the SHELL layer.
Use exhaustive pattern matching with Effect.Match instead of switch statements. Example:Match.value(item).pipe(Match.when(...), Match.exhaustive).
Document all functions with comprehensive TSDoc including:@pure(true/false),@effect(required services),@invariant(mathematical invariants),@precondition,@postcondition,@complexity(time and space),@throwsNever (errors must be typed in Effect).
Use functional comment markers for code clarity: CHANGE (brief description), WHY (mathematical/architectural justification), QUOTE(ТЗ) (requirement citation), REF (RTM or message ID), SOURCE (external source with quote), FORMAT THEOREM (∀x ∈ Domain: P(x) → Q(f(x))), PURITY (CORE|SHELL), EFFECT (Effect type signature), INVARIANT (mathematical invariant), COMPLEXITY (time/space).
Define all external service dependencies as Context.Tag classes with fully typed methods returning Effect types. Example: `class Da...
Files:
packages/api/tests/federation.test.tspackages/api/src/api/schema.tspackages/api/tests/http-config.test.tspackages/api/tests/activitypub-schema-parity.test.tspackages/api/src/services/federation.tspackages/api/src/api/activitypub-schema.tspackages/api/src/api/contracts.tspackages/api/src/http.tspackages/api/src/services/fedify-federation.ts
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.test.{ts,tsx}: Implement property-based testing using fast-check for mathematical properties and invariants. Example:fc.property(fc.array(messageArbitrary), (messages) => isChronologicallySorted(sortMessagesByTimestamp(messages))).
Mock external dependencies in unit tests using Effect's testing utilities. Run tests without Effect runtime for speed. Example:Effect.provide(MockService), Effect.runPromise.
Files:
packages/api/tests/federation.test.tspackages/api/tests/http-config.test.tspackages/api/tests/activitypub-schema-parity.test.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Forbidden constructs in CORE code:any,eslint-disable,ts-ignore,async/await, raw Promise chains (then/catch),Promise.all,try/catchfor logic control,console.*, switch statements (use Match with .exhaustive() instead)
All functions must use Effect-TS for composing effects:Effect<Success, Error, Requirements>. No direct async/await, Promise chains, or try/catch in product logic.
Functional comments must include: CHANGE, WHY, QUOTE(ТЗ) or n/a, REF, SOURCE or n/a, FORMAT THEOREM, PURITY (CORE|SHELL), EFFECT signature for SHELL functions, INVARIANT, and COMPLEXITY.
All data mutations must use immutable patterns (ReadonlyArray, readonly properties, Object.freeze); mutation in SHELL only when absolutely necessary and documented.
Files:
packages/api/tests/federation.test.tspackages/api/src/api/schema.tspackages/api/tests/http-config.test.tspackages/api/tests/activitypub-schema-parity.test.tspackages/api/src/services/federation.tspackages/api/src/api/activitypub-schema.tspackages/api/src/api/contracts.tspackages/api/src/http.tspackages/api/src/services/fedify-federation.ts
**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Property-based tests (fast-check) must verify mathematical invariants; unit tests must use Effect test utilities without async/await.
Files:
packages/api/tests/federation.test.tspackages/api/tests/http-config.test.tspackages/api/tests/activitypub-schema-parity.test.ts
**/*.{sh,bash,py,js,ts,jsx,tsx,go,java,rb,php}
📄 CodeRabbit inference engine (Custom checks)
Fail if changed files introduce command injection or unsafe shell/process execution with user-controlled input
Files:
packages/api/tests/federation.test.tspackages/api/src/api/schema.tspackages/api/tests/http-config.test.tspackages/api/tests/activitypub-schema-parity.test.tspackages/api/src/services/federation.tspackages/api/src/api/activitypub-schema.tspackages/api/src/api/contracts.tspackages/api/src/http.tspackages/api/src/services/fedify-federation.ts
**/*.{py,js,ts,jsx,tsx,go,java,rb,php,sh,bash,c,cpp}
📄 CodeRabbit inference engine (Custom checks)
Fail if changed files introduce path traversal or writes outside intended project/container state directories
Files:
packages/api/tests/federation.test.tspackages/api/src/api/schema.tspackages/api/tests/http-config.test.tspackages/api/tests/activitypub-schema-parity.test.tspackages/api/src/services/federation.tspackages/api/src/api/activitypub-schema.tspackages/api/src/api/contracts.tspackages/api/src/http.tspackages/api/src/services/fedify-federation.ts
packages/api/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (README.md)
API layer should work only with LIB and serve as the intermediary between APP and LIB
Files:
packages/api/tests/federation.test.tspackages/api/src/api/schema.tspackages/api/tests/http-config.test.tspackages/api/tests/activitypub-schema-parity.test.tspackages/api/src/services/federation.tspackages/api/src/api/activitypub-schema.tspackages/api/src/api/contracts.tspackages/api/src/http.tspackages/api/src/services/fedify-federation.ts
🧠 Learnings (1)
📚 Learning: 2026-05-18T07:43:38.131Z
Learnt from: skulidropek
Repo: ProverCoderAI/docker-git PR: 313
File: packages/api/src/services/panel-cloudflare-tunnel.ts:123-135
Timestamp: 2026-05-18T07:43:38.131Z
Learning: In this repo’s ProverCoderAI/docker-git architecture, it is intentional for service modules under packages/api/src/services/ to call Node.js APIs directly (e.g., fs, child_process, fetch). Do not treat direct Node API usage in these service modules as a dependency-injection (DI) violation. This codebase provides the NodeContext at the program boundary (entry point) rather than injecting Context.Tag/Layer services into individual service modules; reviewers should only flag DI/context issues if the expected boundary setup is missing.
Applied to files:
packages/api/src/services/federation.tspackages/api/src/services/fedify-federation.ts
🔇 Additional comments (15)
packages/api/src/api/activitypub-schema.ts (1)
1-67: LGTM!packages/api/src/api/schema.ts (1)
3-10: LGTM!packages/api/src/services/federation.ts (1)
47-51: LGTM!Also applies to: 580-582
packages/api/src/services/fedify-federation.ts (3)
1-33: LGTM!Also applies to: 69-89, 146-173
99-110: 💤 Low valueAction required: Provide the original review comment inside the
<review_comment>tags (and any relevant code/file context) so I can rewrite it correctly.
214-227: ⚡ Quick winRequest missing input: Provide the original review comment inside
<review_comment>...</review_comment>(and any relevant diff/code context) so it can be rewritten in the required style.packages/api/src/http.ts (1)
81-89: LGTM!Also applies to: 646-751, 1044-1047
packages/api/tests/activitypub-schema-parity.test.ts (1)
88-223: LGTM!packages/api/src/api/contracts.ts (1)
559-562: 💤 Low valueMissing input: Paste the original
<review_comment>text you want rewritten (including any diff snippets and context).packages/api/package.json (1)
26-27: Проверьте известные уязвимости для@fedify/fedify@^2.2.3 и@fedify/vocab@^2.2.3В
packages/api/package.jsonдобавлены@fedify/fedifyи@fedify/vocabверсии^2.2.3(пакет2.2.3реально существует на npm). В показанной выборке из GitHub Advisory Database у@fedify/fedifyуязвимости относятся к диапазонам ниже2.2.3(в частности, верхние границы <2.1.0), поэтому пересечение с^2.2.3в этой части не обнаруживается; для@fedify/vocabв текущей выборке уязвимости не возвращались. Нужно прогнать проверку по всем advisory-записям (с пагинацией), чтобы исключить уязвимости, которые могут попадать в интервал>=2.2.3 <3.0.0.packages/api/tests/federation.test.ts (2)
9-12: LGTM!
26-34: 🏗️ Heavy liftMissing input: provide the original
<review_comment>content (and any relevant code context/diff) so I can rewrite it correctly.packages/api/tests/http-config.test.ts (3)
4-4: LGTM!Also applies to: 8-11, 19-19
61-61: LGTM!
170-192: LGTM!
|
@coderabbitai please re-check the latest commit. I addressed the test review comments by removing the test helper type assertion, replacing string-based Mastodon-term checks with structural context/key checks, adding Fedify actor/following property invariants, adding WebFinger invariant coverage for supported actor resources, and parsing followers?page=1 with OrderedCollectionPage.fromJsonLd. Please confirm whether any blocker remains. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 13997
Verification of commit
|
AI Session BackupCommit: 0444748
|
|
@coderabbitai please re-check the latest commit 0444748. I added README documentation for the Fedify WebFinger endpoint and updated the PR body with the proof obligations. Please verify whether issue #334 is now implemented under the corrected interpretation: Mastodon JSON is only an example, local ActivityPub documents are generated through Fedify/@fedify/vocab, unsupported Mastodon extension context terms/keys are not emitted, existing /federation/* routes still work, /.well-known/webfinger is served through Fedify, ForgeFed Ticket remains schema-typed at the boundary, and followers?page=2 still returns typed HTTP 400. If any proof gap remains, list the exact blocker. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 5367
Final Verification — commit
|
| # | Requirement | Status |
|---|---|---|
| 1 | Local ActivityPub output built through Fedify / @fedify/vocab |
✅ fedify-federation.ts — Person, OrderedCollection, OrderedCollectionPage, Follow all serialized via .toJsonLd() |
| 2 | No unsupported Mastodon extension context terms or keys emitted | ✅ Structural recursive walkers assertNoMastodonContextTerms + assertNoMastodonKeys in parity and HTTP tests; README now documents the guarantee |
| 3 | Existing /federation/* routes still work |
✅ All five routes preserved; HTTP config test covers each with @context, type, id assertions |
| 4 | /.well-known/webfinger served through Fedify |
✅ federationWebFingerResponse → fetchFedifyWebFinger; property-based WebFinger invariant test covers both acct: and actor URL resource forms |
| 5 | ForgeFed Ticket remains schema-typed at the Effect boundary | ✅ ForgeFedTicketSchema intact in activitypub-schema.ts; "keeps ForgeFed Ticket validation at the JSON boundary" test passes with Either.isRight |
| 6 | followers?page=2 returns typed HTTP 400 |
✅ readFollowersPageMode returns ApiBadRequestError; HTTP config test asserts status: 400, type: "ApiBadRequestError" |
PR body now includes all seven formal invariants, executable evidence section, and states 168 tests passing on this commit.
No proof gaps remain. PR #337 is complete.
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 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 `@packages/api/tests/federation.test.ts`:
- Around line 210-242: The property tests use async/await inside
fc.asyncProperty callbacks; refactor the callbacks to return effects instead of
being async functions: inside the it.effect tests (e.g., "satisfies Fedify actor
JSON-LD property invariants" and the "following collection" test) replace direct
awaits of Effect.runPromise(makeFederationContext(...)) and
makeFedifyActorJsonLd(...) with an Effect-based composition (use Effect.gen or
pipe/Effect.flatMap) and call Effect.runPromise at the end synchronously (no
async callback). Also replace any for+await loops (in the following collection
test) with Effect.forEach over the collection to sequence effects. Keep
references to the same helpers (makeFederationContext, makeFedifyActorJsonLd,
Person.fromJsonLd) but build and return a single Effect for fc.asyncProperty to
run instead of using async/await inside the property callback.
In `@packages/api/tests/http-config.test.ts`:
- Around line 381-433: Remove async/await from the WebFinger property test by
making the fc.asyncProperty callback a non-async function that builds and runs
an Effect pipeline instead of awaiting; specifically, replace the async arrow
used with webFingerResourceArbitrary with a synchronous callback that composes
operations using pipe/Effect.flatMap (and Effect.map) calling
clearFederationState, readFederationDocumentRoute(resourceQuery),
parseJsonObject, readField, isJsonRecord and the subsequent assertions as
Effects, then execute that pipeline with Effect.runPromise (or return the
Effect.runPromise call) instead of using await; keep unique symbols like
it.effect, fc.asyncProperty, webFingerResourceArbitrary, clearFederationState,
readFederationDocumentRoute, parseJsonObject, readField, isJsonRecord and ensure
all former await usages (previously on
Effect.runPromise(readFederationDocumentRoute(...)) and
Effect.runPromise(readFederationDocumentRoute("/federation/actor"))) are
replaced by composing Effects and running them once at the end.
🪄 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: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 980b7c23-4e06-4fd7-ba48-a6a185b9f3c7
📒 Files selected for processing (3)
packages/api/tests/activitypub-schema-parity.test.tspackages/api/tests/federation.test.tspackages/api/tests/http-config.test.ts
📜 Review details
⏰ Context from checks skipped due to timeout of 900000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
- GitHub Check: Lint
- GitHub Check: E2E (Browser command)
- GitHub Check: Test
- GitHub Check: E2E (OpenCode)
- GitHub Check: E2E (Clone cache)
- GitHub Check: E2E (Login context)
- GitHub Check: E2E (Runtime volumes + SSH)
- GitHub Check: E2E (Clone auto-open SSH)
- GitHub Check: Final build (windows-latest)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.{ts,tsx}: Implement Functional Core, Imperative Shell (FCIS) pattern: CORE layer contains only pure functions with immutable data and mathematical operations; SHELL layer isolates all effects (IO, network, database). Strict dependency direction: SHELL → CORE (never reverse).
Never useany,unknown,eslint-disable,ts-ignore, orastype assertions (except in rigorously justified cases with documentation). Always use exhaustive union type analysis through.exhaustive()pattern matching.
All external dependencies must be wrapped through typed interfaces and injected via Effect-TS Layer pattern. Never call external services directly from CORE functions.
Use monadic composition with Effect-TS for all effects:Effect<Success, Error, Requirements>. Compose effects throughpipe()andEffect.flatMap(). Implement dependency injection via Layer pattern. Handle errors without try/catch blocks.
All functions must be pure in the CORE layer: no side effects (logging, console output, IO operations, mutations). Separate all side effects into the SHELL layer.
Use exhaustive pattern matching with Effect.Match instead of switch statements. Example:Match.value(item).pipe(Match.when(...), Match.exhaustive).
Document all functions with comprehensive TSDoc including:@pure(true/false),@effect(required services),@invariant(mathematical invariants),@precondition,@postcondition,@complexity(time and space),@throwsNever (errors must be typed in Effect).
Use functional comment markers for code clarity: CHANGE (brief description), WHY (mathematical/architectural justification), QUOTE(ТЗ) (requirement citation), REF (RTM or message ID), SOURCE (external source with quote), FORMAT THEOREM (∀x ∈ Domain: P(x) → Q(f(x))), PURITY (CORE|SHELL), EFFECT (Effect type signature), INVARIANT (mathematical invariant), COMPLEXITY (time/space).
Define all external service dependencies as Context.Tag classes with fully typed methods returning Effect types. Example: `class Da...
Files:
packages/api/tests/activitypub-schema-parity.test.tspackages/api/tests/federation.test.tspackages/api/tests/http-config.test.ts
**/*.test.{ts,tsx}
📄 CodeRabbit inference engine (CLAUDE.md)
**/*.test.{ts,tsx}: Implement property-based testing using fast-check for mathematical properties and invariants. Example:fc.property(fc.array(messageArbitrary), (messages) => isChronologicallySorted(sortMessagesByTimestamp(messages))).
Mock external dependencies in unit tests using Effect's testing utilities. Run tests without Effect runtime for speed. Example:Effect.provide(MockService), Effect.runPromise.
Files:
packages/api/tests/activitypub-schema-parity.test.tspackages/api/tests/federation.test.tspackages/api/tests/http-config.test.ts
**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx}: Forbidden constructs in CORE code:any,eslint-disable,ts-ignore,async/await, raw Promise chains (then/catch),Promise.all,try/catchfor logic control,console.*, switch statements (use Match with .exhaustive() instead)
All functions must use Effect-TS for composing effects:Effect<Success, Error, Requirements>. No direct async/await, Promise chains, or try/catch in product logic.
Functional comments must include: CHANGE, WHY, QUOTE(ТЗ) or n/a, REF, SOURCE or n/a, FORMAT THEOREM, PURITY (CORE|SHELL), EFFECT signature for SHELL functions, INVARIANT, and COMPLEXITY.
All data mutations must use immutable patterns (ReadonlyArray, readonly properties, Object.freeze); mutation in SHELL only when absolutely necessary and documented.
Files:
packages/api/tests/activitypub-schema-parity.test.tspackages/api/tests/federation.test.tspackages/api/tests/http-config.test.ts
**/*.{test,spec}.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Property-based tests (fast-check) must verify mathematical invariants; unit tests must use Effect test utilities without async/await.
Files:
packages/api/tests/activitypub-schema-parity.test.tspackages/api/tests/federation.test.tspackages/api/tests/http-config.test.ts
**/*.{sh,bash,py,js,ts,jsx,tsx,go,java,rb,php}
📄 CodeRabbit inference engine (Custom checks)
Fail if changed files introduce command injection or unsafe shell/process execution with user-controlled input
Files:
packages/api/tests/activitypub-schema-parity.test.tspackages/api/tests/federation.test.tspackages/api/tests/http-config.test.ts
**/*.{py,js,ts,jsx,tsx,go,java,rb,php,sh,bash,c,cpp}
📄 CodeRabbit inference engine (Custom checks)
Fail if changed files introduce path traversal or writes outside intended project/container state directories
Files:
packages/api/tests/activitypub-schema-parity.test.tspackages/api/tests/federation.test.tspackages/api/tests/http-config.test.ts
**/*.{js,ts,jsx,tsx,py,java,go,rb,php,sh,bash,yml,yaml,json,env*,toml,cfg,config,dockerfile,dockerignore}
📄 CodeRabbit inference engine (Custom checks)
Fail if changed files expose credentials, tokens, private-keys, or PII in source, generated config, logs, or CI output
Files:
packages/api/tests/activitypub-schema-parity.test.tspackages/api/tests/federation.test.tspackages/api/tests/http-config.test.ts
packages/api/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (README.md)
API layer should work only with LIB and serve as the intermediary between APP and LIB
Files:
packages/api/tests/activitypub-schema-parity.test.tspackages/api/tests/federation.test.tspackages/api/tests/http-config.test.ts
**/*
⚙️ CodeRabbit configuration file
**/*: Ты строгий ревьюер SPEC DRIVEN DEVELOPMENT.Перед выводами изучи README.md, другие *.md файлы, linked issues,
PR description, PR comments/discussion и релевантную кодовую базу.Сверь изменения с исходным ТЗ/спекой и обсуждением. Флагай любой уход
от спеки, недокументированное изменение поведения, отсутствие тестов
для заявленного поведения и security-риск. Если спека не видна,
попроси автора добавить ее в issue или PR description.Проверь решение с точки зрения формальной верификации: какие инварианты,
предусловия и постусловия можно доказать математически, а где доказуемость
слабая. Оцени решение с точки зрения теории игр: устойчивы ли стимулы,
нет ли выгодного обхода правил, и какое решение было бы сильнее.
Files:
packages/api/tests/activitypub-schema-parity.test.tspackages/api/tests/federation.test.tspackages/api/tests/http-config.test.ts
|
@coderabbitai please re-check the latest commit 2ed13f7. I addressed the new actionable review comments by removing async/await from the federation/WebFinger property tests, returning Effect.runPromise(Effect.gen(...)) from fast-check callbacks, and using Effect.forEach for sequenced follow/WebFinger assertions. Local verification passed: bun --cwd packages/api typecheck, lint, full test suite, and targeted federation/http-config tests. Please confirm whether any blocker remains for issue #334 under the corrected Fedify-based implementation. |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 18726
Verification of commit
|
| # | Requirement | Status |
|---|---|---|
| 1 | Local ActivityPub built through Fedify | ✅ Unchanged |
| 2 | No unsupported Mastodon terms emitted | ✅ Unchanged |
| 3 | /federation/* routes preserved |
✅ Unchanged |
| 4 | /.well-known/webfinger via Fedify |
✅ Unchanged |
| 5 | ForgeFed Ticket typed at Effect boundary | ✅ Unchanged |
| 6 | followers?page=2 → typed HTTP 400 |
✅ Unchanged |
PR #337 is complete with no remaining blockers.
|
@coderabbitai please verify whether issue #334 is fully implemented after commit 3c72a3b. In particular, check the corrected Fedify-based protocol contract and the new root WebFinger browser exposure: |
|
Tip For best results, initiate chat on the files or code changes. 🧩 Analysis chain🏁 Script executed: Length of output: 9681
Verification — commit
|
| File | Purpose |
|---|---|
packages/app/scripts/serve-dist-web-routing.mjs |
New shared routing module; exposes shouldProxyHttpPath |
packages/app/scripts/serve-dist-web.mjs |
Imports from routing module; removes inline logic |
packages/app/tests/docker-git/serve-dist-web.test.ts |
Unit tests for the routing logic |
packages/app/vite.web.config.ts |
Adds /.well-known/webfinger proxy entry |
✅ 1. /.well-known/webfinger proxied at public origin without /api
isWellKnownWebFingerPath in serve-dist-web-routing.mjs uses an exact match (pathname === "/.well-known/webfinger"), and shouldProxyHttpPath includes it in the OR chain alongside /api/ and /federation/. The matching vite.web.config.ts entry forwards to apiTarget (the API server).
✅ 2. Query string preserved
resolveUpstreamPath(url) in serve-dist-web.mjs returns ${pathname}${parsed.search} — the ?resource=acct:… query parameter is forwarded verbatim to the API. Vite's http-proxy also forwards the full URL including query string by default.
✅ 3. Returns Fedify application/jrd+json
The API-side handler (fetchFedifyWebFinger → Fedify federation.fetch) was verified in prior commits and is unchanged. Fedify sets Content-Type: application/jrd+json on WebFinger responses. The proxy does not alter response headers (changeOrigin: false).
✅ 4. Non-standard /.well-known/webfinger/extra not claimed
The exact-match guard (===) means /.well-known/webfinger/extra falls through to the static file handler, not the API proxy. The test in serve-dist-web.test.ts explicitly asserts this:
expect(shouldProxyHttpPath("/.well-known/webfinger/extra")).toBe(false)All six issue #334 requirements — still satisfied
| # | Requirement | Status |
|---|---|---|
| 1 | Local ActivityPub output built through Fedify | ✅ Unchanged |
| 2 | No unsupported Mastodon extension terms emitted | ✅ Unchanged |
| 3 | /federation/* routes preserved |
✅ Unchanged |
| 4 | /.well-known/webfinger served through Fedify |
✅ Now also exposed at browser root |
| 5 | ForgeFed Ticket typed at Effect boundary | ✅ Unchanged |
| 6 | followers?page=2 → typed HTTP 400 |
✅ Unchanged |
PR #337 is complete with no remaining blockers.
Summary
Fixes #334 by replacing the local ActivityPub document builders with Fedify/@fedify/vocab instead of treating one Mastodon actor response as docker-git's exact contract.
Person,OrderedCollection,OrderedCollectionPage, andFollowdocuments are now constructed through Fedify vocabulary classes./federation/actor,/federation/outbox,/federation/followers,/federation/followers?page=1,/federation/following, and/federation/likedURLs are preserved./.well-known/webfingeris served through Fedify for the local federation actor and is exposed by the browser frontend, not only the/apiproxy prefix.Ticketremains validated at the Effect Schema boundary.Corrected Protocol Interpretation
The Mastodon JSON from the discussion is a compatibility example, not the protocol contract for docker-git. docker-git emits only the supported ActivityStreams/security JSON-LD shape needed for its local actor and collections. It does not emit Mastodon extension context terms or keys such as
https://purl.archive.org/socialweb/webfinger,toot,featured,featuredTags,alsoKnownAs,movedTo,discoverable, orinteractionPolicy.WebFinger discovery is different from the API namespace: RFC 7033 requires the path component
/.well-known/webfinger, so a public browser/tunnel origin must proxy that exact root route to the API./api/.well-known/webfingercan work as an internal alias, but remote ActivityPub servers will query the root route.Proof Obligations
Invariants
forall d in LocalActivityPubDocuments: d = FedifyVocabularyObject.toJsonLd(d)for actor/collections/follow activities.forall d in LocalActivityPubDocuments: unsupported_mastodon_terms(d) = empty.forall route in LegacyFederationRoutes: HTTP_GET(route) = 200 and content-type(route) = application/activity+json.GET /federation/followers?page=1parses as FedifyOrderedCollectionPageand haspartOf = /federation/followers.GET /federation/followers?page=n, n != 1returns typedApiBadRequestErrorwith HTTP 400.forall f in ForgeFedTickets: accepted(f) -> Decode(ForgeFedTicketSchema, f) = Right(decoded).forall r in {acct:docker-git@origin, actorUrl}: WebFinger(r)returns a JRD self link to the same Fedify actor URL.forall q in QueryString: BrowserGET('/.well-known/webfinger' + q) -> ApiGET('/.well-known/webfinger' + q)withx-forwarded-prefix = ''.BrowserGET('/.well-known/webfinger/extra')is not claimed as WebFinger, so the browser shell only exposes the standards-defined well-known path.Executable Evidence
Person.fromJsonLd,OrderedCollection.fromJsonLd,OrderedCollectionPage.fromJsonLd, andFollow.fromJsonLd.application/jrd+json, subjectacct:docker-git@origin, alias actor URL, and self linkapplication/activity+json./.well-known/webfingeris proxied to API while/.well-known/webfinger/extrais not.Effect.runPromise(Effect.gen(...))to fast-check.Verification
Latest local verification on commit
3c72a3b64f6b4379a75046ba22e4303ebbce21e2:Live tunnel verification after restarting the browser runtime: