feat(server): activate projected authentication safely

This commit is contained in:
User
2026-08-22 01:01:36 +02:00
parent 903c0b4de5
commit 3d9a9f0675
32 changed files with 1837 additions and 38 deletions
+5
View File
@@ -32,6 +32,8 @@ import (
"github.com/aritmolab/thothii/tools/tht/internal/workspaceops"
)
var requireRuntimeAuthProjectionReady = authconfig.RequireRuntimeAuthProjectionReady
const usage = `Usage: tht [--installation <absolute-path>/thothii-installation.yaml] <command>
When --installation is omitted, tht uses THOTHII_INSTALLATION or discovers one valid
@@ -192,6 +194,9 @@ func run(ctx context.Context, args []string, stdout, stderr io.Writer) int {
if len(commandArgs) != 1 || commandArgs[0] != "--check-only" {
return commandUsageError(stderr, "update currently requires --check-only")
}
if err := requireRuntimeAuthProjectionReady(installation); err != nil {
return lifecycleFailure(stderr, errors.New("runtime authentication projection is unavailable"), secretValues)
}
result, err = runner.Run(ctx, installation.ComposeArgs("config", "--quiet"), nil)
case "backup":
return backupCommand(ctx, installation, commandArgs, stdout, stderr)
+45
View File
@@ -4,6 +4,7 @@ import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
"io"
"os"
@@ -1049,6 +1050,31 @@ func TestRunPreservesChildExitCodes(t *testing.T) {
}
}
func TestRunUpdateCheckOnlyRefusesProjectedAuthenticationBeforeCompose(t *testing.T) {
for _, state := range []string{"missing", "blocked", "divergent"} {
t.Run(state, func(t *testing.T) {
fixture := projectedUpdateFixture(t)
previous := requireRuntimeAuthProjectionReady
requireRuntimeAuthProjectionReady = func(installation config.Installation) error {
if !installation.HasRuntimeAuthProjection() {
t.Fatal("update readiness gate received an unprojected installation")
}
return errors.New("synthetic " + state + " projection")
}
t.Cleanup(func() { requireRuntimeAuthProjectionReady = previous })
var stdout, stderr bytes.Buffer
if code := run(context.Background(), []string{"--installation", fixture.installationPath, "update", "--check-only"}, &stdout, &stderr); code == 0 {
t.Fatalf("update --check-only accepted %s projection", state)
}
assertDockerNotInvoked(t, fixture)
if strings.Contains(stdout.String()+stderr.String(), "synthetic "+state+" projection") {
t.Fatalf("update leaked readiness detail: stdout=%q stderr=%q", stdout.String(), stderr.String())
}
})
}
}
func TestRunPiStatusUsesImageBundledPi(t *testing.T) {
fixture := newCLIFixture(t, "THT_LLM_URL=https://llm.example.invalid\n")
fixture.setEnvironment(t)
@@ -1575,6 +1601,25 @@ func (f cliFixture) setProfile(t *testing.T, profile string) {
}
}
func projectedUpdateFixture(t *testing.T) cliFixture {
t.Helper()
fixture := newCLIFixture(t, "SAFE_VALUE=1\n")
fixture.setProfile(t, "server")
runtimeRoot := filepath.Join(fixture.root, "runtime-auth")
if err := os.Mkdir(runtimeRoot, 0o700); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(fixture.projectDirectory, "deploy", "compose.auth-runtime-projection.yaml"), []byte("services: {}\n"), 0o600); err != nil {
t.Fatal(err)
}
descriptor := "profile: server\nprojectDirectory: " + fixture.projectDirectory + "\nenvFile: " + fixture.envFile + "\nauthentication:\n configDirectory: " + filepath.Join(fixture.root, "auth") + "\n runtimeProjection:\n directory: " + runtimeRoot + "\n uid: 10001\n gid: 10001\n"
if err := os.WriteFile(fixture.installationPath, []byte(descriptor), 0o600); err != nil {
t.Fatal(err)
}
fixture.setEnvContents(t, "SAFE_VALUE=1\nTHT_AUTH_RUNTIME_ROOT="+strconv.Quote(runtimeRoot)+"\n")
return fixture
}
func (f cliFixture) invocations(t *testing.T) [][]string {
t.Helper()
contents, err := os.ReadFile(f.argsFile)