use miette::Diagnostic;
use smol_str::SmolStr;
use thiserror::Error;
use crate::{
ast::{Eid, EntityType, EntityUID, PartialValueToValueError},
entities::{conformance::err::EntitySchemaConformanceError, err::Duplicate},
evaluator::{evaluation_errors::UnlinkedSlotError, EvaluationError},
transitive_closure::TcError,
validator::{RequestValidationError, ValidationError},
};
#[derive(Debug, Error, Diagnostic)]
#[error("Unexpected action: `{}`", .action)]
pub struct UnexpectedActionError {
pub(super) action: EntityUID,
}
#[derive(Debug, Error, Diagnostic)]
pub enum JsonDeserializationError {
#[error(transparent)]
#[diagnostic(transparent)]
Concrete(#[from] crate::entities::json::err::JsonDeserializationError),
#[error(transparent)]
#[diagnostic(transparent)]
UnexpectedAction(#[from] UnexpectedActionError),
#[error(transparent)]
#[diagnostic(transparent)]
RestrictedExprEvaluation(#[from] EvaluationError),
}
#[derive(Debug, Error, Diagnostic)]
pub enum EntityValidationError {
#[error(transparent)]
#[diagnostic(transparent)]
Concrete(#[from] EntitySchemaConformanceError),
#[error(transparent)]
#[diagnostic(transparent)]
UnknownActionComponent(#[from] UnknownActionComponentError),
#[error(transparent)]
#[diagnostic(transparent)]
MismatchedActionAncestors(#[from] MismatchedActionAncestorsError),
}
#[derive(Debug, Error, Diagnostic)]
#[error("action `{}` has unknown ancestors/attrs/tags", .action)]
pub struct UnknownActionComponentError {
pub(super) action: EntityUID,
}
#[derive(Debug, Error, Diagnostic)]
#[error("action `{}`'s ancestors do not match the schema", .action)]
pub struct MismatchedActionAncestorsError {
pub(super) action: EntityUID,
}
#[derive(Debug, Error, Diagnostic)]
#[error("ancestor `{ancestor}` of `{uid}` has unknown ancestors")]
#[diagnostic(help(
"an entity with known ancestors cannot have an ancestor whose own ancestors are unknown"
))]
pub struct AncestorValidationError {
pub(crate) uid: EntityUID,
pub(crate) ancestor: EntityUID,
}
#[derive(Debug, Error, Diagnostic)]
pub enum TpeError {
#[error(transparent)]
#[diagnostic(transparent)]
NoMatchingReqEnv(#[from] NoMatchingReqEnvError),
#[error(transparent)]
#[diagnostic(transparent)]
Validation(#[from] PolicyValidationError),
#[error(transparent)]
#[diagnostic(transparent)]
ExprToResidualError(#[from] ExprToResidualError),
}
#[derive(Debug, Error, Diagnostic)]
#[error("policy failed to validate against the schema")]
pub struct PolicyValidationError {
#[related]
pub(super) errors: Vec<ValidationError>,
}
impl PolicyValidationError {
pub(crate) fn new(errors: Vec<ValidationError>) -> Self {
Self { errors }
}
pub fn errors(&self) -> impl Iterator<Item = &ValidationError> {
self.errors.iter()
}
}
#[derive(Debug, Error, Diagnostic)]
#[non_exhaustive]
pub enum ExprToResidualError {
#[error(transparent)]
#[diagnostic(transparent)]
MissingTypeAnnotation(#[from] MissingTypeAnnotationError),
#[error(transparent)]
#[diagnostic(transparent)]
UnlinkedSlotError(#[from] UnlinkedSlotError),
#[error(transparent)]
#[diagnostic(transparent)]
UnknownNotSupported(#[from] UnknownNotSupportedError),
#[error(transparent)]
#[diagnostic(transparent)]
ErrorNotSupported(#[from] ErrorNotSupportedError),
}
#[derive(Debug, Error, Diagnostic)]
#[error("expression is missing a type annotation")]
#[diagnostic(help(
"expressions must be typechecked by the policy validator before partial evaluation"
))]
pub struct MissingTypeAnnotationError;
#[derive(Debug, Error, Diagnostic)]
#[error("expression contains an unknown, which is not supported in residuals")]
pub struct UnknownNotSupportedError;
#[derive(Debug, Error, Diagnostic)]
#[error("expression contains an error node, which is not supported in residuals")]
pub struct ErrorNotSupportedError;
#[derive(Debug, Error, Diagnostic)]
#[error("expected a concrete request, but found a partial request")]
pub struct PartialRequestError {}
#[derive(Debug, Error, Diagnostic)]
#[error("no request environment in the schema matches the given request")]
pub struct NoMatchingReqEnvError;
#[derive(Debug, Error, Diagnostic)]
pub enum RequestBuilderError {
#[error(transparent)]
#[diagnostic(transparent)]
Validation(#[from] RequestValidationError),
#[error(transparent)]
#[diagnostic(transparent)]
ExistingPrincipal(#[from] ExistingPrincipalError),
#[error(transparent)]
#[diagnostic(transparent)]
ExistingResource(#[from] ExistingResourceError),
#[error("a context has already been set on this request")]
ExistingContext,
#[error(transparent)]
#[diagnostic(transparent)]
IncorrectPrincipalEntityType(#[from] IncorrectPrincipalEntityTypeError),
#[error(transparent)]
#[diagnostic(transparent)]
IncorrectResourceEntityType(#[from] IncorrectResourceEntityTypeError),
#[error("context candidate contains unknowns")]
UnknownContextCandidate,
}
#[derive(Debug, Error, Diagnostic)]
#[error("a principal (`{principal}`) has already been set on this request")]
pub struct ExistingPrincipalError {
pub(super) principal: EntityUID,
}
#[derive(Debug, Error, Diagnostic)]
#[error("a resource (`{resource}`) has already been set on this request")]
pub struct ExistingResourceError {
pub(super) resource: EntityUID,
}
#[derive(Debug, Error, Diagnostic)]
#[error("principal type `{ty}` does not match the partial request's principal type `{expected}`")]
pub struct IncorrectPrincipalEntityTypeError {
pub(super) ty: EntityType,
pub(super) expected: EntityType,
}
#[derive(Debug, Error, Diagnostic)]
#[error("resource type `{ty}` does not match the partial request's resource type `{expected}`")]
pub struct IncorrectResourceEntityTypeError {
pub(super) ty: EntityType,
pub(super) expected: EntityType,
}
#[derive(Debug, Error, Diagnostic)]
pub enum EntitiesError {
#[error(transparent)]
#[diagnostic(transparent)]
Deserialization(#[from] JsonDeserializationError),
#[error(transparent)]
#[diagnostic(transparent)]
Validation(#[from] EntityValidationError),
#[error(transparent)]
#[diagnostic(transparent)]
AncestorValidation(#[from] AncestorValidationError),
#[error(transparent)]
#[diagnostic(transparent)]
TCComputation(#[from] TcError<EntityUID>),
#[error(transparent)]
#[diagnostic(transparent)]
Duplicate(#[from] Duplicate),
#[error(transparent)]
#[diagnostic(transparent)]
PartialValueToValue(#[from] PartialValueToValueError),
}
#[derive(Debug, Error, Diagnostic)]
pub enum EntitiesConsistencyError {
#[error(transparent)]
#[diagnostic(transparent)]
MissingEntity(#[from] MissingEntityError),
#[error(transparent)]
#[diagnostic(transparent)]
UnknownEntity(#[from] UnknownEntityError),
#[error(transparent)]
#[diagnostic(transparent)]
InconsistentEntity(#[from] EntityConsistencyError),
}
#[derive(Debug, Error, Diagnostic)]
pub enum EntityConsistencyError {
#[error(transparent)]
#[diagnostic(transparent)]
UnknownAttribute(#[from] UnknownAttributeError),
#[error(transparent)]
#[diagnostic(transparent)]
MismatchedAttribute(#[from] MismatchedAttributeError),
#[error(transparent)]
#[diagnostic(transparent)]
MismatchedAncestor(#[from] MismatchedAncestorError),
#[error(transparent)]
#[diagnostic(transparent)]
UnknownTag(#[from] UnknownTagError),
#[error(transparent)]
#[diagnostic(transparent)]
MismatchedTag(#[from] MismatchedTagError),
}
#[derive(Debug, Error, Diagnostic)]
#[error("concrete entity `{uid}` has attribute `{attr}` not present in the partial entity")]
pub struct UnknownAttributeError {
pub(super) uid: EntityUID,
pub(super) attr: SmolStr,
}
#[derive(Debug, Error, Diagnostic)]
#[error("concrete entity `{uid}` has attribute values that do not match the partial entity")]
pub struct MismatchedAttributeError {
pub(super) uid: EntityUID,
}
#[derive(Debug, Error, Diagnostic)]
#[error("concrete entity `{uid}` has tag `{tag}` not present in the partial entity")]
pub struct UnknownTagError {
pub(super) uid: EntityUID,
pub(super) tag: SmolStr,
}
#[derive(Debug, Error, Diagnostic)]
#[error("concrete entity `{uid}` has tag values that do not match the partial entity")]
pub struct MismatchedTagError {
pub(super) uid: EntityUID,
}
#[derive(Debug, Error, Diagnostic)]
#[error("concrete entity `{uid}` has ancestors that do not match the partial entity")]
pub struct MismatchedAncestorError {
pub(super) uid: EntityUID,
}
#[derive(Debug, Error, Diagnostic)]
#[error("entity `{uid}` is present in the partial entities but missing from the concrete entities")]
pub struct MissingEntityError {
pub(super) uid: EntityUID,
}
#[derive(Debug, Error, Diagnostic)]
#[error("concrete entities contain unknown entity `{uid}`")]
pub struct UnknownEntityError {
pub(super) uid: EntityUID,
}
#[derive(Debug, Error, Diagnostic)]
#[error("failed to load entities: {}", .missing_entities.iter().map(|uid| uid.to_string()).collect::<Vec<_>>().join(", "))]
pub struct MissingEntitiesError {
pub(super) missing_entities: Vec<EntityUID>,
}
impl MissingEntitiesError {
pub fn new(missing_entities: Vec<EntityUID>) -> Self {
Self { missing_entities }
}
}
#[derive(Debug, Error, Diagnostic)]
pub enum RequestConsistencyError {
#[error("the concrete request's principal is unknown")]
UnknownPrincipal,
#[error("the concrete request's resource is unknown")]
UnknownResource,
#[error("the concrete request's action is unknown")]
UnknownAction,
#[error("the concrete request's context is unknown")]
UnknownContext,
#[error(transparent)]
#[diagnostic(transparent)]
InconsistentPrincipalType(#[from] InconsistentPrincipalTypeError),
#[error(transparent)]
#[diagnostic(transparent)]
InconsistentPrincipalEid(#[from] InconsistentPrincipalEidError),
#[error(transparent)]
#[diagnostic(transparent)]
InconsistentResourceType(#[from] InconsistentResourceTypeError),
#[error(transparent)]
#[diagnostic(transparent)]
InconsistentResourceEid(#[from] InconsistentResourceEidError),
#[error(transparent)]
#[diagnostic(transparent)]
InconsistentAction(#[from] InconsistentActionError),
#[error("the partial and concrete request contexts do not match")]
InconsistentContext,
#[error("the concrete request's context contains unknowns")]
ConcreteContextContainsUnknowns,
}
#[derive(Debug, Error, Diagnostic)]
#[error("partial request principal type `{partial}` does not match concrete request principal type `{concrete}`")]
pub struct InconsistentPrincipalTypeError {
pub(super) partial: EntityType,
pub(super) concrete: EntityType,
}
#[derive(Debug, Error, Diagnostic)]
#[error("partial request principal id `{}` does not match concrete request principal id `{}`", .partial.escaped(), .concrete.escaped())]
pub struct InconsistentPrincipalEidError {
pub(super) partial: Eid,
pub(super) concrete: Eid,
}
#[derive(Debug, Error, Diagnostic)]
#[error("partial request resource type `{partial}` does not match concrete request resource type `{concrete}`")]
pub struct InconsistentResourceTypeError {
pub(super) partial: EntityType,
pub(super) concrete: EntityType,
}
#[derive(Debug, Error, Diagnostic)]
#[error("partial request resource id `{}` does not match concrete request resource id `{}`", .partial.escaped(), .concrete.escaped())]
pub struct InconsistentResourceEidError {
pub(super) partial: Eid,
pub(super) concrete: Eid,
}
#[derive(Debug, Error, Diagnostic)]
#[error("partial request action `{partial}` does not match concrete request action `{concrete}`")]
pub struct InconsistentActionError {
pub(super) partial: EntityUID,
pub(super) concrete: EntityUID,
}
#[derive(Debug, Error, Diagnostic)]
pub enum ReauthorizationError {
#[error(transparent)]
#[diagnostic(transparent)]
RequestValidation(#[from] RequestValidationError),
#[error(transparent)]
#[diagnostic(transparent)]
EntityValidation(#[from] EntitySchemaConformanceError),
#[error(transparent)]
#[diagnostic(transparent)]
EntitiesConsistency(#[from] EntitiesConsistencyError),
#[error(transparent)]
#[diagnostic(transparent)]
RequestConsistency(#[from] RequestConsistencyError),
}