Skip to content

Scaffolding: Federation sync app creation#298

Open
klpoland wants to merge 17 commits into
masterfrom
feature-kpoland-federation-sync-scaffolding
Open

Scaffolding: Federation sync app creation#298
klpoland wants to merge 17 commits into
masterfrom
feature-kpoland-federation-sync-scaffolding

Conversation

@klpoland

@klpoland klpoland commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

In this PR:

  • [NEW] federation/ (v1) application with:
    • services:
      • bootstrap.py: for initialization of federated data from home site and peers (including when new peer is added)
      • fed_index.py: for handling (external peer) asset indexing on webhook events
      • local_events.py: for handling redis dispatches to fetch local data
      • peer registry.py: for registering new peers and holding site information from site hellos
      • peer_sync.py: for packaging and sending asset data to peer sites (through their webhook routes)
    • routes:
      • health.py: (stub for now) for pinging site health (is connection established?)
      • webhooks.py: for receiving payloads FROM peers to index into LOCAL federated asset indices as well as a site-hello hook to confirm federation between peers
    • schemas and models: for type checking and providing data structures to federation configs, events, and documents (how asset docs are represented by FederatedDatasetDoc, FederatedCaptureDoc may warrant further consideration re: anticipating schema flexibility)
    • a main app that subscribes to redis events for picking up signals from gateway (handled in PR Scaffolding: Federation gateway setup #299)

Note

Medium Risk
New cross-site data path (OpenSearch writes, unauthenticated peer webhooks gated only by config allowlists) and startup bootstrap against gateway exports; mitigated by strict schema validation and origin checks but worth careful ops review.

Overview
Adds a new federation/ package: a FastAPI sync service that keeps fed-datasets / fed-captures OpenSearch indices in sync across SDS sites.

On startup it can bootstrap from local and peer gateway /federation/export/ APIs, then site-hello peers. A Redis pub/sub subscriber (site channel federation:events:{site}) loads the local asset from OpenSearch and POSTs asset-updated webhooks to configured peers; inbound webhooks index peer assets with allowlisted site_name and stale-event skipping. /sync/health reports Redis, OpenSearch, and subscriber readiness.

Also adds Docker/compose, justfile, dev mTLS cert scripts, example federation.toml, and extends pre-commit (federation-specific ruff, deptry, pyrefly) plus a broad pytest suite (mesh, bootstrap, webhooks).

Reviewed by Cursor Bugbot for commit 7bcbcba. Bugbot is set up for automated code reviews on this repo. Configure here.

@klpoland klpoland self-assigned this Jun 19, 2026
@klpoland klpoland added feature New feature or request federation Federation related work (sync service, document storage, peer configuration, etc.) labels Jun 19, 2026
@semanticdiff-com

semanticdiff-com Bot commented Jun 19, 2026

Copy link
Copy Markdown

Review changes with  SemanticDiff

Changed Files
File Status
  .pre-commit-config.yaml  4% smaller
  federation/.envs/example/sync.env Unsupported file format
  federation/.gitignore Unsupported file format
  federation/Dockerfile Unsupported file format
  federation/certs/.gitignore Unsupported file format
  federation/compose.local.yaml  0% smaller
  federation/compose.production.yaml  0% smaller
  federation/federation.example.toml Unsupported file format
  federation/justfile Unsupported file format
  federation/pyproject.toml Unsupported file format
  federation/scripts/env-selection.sh Unsupported file format
  federation/scripts/generate-dev-certs.sh Unsupported file format
  federation/scripts/simulate_redis_event.py  0% smaller
  federation/sds_federation/__init__.py  0% smaller
  federation/sds_federation/main.py  0% smaller
  federation/sds_federation/models.py  0% smaller
  federation/sds_federation/routes/__init__.py  0% smaller
  federation/sds_federation/routes/health.py  0% smaller
  federation/sds_federation/routes/webhooks.py  0% smaller
  federation/sds_federation/schemas/__init__.py  0% smaller
  federation/sds_federation/schemas/webhooks.py  0% smaller
  federation/sds_federation/services/__init__.py  0% smaller
  federation/sds_federation/services/bootstrap.py  0% smaller
  federation/sds_federation/services/fed_index.py  0% smaller
  federation/sds_federation/services/fed_search.py  0% smaller
  federation/sds_federation/services/local_events.py  0% smaller
  federation/sds_federation/services/operational.py  0% smaller
  federation/sds_federation/services/peer_registry.py  0% smaller
  federation/sds_federation/services/peer_sync.py  0% smaller
  federation/sds_federation/services/redis_channel.py  0% smaller
  federation/sds_federation/testing/__init__.py  0% smaller
  federation/sds_federation/testing/sample_data.py  0% smaller
  federation/tests/__init__.py  0% smaller
  federation/tests/conftest.py  0% smaller
  federation/tests/support/__init__.py  0% smaller
  federation/tests/support/federation_mesh.py  0% smaller
  federation/tests/support/gateway_export_mock.py  0% smaller
  federation/tests/support/mock_opensearch.py  0% smaller
  federation/tests/support/mock_peer_registry.py  0% smaller
  federation/tests/test_integration_bootstrap.py  0% smaller
  federation/tests/test_integration_mesh.py  0% smaller
  federation/tests/test_integration_pipeline.py  0% smaller
  federation/tests/test_integration_webhooks.py  0% smaller
  federation/tests/test_operational.py  0% smaller
  federation/tests/test_redis_event_pipeline.py  0% smaller
  federation/tests/test_regression_fed_search.py  0% smaller
  federation/tests/test_regression_indexer.py  0% smaller
  federation/tests/test_regression_peer_sync.py  0% smaller
  federation/tests/test_regression_redis_channel.py  0% smaller
  federation/tests/test_regression_schemas.py  0% smaller
  federation/uv.lock Unsupported file format

@klpoland klpoland changed the title Scaffolding: Federation Sync App Scaffolding: Federation sync app creation Jun 19, 2026
@klpoland
klpoland marked this pull request as ready for review June 25, 2026 19:50
@klpoland
klpoland requested a review from lucaspar June 25, 2026 19:50
Comment thread federation/sds_federation/services/local_events.py
Comment thread federation/sds_federation/services/local_events.py Outdated
Comment thread federation/sds_federation/services/bootstrap.py Outdated
Comment thread federation/compose.yaml Outdated
Comment thread federation/sds_federation/services/local_events.py Outdated
Comment thread federation/sds_federation/services/fed_index.py Outdated
Comment thread federation/pyproject.toml
Comment thread federation/pyproject.toml Outdated
@lucaspar

Copy link
Copy Markdown
Member

I'll add more comments after those are addressed to reduce the noise

Comment thread federation/sds_federation/services/local_events.py Outdated
Comment thread federation/sds_federation/services/peer_sync.py Outdated
Comment thread federation/sds_federation/services/fed_index.py
Comment thread federation/sds_federation/routes/webhooks.py
Comment thread federation/justfile Outdated
Comment thread federation/sds_federation/services/bootstrap.py
Comment thread federation/sds_federation/main.py Outdated
Comment thread federation/sds_federation/main.py
Comment thread federation/sds_federation/services/fed_index.py
Comment thread federation/sds_federation/services/local_events.py Outdated
Comment thread federation/sds_federation/services/fed_search.py
Comment thread federation/compose.local.yaml Outdated
Comment thread federation/sds_federation/services/fed_index.py
Comment thread federation/sds_federation/services/bootstrap.py
Comment thread federation/sds_federation/main.py
Comment thread federation/compose.local.yaml
Comment thread federation/compose.local.yaml
Comment thread federation/Dockerfile Outdated

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using high effort and found 4 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 7bcbcba. Configure here.

site_name=doc.site_name,
asset=doc,
asset_type=asset_type,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Bootstrap trusts export site names

Medium Severity

bootstrap_gateway_exports indexes each export document using doc.site_name without checking it matches the peer (or local site) being pulled. A misconfigured or hostile export can write into another site’s site:uuid keys, including overwriting this site’s own federated documents.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7bcbcba. Configure here.

hello = hello.model_copy(update={"timestamp": datetime.now(UTC)})

_peer_registry(request).register(hello)
return {"status": "registered", "site_name": hello.site_name}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Unauthenticated hello rewrites peer URLs

Medium Severity

site-hello accepts any caller that supplies a configured peer site_name and stores their sync_service_url with no authentication. peer_for_outbound then prefers that URL for asset webhooks, so a reachable sync port lets an attacker redirect outbound federation POSTs to an arbitrary host.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7bcbcba. Configure here.

id=_id,
body=body,
refresh="wait_for",
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Sync OpenSearch blocks async handlers

Medium Severity

apply_asset_event performs synchronous OpenSearch index calls with refresh="wait_for" directly from async webhook handlers and bootstrap. Unlike federated reads, writes are not offloaded with asyncio.to_thread, so each peer update can stall the event loop and delay Redis subscription and health responses.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7bcbcba. Configure here.

return self._peers.get(site_name)

def known_site_names(self) -> set[str]:
return set(self._peers.keys())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Unused peer registry tracking fields

Low Severity

PeerRegistry stores _last_seen on every register and exposes known_site_names, but nothing in the app or tests reads either. That dead state suggests incomplete registry behavior and adds noise for future maintainers.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7bcbcba. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request federation Federation related work (sync service, document storage, peer configuration, etc.)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants