Skip to content

fix(api): use Fedify for ActivityPub protocol documents#337

Merged
skulidropek merged 5 commits into
mainfrom
issue-334-fedify
May 21, 2026
Merged

fix(api): use Fedify for ActivityPub protocol documents#337
skulidropek merged 5 commits into
mainfrom
issue-334-fedify

Conversation

@skulidropek
Copy link
Copy Markdown
Member

@skulidropek skulidropek commented May 21, 2026

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.

  • Local ActivityPub Person, OrderedCollection, OrderedCollectionPage, and Follow documents are now constructed through Fedify vocabulary classes.
  • Existing /federation/actor, /federation/outbox, /federation/followers, /federation/followers?page=1, /federation/following, and /federation/liked URLs are preserved.
  • Root /.well-known/webfinger is served through Fedify for the local federation actor and is exposed by the browser frontend, not only the /api proxy prefix.
  • ForgeFed Ticket remains validated at the Effect Schema boundary.
  • Mastodon-specific extension fields are intentionally not supported or emitted.

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, or interactionPolicy.

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/webfinger can 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=1 parses as Fedify OrderedCollectionPage and has partOf = /federation/followers.
  • GET /federation/followers?page=n, n != 1 returns typed ApiBadRequestError with 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) with x-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

  • Fedify round-trip tests parse local actor/collection/page documents through Person.fromJsonLd, OrderedCollection.fromJsonLd, OrderedCollectionPage.fromJsonLd, and Follow.fromJsonLd.
  • HTTP tests assert all local federation routes still respond at the existing URLs and reject unsupported followers pages.
  • API HTTP tests assert Fedify WebFinger returns application/jrd+json, subject acct:docker-git@origin, alias actor URL, and self link application/activity+json.
  • Browser frontend routing tests assert root /.well-known/webfinger is proxied to API while /.well-known/webfinger/extra is not.
  • Structural negative tests recursively reject unsupported Mastodon context terms and keys without stringifying the whole document.
  • Property-based tests cover Fedify actor URL/context invariants, following collection item-count invariants, WebFinger JRD invariants, and ForgeFed Ticket boundary decoding.
  • Property tests keep async boundaries inside Effect composition and return Effect.runPromise(Effect.gen(...)) to fast-check.
  • README documents the supported WebFinger endpoint and the intentionally unsupported Mastodon extension terms.

Verification

Latest local verification on commit 3c72a3b64f6b4379a75046ba22e4303ebbce21e2:

bun --cwd packages/api typecheck
bun --cwd packages/api lint
bun --cwd packages/api test
bun --cwd packages/api test federation http-config
bun --cwd packages/api test http-config
bun run --cwd packages/app vitest run tests/docker-git/serve-dist-web.test.ts -t "proxies root WebFinger to API"
bun run --cwd packages/app typecheck
bun run --cwd packages/app lint:tests
bun run --cwd packages/app lint:effect
bun run --cwd packages/app build:web
bun run --cwd packages/api vitest run tests/http-config.test.ts -t "serves WebFinger through Fedify"

Live tunnel verification after restarting the browser runtime:

curl -i 'https://speaking-creator-headquarters-nearest.trycloudflare.com/.well-known/webfinger?resource=acct:docker-git@speaking-creator-headquarters-nearest.trycloudflare.com'
# HTTP 200, content-type: application/jrd+json
# self.href = https://speaking-creator-headquarters-nearest.trycloudflare.com/federation/actor

@skulidropek
Copy link
Copy Markdown
Member Author

@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.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 628c5d0b-53b1-4234-920f-5fd72305f68f

📥 Commits

Reviewing files that changed from the base of the PR and between 2ed13f7 and 3c72a3b.

📒 Files selected for processing (4)
  • packages/app/scripts/serve-dist-web-routing.mjs
  • packages/app/scripts/serve-dist-web.mjs
  • packages/app/tests/docker-git/serve-dist-web.test.ts
  • packages/app/vite.web.config.ts
📜 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)
  • GitHub Check: E2E (Clone auto-open SSH)
  • GitHub Check: E2E (Runtime volumes + SSH)
  • GitHub Check: E2E (Clone cache)
  • GitHub Check: E2E (Browser command)
  • GitHub Check: E2E (Login context)
  • GitHub Check: E2E (OpenCode)
  • GitHub Check: Lint
  • GitHub Check: Test
  • 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 use any, unknown, eslint-disable, ts-ignore, or as type 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 through pipe() and Effect.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), @throws Never (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/app/vite.web.config.ts
  • packages/app/tests/docker-git/serve-dist-web.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/catch for 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/app/vite.web.config.ts
  • packages/app/tests/docker-git/serve-dist-web.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/app/vite.web.config.ts
  • packages/app/tests/docker-git/serve-dist-web.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/app/vite.web.config.ts
  • packages/app/tests/docker-git/serve-dist-web.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/app/vite.web.config.ts
  • packages/app/tests/docker-git/serve-dist-web.test.ts
packages/app/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (README.md)

App layer (APP) should work only with API and not have direct access to LIB layer

Files:

  • packages/app/vite.web.config.ts
  • packages/app/tests/docker-git/serve-dist-web.test.ts
**/*

⚙️ CodeRabbit configuration file

**/*: Ты строгий ревьюер SPEC DRIVEN DEVELOPMENT.

Перед выводами изучи README.md, другие *.md файлы, linked issues,
PR description, PR comments/discussion и релевантную кодовую базу.

Сверь изменения с исходным ТЗ/спекой и обсуждением. Флагай любой уход
от спеки, недокументированное изменение поведения, отсутствие тестов
для заявленного поведения и security-риск. Если спека не видна,
попроси автора добавить ее в issue или PR description.

Проверь решение с точки зрения формальной верификации: какие инварианты,
предусловия и постусловия можно доказать математически, а где доказуемость
слабая. Оцени решение с точки зрения теории игр: устойчивы ли стимулы,
нет ли выгодного обхода правил, и какое решение было бы сильнее.

Files:

  • packages/app/vite.web.config.ts
  • packages/app/tests/docker-git/serve-dist-web.test.ts
  • packages/app/scripts/serve-dist-web-routing.mjs
  • packages/app/scripts/serve-dist-web.mjs
**/*.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/app/tests/docker-git/serve-dist-web.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/app/tests/docker-git/serve-dist-web.test.ts
🔇 Additional comments (4)
packages/app/scripts/serve-dist-web-routing.mjs (1)

1-54: LGTM!

packages/app/scripts/serve-dist-web.mjs (1)

10-11: LGTM!

Also applies to: 246-247

packages/app/vite.web.config.ts (1)

21-26: LGTM!

packages/app/tests/docker-git/serve-dist-web.test.ts (1)

7-14: ⚡ Quick win

Missing input: Paste the original <review_comment> content (and any referenced file/line context) so it can be rewritten accurately.


📝 Walkthrough

Summary by CodeRabbit

  • Новые функции

    • Добавлен WebFinger-эндпоинт (GET /.well-known/webfinger) для обнаружения актёров в федерации
    • Внедрена генерация федерационных JSON‑LD документов через Fedify
  • Изменения

    • Упрощена и консолидирована генерация федерационных документов и JSON‑LD context’ов
    • Опубликован API для чтения локальных ключей актёра
    • Обновлена логика проксирования HTTP-путей и поддержки WebFinger в маршрутизации
  • Тесты

    • Переписаны интеграционные и property‑based тесты на Fedify сериализацию и парсинг
  • Документация

    • README дополнен описанием WebFinger и workflow федерации

Walkthrough

Данный PR переводит федерационные документы с ActivityPub schema-based валидации на генерацию через библиотеку Fedify: добавлены зависимости Fedify, создан модуль fedify-federation, переработаны контракты и HTTP-обработчики (включая WebFinger), и обновлены тесты для проверки Fedify-сериализации и последующего парсинга.

Changes

Миграция федеральной архитектуры на Fedify библиотеку

Layer / File(s) Summary
Зависимости и очистка схем
packages/api/package.json, packages/api/src/api/activitypub-schema.ts, packages/api/src/api/schema.ts, packages/api/README.md
Добавлены @fedify/fedify и @fedify/vocab v^2.2.3; удалены экспортируемые ActivityPub схемы/контексты и exactActivityPubParseOptions; сохранены только ForgeFedTicket и LocalActivityPubOrderedCollectionSchema в ре-экспортах; README обновлён с WebFinger endpoint.
Обновление контрактов и API федерации
packages/api/src/api/contracts.ts, packages/api/src/services/federation.ts
Обновлены импорты/контексты в contracts.ts (удалён forgeFedJsonLdContext из actorJsonLdContext, удалён тип ActorJsonLdContext); в services/federation.ts удалены фабрики makeFederation* и добавлены экспортируемый тип LocalActorKeys и функция readLocalActorKeys().
Реализация генерации через Fedify
packages/api/src/services/fedify-federation.ts
Новый модуль: импорт публичного ключа (PEM→JWK→CryptoKey), создание CryptographicKey и Fedify Person, генерация outbox/followers/following/liked коллекций, сериализация объектов в compact JSON-LD, реализация fetchFedifyWebFinger через Fedify federation.
Миграция HTTP обработчиков
packages/api/src/http.ts
Удалена валидационная оболочка validatedJsonLdResponse и связанные ActivityPub схемы; федерационные обработчики теперь используют makeFedify*JsonLd + jsonLdResponse; добавлен federationWebFingerResponse и маршрут GET /.well-known/webfinger.
Обновление тестов
packages/api/tests/activitypub-schema-parity.test.ts, packages/api/tests/federation.test.ts, packages/api/tests/http-config.test.ts
Тесты переписаны под Fedify: добавлены утилиты для безопасного чтения JSON, проверки отсутствия Mastodon-терминов, интеграционные сценарии сериализации Fedify и парсинга через .fromJsonLd; WebFinger и федерационные коллекции проверяются по Fedify-выходу.
Маршрутизация и прокси
packages/app/scripts/serve-dist-web-routing.mjs, packages/app/scripts/serve-dist-web.mjs, packages/app/tests/docker-git/serve-dist-web.test.ts, packages/app/vite.web.config.ts
Вынесена логика проксирования путей в shouldProxyHttpPath; добавлена поддержка /.well-known/webfinger в прокси и Vite; обновлён сервер для использования нового модуля и добавлены тесты маршрутизации.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • ProverCoderAI/docker-git#335: Затрагивает ActivityPub schema/exports (пересечения по exactActivityPubParseOptions и схемам Person/Collection).
  • ProverCoderAI/docker-git#295: Пересекается по изменениям контекстов и федерационных JSON-LD контрактов в contracts.ts.
🚥 Pre-merge checks | ✅ 7
✅ Passed checks (7 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title accurately describes the main change: replacing hand-rolled ActivityPub document builders with Fedify for protocol compliance.
Description check ✅ Passed The description covers the summary, requirements alignment, verification steps, proof obligations, and executable evidence, but does not follow the provided template structure with explicit sections.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Requirements Alignment ✅ Passed Fedify replaced local builders, routes intact, WebFinger added, Mastodon terms blocked, followers page enforced, ForgeFedTicket kept, tests exist, docs updated. No contradictions found.
Security Regression ✅ Passed No security regressions found. PR uses Fedify for ActivityPub documents; only public keys exported; WebFinger input validated; safe error handling; no dangerous operations detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-334-fedify

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Get the issue `#334` details
gh issue view 334 --repo ProverCoderAI/docker-git

echo "=== PR `#337` Files Changed ==="
gh pr view 337 --repo ProverCoderAI/docker-git

echo "=== PR diff files ==="
gh pr diff 337 --repo ProverCoderAI/docker-git --name-only

Length of output: 4759


🏁 Script executed:

#!/bin/bash
# Get the full diff of PR `#337`
gh pr diff 337 --repo ProverCoderAI/docker-git 2>/dev/null | head -2000

Length of output: 93692


Let me gather the remaining details needed for a full verification.


🏁 Script executed:

#!/bin/bash
# Get remaining diff content
gh pr diff 337 --repo ProverCoderAI/docker-git 2>/dev/null | tail -n +2000 | head -1500

Length of output: 12806


🏁 Script executed:

#!/bin/bash
echo "=== readFollowersPageMode function ==="
rg -n "readFollowersPageMode" packages/api/src/http.ts -A 20 -B 2

echo "=== ForgeFedTicket schema boundary ==="
rg -n "ForgeFedTicket" packages/api/src/http.ts -A 5 -B 2

echo "=== federation routes in http.ts ==="
rg -n "federation" packages/api/src/http.ts -A 2 | head -80

echo "=== actorJsonLdContext definition ==="
rg -n "actorJsonLdContext" packages/api/src/api/contracts.ts -A 5 -B 2

echo "=== ForgeFedTicket in http.ts usage ==="
rg -n "ForgeFedTicket\|forgeFedTicket\|Ticket" packages/api/src/http.ts | head -30

Length of output: 7499


🏁 Script executed:

#!/bin/bash
echo "=== followers page=2 test ==="
rg -n "page=2\|unsupported followers\|rejects.*followers\|400" packages/api/tests/http-config.test.ts -A 20 -B 5

echo "=== ForgeFedTicket usage in http.ts (ingest/apply) ==="
rg -n "ForgeFedTicket\|ingestFederation\|applyForgeFed\|forgeFedTicket" packages/api/src/http.ts -A 3 -B 2

echo "=== ForgeFedTicketSchema import/usage ==="
rg -n "ForgeFedTicket" packages/api/src/ -r -A 3 -B 2

echo "=== Effect Schema boundary for ticket ==="
rg -n "decodeUnknown\|Schema.decode" packages/api/src/ -r | grep -i "ticket\|forgefed" | head -20

echo "=== http.ts federation routes list ==="
rg -n "HttpRouter\.(get|post|put|delete)" packages/api/src/http.ts | grep -i "federation\|webfinger\|well-known"

Length of output: 3341


🏁 Script executed:

#!/bin/bash
echo "=== followers page=2 test ==="
grep -n "page=2\|unsupported\|400\|rejects.*followers" packages/api/tests/http-config.test.ts | head -20

echo ""
echo "=== page=2 test body ==="
grep -n -A 25 "rejects unsupported followers" packages/api/tests/http-config.test.ts

echo ""
echo "=== ForgeFedTicketSchema in activitypub-schema.ts (lines 30-55) ==="
sed -n '28,60p' packages/api/src/api/activitypub-schema.ts

echo ""
echo "=== ForgeFedTicket ingest in federation.ts ==="
grep -n "ForgeFedTicket\|readTicket\|decodeUnknown\|Schema.decode" packages/api/src/services/federation.ts | head -20

echo ""
echo "=== serializeFedifyObject context for collections ==="
grep -n "activityStreamsJsonLdContext\|activityForgeFedJsonLdContext\|actorJsonLdContext" packages/api/src/services/fedify-federation.ts | head -20

echo ""
echo "=== WebFinger test in http-config ==="
grep -n -A 40 "serves WebFinger" packages/api/tests/http-config.test.ts | head -50

Length of output: 4912


@skulidropek: Here is the complete verification of issue #334 against PR #337. All six requirements are fully satisfied — no proof gaps remain.


Verification Summary

✅ 1. Local ActivityPub output is built through Fedify / @fedify/vocab

The new packages/api/src/services/fedify-federation.ts replaces all hand-rolled JSON construction. Person, OrderedCollection, OrderedCollectionPage, and Follow are all imported from @fedify/vocab and serialized via object.toJsonLd({ format: "compact", context: ... }). The old makeFederationActorDocument, makeFederationOutboxCollection, etc. are fully removed from federation.ts.


✅ 2. Explicit contexts do not leak unsupported Mastodon/GTS terms

Every removed or renamed item:

  • socialWebWebfingerJsonLdContext ("https://purl.archive.org/socialweb/webfinger") — deleted from contracts.ts
  • MastodonActorJsonLdContextSchema, MastodonActorContextExtensionsSchema, MastodonIssueActivityPubPersonSchemaall deleted from activitypub-schema.ts
  • actorJsonLdContext is now [activityStreams, security] only (removed the old forgeFedJsonLdContext entry that was never needed on the Person document)
  • Collections use the plain activityStreamsJsonLdContext string

Both the parity test file and the HTTP config test include assertNoMastodonTerms(payload), which scans the serialized JSON for: webfinger, joinmastodon.org, toot:, featuredTags, alsoKnownAs, movedTo, manuallyApprovesFollowers, discoverable, suspended, memorial, indexable, interactionPolicy, canQuote, automaticApproval, manualApproval, showFeatured, showMedia, showRepliesInMedia.


✅ 3. Existing /federation/* URLs still work

All five routes are preserved in http.ts and now delegate to Fedify helpers:

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: 200
  • Content-Type: application/jrd+json
  • subject: "acct:[email protected]"
  • 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.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 тестов:

  1. Round-trip инвариант: ∀doc: Fedify.fromJsonLd(makeFedifyActorJsonLd(ctx)) succeeds
  2. Структурный инвариант: ∀collection: collection.totalItems === collection.orderedItems.length
  3. JSON-LD компактность: Сгенерированный документ не содержит избыточных контекстов
  4. 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

📥 Commits

Reviewing files that changed from the base of the PR and between 9408763 and a373667.

⛔ Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
📒 Files selected for processing (10)
  • packages/api/package.json
  • packages/api/src/api/activitypub-schema.ts
  • packages/api/src/api/contracts.ts
  • packages/api/src/api/schema.ts
  • packages/api/src/http.ts
  • packages/api/src/services/federation.ts
  • packages/api/src/services/fedify-federation.ts
  • packages/api/tests/activitypub-schema-parity.test.ts
  • packages/api/tests/federation.test.ts
  • packages/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.json
  • packages/api/tests/federation.test.ts
  • packages/api/src/api/schema.ts
  • packages/api/tests/http-config.test.ts
  • packages/api/tests/activitypub-schema-parity.test.ts
  • packages/api/src/services/federation.ts
  • packages/api/src/api/activitypub-schema.ts
  • packages/api/src/api/contracts.ts
  • packages/api/src/http.ts
  • packages/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.json
  • packages/api/tests/federation.test.ts
  • packages/api/src/api/schema.ts
  • packages/api/tests/http-config.test.ts
  • packages/api/tests/activitypub-schema-parity.test.ts
  • packages/api/src/services/federation.ts
  • packages/api/src/api/activitypub-schema.ts
  • packages/api/src/api/contracts.ts
  • packages/api/src/http.ts
  • packages/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 use any, unknown, eslint-disable, ts-ignore, or as type 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 through pipe() and Effect.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), @throws Never (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.ts
  • packages/api/src/api/schema.ts
  • packages/api/tests/http-config.test.ts
  • packages/api/tests/activitypub-schema-parity.test.ts
  • packages/api/src/services/federation.ts
  • packages/api/src/api/activitypub-schema.ts
  • packages/api/src/api/contracts.ts
  • packages/api/src/http.ts
  • packages/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.ts
  • packages/api/tests/http-config.test.ts
  • packages/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/catch for 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.ts
  • packages/api/src/api/schema.ts
  • packages/api/tests/http-config.test.ts
  • packages/api/tests/activitypub-schema-parity.test.ts
  • packages/api/src/services/federation.ts
  • packages/api/src/api/activitypub-schema.ts
  • packages/api/src/api/contracts.ts
  • packages/api/src/http.ts
  • packages/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.ts
  • packages/api/tests/http-config.test.ts
  • packages/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.ts
  • packages/api/src/api/schema.ts
  • packages/api/tests/http-config.test.ts
  • packages/api/tests/activitypub-schema-parity.test.ts
  • packages/api/src/services/federation.ts
  • packages/api/src/api/activitypub-schema.ts
  • packages/api/src/api/contracts.ts
  • packages/api/src/http.ts
  • packages/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.ts
  • packages/api/src/api/schema.ts
  • packages/api/tests/http-config.test.ts
  • packages/api/tests/activitypub-schema-parity.test.ts
  • packages/api/src/services/federation.ts
  • packages/api/src/api/activitypub-schema.ts
  • packages/api/src/api/contracts.ts
  • packages/api/src/http.ts
  • packages/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.ts
  • packages/api/src/api/schema.ts
  • packages/api/tests/http-config.test.ts
  • packages/api/tests/activitypub-schema-parity.test.ts
  • packages/api/src/services/federation.ts
  • packages/api/src/api/activitypub-schema.ts
  • packages/api/src/api/contracts.ts
  • packages/api/src/http.ts
  • packages/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.ts
  • packages/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 value

Action 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 win

Request 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 value

Missing 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 lift

Missing 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!

Comment thread packages/api/tests/activitypub-schema-parity.test.ts
Comment thread packages/api/tests/http-config.test.ts Outdated
Comment thread packages/api/tests/http-config.test.ts
@skulidropek
Copy link
Copy Markdown
Member Author

skulidropek commented May 21, 2026

AI Session Backup

Commit: 79a2e21
Status: success
Files: 6 (7.38 MB)
Links: README | Manifest

git status

On branch issue-334-fedify
Your branch is up to date with 'origin/issue-334-fedify'.

nothing to commit, working tree clean

@skulidropek
Copy link
Copy Markdown
Member Author

@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.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== HEAD commit info ==="
git log --oneline -3

echo ""
echo "=== Latest diff (tests only) ==="
git diff HEAD~1 HEAD -- packages/api/tests/ 2>/dev/null | head -500

Length of output: 13997


@skulidropek: All five claimed changes are confirmed in commit 79a2e21. No blockers remain.


Verification of commit 79a2e21 — "test(api): strengthen Fedify protocol invariants"

1. ✅ Type assertion removed from test helpers
Both activitypub-schema-parity.test.ts and federation.test.ts now share the isJsonRecord type guard pattern. asRecord returns value directly instead of value as JsonRecord / value as Record<string, unknown>. Type narrowing is done properly through the guard.

2. ✅ String-based Mastodon-term checks replaced with structural checks
assertNoMastodonTerms now delegates to two separate recursive walkers:

  • assertNoMastodonContextTerms — visits only the @context subtree, checking string values against the URL-based blocklist (purl.archive.org/socialweb/webfinger, joinmastodon.org/ns#, toot:).
  • assertNoMastodonKeys — walks the entire JSON tree and asserts that no key matches the extended unsupportedMastodonKeys list (which now also covers "toot", "featured", "canQuote", "automaticApproval", "manualApproval" — a superset of the previous list).

3. ✅ Fedify actor / following property invariants added
federation.test.ts gains two fast-check property tests (numRuns: 10 each):

  • satisfies Fedify actor JSON-LD property invariants — round-trips through Person.fromJsonLd, checks id, preferredUsername, all six endpoint URLs, and uses the new countKey(actor, "@context") === 1 guard to detect accidental double-injection of @context.
  • satisfies Fedify following collection property invariants — builds a variable set of accepted follows, then asserts id, totalItems === items.length, and single @context.

4. ✅ WebFinger invariant coverage for both supported resource forms
http-config.test.ts adds satisfies WebFinger invariants for supported actor resources. The webFingerResourceArbitrary covers both acct:[email protected] and https://public.example.test/federation/actor. For each resource the test checks: subject === resource, all aliases parse as valid URLs, a self link with type: application/activity+json is present, and crucially, the self link href matches the id field of the live /federation/actor response (cross-route validation).

5. ✅ followers?page=1 parsed with OrderedCollectionPage.fromJsonLd
The followers page=1 test now calls parseOrderedCollectionPage(payload) (wrapping OrderedCollectionPage.fromJsonLd) and asserts page.id?.href, page.partOfId?.href, and page.totalItems === 0 on the typed Fedify object, replacing the raw field reads.


Overall verdict: PR #337 is complete with no remaining proof gaps. The latest commit brings the test suite up to structural/invariant-level coverage across all six requirements from issue #334.

@skulidropek
Copy link
Copy Markdown
Member Author

skulidropek commented May 21, 2026

AI Session Backup

Commit: 0444748
Status: failure
Error: failed to list tree for skulidropek/docker-git-sessions@main: stream error: stream ID 1; CANCEL; received from peer

git status

On branch issue-334-fedify
Your branch is up to date with 'origin/issue-334-fedify'.

nothing to commit, working tree clean

@skulidropek
Copy link
Copy Markdown
Member Author

@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.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== Commit info ==="
git log --oneline -5

echo ""
echo "=== Diff of latest commit ==="
git show 0444748f0a26b7423db71a1d7202336da16d3f06 --stat

echo ""
echo "=== Full diff of latest commit ==="
git show 0444748f0a26b7423db71a1d7202336da16d3f06

echo ""
echo "=== PR body ==="
gh pr view 337 --repo ProverCoderAI/docker-git --json body -q '.body'

Length of output: 5367


@skulidropek: Commit 0444748 is a pure documentation commit — one file changed, 9 lines added to packages/api/README.md. All six proof requirements remain satisfied with no regressions. Here is the final complete verification.


Final Verification — commit 0444748f0a26b7423db71a1d7202336da16d3f06

Commit contents

This commit adds documentation only:

  1. Route listGET /.well-known/webfinger (Fedify WebFinger document for the local federation actor) inserted in the correct position (before /federation/issues).
  2. Prose section — accurately states that local ActivityPub documents use only ActivityStreams and security JSON-LD contexts and lists the specific Mastodon extension terms (toot, featured, featuredTags, alsoKnownAs, movedTo, interactionPolicy, https://purl.archive.org/socialweb/webfinger) that are not emitted.
  3. Bash example — demonstrates WebFinger lookup via ./ctl request GET '/.well-known/webfinger?resource=acct:[email protected]'.

The listed terms match exactly what assertNoMastodonContextTerms and assertNoMastodonKeys enforce in the test suite (verified in commit 79a2e21).


Six proof requirements — all still satisfied

# Requirement Status
1 Local ActivityPub output built through Fedify / @fedify/vocab fedify-federation.tsPerson, 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 federationWebFingerResponsefetchFedifyWebFinger; 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.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between a373667 and 79a2e21.

📒 Files selected for processing (3)
  • packages/api/tests/activitypub-schema-parity.test.ts
  • packages/api/tests/federation.test.ts
  • packages/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 use any, unknown, eslint-disable, ts-ignore, or as type 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 through pipe() and Effect.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), @throws Never (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.ts
  • packages/api/tests/federation.test.ts
  • packages/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.ts
  • packages/api/tests/federation.test.ts
  • packages/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/catch for 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.ts
  • packages/api/tests/federation.test.ts
  • packages/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.ts
  • packages/api/tests/federation.test.ts
  • packages/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.ts
  • packages/api/tests/federation.test.ts
  • packages/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.ts
  • packages/api/tests/federation.test.ts
  • packages/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.ts
  • packages/api/tests/federation.test.ts
  • packages/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.ts
  • packages/api/tests/federation.test.ts
  • packages/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.ts
  • packages/api/tests/federation.test.ts
  • packages/api/tests/http-config.test.ts

Comment thread packages/api/tests/federation.test.ts
Comment thread packages/api/tests/http-config.test.ts
@skulidropek
Copy link
Copy Markdown
Member Author

skulidropek commented May 21, 2026

AI Session Backup

Commit: 2ed13f7
Status: success
Files: 6 (7.90 MB)
Links: README | Manifest

git status

On branch issue-334-fedify
Your branch is up to date with 'origin/issue-334-fedify'.

nothing to commit, working tree clean

@skulidropek
Copy link
Copy Markdown
Member Author

@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.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== Commit info ==="
git log --oneline -5

echo ""
echo "=== Diff stat of latest commit ==="
git show 2ed13f71f08bb9d620b90cbe66cb0233ad8ed04a --stat

echo ""
echo "=== Full diff of latest commit ==="
git show 2ed13f71f08bb9d620b90cbe66cb0233ad8ed04a

echo ""
echo "=== Check for async/await in property test callbacks ==="
grep -n "async\|await" packages/api/tests/federation.test.ts | head -40

echo ""
echo "=== Check fast-check fc.assert in federation.test.ts ==="
grep -n -A 20 "fc\.assert\|fc\.asyncProperty\|fc\.property" packages/api/tests/federation.test.ts | head -80

echo ""
echo "=== Check Effect.runPromise usage in federation.test.ts ==="
grep -n "Effect\.runPromise\|Effect\.forEach\|Effect\.gen" packages/api/tests/federation.test.ts | head -30

echo ""
echo "=== Check async/await in http-config property tests ==="
grep -n "async\|await" packages/api/tests/http-config.test.ts | grep -v "//\|it\.\|describe\|test\." | head -40

echo ""
echo "=== fc.assert blocks in http-config.test.ts ==="
grep -n -A 20 "fc\.assert\|fc\.asyncProperty\|fc\.property" packages/api/tests/http-config.test.ts | head -100

echo ""
echo "=== Effect.forEach usage ==="
grep -n "Effect\.forEach" packages/api/tests/federation.test.ts packages/api/tests/http-config.test.ts | head -20

Length of output: 18726


@skulidropek: Commit 2ed13f71 is confirmed. All three claimed changes are implemented correctly — no blockers remain.


Verification of commit 2ed13f71 — "test(api): keep federation properties in Effect"

1. ✅ async/await removed from property test callbacks

Both fc.asyncProperty callbacks in federation.test.ts (Lines 225 and 261) and the fc.asyncProperty callback in http-config.test.ts (Line 385) are now plain arrow functions with no async keyword and no await expressions. fc.asyncProperty remains correct since the callbacks still return a Promise (via Effect.runPromise).

2. ✅ Effect.runPromise(Effect.gen(...)) returned from fast-check callbacks

All three callbacks follow the exact pattern:

({ ... }) =>
  Effect.runPromise(
    Effect.gen(function*(_) {
      yield* _(...)
      ...
    })
  )

Internal operations that were previously await Effect.runPromise(x) are now yield* _(x) inside a single unified Effect.gen block — a single runPromise at the boundary.

3. ✅ Effect.forEach for sequenced assertions

  • federation.test.ts Line 273: Effect.forEach(targetIds, (targetId) => Effect.gen(...), { discard: true }) replaces the old for...of loop that called await Effect.runPromise(...) twice per iteration.
  • http-config.test.ts Line 408: Effect.forEach(aliases, (alias) => Effect.sync(() => { expect(...) }), { discard: true }) replaces the old for...of loop.

Bonus: The new parsePersonJsonLd helper (Line 57–62 of federation.test.ts) correctly wraps Person.fromJsonLd with Effect.tryPromise, keeping the fromJsonLd call inside the Effect pipeline without bare await.


All six issue #334 requirements — still satisfied

# 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.

@skulidropek
Copy link
Copy Markdown
Member Author

skulidropek commented May 21, 2026

AI Session Backup

Commit: 3c72a3b
Status: success
Files: 8 (11.17 MB)
Links: README | Manifest

git status

On branch issue-334-fedify
Your branch is up to date with 'origin/issue-334-fedify'.

nothing to commit, working tree clean

@skulidropek
Copy link
Copy Markdown
Member Author

@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: /.well-known/webfinger must be proxied at the public origin without /api, preserve the query string, return Fedify application/jrd+json, and avoid claiming non-standard /.well-known/webfinger/extra. Please confirm whether the issue and the latest WebFinger/root-route feedback are fully satisfied, or list the exact remaining blocker.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 21, 2026

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
echo "=== Commit info ==="
git log --oneline -5

echo ""
echo "=== Diff stat of commit 3c72a3b ==="
git show 3c72a3b64f6b4379a75046ba22e4303ebbce21e2 --stat

echo ""
echo "=== Full diff of commit 3c72a3b ==="
git show 3c72a3b64f6b4379a75046ba22e4303ebbce21e2

echo ""
echo "=== Search for webfinger proxy/route in config files ==="
rg -rn "webfinger" --type-not=ts --type-not=md | grep -v "node_modules" | head -60

echo ""
echo "=== Search for well-known in nginx/caddy/traefik configs ==="
fd -e conf -e Caddyfile -e yaml -e yml --exec grep -l "well-known" {} \; 2>/dev/null | head -20

echo ""
echo "=== List any proxy/reverse-proxy config files ==="
fd -e conf -e Caddyfile | grep -v node_modules | head -20
fd "nginx" | grep -v node_modules | head -20
fd "caddy" | grep -v node_modules | head -20

echo ""
echo "=== Check http.ts for webfinger and well-known routes ==="
rg -n "webfinger\|well-known" packages/api/src/http.ts -A 5 -B 2

echo ""
echo "=== Check for webfinger/extra ==="
rg -rn "webfinger/extra\|webfinger.*extra" --include="*.ts" --include="*.js" --include="*.conf" --include="*.yaml" --include="*.yml" | grep -v node_modules | head -20

echo ""
echo "=== Check query string handling in federationWebFingerResponse ==="
rg -n "query\|search\|url\|fetch\|request" packages/api/src/services/fedify-federation.ts | grep -i "query\|search\|webfinger" | head -20
rg -n "federationWebFingerResponse\|fetchFedifyWebFinger" packages/api/src/ -r -A 15 | head -80

echo ""
echo "=== Check tests for webfinger at root (non-api) ==="
rg -n "well-known\|webfinger" packages/api/tests/ -r -A 5 -B 2 | head -100

Length of output: 9681


@skulidropek: Commit 3c72a3b is fully verified. All four WebFinger root-route requirements are satisfied, and all six issue #334 proof obligations remain intact.


Verification — commit 3c72a3b "fix(app): expose WebFinger at browser root"

Files changed

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.

@skulidropek skulidropek merged commit 460deb3 into main May 21, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Можешь ещё раз сверить совпадение этим условиям? У нас типы должны быть 1 в 1

1 participant