ReviewOS

also looking at this

stacks/ts-cloud

docs(cloud): say what attaching does to a credential's blast radius

#171
Merged glennmichael123 wants to merge docs/attach-credential-reach into main
4 files +358 -1

Addresses #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.

BeforeAfter
loghq CI reaches the loghq boxloghq CI reaches statushq, bughq, stacks, localtunnels
bughq CI reaches the bughq boxbughq 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 attachTo docstring now states the radius, the write requirement, and the mutual exclusivity.
  • A new docs/config.md section, "Attaching to another project's server", since attachTo appeared nowhere in docs/ 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

  • attachTo documents 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 loghq to statushq reports 4 servers reachable that neither project owns
  • Full suite 4005 pass, 0 fail; typecheck clean; lint 0 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.