generated from coulomb/repo-seed
feat: implement T01-T04 — Go module, canonical model, LDAP validator, error taxonomy
- T01: Go module (keycape), full directory skeleton, Makefile, CI workflow - T02: spec/canonical-model.yaml with 6 entities + Go domain types - T03: spec/ldap-schema.yaml + validator binary with structural/semantic rules - T04: Error taxonomy — 4 stable error types, JSON format, HTTP helpers 28 tests pass, go vet clean, go build clean. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
85
src/internal/errors/taxonomy.go
Normal file
85
src/internal/errors/taxonomy.go
Normal file
@@ -0,0 +1,85 @@
|
||||
// Package errors implements the KeyCape error taxonomy from spec §5.
|
||||
// All profile errors are structured and machine-readable.
|
||||
// Errors MUST NOT be silent — every unsupported or misused feature returns a typed error.
|
||||
package errors
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// ErrorType is a stable string identifier for profile error categories.
|
||||
type ErrorType string
|
||||
|
||||
const (
|
||||
// ErrFeatureNotSupported is returned when a feature is outside the NetKingdom IAM Profile.
|
||||
ErrFeatureNotSupported ErrorType = "feature_not_supported_by_profile"
|
||||
|
||||
// ErrKeycloakModeOnly is returned when a feature exists only in expanded (Keycloak) mode.
|
||||
ErrKeycloakModeOnly ErrorType = "available_in_keycloak_mode_only"
|
||||
|
||||
// ErrRejectedForSafety is returned when a feature is intentionally blocked for security reasons.
|
||||
ErrRejectedForSafety ErrorType = "rejected_for_profile_safety"
|
||||
|
||||
// ErrInvalidProfileUsage is returned when a supported endpoint/feature is used incorrectly.
|
||||
ErrInvalidProfileUsage ErrorType = "invalid_profile_usage"
|
||||
)
|
||||
|
||||
// ProfileError is a structured error per spec §5.2.
|
||||
// JSON format: {"error": "...", "description": "...", "feature": "..."}
|
||||
type ProfileError struct {
|
||||
Error ErrorType `json:"error"`
|
||||
Description string `json:"description"`
|
||||
Feature string `json:"feature,omitempty"`
|
||||
}
|
||||
|
||||
// Write writes the error as JSON with the given HTTP status code.
|
||||
func (e *ProfileError) Write(w http.ResponseWriter, status int) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(status)
|
||||
_ = json.NewEncoder(w).Encode(e)
|
||||
}
|
||||
|
||||
// GoError implements the standard error interface.
|
||||
func (e *ProfileError) GoError() string {
|
||||
if e.Feature != "" {
|
||||
return string(e.Error) + ": " + e.Description + " [feature=" + e.Feature + "]"
|
||||
}
|
||||
return string(e.Error) + ": " + e.Description
|
||||
}
|
||||
|
||||
// FeatureNotSupported constructs a feature_not_supported_by_profile error.
|
||||
func FeatureNotSupported(description, feature string) *ProfileError {
|
||||
return &ProfileError{
|
||||
Error: ErrFeatureNotSupported,
|
||||
Description: description,
|
||||
Feature: feature,
|
||||
}
|
||||
}
|
||||
|
||||
// KeycloakModeOnly constructs an available_in_keycloak_mode_only error.
|
||||
func KeycloakModeOnly(description, feature string) *ProfileError {
|
||||
return &ProfileError{
|
||||
Error: ErrKeycloakModeOnly,
|
||||
Description: description,
|
||||
Feature: feature,
|
||||
}
|
||||
}
|
||||
|
||||
// RejectedForSafety constructs a rejected_for_profile_safety error.
|
||||
func RejectedForSafety(description, feature string) *ProfileError {
|
||||
return &ProfileError{
|
||||
Error: ErrRejectedForSafety,
|
||||
Description: description,
|
||||
Feature: feature,
|
||||
}
|
||||
}
|
||||
|
||||
// InvalidProfileUsage constructs an invalid_profile_usage error.
|
||||
func InvalidProfileUsage(description, feature string) *ProfileError {
|
||||
return &ProfileError{
|
||||
Error: ErrInvalidProfileUsage,
|
||||
Description: description,
|
||||
Feature: feature,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user