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}