Implement Phase 1: core framework, operational tooling, and runbook

Core packages: crypto (Argon2id/AES-256-GCM), config (TOML/viper),
db (SQLite/migrations), barrier (encrypted storage), seal (state machine
with rate-limited unseal), auth (MCIAS integration with token cache),
policy (priority-based ACL engine), engine (interface + registry).

Server: HTTPS with TLS 1.2+, REST API, auth/admin middleware, htmx web UI
(init, unseal, login, dashboard pages).

CLI: cobra/viper subcommands (server, init, status, snapshot) with env
var override support (METACRYPT_ prefix).

Operational tooling: Dockerfile (multi-stage, non-root), docker-compose,
hardened systemd units (service + daily backup timer), install script,
backup script with retention pruning, production config examples.

Runbook covering installation, configuration, daily operations,
backup/restore, monitoring, troubleshooting, and security procedures.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-14 20:43:11 -07:00
commit 4ddd32b117
60 changed files with 4644 additions and 0 deletions

93
cmd/metacrypt/init.go Normal file
View File

@@ -0,0 +1,93 @@
package main
import (
"context"
"fmt"
"syscall"
"github.com/spf13/cobra"
"golang.org/x/term"
"git.wntrmute.dev/kyle/metacrypt/internal/barrier"
"git.wntrmute.dev/kyle/metacrypt/internal/config"
"git.wntrmute.dev/kyle/metacrypt/internal/crypto"
"git.wntrmute.dev/kyle/metacrypt/internal/db"
"git.wntrmute.dev/kyle/metacrypt/internal/seal"
)
var initCmd = &cobra.Command{
Use: "init",
Short: "Interactive first-time setup",
Long: "Initialize Metacrypt with a seal password. This must be run before the server can be used.",
RunE: runInit,
}
func init() {
rootCmd.AddCommand(initCmd)
}
func runInit(cmd *cobra.Command, args []string) error {
configPath := cfgFile
if configPath == "" {
configPath = "metacrypt.toml"
}
cfg, err := config.Load(configPath)
if err != nil {
return err
}
database, err := db.Open(cfg.Database.Path)
if err != nil {
return err
}
defer database.Close()
if err := db.Migrate(database); err != nil {
return err
}
b := barrier.NewAESGCMBarrier(database)
sealMgr := seal.NewManager(database, b)
if err := sealMgr.CheckInitialized(); err != nil {
return err
}
if sealMgr.State() != seal.StateUninitialized {
return fmt.Errorf("already initialized")
}
fmt.Print("Enter seal password: ")
pw1, err := term.ReadPassword(int(syscall.Stdin))
fmt.Println()
if err != nil {
return fmt.Errorf("reading password: %w", err)
}
fmt.Print("Confirm seal password: ")
pw2, err := term.ReadPassword(int(syscall.Stdin))
fmt.Println()
if err != nil {
return fmt.Errorf("reading password: %w", err)
}
if !crypto.ConstantTimeEqual(pw1, pw2) {
return fmt.Errorf("passwords do not match")
}
params := crypto.Argon2Params{
Time: cfg.Seal.Argon2Time,
Memory: cfg.Seal.Argon2Memory,
Threads: cfg.Seal.Argon2Threads,
}
fmt.Println("Initializing (this may take a moment)...")
if err := sealMgr.Initialize(context.Background(), pw1, params); err != nil {
return err
}
crypto.Zeroize(pw1)
crypto.Zeroize(pw2)
fmt.Println("Metacrypt initialized and unsealed successfully.")
return nil
}

14
cmd/metacrypt/main.go Normal file
View File

@@ -0,0 +1,14 @@
// Metacrypt is a cryptographic service for the Metacircular platform.
package main
import (
"fmt"
"os"
)
func main() {
if err := rootCmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}

33
cmd/metacrypt/root.go Normal file
View File

@@ -0,0 +1,33 @@
package main
import (
"github.com/spf13/cobra"
"github.com/spf13/viper"
)
var cfgFile string
var rootCmd = &cobra.Command{
Use: "metacrypt",
Short: "Metacrypt cryptographic service",
Long: "Metacrypt is a cryptographic service for the Metacircular platform.",
}
func init() {
cobra.OnInitialize(initConfig)
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default metacrypt.toml)")
}
func initConfig() {
if cfgFile != "" {
viper.SetConfigFile(cfgFile)
} else {
viper.SetConfigName("metacrypt")
viper.SetConfigType("toml")
viper.AddConfigPath(".")
viper.AddConfigPath("/etc/metacrypt")
}
viper.AutomaticEnv()
viper.SetEnvPrefix("METACRYPT")
viper.ReadInConfig()
}

90
cmd/metacrypt/server.go Normal file
View File

@@ -0,0 +1,90 @@
package main
import (
"context"
"log/slog"
"os"
"os/signal"
"syscall"
mcias "git.wntrmute.dev/kyle/mcias/clients/go"
"github.com/spf13/cobra"
"git.wntrmute.dev/kyle/metacrypt/internal/auth"
"git.wntrmute.dev/kyle/metacrypt/internal/barrier"
"git.wntrmute.dev/kyle/metacrypt/internal/config"
"git.wntrmute.dev/kyle/metacrypt/internal/db"
"git.wntrmute.dev/kyle/metacrypt/internal/engine"
"git.wntrmute.dev/kyle/metacrypt/internal/policy"
"git.wntrmute.dev/kyle/metacrypt/internal/seal"
"git.wntrmute.dev/kyle/metacrypt/internal/server"
)
var serverCmd = &cobra.Command{
Use: "server",
Short: "Start the Metacrypt server",
Long: "Start the Metacrypt HTTPS server. The service starts in sealed state.",
RunE: runServer,
}
func init() {
rootCmd.AddCommand(serverCmd)
}
func runServer(cmd *cobra.Command, args []string) error {
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
configPath := cfgFile
if configPath == "" {
configPath = "metacrypt.toml"
}
cfg, err := config.Load(configPath)
if err != nil {
return err
}
database, err := db.Open(cfg.Database.Path)
if err != nil {
return err
}
defer database.Close()
if err := db.Migrate(database); err != nil {
return err
}
b := barrier.NewAESGCMBarrier(database)
sealMgr := seal.NewManager(database, b)
if err := sealMgr.CheckInitialized(); err != nil {
return err
}
mcClient, err := mcias.New(cfg.MCIAS.ServerURL, mcias.Options{
CACertPath: cfg.MCIAS.CACert,
})
if err != nil {
return err
}
authenticator := auth.NewAuthenticator(mcClient)
policyEngine := policy.NewEngine(b)
engineRegistry := engine.NewRegistry(b)
srv := server.New(cfg, sealMgr, authenticator, policyEngine, engineRegistry, logger)
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
defer stop()
go func() {
if err := srv.Start(); err != nil {
logger.Error("server error", "error", err)
os.Exit(1)
}
}()
<-ctx.Done()
logger.Info("shutting down")
return srv.Shutdown(context.Background())
}

58
cmd/metacrypt/snapshot.go Normal file
View File

@@ -0,0 +1,58 @@
package main
import (
"database/sql"
"fmt"
"os"
"github.com/spf13/cobra"
"git.wntrmute.dev/kyle/metacrypt/internal/config"
"git.wntrmute.dev/kyle/metacrypt/internal/db"
)
var snapshotCmd = &cobra.Command{
Use: "snapshot",
Short: "Create a database snapshot",
Long: "Create a backup of the Metacrypt database using SQLite's VACUUM INTO.",
RunE: runSnapshot,
}
var snapshotOutput string
func init() {
snapshotCmd.Flags().StringVarP(&snapshotOutput, "output", "o", "backup.db", "output file path")
rootCmd.AddCommand(snapshotCmd)
}
func runSnapshot(cmd *cobra.Command, args []string) error {
configPath := cfgFile
if configPath == "" {
configPath = "metacrypt.toml"
}
cfg, err := config.Load(configPath)
if err != nil {
return err
}
database, err := db.Open(cfg.Database.Path)
if err != nil {
return err
}
defer database.Close()
if err := sqliteBackup(database, snapshotOutput); err != nil {
return err
}
fmt.Printf("Snapshot saved to %s\n", snapshotOutput)
return nil
}
func sqliteBackup(srcDB *sql.DB, dstPath string) error {
_, err := srcDB.Exec("VACUUM INTO ?", dstPath)
if err != nil {
return fmt.Errorf("snapshot: %w", err)
}
return os.Chmod(dstPath, 0600)
}

66
cmd/metacrypt/status.go Normal file
View File

@@ -0,0 +1,66 @@
package main
import (
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"net/http"
"os"
"github.com/spf13/cobra"
)
var statusCmd = &cobra.Command{
Use: "status",
Short: "Check service seal state",
Long: "Query a running Metacrypt server for its current seal state.",
RunE: runStatus,
}
var (
statusAddr string
statusCACert string
)
func init() {
statusCmd.Flags().StringVar(&statusAddr, "addr", "", "server address (e.g., https://localhost:8443)")
statusCmd.Flags().StringVar(&statusCACert, "ca-cert", "", "path to CA certificate for TLS verification")
statusCmd.MarkFlagRequired("addr")
rootCmd.AddCommand(statusCmd)
}
func runStatus(cmd *cobra.Command, args []string) error {
tlsCfg := &tls.Config{MinVersion: tls.VersionTLS12}
if statusCACert != "" {
pem, err := os.ReadFile(statusCACert)
if err != nil {
return fmt.Errorf("read CA cert: %w", err)
}
pool := x509.NewCertPool()
if !pool.AppendCertsFromPEM(pem) {
return fmt.Errorf("no valid certs in CA file")
}
tlsCfg.RootCAs = pool
}
client := &http.Client{
Transport: &http.Transport{TLSClientConfig: tlsCfg},
}
resp, err := client.Get(statusAddr + "/v1/status")
if err != nil {
return err
}
defer resp.Body.Close()
var status struct {
State string `json:"state"`
}
if err := json.NewDecoder(resp.Body).Decode(&status); err != nil {
return fmt.Errorf("decode response: %w", err)
}
fmt.Printf("State: %s\n", status.State)
return nil
}