Claude Config API (v0.6): - Add CRUD endpoints for commands, skills, and agents - Commands/skills/agents stored in /workspace/.claude/ (per-project, in git) - Credentials shared via PVC at /root/.claude/ (shared across pods) - Use base64 encoding for file writes (prevents shell injection) - Add content size limits (1MB max) Security Hardening: - Add sanitize package for command/prompt validation - Add rate limiting middleware (token bucket algorithm) - Add concurrent command limiting - Add input sanitization to all command handlers - Gitignore secrets.yaml and credentials.yaml - Add *.example templates for secrets Testing Infrastructure: - Add testutil package with mocks and fixtures - Add unit tests for auth package (63% coverage) - Add unit tests for executor (47% coverage) - Add handler integration tests (40% coverage) - Add 100% coverage for sanitize, cmdlimit packages - Add 96% coverage for ratelimit package Infrastructure: - Shared Claude credentials PVC (ReadWriteMany) - Reduced workspace PVC size from 20Gi to 5Gi - Add init container cleanup before git clone - Document Longhorn RWX requirements Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
84 lines
2.0 KiB
Go
84 lines
2.0 KiB
Go
package domain
|
|
|
|
import "time"
|
|
|
|
// APIKeyID is a strongly-typed identifier for API keys.
|
|
type APIKeyID string
|
|
|
|
// Scope represents a permission scope for API keys.
|
|
type Scope string
|
|
|
|
const (
|
|
ScopeAdmin Scope = "admin"
|
|
ScopeProjectsRead Scope = "projects:read"
|
|
ScopeProjectsExecute Scope = "projects:execute"
|
|
ScopeKeysManage Scope = "keys:manage"
|
|
)
|
|
|
|
// APIKey represents an API key for authentication.
|
|
type APIKey struct {
|
|
ID APIKeyID
|
|
Name string
|
|
KeyPrefix string // First 8 chars of key for identification
|
|
Scopes []Scope
|
|
ProjectIDs []ProjectID // nil = access to all projects
|
|
CreatedAt time.Time
|
|
ExpiresAt *time.Time
|
|
LastUsedAt *time.Time
|
|
RevokedAt *time.Time
|
|
CreatedBy string
|
|
}
|
|
|
|
// IsExpired returns true if the key has expired.
|
|
func (k *APIKey) IsExpired() bool {
|
|
if k.ExpiresAt == nil {
|
|
return false
|
|
}
|
|
return time.Now().After(*k.ExpiresAt)
|
|
}
|
|
|
|
// IsRevoked returns true if the key has been revoked.
|
|
func (k *APIKey) IsRevoked() bool {
|
|
return k.RevokedAt != nil
|
|
}
|
|
|
|
// IsActive returns true if the key is valid for use.
|
|
func (k *APIKey) IsActive() bool {
|
|
return !k.IsRevoked() && !k.IsExpired()
|
|
}
|
|
|
|
// HasScope returns true if the key has the specified scope.
|
|
func (k *APIKey) HasScope(scope Scope) bool {
|
|
// Admin scope grants all permissions
|
|
for _, s := range k.Scopes {
|
|
if s == ScopeAdmin || s == scope {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// HasAnyScope returns true if the key has any of the specified scopes.
|
|
func (k *APIKey) HasAnyScope(scopes ...Scope) bool {
|
|
for _, scope := range scopes {
|
|
if k.HasScope(scope) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// HasProjectAccess returns true if the key can access the given project.
|
|
func (k *APIKey) HasProjectAccess(projectID ProjectID) bool {
|
|
// Admin or nil project list means access to all projects
|
|
if k.HasScope(ScopeAdmin) || k.ProjectIDs == nil {
|
|
return true
|
|
}
|
|
for _, pid := range k.ProjectIDs {
|
|
if pid == projectID {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|