don't
5
fork

Configure Feed

Select the types of activity you want to include in your feed.

refactor(knot): condense repository_path and repository_key into one module

Signed-off-by: tjh <x@tjh.dev>

tjh 08a2f4dc 431608fa

+113 -116
+3 -7
crates/gordian-knot/src/model/knot_state.rs
··· 35 35 use crate::services::database::DataStore; 36 36 use crate::services::database::DataStoreError; 37 37 use crate::types::RecordKey; 38 - use crate::types::repository_key::RepositoryKey; 39 - use crate::types::repository_path::RepositoryPath; 40 - use crate::types::repository_path::{self}; 38 + use crate::types::repository_spec::RepositoryKey; 39 + use crate::types::repository_spec::RepositoryPath; 41 40 42 41 /// Default number of ({handle,did},{name,rkey}) -> (did,rkey) mappings to 43 42 /// keep in cache. ··· 273 274 assert_eq!(repo.knot, self.instance_ident()); 274 275 275 276 let repo_key = RepositoryKey::new(did, rkey)?; 276 - repository_path::validate(&repo.name)?; 277 277 278 278 // We're going to receive the jetstream event and the xrpc request. 279 279 // ··· 298 300 } 299 301 300 302 pub fn init_repo(&self, repo_key: &RepositoryKey, name: &str) -> anyhow::Result<()> { 301 - repository_path::validate(&repo_key.owner)?; 302 - repository_path::validate(&repo_key.rkey)?; 303 - repository_path::validate(name)?; 303 + crate::types::repository_spec::validate(name)?; 304 304 305 305 let path = self.path_for_repository(repo_key); 306 306
+2 -2
crates/gordian-knot/src/model/repository.rs
··· 38 38 use crate::public::xrpc::XrpcQuery; 39 39 use crate::public::xrpc::XrpcResponse; 40 40 use crate::public::xrpc::XrpcResult; 41 - use crate::types::repository_key::RepositoryKey; 42 - use crate::types::repository_path::RepositoryPath; 41 + use crate::types::repository_spec::RepositoryKey; 42 + use crate::types::repository_spec::RepositoryPath; 43 43 use crate::types::sh_tangled::repo::branches; 44 44 use crate::types::sh_tangled::repo::compare; 45 45 use crate::types::sh_tangled::repo::diff;
+1 -1
crates/gordian-knot/src/private.rs
··· 30 30 use crate::model::repository::TangledRepository; 31 31 use crate::public::xrpc::XrpcError; 32 32 use crate::types::push_certificate::PushCertificate; 33 - use crate::types::repository_key::RepositoryKey; 33 + use crate::types::repository_spec::RepositoryKey; 34 34 35 35 /// Environment variable containing one or more whitespace separated URLs for 36 36 /// the internal API.
+1 -1
crates/gordian-knot/src/public/authorize.rs
··· 39 39 use url::Url; 40 40 41 41 use crate::Knot; 42 - use crate::types::repository_key::RepositoryKey; 42 + use crate::types::repository_spec::RepositoryKey; 43 43 44 44 const WELL_KNOWN_CLIENT_METADATA: &str = "/oauth-client-metadata.json"; 45 45 const WELL_KNOWN_JWKS: &str = "/.well-known/jwks";
+1 -1
crates/gordian-knot/src/public/xrpc/sh_tangled/repo/impl_archive.rs
··· 17 17 use crate::model::repository::TangledRepository; 18 18 use crate::public::xrpc::XrpcError; 19 19 use crate::public::xrpc::XrpcQuery; 20 - use crate::types::repository_path::RepositoryPath; 20 + use crate::types::repository_spec::RepositoryPath; 21 21 22 22 pub const LXM: &str = "/sh.tangled.repo.archive"; 23 23
+3 -5
crates/gordian-knot/src/public/xrpc/sh_tangled/repo/impl_merge_check.rs
··· 8 8 use crate::model::errors; 9 9 use crate::model::repository::TangledRepository; 10 10 use crate::public::xrpc::XrpcResult; 11 - use crate::types::repository_path::RepositoryPath; 11 + use crate::types::repository_spec::RepositoryPath; 12 12 13 13 pub const LXM: &str = "/sh.tangled.repo.mergeCheck"; 14 14 ··· 22 22 branch, 23 23 }): Json<Input>, 24 24 ) -> XrpcResult<Json<Output>> { 25 - let repo_path = RepositoryPath { 26 - owner: did.into_boxed().into(), 27 - name: name.into_boxed_str(), 28 - }; 25 + let repo_path = 26 + RepositoryPath::from_parts(did.as_str(), name).map_err(errors::InvalidRequest)?; 29 27 30 28 let repo_key = knot 31 29 .resolve_repo_key(&repo_path)
+1 -1
crates/gordian-knot/src/public/xrpc/sh_tangled/repo/impl_set_default_branch.rs
··· 21 21 use crate::services::rbac::PolicyResult::Granted; 22 22 use crate::services::rbac::RepositoryEditPolicy; 23 23 use crate::services::rbac::RepositoryRef; 24 - use crate::types::repository_key::RepositoryKey; 24 + use crate::types::repository_spec::RepositoryKey; 25 25 26 26 pub const LXM: &str = "/sh.tangled.repo.setDefaultBranch"; 27 27
+1 -1
crates/gordian-knot/src/services/rbac.rs
··· 3 3 use gordian_types::Did; 4 4 5 5 use crate::model::KnotState; 6 - use crate::types::repository_key::RepositoryKey; 6 + use crate::types::repository_spec::RepositoryKey; 7 7 8 8 pub trait Policy<Subject, Resource, Action, Context>: Send + Sync { 9 9 /// Evaluates whether access should be granted.
+6 -6
crates/gordian-knot/src/tests.rs
··· 113 113 use super::*; 114 114 use crate::nsid::SH_TANGLED_REPO_CREATE; 115 115 use crate::nsid::SH_TANGLED_REPO_DELETE; 116 + use crate::types::repository_spec::RepositoryPath; 116 117 117 118 fn make_claims<F>(iss: &Did, aud: &Did, modify_claims: F) -> Claims 118 119 where ··· 224 223 } 225 224 226 225 async fn repo_exists_in_db(knot: &Knot, did: &Did, rkey: &str) -> bool { 227 - knot.resolve_repo_key(&crate::types::repository_path::RepositoryPath { 228 - owner: did.into_boxed().into(), 229 - name: rkey.into(), 230 - }) 231 - .await 232 - .is_ok() 226 + let Ok(repo_path) = RepositoryPath::from_parts(did.as_str(), rkey) else { 227 + return false; 228 + }; 229 + 230 + knot.resolve_repo_key(&repo_path).await.is_ok() 233 231 } 234 232 235 233 #[tokio::test]
+1 -2
crates/gordian-knot/src/types.rs
··· 6 6 use crate::lexicon::com::atproto::repo::list_records::Record; 7 7 8 8 pub mod push_certificate; 9 - pub mod repository_key; 10 - pub mod repository_path; 9 + pub mod repository_spec; 11 10 pub mod sh_tangled; 12 11 13 12 #[derive(Debug)]
-77
crates/gordian-knot/src/types/repository_key.rs
··· 1 - use core::fmt; 2 - 3 - use gordian_types::DidBuf; 4 - use serde::Deserialize; 5 - 6 - use super::repository_path::Error; 7 - use super::repository_path::validate; 8 - 9 - #[derive(Clone, Debug, Hash, PartialEq, Eq, Deserialize)] 10 - #[serde(try_from = "UnvalidatedRepositoryKey")] 11 - pub struct RepositoryKey { 12 - /// Repository owner's Did. 13 - pub owner: DidBuf, 14 - 15 - /// Repository record key. 16 - pub rkey: String, 17 - } 18 - 19 - impl RepositoryKey { 20 - pub fn new(owner: impl Into<DidBuf>, rkey: impl Into<String>) -> Result<Self, Error> { 21 - fn inner(owner: DidBuf, rkey: String) -> Result<RepositoryKey, Error> { 22 - validate(&owner)?; 23 - validate(&rkey)?; 24 - 25 - Ok(RepositoryKey { owner, rkey }) 26 - } 27 - inner(owner.into(), rkey.into()) 28 - } 29 - } 30 - 31 - #[derive(Deserialize)] 32 - struct UnvalidatedRepositoryKey { 33 - owner: DidBuf, 34 - rkey: String, 35 - } 36 - 37 - impl TryFrom<UnvalidatedRepositoryKey> for RepositoryKey { 38 - type Error = Error; 39 - fn try_from(value: UnvalidatedRepositoryKey) -> Result<Self, Self::Error> { 40 - let UnvalidatedRepositoryKey { owner, rkey } = value; 41 - validate(&owner)?; 42 - validate(&rkey)?; 43 - Ok(Self { owner, rkey }) 44 - } 45 - } 46 - 47 - impl RepositoryKey { 48 - pub fn owner_str(&self) -> &str { 49 - &self.owner 50 - } 51 - 52 - pub fn rkey(&self) -> &str { 53 - &self.rkey 54 - } 55 - } 56 - 57 - impl fmt::Display for RepositoryKey { 58 - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 59 - write!(f, "{}/{}", self.owner, self.rkey) 60 - } 61 - } 62 - 63 - impl std::str::FromStr for RepositoryKey { 64 - type Err = Error; 65 - fn from_str(s: &str) -> Result<Self, Self::Err> { 66 - let (owner, name) = s.split_once('/').ok_or(Error::Format)?; 67 - 68 - let owner: DidBuf = owner.parse().map_err(|_| Error::Format)?; 69 - validate(owner.as_str())?; 70 - validate(name)?; 71 - 72 - Ok(Self { 73 - owner, 74 - rkey: name.into(), 75 - }) 76 - } 77 - }
+93 -12
crates/gordian-knot/src/types/repository_path.rs crates/gordian-knot/src/types/repository_spec.rs
··· 1 1 use core::fmt; 2 2 3 + use gordian_types::DidBuf; 3 4 use serde::Deserialize; 4 5 6 + #[derive(Deserialize)] 7 + #[serde(deny_unknown_fields)] 8 + struct UnvalidatedRepositoryPath { 9 + owner: Box<str>, 10 + name: Box<str>, 11 + } 12 + 5 13 /// Repository path specifier. 14 + /// 15 + /// May be any combination of "{handle,did}/{name,rkey}" 6 16 #[derive(Clone, Debug, Hash, PartialEq, Eq, Deserialize)] 7 - #[serde(try_from = "UnvalidatedRepositoryPath")] 17 + #[serde(deny_unknown_fields, try_from = "UnvalidatedRepositoryPath")] 8 18 pub struct RepositoryPath { 9 19 /// Repository owner's DID or handle. 10 20 pub owner: Box<str>, ··· 23 13 pub name: Box<str>, 24 14 } 25 15 26 - #[derive(Deserialize)] 27 - struct UnvalidatedRepositoryPath { 28 - owner: Box<str>, 29 - name: Box<str>, 30 - } 31 - 32 16 impl TryFrom<UnvalidatedRepositoryPath> for RepositoryPath { 33 17 type Error = Error; 34 18 35 - #[inline] 36 19 fn try_from( 37 20 UnvalidatedRepositoryPath { owner, name }: UnvalidatedRepositoryPath, 38 21 ) -> Result<Self, Self::Error> { ··· 57 54 58 55 impl fmt::Display for RepositoryPath { 59 56 #[inline] 60 - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 57 + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 61 58 write!(f, "{}/{}", self.owner, self.name) 62 59 } 63 60 } ··· 80 77 } 81 78 } 82 79 83 - impl TryFrom<&str> for RepositoryPath { 80 + #[derive(Deserialize)] 81 + #[serde(deny_unknown_fields)] 82 + struct UnvalidatedRepositoryKey { 83 + owner: DidBuf, 84 + rkey: String, 85 + } 86 + 87 + /// The canonical reference for a repository and should consist of the DID and 88 + /// rkey of the repository's AT record. 89 + #[derive(Clone, Debug, Hash, PartialEq, Eq, Deserialize)] 90 + #[serde(deny_unknown_fields, try_from = "UnvalidatedRepositoryKey")] 91 + pub struct RepositoryKey { 92 + /// Repository owner's Did. 93 + pub owner: DidBuf, 94 + 95 + /// Repository record key. 96 + pub rkey: String, 97 + } 98 + 99 + impl RepositoryKey { 100 + /// Create a new repository key from an owner DID and rkey. 101 + /// 102 + /// # Errors 103 + /// 104 + /// Rejects the repository key if either `owner` or `rkey` contain forbidden 105 + /// characters or substrings. 106 + pub fn new(owner: impl Into<DidBuf>, rkey: impl Into<String>) -> Result<Self, Error> { 107 + fn inner(owner: DidBuf, rkey: String) -> Result<RepositoryKey, Error> { 108 + validate(&owner)?; 109 + validate(&rkey)?; 110 + 111 + Ok(RepositoryKey { owner, rkey }) 112 + } 113 + inner(owner.into(), rkey.into()) 114 + } 115 + } 116 + 117 + impl TryFrom<UnvalidatedRepositoryKey> for RepositoryKey { 84 118 type Error = Error; 85 - fn try_from(value: &str) -> Result<Self, Self::Error> { 86 - std::str::FromStr::from_str(value) 119 + 120 + fn try_from(value: UnvalidatedRepositoryKey) -> Result<Self, Self::Error> { 121 + let UnvalidatedRepositoryKey { owner, rkey } = value; 122 + validate(&owner)?; 123 + validate(&rkey)?; 124 + Ok(Self { owner, rkey }) 125 + } 126 + } 127 + 128 + impl RepositoryKey { 129 + /// Get the repository owner's DID as a `&str`. 130 + #[must_use] 131 + pub fn owner_str(&self) -> &str { 132 + &self.owner 133 + } 134 + 135 + /// Get the repository rkey as a `&str`. 136 + #[must_use] 137 + pub fn rkey(&self) -> &str { 138 + &self.rkey 139 + } 140 + } 141 + 142 + impl fmt::Display for RepositoryKey { 143 + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 144 + write!(f, "{}/{}", self.owner, self.rkey) 145 + } 146 + } 147 + 148 + impl std::str::FromStr for RepositoryKey { 149 + type Err = Error; 150 + 151 + fn from_str(s: &str) -> Result<Self, Self::Err> { 152 + let (owner, name) = s.split_once('/').ok_or(Error::Format)?; 153 + 154 + let owner: DidBuf = owner.parse().map_err(|_| Error::Format)?; 155 + validate(owner.as_str())?; 156 + validate(name)?; 157 + 158 + Ok(Self { 159 + owner, 160 + rkey: name.into(), 161 + }) 87 162 } 88 163 } 89 164