[feat](maestro): adopt externally managed services without owning them

The dashboard sees containers Maestro did not create (each repo dev debug compose), and treating them as installs made start/uninstall/config act on a project file that never created them. Mark them external, refuse start/update/uninstall with a message pointing at their own compose project, and let stop work at the container level. Inject runtime env (config-signing public key, plaintext shared-DB DSN) on the managed start path, and keep the external flag a property of the service so a debug sibling cannot flip a managed service.
This commit is contained in:
2026-10-19 02:40:05 +01:00
parent 7afd019215
commit 13f6d14521
12 changed files with 738 additions and 183 deletions
+10 -7
View File
@@ -73,10 +73,11 @@ func InstallContainer(ctx context.Context, item types.RegistryContainer) error {
}
// 2.6. Pin the auth service's signing key (security theme M2 §5): fetch its
// attestation over mTLS and store the fingerprint in the install record so
// the container gets AUTH_PINNED_FINGERPRINT at start. Best-effort — when
// the auth service is not reachable yet the pin stays empty and is retried
// on start.
// attestation over plaintext HTTP and store the fingerprint in the install
// record so the container gets AUTH_PINNED_FINGERPRINT at start. This is an
// app-level fingerprint comparison, not a transport identity. Best-effort —
// when the auth service is not reachable yet the pin stays empty and is
// retried on start.
if att, err := fetchAuthAttestation(ctx); err == nil {
metadata.AuthFingerprint = att.Fingerprint
metadata.AuthKid = att.Kid
@@ -176,7 +177,8 @@ func getDataRoot() (string, error) {
}
// DataRoot is the exported accessor for the storage root shared by installed
// container metadata and the instance PKI (CA + service identities).
// container metadata and Maestro's private key material (instance identity,
// session/secrets keys, config-signing keypair).
func DataRoot() (string, error) {
return getDataRoot()
}
@@ -500,8 +502,9 @@ func writeMetadata(path string, metadata types.InstalledMetadata) error {
}
// fetchAuthAttestation fetches the auth service's public key statement over
// mTLS (Maestro's own identity certificate). It backs the M2 §5 TOFU pin: the
// returned fingerprint is what consumer containers are pinned to.
// plaintext HTTP (rev 9 removed the mTLS identity layer). It backs the M2 §5
// app-level pin: the returned fingerprint is what consumer containers are
// pinned to.
func fetchAuthAttestation(ctx context.Context) (*authmgmt.Attestation, error) {
client, err := authmgmt.New()
if err != nil {