#[derive(Debug, thiserror::Error)]
pub(crate) enum CedarSchemaErrorType {
#[error("Schema file is empty")]
EmptySchema,
#[error("Schema parsing failed: {0}")]
ParseError(String),
#[error("Schema validation failed: {0}")]
ValidationError(String),
}
#[derive(Debug, thiserror::Error)]
pub(crate) enum CedarEntityErrorType {
#[error("Failed to parse entity from JSON: {0}")]
JsonParseError(String),
#[error("Invalid entity type name '{0}': {1}")]
InvalidTypeName(String, String),
#[error("Invalid entity ID: {0}")]
InvalidEntityId(String),
#[error("Failed to create entity store: {0}")]
EntityStoreCreation(String),
}
#[derive(Debug, thiserror::Error)]
pub(crate) enum TrustedIssuerErrorType {
#[error("Trusted issuer file must be a JSON object")]
NotAnObject,
#[error("Issuer '{issuer_id}': missing required field '{field}'")]
MissingRequiredField { issuer_id: String, field: String },
#[error("Issuer '{issuer_id}': invalid OIDC endpoint URL '{url}': {reason}")]
InvalidOidcEndpoint {
issuer_id: String,
url: String,
reason: String,
},
#[error("Issuer '{issuer_id}': token_metadata must be a JSON object")]
TokenMetadataNotAnObject { issuer_id: String },
#[error("Issuer '{issuer_id}': token_metadata.{token_type} must be a JSON object")]
TokenMetadataEntryNotAnObject {
issuer_id: String,
token_type: String,
},
}
#[derive(Debug, thiserror::Error)]
pub(crate) enum PolicyStoreError {
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("Validation error: {0}")]
Validation(#[from] ValidationError),
#[error("Archive error: {0}")]
Archive(#[from] ArchiveError),
#[error("JSON parsing error in '{file}'")]
JsonParsing {
file: String,
#[source]
source: serde_json::Error,
},
#[error("Cedar parsing error in '{file}': {detail}")]
CedarParsing {
file: String,
detail: CedarParseErrorDetail,
},
#[error("Cedar schema error in '{file}': {err}")]
CedarSchemaError {
file: String,
err: CedarSchemaErrorType,
},
#[error("Cedar entity error in '{file}': {err}")]
CedarEntityError {
file: String,
err: CedarEntityErrorType,
},
#[error("Trusted issuer error in '{file}': {err}")]
TrustedIssuerError {
file: String,
err: TrustedIssuerErrorType,
},
#[error("Path not found: {path}")]
PathNotFound { path: String },
#[error("Path is not a directory: {path}")]
NotADirectory { path: String },
#[error("Failed to read directory '{path}'")]
DirectoryReadError {
path: String,
#[source]
source: std::io::Error,
},
#[error("Failed to read file '{path}'")]
FileReadError {
path: String,
#[source]
source: std::io::Error,
},
}
#[derive(Debug, Clone, thiserror::Error)]
pub(crate) enum CedarParseErrorDetail {
#[error("No @id() annotation found and could not derive ID from filename")]
MissingIdAnnotation,
#[error(
"Multi-policy .cedar files require @id(\"...\") on each policy; missing at line {line}: {snippet}"
)]
MultiPolicyMissingExplicitId { line: usize, snippet: String },
#[error("duplicate @id(\"{id}\") within a single .cedar file")]
DuplicatePolicyIdInFile { id: String },
#[error(
"policy file contains {count} template(s); templates must be placed in the `templates/` directory, not mixed with policies"
)]
TemplatesInPolicyFile { count: usize },
#[error(
"template file contains {count} policy/policies; policies must be placed in the `policies/` directory, not mixed with templates"
)]
PoliciesInTemplateFile { count: usize },
#[error(
"Multi-template .cedar files require @id(\"...\") on each template; missing at line {line}: {snippet}"
)]
MultiTemplateMissingExplicitId { line: usize, snippet: String },
#[error("duplicate @id(\"{id}\") within a single template .cedar file")]
DuplicateTemplateIdInFile { id: String },
#[error(
"duplicate @id(\"{id}\") across files: defined in both '{first_file}' and '{second_file}'"
)]
DuplicatePolicyIdAcrossFiles {
id: String,
first_file: String,
second_file: String,
},
#[error("{0}")]
ParseError(String),
#[error("Failed to add policy to set: {0}")]
AddPolicyFailed(String),
#[error("Failed to add template to set: {0}")]
AddTemplateFailed(String),
}
#[derive(Debug, thiserror::Error)]
pub(crate) enum ValidationError {
#[error("Invalid metadata in file {file}: failed to parse JSON")]
MetadataJsonParseFailed {
file: String,
#[source]
source: serde_json::Error,
},
#[error("Invalid metadata in file {file}: invalid cedar_version format")]
MetadataInvalidCedarVersion {
file: String,
#[source]
source: semver::Error,
},
#[error("Missing required file: {file}")]
MissingRequiredFile { file: String },
#[error("Missing required directory: {directory}")]
MissingRequiredDirectory { directory: String },
#[error("Invalid file extension for {file}: expected {expected}, got {actual}")]
InvalidFileExtension {
file: String,
expected: String,
actual: String,
},
#[error("Invalid policy ID format in {file}: Policy ID cannot be empty")]
EmptyPolicyId { file: String },
#[error(
"Invalid policy ID format in {file}: Policy ID '{id}' contains invalid characters. Only alphanumeric, '_', '-', and ':' are allowed"
)]
InvalidPolicyIdCharacters { file: String, id: String },
#[error("Cedar version cannot be empty in metadata.json")]
EmptyCedarVersion,
#[error("Invalid Cedar version format in metadata.json: '{version}' - {details}")]
InvalidCedarVersion { version: String, details: String },
#[error("Policy store name cannot be empty in metadata.json")]
EmptyPolicyStoreName,
#[error("Policy store name too long in metadata.json: {length} chars (max 255)")]
PolicyStoreNameTooLong { length: usize },
#[error(
"Invalid policy store ID format in metadata.json: '{id}' must be hexadecimal (8-64 chars)"
)]
InvalidPolicyStoreId { id: String },
#[error("Invalid policy store version in metadata.json: '{version}' - {details}")]
InvalidPolicyStoreVersion { version: String, details: String },
#[error(
"Policy store description too long in metadata.json: {length} chars (max {max_length})"
)]
DescriptionTooLong { length: usize, max_length: usize },
#[error(
"Invalid timestamp ordering in metadata.json: updated_date cannot be before created_date"
)]
InvalidTimestampOrdering,
#[error("Schema directory '{path}/' exists but contains no .cedarschema files")]
EmptySchemaDirectory { path: String },
#[error("No schema source found: neither '{searched_file}' nor directory '{searched_dir}/' exists")]
MissingSchemaSource {
searched_file: String,
searched_dir: String,
},
}
#[derive(Debug, thiserror::Error)]
pub(crate) enum ArchiveError {
#[error("Invalid file extension: expected '{expected}', found '{found}'")]
#[cfg(not(target_arch = "wasm32"))]
InvalidExtension { expected: String, found: String },
#[error("Cannot read archive file '{path}': {source}")]
#[cfg(not(target_arch = "wasm32"))]
CannotReadFile {
path: String,
#[source]
source: std::io::Error,
},
#[error("Invalid ZIP archive format: {details}")]
InvalidZipFormat { details: String },
#[error("Corrupted archive entry at index {index}: {details}")]
CorruptedEntry { index: usize, details: String },
#[error("Path traversal attempt detected in archive: '{path}'")]
PathTraversal { path: String },
#[cfg(target_arch = "wasm32")]
#[error("Archive operations are not supported on this platform")]
WasmUnsupported,
}