Skip to main content

detritus_protocol/
schema.rs

1//! Per-tenant JSON Schema descriptors for crash and log payload validation.
2//!
3//! This module defines the public types consumed by `detritus-server` when
4//! loading and eventually applying per-project validation rules.  The actual
5//! JSON Schema compilation and validation lives in the server; the protocol
6//! crate only owns the wire-level taxonomy (`SchemaKind`) and the on-disk
7//! descriptor (`SchemaSpec`).
8//!
9//! # Error taxonomy
10//!
11//! [`SchemaError`](crate::schema::SchemaError) is the unified error type for
12//! all schema operations: file I/O, JSON parsing, validation failures, and
13//! look-ups for projects that were never registered.
14
15use std::path::PathBuf;
16
17use serde::{Deserialize, Serialize};
18
19/// The two payload shapes that may carry a per-tenant JSON Schema.
20///
21/// The `snake_case` wire names (`"crash_metadata"`, `"log_attributes"`) are
22/// used both in tokens TOML configuration and in any future API surface.
23#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
24#[serde(rename_all = "snake_case")]
25pub enum SchemaKind {
26    /// Validates the `metadata` field of a [`crate::CrashMetadata`] payload.
27    CrashMetadata,
28    /// Validates the resource / scope attributes of an OTLP log record.
29    LogAttributes,
30}
31
32/// One schema-file declaration as it appears in `tokens.toml`.
33///
34/// `path` is always resolved relative to the tokens config file's parent
35/// directory, never relative to the current working directory.
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct SchemaSpec {
38    /// The payload kind this schema governs.
39    pub kind: SchemaKind,
40    /// Path to the JSON Schema document on disk.
41    pub path: PathBuf,
42}
43
44/// Errors produced during schema loading or validation.
45#[derive(Debug, thiserror::Error)]
46pub enum SchemaError {
47    /// A schema file could not be read from disk.
48    #[error("schema I/O error reading `{path}`: {source}")]
49    Io {
50        /// Path that could not be read.
51        path: PathBuf,
52        /// Underlying I/O error.
53        #[source]
54        source: std::io::Error,
55    },
56
57    /// A schema file was read but is not valid JSON.
58    #[error("schema parse error in `{path}`: {source}")]
59    Parse {
60        /// Path of the offending file.
61        path: PathBuf,
62        /// JSON parse error.
63        #[source]
64        source: serde_json::Error,
65    },
66
67    /// A payload failed validation against the registered schema.
68    ///
69    /// This variant is produced by `validate`; it is never produced by `load`.
70    #[error("validation failed for {kind:?}: {errors:?}")]
71    Validation {
72        /// The kind of schema that rejected the payload.
73        kind: SchemaKind,
74        /// Human-readable description of each validation failure.
75        errors: Vec<String>,
76    },
77
78    /// A handler requested validation for a `(project, kind)` pair that was
79    /// never registered in the [`crate::schema`] registry.
80    #[error("no schema registered for project `{project}` / kind `{kind:?}`")]
81    UnknownSchema {
82        /// Project identifier that was not found.
83        project: String,
84        /// The schema kind that was requested.
85        kind: SchemaKind,
86    },
87}