P1.2-P1.5: Complete Phase 1 core libraries
Four packages built in parallel: - P1.2 runtime: Container runtime abstraction with podman implementation. Interface (Pull/Run/Stop/Remove/Inspect/List), ContainerSpec/ContainerInfo types, CLI arg building, version extraction from image tags. 2 tests. - P1.3 servicedef: TOML service definition file parsing. Load/Write/LoadAll, validation (required fields, unique component names), proto conversion. 5 tests. - P1.4 config: CLI and agent config loading from TOML. Duration type for time fields, env var overrides (MCP_*/MCP_AGENT_*), required field validation, sensible defaults. 7 tests. - P1.5 auth: MCIAS integration. Token validator with 30s SHA-256 cache, gRPC unary interceptor (admin role enforcement, audit logging), Login/LoadToken/SaveToken for CLI. 9 tests. All packages pass build, vet, lint, and test. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
97
internal/config/cli.go
Normal file
97
internal/config/cli.go
Normal file
@@ -0,0 +1,97 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
toml "github.com/pelletier/go-toml/v2"
|
||||
)
|
||||
|
||||
// CLIConfig is the configuration for the mcp CLI binary.
|
||||
type CLIConfig struct {
|
||||
Services ServicesConfig `toml:"services"`
|
||||
MCIAS MCIASConfig `toml:"mcias"`
|
||||
Auth AuthConfig `toml:"auth"`
|
||||
Nodes []NodeConfig `toml:"nodes"`
|
||||
}
|
||||
|
||||
// ServicesConfig defines where service definition files live.
|
||||
type ServicesConfig struct {
|
||||
Dir string `toml:"dir"`
|
||||
}
|
||||
|
||||
// MCIASConfig holds MCIAS connection settings, shared by CLI and agent.
|
||||
type MCIASConfig struct {
|
||||
ServerURL string `toml:"server_url"`
|
||||
CACert string `toml:"ca_cert"`
|
||||
ServiceName string `toml:"service_name"`
|
||||
}
|
||||
|
||||
// AuthConfig holds authentication settings for the CLI.
|
||||
type AuthConfig struct {
|
||||
TokenPath string `toml:"token_path"`
|
||||
Username string `toml:"username"` // optional, for unattended operation
|
||||
PasswordFile string `toml:"password_file"` // optional, for unattended operation
|
||||
}
|
||||
|
||||
// NodeConfig defines a managed node that the CLI connects to.
|
||||
type NodeConfig struct {
|
||||
Name string `toml:"name"`
|
||||
Address string `toml:"address"`
|
||||
}
|
||||
|
||||
// LoadCLIConfig reads and validates a CLI configuration file.
|
||||
// Environment variables override file values for select fields.
|
||||
func LoadCLIConfig(path string) (*CLIConfig, error) {
|
||||
data, err := os.ReadFile(path) //nolint:gosec // config path from trusted CLI flag
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read config %q: %w", path, err)
|
||||
}
|
||||
|
||||
var cfg CLIConfig
|
||||
if err := toml.Unmarshal(data, &cfg); err != nil {
|
||||
return nil, fmt.Errorf("parse config %q: %w", path, err)
|
||||
}
|
||||
|
||||
applyCLIEnvOverrides(&cfg)
|
||||
|
||||
if err := validateCLIConfig(&cfg); err != nil {
|
||||
return nil, fmt.Errorf("validate config: %w", err)
|
||||
}
|
||||
|
||||
return &cfg, nil
|
||||
}
|
||||
|
||||
func applyCLIEnvOverrides(cfg *CLIConfig) {
|
||||
if v := os.Getenv("MCP_SERVICES_DIR"); v != "" {
|
||||
cfg.Services.Dir = v
|
||||
}
|
||||
if v := os.Getenv("MCP_MCIAS_SERVER_URL"); v != "" {
|
||||
cfg.MCIAS.ServerURL = v
|
||||
}
|
||||
if v := os.Getenv("MCP_MCIAS_CA_CERT"); v != "" {
|
||||
cfg.MCIAS.CACert = v
|
||||
}
|
||||
if v := os.Getenv("MCP_MCIAS_SERVICE_NAME"); v != "" {
|
||||
cfg.MCIAS.ServiceName = v
|
||||
}
|
||||
if v := os.Getenv("MCP_AUTH_TOKEN_PATH"); v != "" {
|
||||
cfg.Auth.TokenPath = v
|
||||
}
|
||||
}
|
||||
|
||||
func validateCLIConfig(cfg *CLIConfig) error {
|
||||
if cfg.Services.Dir == "" {
|
||||
return fmt.Errorf("services.dir is required")
|
||||
}
|
||||
if cfg.MCIAS.ServerURL == "" {
|
||||
return fmt.Errorf("mcias.server_url is required")
|
||||
}
|
||||
if cfg.MCIAS.ServiceName == "" {
|
||||
return fmt.Errorf("mcias.service_name is required")
|
||||
}
|
||||
if cfg.Auth.TokenPath == "" {
|
||||
return fmt.Errorf("auth.token_path is required")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user