also looking at this
docs(cloud): say what attaching does to a credential's blast radius
#171Addresses #169 (three of its four acceptance criteria; the fourth is called out below).
What was wrong
cloud.attachTo finds the owner's box by listing the provider's servers with the attaching project's own token. That listing is the whole mechanism, and it forces something the config never said: the owner's box must be visible to the attacher's credential, so both projects have to share one provider project. On Hetzner a Cloud API token is project-scoped with Read or Read & Write, has no per-resource scoping, and a deploy needs write.
The old docstring said "Requires read access via the same HCLOUD_TOKEN", which understates it twice: the access needed is write, and the reach is the whole provider project, not the one box.
| Before | After |
|---|---|
loghq CI reaches the loghq box | loghq CI reaches statushq, bughq, stacks, localtunnels |
bughq CI reaches the bughq box | bughq CI reaches all of the above |
And the other half of the same decision, now stated: per-project isolation and attaching are mutually exclusive. An app kept in its own provider project cannot be attached at all, because its token cannot see the owner's box.
What this adds
- The
attachTodocstring now states the radius, the write requirement, and the mutual exclusivity. - A new
docs/config.mdsection, "Attaching to another project's server", sinceattachToappeared nowhere indocs/at all. describeCredentialReach()attributes every server a credential can enumerate to a project, keeping the owner's boxes and this project's own separate from the ones nobody asked to reach. Only that last number is an argument against attaching, so collapsing them would bury the point.formatCredentialReach()renders sorted, run-to-run stable plan lines, and stays quiet with one summary line when the reach really is just the two projects being joined. A warning that fires every time is a warning that gets skipped.
Both are pure and structurally typed over { name, labels } rather than a Hetzner server, so any driver that can enumerate what its credential sees can report a radius.
Acceptance criteria
attachTodocuments that it requires the same provider project and what that grants- The docs state plainly that per-project isolation and attaching are mutually exclusive
- The attach plan can report the other resources the credential reaches (the reporting exists and is tested; the print call belongs to the attach plan surface in #167 / stacksjs/stacks#2342, which is where a plan is actually rendered)
- The driver interface allows a narrower credential where a provider supports one
On that last box
I did not change the CloudDriver interface. Hetzner cannot express a narrower credential at all, so the only honest way to design that seam is against a provider that can (AWS IAM), and guessing the shape from the provider that cannot is how you get an abstraction that fits nobody. Making the reporting provider-agnostic is the part that is useful today and does not need that guess; I would rather leave the interface change to whoever does it against a real second credential model.
Verification
- 10 new tests, including the issue's own five-box fleet: attaching
loghqtostatushqreports 4 servers reachable that neither project owns - Full suite
4005 pass, 0 fail;typecheckclean;lint0 errors 0 warnings
Related: #168 / #170 covers the port collision on the same shared box.
4 changed files on the files tab, with 0 review threads.