fix(orb): point collector at the live receiver + rate-limit ingest + document the multi-tenant security model - #1254
Merged
Merged
Conversation
…ngest endpoint The default ORB_COLLECTOR_URL pointed at https://orb.gittensory.app/v1/ingest, which does not resolve (DNS HTTP 000) — so every Orb export silently failed. Point it at the deployed receiver https://gittensory-api.aethereal.dev/v1/orb/ingest (verified responding live). Classify the open, unauthenticated /v1/orb/ingest endpoint as the `strict` rate-limit class (10/min per IP), since it accepts anonymized batches from untrusted self-host instances; legitimate instances export hourly. Document the multi-tenant security model in .env.example, since this image is self-hosted by many independent maintainers: the image bakes no secrets, each operator creates their OWN Orb App via /orb/setup (per-instance secrets, local only), and export carries NO shared key — repo/PR identifiers are HMAC-anonymized with the operator's own ORB_WEBHOOK_SECRET, and the collector treats the batch as untrusted, rate-limited, aggregate-only telemetry. Also recommend the ORB_PRIVATE_KEY_FILE convention.
Contributor
|
Superagent didn't find any vulnerabilities or security issues in this PR. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #1254 +/- ##
=======================================
Coverage 94.97% 94.97%
=======================================
Files 177 177
Lines 19826 19827 +1
Branches 7132 7133 +1
=======================================
+ Hits 18830 18831 +1
Misses 397 397
Partials 599 599
🚀 New features to boost your workflow:
|
8 tasks
This was referenced Jun 29, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Makes Orb export actually work end-to-end and hardens/documents it for the multi-tenant self-host case (this image is run by many independent maintainers).
1. Export was broken. The default
ORB_COLLECTOR_URLwashttps://orb.gittensory.app/v1/ingest, which does not resolve (verified: HTTP 000) — and the path didn't match the receiver route. Every export silently failed. Pointed it at the deployed receiverhttps://gittensory-api.aethereal.dev/v1/orb/ingest(verified responding live: HTTP 400 to bad input, the receiver from #1234).2. Hardened the open ingest endpoint.
/v1/orb/ingestis unauthenticated + write, accepting anonymized batches from untrusted instances. Classified it as thestrictrate-limit class (10/min per IP — the limiter keys unauth requests by hashed client IP). Legitimate instances export hourly, so this is generous for them and caps abuse.3. Documented the multi-tenant security model in
.env.example.The security model (why no secret is exposed)
This is the key design point for "self-hosted by other maintainers":
/orb/setup. The resultingORB_*secrets are unique to that instance and live only in its/data— never shared, never sent to the collector. gittensory's own App secrets are never in the image.ORB_WEBHOOK_SECRET(so even the collector operator can't de-anonymize them), and the collector accepts the batch as untrusted, rate-limited, aggregate-only telemetry. Nothing in the container, if leaked, can compromise the collector, other operators, or the main App.ORB_PRIVATE_KEY_FILEconvention (mount the key as a file rather than an inline env value).This mirrors the secret-hygiene principle in
entrius/das-github-mirror(each service holds its own App secrets at runtime; consumers use per-consumer issued keys, never a shared secret) — adapted to Orb's push-telemetry direction.Validation
gittensory-api.aethereal.dev/v1/orb/ingest→ 400 on bad input) and the old default is dead (orb.gittensory.app→ 000)npm run typecheckclean;selfhost-orb-collector+authtests pass (42)/v1/orb/ingestFollow-up (not in this PR)
Per-instance issued API keys (a registration flow → the collector can authenticate + revoke a specific instance) would add abuse control beyond per-IP rate limiting — the pattern
das-github-mirroruses for its read API (API_KEYS). Worth doing if poisoning of the aggregate calibration data becomes a concern; v1 relies on anonymization + per-IP limits + dedup + outlier-robust aggregation.