Implement KeyCape provider and service identity contracts
All checks were successful
Build and Publish Container Image / build-and-push (push) Successful in 25s

Assistant: codex
Assistant-Model: gpt-5.6-sol
Assistant-Session: 01a02e3f-7301-7622-9be1-12e5f352881c
This commit is contained in:
tegwick 2026-08-23 13:10:13 +02:00
parent cdfb046b80
commit efce3e9331
15 changed files with 579 additions and 26 deletions

View file

@ -337,6 +337,78 @@ func TestValidate_MissingPrivateKeyPEM(t *testing.T) {
}
}
func TestValidate_ClientCredentialsTokenLifetime(t *testing.T) {
keyPath := writeTempFile(t, "key")
cfg := validConfig(keyPath)
cfg.Clients[0] = config.ClientConfig{
ClientID: "service-client",
ClientType: "confidential",
GrantTypes: []string{"client_credentials"},
AllowedScopes: []string{"openbao:login"},
SecretRef: "env:SERVICE_CLIENT_SECRET",
ServiceSubject: "service:test",
Tenant: "tenant:coulomb",
TokenLifetime: "15m",
}
if errs := config.ValidateConfig(cfg); len(errs) != 0 {
t.Fatalf("valid per-client token lifetime rejected: %v", errs)
}
cfg.Clients[0].TokenLifetime = "90m"
if errs := config.ValidateConfig(cfg); !containsErr(errs, "between 1m and 1h") {
t.Fatalf("expected bounded tokenLifetime error, got %v", errs)
}
cfg.Clients[0].TokenLifetime = "not-a-duration"
if errs := config.ValidateConfig(cfg); !containsErr(errs, "valid duration") {
t.Fatalf("expected invalid tokenLifetime error, got %v", errs)
}
}
func TestValidate_PublicClientRejectsTokenLifetime(t *testing.T) {
keyPath := writeTempFile(t, "key")
cfg := validConfig(keyPath)
cfg.Clients[0].TokenLifetime = "15m"
if errs := config.ValidateConfig(cfg); !containsErr(errs, "only supported for client_credentials") {
t.Fatalf("expected public-client tokenLifetime error, got %v", errs)
}
}
func TestServiceClientExampleContracts(t *testing.T) {
cfg, err := config.Load(filepath.Join("..", "..", "..", "config", "service-clients.example.yaml"))
if err != nil {
t.Fatalf("load service client examples: %v", err)
}
cfg.Issuer = "https://kc.coulomb.social"
cfg.Port = 8080
cfg.PrivateKeyPEM = writeTempFile(t, "key")
if errs := config.ValidateConfig(cfg); len(errs) != 0 {
t.Fatalf("service client examples must validate: %v", errs)
}
if len(cfg.Clients) != 2 {
t.Fatalf("service client examples: want 2, got %d", len(cfg.Clients))
}
codingAgent := cfg.Clients[0]
if codingAgent.ClientID != "codex-railiance-platform" ||
codingAgent.ServiceSubject != "service:codex:railiance-platform" ||
codingAgent.Tenant != "tenant:coulomb" ||
codingAgent.TokenLifetime != "15m" {
t.Fatalf("coding-agent contract drifted: %+v", codingAgent)
}
if len(codingAgent.Roles) != 1 || codingAgent.Roles[0] != "coding-agent" ||
len(codingAgent.AllowedScopes) != 1 || codingAgent.AllowedScopes[0] != "openbao:login" {
t.Fatalf("coding-agent authorization contract drifted: %+v", codingAgent)
}
secretsEngine := cfg.Clients[1]
if secretsEngine.ClientID != "secrets-engine-openbao" ||
secretsEngine.ServiceSubject != "service:secrets-engine" ||
secretsEngine.TokenLifetime != "15m" {
t.Fatalf("secrets-engine contract drifted: %+v", secretsEngine)
}
}
// ---------------------------------------------------------------------------
// Env var loading test
// ---------------------------------------------------------------------------