Partition org-owned shared tongs per org#17
Merged
Conversation
A `shared` tong is keyed only by its name, so two orgs that ship the same
tong file (same filename, same `interface.name`) but different credentials
resolve to one daemon-global container name -- each launch tearing the
other's container down -- and sit reachable side by side on the shared base
network.
Introduce the naming primitives to partition them, without wiring them in
yet:
* `org_scope_token` derives a stable short token from the org layer's
tongs directory, so every launch pointed at one org shares a token while
different orgs differ; None when no org layer is present.
* `shared_container_name` takes an optional `scope` so identically-named
shared tongs get distinct container names (no scope == today's name).
* `shared_network_name` names the isolated per-scope network a scoped tong
will live on.
Partition every `shared` tong owned by the org layer onto its own network and a scoped container name, so two orgs running the same tong no longer collide or reach each other. For an org-sourced shared tong the launcher now ensures a per-org network, starts the tong there (under a scoped container name) instead of on the shared base network, and joins the anvil to that network as an extra -- the anvil keeps the base network for the model backend. The tong is left off the per-session fabric and probed for readiness on its own network. Because each org's tong is alone on its network, its DNS alias (the agent-facing MCP server name) stays unchanged. This closes a cross-tenant gap: another org's anvil has no interface on the network, so it cannot reach the tong even by dialing a raw IP. A scoped launch requires the anvil `--name` (to join the network), checked up front like the session case. On teardown the network is pruned best-effort -- docker refuses while the long-lived tong is attached, so it persists with its tong. Non-org shared tongs are untouched.
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
Two orgs that ship the same
sharedtong (same filename, sameinterface.name) but different credentials used to collide. Asharedtong iskeyed only by its name, so both resolved to one daemon-global container
(
swarmforge-shared-asana): launching the second org tore down the first. Andeven side by side, both tongs sat on the shared base network under the same DNS
alias, so an agent could reach the wrong org's MCP -- by name, or by raw IP.
(I've seen agents scan the network looking for the MCP server to connect to
when it wasn't broadcast that it was available and successfully connect).
This partitions org-owned shared tongs per org, along two axes: a scoped
container name and an isolated per-org network.
What this changes
tongs.py):org_scope_token-- a stable short token derived from the org layer's tongsdirectory (same org -> same token, different orgs -> different;
Nonewhenno org layer).
shared_container_name(name, scope=...)-- scoped container names soidentically-named org tongs no longer collide on one daemon-global name.
shared_network_name(scope)-- the isolated per-org network.run_anvil.py): an org-sourcedsharedtong is startedon its own per-org network (not the shared base network) under a scoped
container name; the anvil joins that network as an extra while keeping the
base network for the model backend; the tong is kept off the per-session
fabric and probed on its own network. The network is pruned best-effort on
teardown (docker refuses while the long-lived tong is attached, so it
persists). A scoped launch requires the anvil
--name, checked up front.Why network isolation, not just naming
Scoping the container name alone fixes the teardown but leaves both tongs
reachable on the shared base network. Scoping the DNS alias too still leaves a
routable IP. Putting each org's shared tongs on their own network -- which only
that org's anvil joins -- removes the route entirely: another org's anvil has no
interface on it. Because each org's tong is then alone on its network, the
agent-facing MCP server name stays unchanged.
Scope
Covers org-layer shared tongs. Repo-layer shared tongs still share the base
network; the mechanism generalizes to them in a follow-up. Non-org shared tongs
are untouched.