Skip to content

[mirror] Normalize outgoing JSON-LD for Pixelfed interop#3

Open
yashwant86 wants to merge 13 commits intomm-base-721from
mm-pr-721
Open

[mirror] Normalize outgoing JSON-LD for Pixelfed interop#3
yashwant86 wants to merge 13 commits intomm-base-721from
mm-pr-721

Conversation

@yashwant86
Copy link
Copy Markdown

@yashwant86 yashwant86 commented Apr 26, 2026

Mirror of upstream fedify-dev#721 for benchmark. Do not merge.


Summary by MergeMonkey

  • Documentation:
    • Updated send.md with JSON-LD normalization configuration details.
    • Added CHANGES.md entry documenting outgoing JSON-LD wire-format fixes.
  • What's New:
    • Normalizes outgoing ActivityStreams attachments to arrays for Pixelfed interop.
    • Adds normalizeExistingProofs option to preserve pre-signed activity normalization.
    • Implements preloaded-only JSON-LD context loader for safe verification fallbacks.
  • Squashed Bugs:
    • Fixes single-item attachment scalars rejected by Pixelfed's JSON parser.
    • Ensures proof verification accepts both wire-form and normalized JSON-LD.

dahlia added 13 commits April 25, 2026 01:47
Move outgoing JSON-LD compatibility adjustments into a dedicated layer
so send and proof creation use the same wire representation.  Keep the
existing public audience workaround and add attachment array preservation
for Pixelfed compatibility, while skipping attachment rewrites that would
change JSON-LD semantics.

Document the distinction from activity transformers and cover the new
normalization behavior in send and proof tests.

pixelfed/pixelfed#6588

Assisted-by: Codex:gpt-5.5
Skip the JSON-LD canonicalization equivalence check when scalar
attachment wrapping runs under an ActivityStreams-only context without
nested context scopes.  Also make the fallback log messages context
neutral, since the helper can run from proof verification as well as
send paths.

References fedify-dev#721 (comment)
References fedify-dev#721 (comment)

Assisted-by: Codex:gpt-5
Keep the fast path semantics-preserving by leaving JSON-LD list
objects unwrapped, since array-wrapping list objects can change their
meaning.  Broaden the known-safe context check to allow additional
preloaded contexts alongside ActivityStreams, and avoid allocating a
replacement object until the attachment walker actually changes a
subtree.

References fedify-dev#721 (comment)
References fedify-dev#721 (comment)
References fedify-dev#721 (comment)

Assisted-by: Codex:gpt-5
Do not recurse into `@value` payloads while normalizing attachment
properties.  Those payloads can carry raw JSON data, such as `@json`
values, where a sibling key named `attachment` is not an ActivityStreams
term and must not be wrapped by the outgoing compatibility layer.

References fedify-dev#721 (comment)

Assisted-by: Codex:gpt-5
Make the send documentation explicit that internal JSON-LD wire-format
fixes are applied automatically after serialization, and that the
`activityTransformers` option configures only activity transformers.

References fedify-dev#721 (comment)

Assisted-by: Codex:gpt-5
Make the attachment normalization walker allocate replacement arrays only
after a child changes, matching the existing lazy object cloning path.
This avoids unnecessary allocations for unchanged arrays on the send,
sign, and verification paths.

References fedify-dev#721 (comment)
References fedify-dev#721 (comment)

Assisted-by: Codex:gpt-5
Try the received JSON-LD form before computing Fedify's outgoing
compatibility form during proof verification.  This avoids traversing or
canonicalizing the document on the common path where the on-wire bytes
already verify.

References fedify-dev#721 (comment)

Assisted-by: Codex:gpt-5
Skip outgoing JSON-LD normalization for activities that arrive at
FederationImpl.sendActivity() with an existing proof, so the send path
does not mutate the JSON-LD bytes after an external signing step.  Keep
normalization enabled for proofs Fedify created during its own fanout
pre-signing path and cover the pre-signed attachment case.

References fedify-dev#721 (comment)

Assisted-by: Codex:gpt-5
Skip attachment array normalization when a JSON-LD document exceeds the
safe traversal depth, instead of falling through to URDNA2015
canonicalization.  This keeps adversarial deep documents from forcing
expensive canonicalization work in verification fallback paths.

Document that custom or inline contexts may require canonicalization to
prove that an outgoing wire-format fix preserves JSON-LD semantics.

References fedify-dev#721 (comment)
References fedify-dev#721 (comment)

Assisted-by: Codex:gpt-5
Share the preloaded-only context loader between outgoing JSON-LD
compatibility helpers so security-sensitive fallback behavior cannot drift.
Keep the proof verification fallback on that restricted loader instead of
reusing a caller-provided context loader for inbound JSON-LD.

Also document the attachment normalization loader contract, add safe
correlation metadata to the semantic-divergence warning, and tighten the
pathological nesting regression assertion.

fedify-dev#721 (comment)
fedify-dev#721 (comment)
fedify-dev#721 (comment)
fedify-dev#721 (comment)
fedify-dev#721 (comment)

Assisted-by: Codex:gpt-5
Add a public sendActivity option for callers that pre-sign activities with
Fedify and need the outgoing compact JSON-LD to match the normalized bytes
covered by the proof. Preserve existing proofs by default, and document that
trade-off in the send path, queue message type, and manual.

fedify-dev#721 (comment)
fedify-dev#721 (comment)
fedify-dev#721 (comment)
fedify-dev#721 (comment)
fedify-dev#721 (comment)

Assisted-by: Codex:gpt-5
Enforce the preloaded context invariant that keeps the attachment term
compatible with ActivityStreams before using the known-safe fast path.
Also keep JSON-LD value payloads out of the nested-context detector,
fix the newly added option's release annotation, and cover queued fanout
for pre-signed activities that opt into existing-proof normalization.

Addresses review comments:

fedify-dev#721 (comment)
fedify-dev#721 (comment)
fedify-dev#721 (comment)
fedify-dev#721 (comment)

Assisted-by: Codex:gpt-5
Build the known-safe preloaded context set by filtering contexts that keep
ActivityStreams attachment semantics intact instead of failing at module
load.  The check now descends into scoped context definitions so future
preloaded contexts cannot silently bypass canonicalization when they
redefine attachment locally.

Pass the restricted preloaded-only loader explicitly in proof verification
fallbacks so inbound JSON-LD normalization cannot start depending on a
network-capable default after future refactors.

Addresses review comments:

fedify-dev#721 (comment)
fedify-dev#721 (comment)
fedify-dev#721 (comment)

Assisted-by: Codex:gpt-5
@bot-mergemonkey
Copy link
Copy Markdown

bot-mergemonkey Bot commented Apr 26, 2026

Risk AssessmentCRITICAL · ~45 min review

Focus areas: Proof verification fallback logic with preloaded-only loader · normalizeExistingProofs flag propagation through fanout queue · Async test coverage for attachment normalization

Assessment: Modifies proof creation and verification logic, adds conditional normalization affecting signed activity bytes.

Walkthrough

When sending an activity, Fedify now normalizes outgoing JSON-LD to fix interoperability issues: scalar attachments are wrapped in arrays (Pixelfed expects arrays), and public audience URIs are expanded. For pre-signed activities, normalization is skipped by default to preserve proof bytes, but callers can opt in via normalizeExistingProofs. Proof verification accepts both wire-form and normalized forms, using a preloaded-only context loader to prevent attacker-controlled contexts from triggering network fetches.

Changes

Files Summary
Outgoing JSON-LD Normalization Core
packages/fedify/src/compat/outgoing-jsonld.ts, outgoing-jsonld.test.ts, preloaded-context-loader.ts
Adds attachment array normalization and public audience fixes for outgoing activities. Wraps scalar attachments in arrays when semantically safe, with depth-bounded traversal and JSON-LD canonicalization validation. Preloaded-only context loader prevents network fetches on adversarial JSON-LD.
Public Audience Normalization Refactor
packages/fedify/src/compat/public-audience.ts
Extracts preloaded-only document loader to shared module for reuse in proof verification and attachment normalization.
Proof Creation & Verification
packages/fedify/src/sig/proof.ts, proof.test.ts
Updates createProof() to normalize outgoing JSON-LD before signing. Refactors verifyProofInternal() to use preloaded-only loader for fallback normalization, preventing attacker-controlled context URLs from triggering network fetches. Adds test coverage for attachment normalization in signed objects.
Activity Sending & Fanout
packages/fedify/src/federation/middleware.ts, context.ts, queue.ts
Adds normalizeExistingProofs option to sendActivity() and fanout queue. Conditionally applies outgoing JSON-LD normalization based on proof creation state: normalizes unsigned activities and Fedify-created proofs, preserves existing proofs unless explicitly opted in. Propagates flag through fanout pipeline.
Documentation & Configuration
docs/manual/send.md
CHANGES.md
Documents JSON-LD normalization configuration and wire-format interoperability fixes.

Sequence Diagram

sequenceDiagram
  participant Caller
  participant sendActivity
  participant createProof
  participant normalizeOutgoing
  participant verifyProof
  Caller->>sendActivity: activity, keys, options
  alt has existing proof
    sendActivity->>sendActivity: check normalizeExistingProofs flag
    alt flag true or proof created by Fedify
      sendActivity->>normalizeOutgoing: normalize JSON-LD
    else flag false
      sendActivity->>sendActivity: skip normalization
    end
  else no proof
    sendActivity->>createProof: sign activity
    createProof->>normalizeOutgoing: normalize before signing
    normalizeOutgoing-->>createProof: normalized bytes
    createProof->>createProof: sign normalized form
  end
  sendActivity->>sendActivity: serialize to compact JSON-LD
  sendActivity-->>Caller: send to inbox
  Caller->>verifyProof: received JSON-LD, proof
  verifyProof->>verifyProof: try verify on-wire form
  alt verification fails
    verifyProof->>normalizeOutgoing: normalize with preloaded-only loader
    verifyProof->>verifyProof: try verify normalized form
  end
  verifyProof-->>Caller: verification result
Loading

Dig Deeper With Commands

  • /review <file-path> <function-optional>
  • /chat <file-path> "<question>"
  • /roast <file-path>

Runs only when explicitly triggered.

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.

2 participants