Rename Installation to Instance

Follows the portal: the noun is "instance" everywhere the app says it —
UI strings, CLI output, error details, docs and comments. The wire keys
(`instance_id`, `instance_token`) and the hub route this calls move with it.

An existing cloud.json is adopted rather than refused: without the key
alias the dataclass fails to parse, which the caller swallows and reads as
"never enrolled" instead of "reconnect".

`instance_key` on a node type becomes `target_key`. It means the outside
thing a node points at, which is a different sense of the word, and keeping
both would put two meanings of "instance" in one codebase.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015YrQnKV3bnQd4K342y8tKj
This commit is contained in:
2026-08-31 10:12:01 +02:00
co-authored by Claude Opus 5
parent 6534855492
commit d01a8dad37
101 changed files with 374 additions and 375 deletions
+11 -11
View File
@@ -1,7 +1,7 @@
"""Remote access: off by default, and only ever as much as somebody granted.
The property worth pinning down is the one everything else rests on — a
portal's token is worth nothing here until somebody at this installation
portal's token is worth nothing here until somebody at this instance
enrolled it, and even then it grants exactly the rights of the local account
the portal identity holding it was mapped to. An identity nobody mapped gets
nothing, which is what makes deleting that local account a revocation.
@@ -31,7 +31,7 @@ from tests.utils.portal import ISSUER, portal_token
def test_portal_token_is_refused_when_not_enrolled(
portal_key: rsa.RSAPrivateKey, tmp_path_factory: pytest.TempPathFactory
) -> None:
"""An installation nobody connected trusts no portal at all."""
"""An instance nobody connected trusts no portal at all."""
original = settings.CLOUD_CONFIG_FILE
settings.CLOUD_CONFIG_FILE = tmp_path_factory.mktemp("empty") / "cloud.json"
try:
@@ -55,11 +55,11 @@ def test_portal_token_resolves_by_portal_identity(
assert user_from_token(db, portal_token(portal_key, subject="nobody")) is None
def test_token_for_another_installation_is_refused(
def test_token_for_another_instance_is_refused(
enrolled: User, # noqa: ARG001 (fixture installs the enrolment)
portal_key: rsa.RSAPrivateKey,
) -> None:
"""The audience is this installation's id, so someone else's is worthless."""
"""The audience is this instance's id, so someone else's is worthless."""
with pytest.raises(jwt.exceptions.InvalidTokenError):
decode_token(portal_token(portal_key, audience=str(uuid.uuid4())))
@@ -67,7 +67,7 @@ def test_token_for_another_installation_is_refused(
def test_token_from_an_unpinned_key_is_refused(
enrolled: User, # noqa: ARG001 (fixture installs the enrolment)
) -> None:
"""A different portal, or a hijacked one, cannot sign for this installation."""
"""A different portal, or a hijacked one, cannot sign for this instance."""
impostor = rsa.generate_private_key(public_exponent=65537, key_size=2048)
with pytest.raises(jwt.exceptions.InvalidTokenError):
decode_token(portal_token(impostor))
@@ -104,7 +104,7 @@ def test_status_reports_not_enrolled(
def test_enrolling_needs_a_superuser(
client: TestClient, normal_user_token_headers: dict[str, str]
) -> None:
"""Remote access is an installation-wide grant, not a personal setting."""
"""Remote access is an instance-wide grant, not a personal setting."""
response = client.post(
f"{settings.API_V1_STR}/cloud/enroll",
headers=normal_user_token_headers,
@@ -122,7 +122,7 @@ def test_a_panel_scoped_portal_token_reaches_only_its_panel(
"""A screen paired through the portal is bounded here, not there.
The portal names the panel; everything about what that means is this
installation's, which is the whole reason it may mint one at all.
instance's, which is the whole reason it may mint one at all.
"""
write_config(
PanelsConfig(
@@ -241,7 +241,7 @@ def test_adding_a_remote_user_maps_and_revokes(
f"{settings.API_V1_STR}/users/{body['id']}", headers=superuser_token_headers
)
assert removed.status_code == 200, removed.text
assert delete.call_args.args[0].endswith("/installation-members/portal-user-9")
assert delete.call_args.args[0].endswith("/instance-members/portal-user-9")
db.expire_all()
assert user_from_token(db, theirs) is None
@@ -251,7 +251,7 @@ def test_adding_a_remote_user_needs_a_superuser(
enrolled: User, # noqa: ARG001 (fixture installs the enrolment)
normal_user_token_headers: dict[str, str],
) -> None:
"""Widening who can reach this installation stays a superuser's decision."""
"""Widening who can reach this instance stays a superuser's decision."""
response = client.post(
f"{settings.API_V1_STR}/cloud/users",
headers=normal_user_token_headers,
@@ -272,8 +272,8 @@ def test_enrolling_against_a_portal_without_an_owner_is_refused(
status_code=200,
json=Mock(
return_value={
"installation_id": str(uuid.uuid4()),
"installation_token": "t",
"instance_id": str(uuid.uuid4()),
"instance_token": "t",
"ws_url": f"{ISSUER}/api/v1/tunnel/attach",
"issuer": ISSUER,
"jwks": {"keys": []},