Radish alpha
h
rad:z3gqcJUoA1n9HaHKufZs5FCSGazv5
Radicle Heartwood Protocol & Stack
Radicle
Git
Add JSON Schema for identity document
Draft lorenz opened 10 months ago
7 files changed +55 -5 6e9517a1 abe0e806
modified Cargo.lock
@@ -2448,6 +2448,7 @@ dependencies = [
 "radicle-crypto",
 "radicle-dag",
 "radicle-git-ext",
+
 "schemars",
 "serde",
 "serde_json",
 "signature 2.2.0",
modified crates/radicle-cob/Cargo.toml
@@ -26,6 +26,7 @@ nonempty = { workspace = true, features = ["serialize"] }
radicle-crypto = { workspace = true, features = ["ssh"] }
radicle-dag = { workspace = true }
radicle-git-ext = { workspace = true, features = ["serde"] }
+
schemars = { workspace = true, optional = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
signature = { workspace = true }
modified crates/radicle-cob/src/type_name.rs
@@ -16,7 +16,17 @@ use thiserror::Error;
/// * `xyz.rad.issues`
/// * `xyz.rad.patches.releases`
#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
-
pub struct TypeName(String);
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
+
#[cfg_attr(feature = "schemars", schemars(
+
    description = "\
+
        The typename of an object. Valid typenames MUST be sequences of \
+
        alphanumeric characters separated by a period. The name must start \
+
        and end with an alphanumeric character.",
+
    extend("examples" = ["abc.def", "xyz.rad.issues", "xyz.rad.patches.releases"]),
+
))]
+
pub struct TypeName(
+
    #[cfg_attr(feature = "schemars", schemars(regex(pattern = r"^\w+(\.\w+)*$")))] String,
+
);

impl TypeName {
    pub fn as_str(&self) -> &str {
modified crates/radicle-schemars/src/main.rs
@@ -7,8 +7,14 @@ use schemars::{generate::*, *};
const SCHEMA_COMMAND: &str = "radicle::node::Command";
const SCHEMA_COMMAND_RESULT: &str = "radicle::node::CommandResult";
const SCHEMA_PROFILE_CONFIG: &str = "radicle::profile::Config";
+
const SCHEMA_IDENTITY_DOC: &str = "radicle::identity::doc::Doc";

-
const SCHEMAS: &[&str] = &[SCHEMA_COMMAND, SCHEMA_COMMAND_RESULT, SCHEMA_PROFILE_CONFIG];
+
const SCHEMAS: &[&str] = &[
+
    SCHEMA_COMMAND,
+
    SCHEMA_COMMAND_RESULT,
+
    SCHEMA_PROFILE_CONFIG,
+
    SCHEMA_IDENTITY_DOC,
+
];

pub static ERROR_MSG: LazyLock<String> = LazyLock::new(|| {
    let schemas = SCHEMAS.to_vec().join("\", \"");
@@ -19,6 +25,7 @@ enum Schema {
    Command,
    CommandResult,
    ProfileConfig,
+
    IdentityDoc,
}

impl std::str::FromStr for Schema {
@@ -29,6 +36,7 @@ impl std::str::FromStr for Schema {
            SCHEMA_COMMAND => Ok(Self::Command),
            SCHEMA_COMMAND_RESULT => Ok(Self::CommandResult),
            SCHEMA_PROFILE_CONFIG => Ok(Self::ProfileConfig),
+
            SCHEMA_IDENTITY_DOC => Ok(Self::IdentityDoc),
            schema => Err(io::Error::new(
                io::ErrorKind::InvalidInput,
                format!("{schema}: {}", *ERROR_MSG),
@@ -68,6 +76,12 @@ fn print_schema() -> io::Result<()> {

            generator.into_root_schema_for::<radicle::node::Command>()
        }
+
        Schema::IdentityDoc => {
+
            let settings = SchemaSettings::default().for_serialize();
+
            let generator = settings.into_generator();
+

+
            generator.into_root_schema_for::<radicle::identity::doc::Doc>()
+
        }
        Schema::CommandResult => {
            #[derive(JsonSchema)]
            #[allow(dead_code)]
modified crates/radicle/src/identity/did.rs
@@ -16,7 +16,17 @@ pub enum DidError {

#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy)]
#[serde(into = "String", try_from = "String")]
-
pub struct Did(crypto::PublicKey);
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
+
pub struct Did(
+
    #[cfg_attr(
+
        feature = "schemars",
+
        schemars(
+
            with = "String",
+
            regex(pattern = r"^did:key:z6Mk[1-9A-HJ-NP-Za-km-z]+$"),
+
        )
+
    )]
+
    crypto::PublicKey,
+
);

impl Did {
    /// We use the format specified by the DID `key` method, which is described as:
modified crates/radicle/src/identity/doc.rs
@@ -80,6 +80,7 @@ impl DocError {
/// If an invalid version is found – either the `0` version, or an unrecognized
/// future version – the parsing of a version will fail.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize)]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Version(NonZeroU32);

impl Version {
@@ -230,6 +231,7 @@ pub enum PayloadError {
/// The payload is identified in the [`Doc`] by its corresponding [`PayloadId`].
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(transparent)]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Payload {
    value: serde_json::Value,
}
@@ -291,6 +293,7 @@ impl AsRef<Doc> for DocAt {
/// Repository visibility.
#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase", tag = "type")]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub enum Visibility {
    /// Anyone and everyone.
    #[default]
@@ -469,7 +472,10 @@ impl RawDoc {
/// It can only be constructed via [`Delegates::new`].
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(try_from = "Vec<Did>")]
-
pub struct Delegates(NonEmpty<Did>);
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
+
pub struct Delegates(
+
    #[cfg_attr(feature = "schemars", schemars(with = "Vec<Did>", length(min = 1)))] NonEmpty<Did>,
+
);

impl AsRef<NonEmpty<Did>> for Delegates {
    fn as_ref(&self) -> &NonEmpty<Did> {
@@ -564,6 +570,7 @@ impl From<Delegates> for Vec<Did> {
/// It can only be constructed via [`Threshold::new`] or [`Threshold::MIN`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize)]
#[serde(transparent)]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct Threshold(NonZeroUsize);

impl From<Threshold> for usize {
@@ -624,6 +631,8 @@ impl Threshold {
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[serde(try_from = "RawDoc")]
+
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
+
#[cfg_attr(feature = "schemars", schemars(rename = "xyz.radicle.id",))]
pub struct Doc {
    #[serde(skip_serializing_if = "Version::skip_serializing")]
    version: Version,
modified crates/radicle/src/schemars_ext.rs
@@ -24,7 +24,12 @@ pub mod crypto {
        "z6MkkfM3tPXNPrPevKr3uSiQtHPuwnNhu2yUVjgd2jXVsVz5",
    ]),
)]
-
    pub struct PublicKey(String);
+
    pub struct PublicKey(
+
        #[schemars(regex(
+
            pattern = r"^z6Mk[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]+$",
+
        ))]
+
        String,
+
    );
}

pub(crate) mod log {