feat(auth): integrate authentication with installation lifecycle

This commit is contained in:
2026-08-17 23:33:51 +02:00
parent 0d0c15b4b8
commit e8b9995ed0
21 changed files with 672 additions and 234 deletions
+25 -36
View File
@@ -48,7 +48,7 @@ func TestActiveSessionsUsesInstallationScopedInventory(t *testing.T) {
if active, err := activeSessions(context.Background(), runner); err != nil || active {
t.Fatalf("activeSessions(%s) = %t, %v; want false, nil", scope, active, err)
}
if len(runner.calls) != 1 || !strings.Contains(runner.calls[0], "/sessions?scope="+scope) {
if len(runner.calls) != 1 || !strings.Contains(runner.calls[0], "operator-command.js session-inventory "+scope) {
t.Fatalf("activeSessions(%s) call = %v; want installation-scoped inventory", scope, runner.calls)
}
}
@@ -250,7 +250,7 @@ func TestMaintenanceTransportLossAfterBackendRestartRequiresRecovery(t *testing.
if fake.backendRestarts != 1 {
t.Fatalf("backend restarts = %d, want 1", fake.backendRestarts)
}
assertCalled(t, fake.calls, "/internal/maintenance/status")
assertCalled(t, fake.calls, "operator-command.js maintenance-status")
for index, active := range fake.maintenanceAtRecreate {
if !active {
t.Fatalf("recreate %d started without durable maintenance", index+1)
@@ -344,8 +344,8 @@ func TestCompensationReactivatesMaintenanceAndRescansBeforeRollback(t *testing.T
t.Fatalf("calls %v contain no rollback", fake.calls)
}
recreate := callIndex(fake.calls, "force-recreate core")
activate := lastCallIndexBefore(fake.calls, "/internal/maintenance/activate", rollback)
scan := lastCallIndexBefore(fake.calls, "/sessions?scope=all", rollback)
activate := lastCallIndexBefore(fake.calls, "operator-command.js maintenance-activate", rollback)
scan := lastCallIndexBefore(fake.calls, "operator-command.js session-inventory all", rollback)
if activate <= recreate || scan <= recreate {
t.Fatalf("calls %v do not reactivate/confirm and rescan after candidate recreate before rollback", fake.calls)
}
@@ -599,7 +599,7 @@ func TestRecoverMaintenanceClearsOnlyAfterTerminalStateAndVerifiedSmoke(t *testi
if selected := readSelectorReference(t, currentImageOverridePath(statePath)); selected != previous.Reference {
t.Fatalf("maintenance cleanup changed durable selector to %q", selected)
}
assertCalled(t, fake.calls, "/pi-management/test")
assertCalled(t, fake.calls, "operator-command.js pi-test")
}
func TestRecoverMaintenanceRefusesPendingTransaction(t *testing.T) {
@@ -774,12 +774,12 @@ func TestUpdateRequiresConfirmationAndDrainsActiveSessions(t *testing.T) {
if err != nil {
t.Fatalf("Update() with drain error = %v", err)
}
assertCalled(t, fake.calls, "http://127.0.0.1:8787/sessions?scope=all")
assertCalled(t, fake.calls, "/internal/maintenance/activate")
assertCalled(t, fake.calls, "/internal/maintenance/deactivate")
assertCalled(t, fake.calls, "operator-command.js session-inventory all")
assertCalled(t, fake.calls, "operator-command.js maintenance-activate")
assertCalled(t, fake.calls, "operator-command.js maintenance-deactivate")
}
func TestMaintenanceControlUsesExactLoopbackOperatorIdentity(t *testing.T) {
func TestMaintenanceControlUsesOnlyTheScopedNonNetworkCommand(t *testing.T) {
fake := newFakeRunner()
if err := setMaintenance(context.Background(), fake, true); err != nil {
t.Fatal(err)
@@ -788,26 +788,15 @@ func TestMaintenanceControlUsesExactLoopbackOperatorIdentity(t *testing.T) {
if _, err := MaintenanceStatus(context.Background(), fake); err != nil {
t.Fatal(err)
}
for _, path := range []string{"/internal/maintenance/activate", "/internal/maintenance/status"} {
found := false
for _, call := range fake.calls {
if !strings.Contains(call, path) {
continue
}
found = true
for _, header := range []string{
"x-thoth-principal-issuer: tht",
"x-thoth-principal-subject: tht-maintenance",
"x-thoth-principal-display-name: Tht maintenance",
"x-thoth-is-admin: 1",
} {
if !strings.Contains(call, header) {
t.Fatalf("maintenance call %q lacks %q", call, header)
}
}
joined := strings.Join(fake.calls, "\n")
for _, action := range []string{"operator-command.js maintenance-activate", "operator-command.js maintenance-status"} {
if !strings.Contains(joined, action) {
t.Fatalf("maintenance action %q was not made: %s", action, joined)
}
if !found {
t.Fatalf("maintenance call %q was not made", path)
}
for _, forbidden := range []string{"curl", "x-thoth-principal", "x-thoth-is-admin"} {
if strings.Contains(joined, forbidden) {
t.Fatalf("maintenance commands retained HTTP identity material %q: %s", forbidden, joined)
}
}
}
@@ -1074,7 +1063,7 @@ func (f *fakeRunner) Run(_ context.Context, args []string, _ io.Reader) (compose
if f.fail == "version" && (f.built || f.recreated) && strings.Contains(call, "pi --version") && strings.Contains(call, "exec") {
return compose.Result{ExitCode: 1}, errors.New("version token=secret")
}
if f.fail == "smoke" && (f.built || f.recreated) && strings.Contains(call, "127.0.0.1:8787/pi-management/test") {
if f.fail == "smoke" && (f.built || f.recreated) && strings.Contains(call, "operator-command.js pi-test") {
return compose.Result{ExitCode: 1}, errors.New("smoke token=secret")
}
switch {
@@ -1106,7 +1095,7 @@ func (f *fakeRunner) Run(_ context.Context, args []string, _ io.Reader) (compose
return compose.Result{Stdout: f.mountsJSON}, nil
}
return compose.Result{Stdout: `[{"Type":"volume","Name":"settings","Source":"settings","Destination":"/data/settings","RW":true},{"Type":"volume","Name":"pi-state","Source":"pi-state","Destination":"/home/thoth/.pi","RW":true},{"Type":"volume","Name":"sessions","Source":"sessions","Destination":"/data/sessions","RW":true},{"Type":"volume","Name":"workspace-registry","Source":"workspace-registry","Destination":"/data/workspace-registry","RW":true}]`}, nil
case strings.Contains(call, "/internal/maintenance/activate"):
case strings.Contains(call, "operator-command.js maintenance-activate"):
f.maintenance = true
if f.fail == "maintenance-activate-durability" || f.fail == "maintenance-activate-durability-without-status-flag" {
return compose.Result{ExitCode: 22}, errors.New("maintenance activation durability was not acknowledged")
@@ -1119,7 +1108,7 @@ func (f *fakeRunner) Run(_ context.Context, args []string, _ io.Reader) (compose
return compose.Result{ExitCode: 52}, errors.New("lost activation response")
}
return compose.Result{Stdout: `{"active":true,"admissions":0}`}, nil
case strings.Contains(call, "/internal/maintenance/deactivate"):
case strings.Contains(call, "operator-command.js maintenance-deactivate"):
if f.fail == "maintenance-clear" {
return compose.Result{ExitCode: 53}, errors.New("maintenance clear failure")
}
@@ -1138,7 +1127,7 @@ func (f *fakeRunner) Run(_ context.Context, args []string, _ io.Reader) (compose
return compose.Result{ExitCode: 52}, errors.New("lost deactivation response")
}
return compose.Result{Stdout: `{"active":false,"admissions":0}`}, nil
case strings.Contains(call, "/internal/maintenance/status"):
case strings.Contains(call, "operator-command.js maintenance-status"):
if f.fail == "maintenance-proof" && f.recreated {
return compose.Result{Stdout: fmt.Sprintf(`{"active":%t,"admissions":0,"recoveryRequired":true}`, f.maintenance)}, nil
}
@@ -1149,7 +1138,7 @@ func (f *fakeRunner) Run(_ context.Context, args []string, _ io.Reader) (compose
return compose.Result{Stdout: fmt.Sprintf(`{"active":%t,"admissions":0,"recoveryRequired":true}`, f.maintenance)}, nil
}
return compose.Result{Stdout: fmt.Sprintf(`{"active":%t,"admissions":0}`, f.maintenance)}, nil
case strings.Contains(call, "/sessions?scope=all"):
case strings.Contains(call, "operator-command.js session-inventory all"):
if f.sessionsWire != "" {
return compose.Result{Stdout: f.sessionsWire}, nil
}
@@ -1230,12 +1219,12 @@ func (f *fakeRunner) Run(_ context.Context, args []string, _ io.Reader) (compose
return compose.Result{Stdout: f.version + "\n"}, nil
case strings.Contains(call, "PI_VERSION"):
return compose.Result{Stdout: f.expectedVersion + "\n"}, nil
case strings.Contains(call, "/pi-management/options"):
case strings.Contains(call, "operator-command.js pi-options"):
if f.piManagementOptionsWire != "" {
return compose.Result{Stdout: f.piManagementOptionsWire}, nil
}
return compose.Result{Stdout: `{"providers":["provider"],"models":[{"id":"model","provider":"provider"}],"reasoning":["low","medium","high"]}`}, nil
case strings.Contains(call, "/pi-management/test"):
case strings.Contains(call, "operator-command.js pi-test"):
if f.currentImage == "sha256:old" {
f.restoredProofComplete = true
}
@@ -1248,7 +1237,7 @@ func (f *fakeRunner) Run(_ context.Context, args []string, _ io.Reader) (compose
return compose.Result{Stdout: f.modelsWire}, nil
}
return compose.Result{Stdout: `{"models":[{"id":"model","provider":"provider"}]}`}, nil
case strings.Contains(call, "/settings"):
case strings.Contains(call, "operator-command.js effective-settings"):
if f.currentImage == "sha256:old" {
f.restoredProofComplete = true
}