package console // The "give this canary a URL" advice the app page and the post-create flash // both render. The property under test is not the wording — it is WHICH verb // the console sends its reader at. `carlos add` writes the box's registry on // local disk (cli.go's defaultRegistry), so a browser session anywhere else // cannot run it; `carlos instances create` is the API-backed door a login // credential can drive, and provision.Reconcile carries its channel onto the // minted route. A dashboard advertising the box-local verb is the bug this // file pins shut (2026-08-07). import ( "context" "strings" "testing" "github.com/carlosframework/platform/internal/provision" ) func TestAttachCommands(t *testing.T) { for _, tc := range []struct { name string domain string appsDomain, sqid string absent bool wantCreate string wantEnable string }{{ // Enabled: the manifest's own domain is where hosts live, whether it // is the platform pin or a custom domain, and no enable step is owed. name: "enabled platform domain", domain: "bab.oncarlos.test", appsDomain: "oncarlos.test", sqid: "bab", wantCreate: "carlos instances create --app echo --host .bab.oncarlos.test --channel canary/rc", }, { name: "enabled custom domain", domain: "go.tito.io", appsDomain: "oncarlos.test", sqid: "bab", wantCreate: "carlos instances create --app echo --host .go.tito.io --channel canary/rc", }, { // Proven absent: lead with enable, and name the host shape the enable // door will pin — the account's own platform subdomain. name: "absent with apps domain", absent: true, appsDomain: "oncarlos.test", sqid: "bab", wantCreate: "carlos instances create --app echo --host .bab.oncarlos.test --channel canary/rc", wantEnable: "carlos instances enable --app echo", }, { // Absent and the deployment has no platform apps domain: the enable // door itself refuses (503), so there is no host shape to promise. name: "absent without apps domain", absent: true, sqid: "bab", wantCreate: "carlos instances create --app echo --host --channel canary/rc", wantEnable: "carlos instances enable --app echo", }, { // Unreadable manifest: neither enabled nor proven absent. The enable // step must NOT appear — that door is guarded and answers 409 over a // standing manifest, so a transient bucket error must not send an // operator at a refusal. name: "unreadable", appsDomain: "oncarlos.test", sqid: "bab", wantCreate: "carlos instances create --app echo --host --channel canary/rc", }} { t.Run(tc.name, func(t *testing.T) { create, enable := attachCommands("echo", "canary/rc", tc.domain, tc.appsDomain, tc.sqid, tc.absent) if create != tc.wantCreate { t.Errorf("create = %q, want %q", create, tc.wantCreate) } if enable != tc.wantEnable { t.Errorf("enable = %q, want %q", enable, tc.wantEnable) } if strings.Contains(create, "carlos add") || strings.Contains(enable, "carlos add") { t.Errorf("advice names the box-local verb: %q / %q", create, enable) } }) } } // TestInstanceDomainForStates pins the three-way answer, because collapsing // "could not read" into "absent" is exactly what would put a doomed // `carlos instances enable` in front of an operator during a bucket hiccup. func TestInstanceDomainForStates(t *testing.T) { fx := newConsoleFixture(t) ctx := context.Background() // No manifest written for the fixture's app: proven absent. if domain, absent := fx.srv.instanceDomainFor(ctx, "bab", "kass"); domain != "" || !absent { t.Fatalf("no manifest: domain=%q absent=%v, want \"\" true", domain, absent) } // A manifest present: its domain, and not absent. m := provision.Manifest{Schema: 1, App: "kass", Domain: "bab.oncarlos.test", Channel: "stable"} if err := provision.PutManifest(ctx, fx.rel, "bab", "kass", m); err != nil { t.Fatal(err) } if domain, absent := fx.srv.instanceDomainFor(ctx, "bab", "kass"); domain != "bab.oncarlos.test" || absent { t.Fatalf("with manifest: domain=%q absent=%v, want bab.oncarlos.test false", domain, absent) } // A read that fails for any reason other than not-found is NOT absent. fx.srv.cfg.Releases = unreadableStore{fx.rel} if domain, absent := fx.srv.instanceDomainFor(ctx, "bab", "kass"); domain != "" || absent { t.Fatalf("unreadable: domain=%q absent=%v, want \"\" false", domain, absent) } } // TestAppPageNamesAPIBackedAttach is the regression at the level the operator // met it: the app page's canary form, rendered, must hand back a command the // reader can run from where they are. func TestAppPageNamesAPIBackedAttach(t *testing.T) { fx := newConsoleFixture(t) fx.srv.cfg.AppsDomain = "oncarlos.test" if err := provision.PutManifest(context.Background(), fx.rel, "bab", "kass", provision.Manifest{Schema: 1, App: "kass", Domain: "bab.oncarlos.test", Channel: "stable"}); err != nil { t.Fatal(err) } c := signInPaul(t, fx) // The releases tab: the canary form lives there since the console's tab // split, and so does the advice beside it. _, _, body := get(t, c, fx.u("/apps/kass/releases")) // html/template escapes the placeholder, so assert around it. for _, want := range []string{ "carlos instances create --app kass --host ", "bab.oncarlos.test --channel canary/", } { if !strings.Contains(body, want) { t.Fatalf("/apps/kass/releases missing %q in:\n%s", want, body) } } // Enabled already: no enable step, and never the box-local verb. if strings.Contains(body, "carlos instances enable") { t.Error("app page offers `instances enable` for an app that already has a manifest") } if strings.Contains(body, "carlos add ") { t.Error("app page still sends the reader at box-local `carlos add`") } }