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`] 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)]
46#[non_exhaustive]
47pub enum SchemaError {
48 /// A schema file could not be read from disk.
49 #[error("schema I/O error reading `{path}`: {source}")]
50 Io {
51 /// Path that could not be read.
52 path: PathBuf,
53 /// Underlying I/O error.
54 #[source]
55 source: std::io::Error,
56 },
57
58 /// A schema file was read but is not valid JSON.
59 #[error("schema parse error in `{path}`: {source}")]
60 Parse {
61 /// Path of the offending file.
62 path: PathBuf,
63 /// JSON parse error.
64 #[source]
65 source: serde_json::Error,
66 },
67
68 /// A payload failed validation against the registered schema.
69 ///
70 /// This variant is produced by `validate`; it is never produced by `load`.
71 #[error("validation failed for {kind:?}: {errors:?}")]
72 Validation {
73 /// The kind of schema that rejected the payload.
74 kind: SchemaKind,
75 /// Human-readable description of each validation failure.
76 errors: Vec<String>,
77 },
78
79 /// A handler requested validation for a `(project, kind)` pair that was
80 /// never registered in the [`crate::schema`] registry.
81 #[error("no schema registered for project `{project}` / kind `{kind:?}`")]
82 UnknownSchema {
83 /// Project identifier that was not found.
84 project: String,
85 /// The schema kind that was requested.
86 kind: SchemaKind,
87 },
88}