feat(auth): add local and OIDC management to tht

This commit is contained in:
2026-08-16 19:23:30 +02:00
parent d17ad0e95b
commit 9646ae09a0
15 changed files with 992 additions and 13 deletions
+14
View File
@@ -14,6 +14,7 @@ import (
"strconv"
"strings"
"github.com/aritmolab/thothii/tools/tht/internal/authconfig"
"github.com/aritmolab/thothii/tools/tht/internal/backup"
"github.com/aritmolab/thothii/tools/tht/internal/compose"
"github.com/aritmolab/thothii/tools/tht/internal/config"
@@ -22,6 +23,7 @@ import (
"github.com/aritmolab/thothii/tools/tht/internal/output"
"github.com/aritmolab/thothii/tools/tht/internal/pi"
"github.com/aritmolab/thothii/tools/tht/internal/project"
"github.com/aritmolab/thothii/tools/tht/internal/safeio"
"github.com/aritmolab/thothii/tools/tht/internal/serverops"
"github.com/aritmolab/thothii/tools/tht/internal/service"
"github.com/aritmolab/thothii/tools/tht/internal/setup"
@@ -38,6 +40,10 @@ Commands:
setup [--configure-only] [--installation-id ID] [--profile local|server]
Create or validate the local non-secret installation configuration.
version [--json] Show the host CLI build identity.
auth configure --mode local|oidc ...
Configure local users or OIDC group mapping; see tht auth for exact options.
auth status [--json] Show the redacted authentication configuration status.
auth user ... Manage local users; unavailable for OIDC installations.
status Show the Compose service state.
doctor [--json] Run non-mutating host, Compose, workflow, and Pi diagnostics.
logs Show the latest 200 sanitized service log lines (bounded; no follow mode).
@@ -130,6 +136,12 @@ func run(ctx context.Context, args []string, stdout, stderr io.Writer) int {
fmt.Fprintf(stderr, "tht: %s\n", output.Sanitize(err.Error(), nil))
return 2
}
if command != "auth" || len(commandArgs) == 0 || commandArgs[0] != "configure" {
if err := safeio.ValidatePrivateDirectory(installation.AuthenticationDirectory()); err != nil {
fmt.Fprintln(stderr, "tht: authentication configuration directory is unavailable or unsafe")
return 2
}
}
secretFiles, err := installation.SecretFiles()
if err != nil {
fmt.Fprintln(stderr, "tht: installation secret declarations could not be read")
@@ -144,6 +156,8 @@ func run(ctx context.Context, args []string, stdout, stderr io.Writer) int {
runner := compose.NewRunner("")
var result compose.Result
switch command {
case "auth":
return authconfig.Run(ctx, installation, commandArgs, os.Stdin, stdout, stderr)
case "status":
if len(commandArgs) != 0 {
return commandUsageError(stderr, "status does not accept arguments")