feat: serve DWH authentication over Unix socket

This commit is contained in:
User
2026-08-21 01:57:19 +02:00
parent 943f809d01
commit 419c3440d7
4 changed files with 855 additions and 16 deletions
+19 -13
View File
@@ -14,6 +14,7 @@ import (
"errors"
"fmt"
"io"
"log"
"os"
"path/filepath"
"strings"
@@ -25,15 +26,15 @@ import (
"github.com/aritmolab/thothii/tools/dwh-auth/internal/record"
"github.com/aritmolab/thothii/tools/dwh-auth/internal/registry"
"github.com/aritmolab/thothii/tools/dwh-auth/internal/securefile"
"github.com/aritmolab/thothii/tools/dwh-auth/internal/service"
)
const (
exitOK = 0
exitUsage = 2
exitNotFound = 3
exitIntegrity = 4
maxReasonBytes = 160
commandServeMsg = "serve is not available in this release"
exitOK = 0
exitUsage = 2
exitNotFound = 3
exitIntegrity = 4
maxReasonBytes = 160
)
var (
@@ -41,6 +42,7 @@ var (
generateCredential = func() (credential.Material, error) { return credential.Generate(rand.Reader) }
addRecord = func(store *registry.Store, value record.Record) error { return store.Add(value) }
closeStore = func(store *registry.Store) error { return store.Close() }
listenAndServe = service.ListenAndServe
)
// Run executes one dwh-auth invocation and returns its stable process exit
@@ -53,7 +55,7 @@ func Run(ctx context.Context, args []string, _ io.Reader, stdout, stderr io.Writ
return exitIntegrity
}
if len(args) > 0 && args[0] == "serve" {
return runServe(args[1:], stderr)
return runServe(ctx, args[1:], stderr)
}
root, rest, err := parseRoot(args)
if err != nil {
@@ -437,17 +439,21 @@ func runCheck(ctx context.Context, root string, args []string, stdout, stderr io
return exitOK
}
func runServe(args []string, stderr io.Writer) int {
if len(args) != 4 || args[0] != "--registry-root" || args[2] != "--socket" || !filepath.IsAbs(args[1]) || !filepath.IsAbs(args[3]) {
func runServe(ctx context.Context, args []string, stderr io.Writer) int {
if len(args) != 4 || args[0] != "--registry-root" || args[2] != "--socket" || !canonicalAbsolute(args[1]) || !canonicalAbsolute(args[3]) {
writeLine(stderr, "unsafe invocation")
return exitUsage
}
// The Unix-socket service is intentionally introduced by Task 4. Keeping
// this exact grammar reserved prevents accidental plaintext or network fallback.
writeLine(stderr, commandServeMsg)
return exitIntegrity
logger := log.New(stderr, "", 0)
if err := listenAndServe(ctx, service.Config{RegistryRoot: args[1], Socket: args[3], Logger: logger}); err != nil {
writeLine(stderr, "integrity failure")
return exitIntegrity
}
return exitOK
}
func canonicalAbsolute(path string) bool { return filepath.IsAbs(path) && filepath.Clean(path) == path }
func snapshotContainsKey(store *registry.Store, keyID string) (bool, error) {
values, err := store.List()
if err != nil {
@@ -19,6 +19,7 @@ import (
"github.com/aritmolab/thothii/tools/dwh-auth/internal/credential"
"github.com/aritmolab/thothii/tools/dwh-auth/internal/record"
"github.com/aritmolab/thothii/tools/dwh-auth/internal/registry"
"github.com/aritmolab/thothii/tools/dwh-auth/internal/service"
)
const sentinelSecret = "SENTINEL-DWH-SECRET-must-never-be-emitted"
@@ -295,17 +296,29 @@ func TestMetadataAndExpiryAreValidatedBeforeKeyGeneration(t *testing.T) {
}
}
func TestServeAcceptsOnlyExactTaskFourReservation(t *testing.T) {
func TestServeAcceptsOnlyExactCheckedServiceConfig(t *testing.T) {
root := t.TempDir()
socket := filepath.Join(t.TempDir(), "verify.sock")
oldListen := listenAndServe
t.Cleanup(func() { listenAndServe = oldListen })
called := false
listenAndServe = func(ctx context.Context, config service.Config) error {
called = true
if ctx == nil || config.RegistryRoot != root || config.Socket != socket || config.Logger == nil {
t.Fatalf("serve config = %#v", config)
}
return nil
}
stdout, stderr, code := run(t, "serve", "--registry-root", root, "--socket", socket)
if code != 4 || stdout != "" || stderr != "serve is not available in this release\n" {
t.Fatalf("valid serve reservation = (%d, %q, %q)", code, stdout, stderr)
if code != 0 || stdout != "" || stderr != "" || !called {
t.Fatalf("valid serve = (%d, %q, %q), called=%v", code, stdout, stderr, called)
}
invalid := [][]string{
{"serve", "--registry-root", "relative", "--socket", socket},
{"serve", "--registry-root", root + "/.", "--socket", socket},
{"serve", "--registry-root", root},
{"serve", "--registry-root", root, "--socket", "relative"},
{"serve", "--registry-root", root, "--socket", filepath.Dir(socket) + "/./verify.sock"},
{"serve", "--registry-root", root, "--socket", socket, "--socket", socket},
{"serve", "--socket", socket, "--registry-root", root},
{"serve", "--registry-root", root, "--socket", socket, "--unknown", "x"},
@@ -319,6 +332,18 @@ func TestServeAcceptsOnlyExactTaskFourReservation(t *testing.T) {
}
}
func TestServeSanitizesServiceStartupFailure(t *testing.T) {
root := t.TempDir()
socket := filepath.Join(t.TempDir(), "verify.sock")
oldListen := listenAndServe
t.Cleanup(func() { listenAndServe = oldListen })
listenAndServe = func(context.Context, service.Config) error { return errors.New(sentinelSecret) }
stdout, stderr, code := run(t, "serve", "--registry-root", root, "--socket", socket)
if code != 4 || stdout != "" || stderr != "integrity failure\n" || strings.Contains(stdout+stderr, sentinelSecret) {
t.Fatalf("service startup failure = (%d, %q, %q)", code, stdout, stderr)
}
}
func TestCreateCleansOnlyWhenFailedPublicationProvesKeyAbsent(t *testing.T) {
oldAdd, oldClose := addRecord, closeStore
t.Cleanup(func() { addRecord, closeStore = oldAdd, oldClose })