Skip to content

feat: authorize what a subscription may listen to - #35

Merged
vitramir merged 2 commits into
mainfrom
feat/authorize-subscribe-rooms
Aug 1, 2026
Merged

feat: authorize what a subscription may listen to#35
vitramir merged 2 commits into
mainfrom
feat/authorize-subscribe-rooms

Conversation

@vitramir

@vitramir vitramir commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Subscribe checked two of its room kinds. Everything else — every organization's, agent's and workload's event stream, and any arbitrary string — was readable by any authenticated caller. The Gateway only confirms an identity exists and forwards the room list untouched.

architecture/authz.md#notifications-service already states the table, and this implements it:

Room Check
thread_participant: / instance_inbox: / sandbox_owner: identity equality (no OpenFGA)
organization: member
sandbox_org: can_list_sandboxes
workload: member on the workload's organization
agent: member on the agent's organization

workload: and agent: are keyed by entity id, so the owning service is asked which organization that is. Both GetWorkload and GetAgent already accept an identity-less internal caller. notifications' config and chart have carried RUNNERS_ADDR and AGENTS_ADDR all along with nothing reading them.

Missing rooms (sandbox_owner:, sandbox_org:, volume:) are now classified rather than falling through to the unknown bucket, and anything genuinely unrecognised is refused.

Three exceptions, each named where it is handled rather than left silent:

  • volume: and trace: — both specified as "member on the owning organization", but neither owner will say which one that is. GetTrace returns raw OTLP spans, and neither the agents nor the runners Volume message carries an organization_id. Closing them needs that field.
  • egress_rules — the Egress Gateway and the Egress service both use this bare literal, not the per-org room the document describes. There is no organization to check against, and default-denying it would cut off rule invalidation.

A failed lookup denies rather than allows: a subscription outlives the request that opened it.

vitramir added 2 commits July 29, 2026 19:07
Dev sessions collide on the same ports, and DevSpace treats a failed bind
as fatal — the session dies, nothing syncs, and the pod silently keeps
running whatever it started with. A dev session replaces a pod; it has no
business binding host ports.
Subscribe checked two of its room kinds. Everything else -- every
organization's, agent's and workload's event stream, and any string at
all -- was readable by any authenticated caller: the Gateway confirms an
identity exists and forwards the room list untouched.

architecture/authz.md already states the table. Identity-keyed rooms are
settled by equality; the rest are gated on the caller's relation to the
organization that owns the entity, which for workload and agent rooms
means asking their owning service which organization that is. The config
and chart have carried RUNNERS_ADDR and AGENTS_ADDR all along with
nothing reading them.

Three rooms cannot be checked yet and say so where they are handled:
volume and trace, because no response carries the organization, and
egress_rules, which is one global literal rather than the per-org room
the document describes. Anything else is refused rather than inheriting
an accidental allow.
@vitramir
vitramir merged commit 25413bd into main Aug 1, 2026
1 check 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 participant