Files
Agent-System-Backend/internal/app/super_admin.go
T

59 lines
2.0 KiB
Go

package app
import (
"errors"
"fmt"
"log"
"agent-system-backend/internal/config"
"agent-system-backend/internal/server"
"agent-system-backend/internal/store"
)
// ErrCLIAdminAppointment rejects every local CLI attempt to create an
// administrator (R4, R5): only the server-side super administrator appoints.
var ErrCLIAdminAppointment = errors.New("administrator appointment is reserved to the super administrator; no CLI path may create an administrator")
// ErrCLIBootstrapAdminDisabled rejects the retired local bootstrap-admin path:
// only service startup establishes the super administrator (KTD4).
var ErrCLIBootstrapAdminDisabled = errors.New("bootstrap-admin is disabled; the super administrator is established at service startup from SUPER_ADMIN_OWNER and SUPER_ADMIN_PASSWORD")
// ValidateSuperAdmin is the startup gate for R1: with authentication enabled,
// missing, partial or policy-violating configuration refuses startup. The
// unauthenticated embedded mode neither requires nor uses the credentials.
func ValidateSuperAdmin(authOn bool, sa config.SuperAdmin) error {
if !authOn {
return nil
}
if err := sa.Validate(server.ValidatePassword); err != nil {
return fmt.Errorf("super admin: %w", err)
}
return nil
}
// BootstrapSuperAdmin establishes the configured super administrator in
// persistent account state (KTD4). Identity conflicts stop startup; logs carry
// the owner only, never the password or its hash.
func BootstrapSuperAdmin(st *store.Store, authOn bool, sa config.SuperAdmin) error {
if !authOn {
return nil
}
if err := ValidateSuperAdmin(authOn, sa); err != nil {
return err
}
hash, err := store.HashPassword(sa.Password())
if err != nil {
return fmt.Errorf("super admin: hash password: %w", err)
}
out, err := st.BootstrapSuperAdmin(sa.Owner, hash)
if err != nil {
return fmt.Errorf("super admin %q: %w", sa.Owner, err)
}
if out.Created {
log.Printf("super admin: established account %q", sa.Owner)
} else {
log.Printf("super admin: account %q already established", sa.Owner)
}
return nil
}