Files

58 lines
1.9 KiB
Go
Raw Permalink Normal View History

package policy
import (
"errors"
"fmt"
"strings"
)
var (
// ErrPolicyEvalFailed marks failures that must be treated as fail-closed
// policy evaluation outcomes.
ErrPolicyEvalFailed = errors.New("policy eval failed")
// ErrPolicyEvalTimeout marks evaluations that exceeded the eval budget. It
// always accompanies ErrPolicyEvalFailed (fail-closed consumers keep
// working unchanged) but lets operators and the activation guard tell a
// slow policy apart from a broken one.
ErrPolicyEvalTimeout = errors.New("policy eval timed out")
// ErrPolicySlowEval marks a policy source rejected by the activation-time
// cost guard: evaluating it exceeded the configured eval budget, so
// activating it would convert to request-path failures for every viewer.
ErrPolicySlowEval = errors.New("policy evaluation exceeds the eval budget")
// ErrUnknownDecision marks requests for a decision that is not loaded.
ErrUnknownDecision = errors.New("unknown policy decision")
// ErrCompileFailed marks policy compilation failures with structured issues.
ErrCompileFailed = errors.New("policy compile failed")
)
// CompileIssue identifies one policy compiler diagnostic.
type CompileIssue struct {
Row int `json:"row"`
Col int `json:"col"`
Message string `json:"message"`
}
// CompileError carries structured policy compiler diagnostics.
type CompileError struct {
Issues []CompileIssue `json:"errors"`
}
func (e *CompileError) Error() string {
if e == nil || len(e.Issues) == 0 {
return ErrCompileFailed.Error()
}
messages := make([]string, 0, len(e.Issues))
for _, issue := range e.Issues {
if issue.Row > 0 || issue.Col > 0 {
messages = append(messages, fmt.Sprintf("%d:%d: %s", issue.Row, issue.Col, issue.Message))
continue
}
messages = append(messages, issue.Message)
}
return fmt.Sprintf("%s: %s", ErrCompileFailed, strings.Join(messages, "; "))
}
func (e *CompileError) Is(target error) bool {
return target == ErrCompileFailed
}