objectiveai_cli/filesystem/install/
identifiers.rs1use super::{InstallError, InstallKind};
2
3fn check_repository_name(repository: &str) -> Result<(), InstallError> {
9 if repository.eq_ignore_ascii_case("objectiveai") {
10 return Err(InstallError::ReservedRepositoryName {
11 repository: repository.to_string(),
12 });
13 }
14 Ok(())
15}
16
17fn validate_identifier(
23 kind: &'static str,
24 value: &str,
25) -> Result<(), InstallError> {
26 let valid_len = !value.is_empty() && value.len() <= 128;
27 let valid_chars = value
28 .chars()
29 .all(|c| c.is_ascii_alphanumeric() || matches!(c, '_' | '-' | '.'));
30 if !valid_len || !valid_chars {
31 return Err(InstallError::InvalidIdentifier {
32 kind,
33 value: value.to_string(),
34 });
35 }
36 Ok(())
37}
38
39pub(crate) fn validate_install_inputs(
45 kind: InstallKind,
46 owner: &str,
47 repository: &str,
48 commit_sha: Option<&str>,
49) -> Result<(), InstallError> {
50 if matches!(kind, InstallKind::Plugin) {
51 check_repository_name(repository)?;
52 }
53 validate_identifier("owner", owner)?;
54 validate_identifier("repository", repository)?;
55 if let Some(sha) = commit_sha {
56 validate_identifier("commit", sha)?;
57 }
58 Ok(())
59}
60
61pub fn raw_manifest_url(
66 owner: &str,
67 repository: &str,
68 commit_sha: Option<&str>,
69) -> String {
70 let reference = commit_sha.unwrap_or("HEAD");
71 format!(
72 "https://raw.githubusercontent.com/{owner}/{repository}/{reference}/objectiveai.json"
73 )
74}
75
76pub(crate) fn build_headers(
77 headers: Option<&indexmap::IndexMap<String, String>>,
78) -> Result<reqwest::header::HeaderMap, InstallError> {
79 let mut out = reqwest::header::HeaderMap::new();
80 let Some(h) = headers else {
81 return Ok(out);
82 };
83 for (k, v) in h {
84 let name = reqwest::header::HeaderName::from_bytes(k.as_bytes())
85 .map_err(|e| InstallError::InvalidHeaderName {
86 name: k.clone(),
87 reason: e.to_string(),
88 })?;
89 let value = reqwest::header::HeaderValue::from_str(v).map_err(|e| {
90 InstallError::InvalidHeaderValue {
91 name: k.clone(),
92 reason: e.to_string(),
93 }
94 })?;
95 out.insert(name, value);
96 }
97 Ok(out)
98}