use runx_contracts::{JsonObject, JsonValue};
use super::util::{display_sha256, trust_tier_string};
use super::{FileRegistryStore, LocalRegistryError, runx_link_for_version, slugify};
use crate::registry::types::{
ProfileMode, RegistryAttestation, RegistryPublisher, RegistrySearchResult, RegistrySkillDetail,
RegistrySkillVersion, RegistrySourceMetadata, TrustSignal, TrustTier,
};
pub(super) fn build_source_attestations(
source_metadata: Option<&RegistrySourceMetadata>,
issued_at: &str,
) -> Vec<RegistryAttestation> {
let Some(source_metadata) = source_metadata else {
return Vec::new();
};
let mut metadata = JsonObject::new();
metadata.insert(
"repo".to_owned(),
JsonValue::String(source_metadata.repo.clone()),
);
metadata.insert(
"ref".to_owned(),
JsonValue::String(source_metadata.r#ref.clone()),
);
metadata.insert(
"sha".to_owned(),
JsonValue::String(source_metadata.sha.clone()),
);
metadata.insert(
"event".to_owned(),
JsonValue::String(source_metadata.event.clone()),
);
metadata.insert(
"skill_path".to_owned(),
JsonValue::String(source_metadata.skill_path.clone()),
);
if let Some(profile_path) = &source_metadata.profile_path {
metadata.insert(
"profile_path".to_owned(),
JsonValue::String(profile_path.clone()),
);
}
vec![RegistryAttestation {
kind: "source".to_owned(),
id: format!("{}_source", source_metadata.provider),
status: "verified".to_owned(),
summary: format!(
"{}:{}@{}",
source_metadata.provider, source_metadata.repo, source_metadata.sha
),
source: Some(source_metadata.repo_url.clone()),
issued_at: Some(issued_at.to_owned()),
metadata: Some(JsonValue::Object(metadata)),
}]
}
pub(super) fn build_publisher_attestations(
publisher: &RegistryPublisher,
trust_tier: &TrustTier,
issued_at: &str,
) -> Vec<RegistryAttestation> {
let label = publisher
.display_name
.as_ref()
.or(publisher.handle.as_ref())
.unwrap_or(&publisher.id);
let mut metadata = JsonObject::new();
metadata.insert(
"publisher_id".to_owned(),
JsonValue::String(publisher.id.clone()),
);
metadata.insert(
"publisher_kind".to_owned(),
JsonValue::String(publisher.kind.clone()),
);
if let Some(handle) = &publisher.handle {
metadata.insert(
"publisher_handle".to_owned(),
JsonValue::String(handle.clone()),
);
}
if let Some(display_name) = &publisher.display_name {
metadata.insert(
"publisher_display_name".to_owned(),
JsonValue::String(display_name.clone()),
);
}
metadata.insert(
"trust_tier".to_owned(),
JsonValue::String(trust_tier_string(trust_tier).to_owned()),
);
vec![RegistryAttestation {
kind: "publisher".to_owned(),
id: format!("publisher:{}", publisher.id),
status: if *trust_tier == TrustTier::Community {
"declared".to_owned()
} else {
"verified".to_owned()
},
summary: label.clone(),
source: None,
issued_at: Some(issued_at.to_owned()),
metadata: Some(JsonValue::Object(metadata)),
}]
}
pub(super) fn merge_registry_attestations(
groups: Vec<Vec<RegistryAttestation>>,
) -> Vec<RegistryAttestation> {
let mut keys: Vec<String> = Vec::new();
let mut merged: Vec<RegistryAttestation> = Vec::new();
for attestation in groups.into_iter().flatten() {
let key = format!("{}:{}", attestation.kind, attestation.id);
if let Some(index) = keys.iter().position(|candidate| candidate == &key) {
merged[index] = attestation;
} else {
keys.push(key);
merged.push(attestation);
}
}
merged
}
pub(super) fn normalize_attestations(
attestations: Vec<RegistryAttestation>,
source_metadata: Option<&RegistrySourceMetadata>,
publisher: &RegistryPublisher,
trust_tier: &TrustTier,
created_at: &str,
) -> Vec<RegistryAttestation> {
merge_registry_attestations(vec![
build_publisher_attestations(publisher, trust_tier, created_at),
build_source_attestations(source_metadata, created_at),
attestations,
])
}
pub(super) fn derive_trust_signals(version: &RegistrySkillVersion) -> Vec<TrustSignal> {
vec![
digest_trust_signal(version),
trust_tier_signal(version),
publisher_trust_signal(version),
provenance_trust_signal(version),
source_type_trust_signal(version),
scopes_trust_signal(version),
runtime_trust_signal(version),
runner_metadata_trust_signal(version),
]
}
pub(super) fn digest_trust_signal(version: &RegistrySkillVersion) -> TrustSignal {
TrustSignal {
id: "digest".to_owned(),
label: "Immutable digest".to_owned(),
status: "verified".to_owned(),
value: display_sha256(&version.digest),
}
}
pub(super) fn trust_tier_signal(version: &RegistrySkillVersion) -> TrustSignal {
TrustSignal {
id: "trust_tier".to_owned(),
label: "Trust tier".to_owned(),
status: if version.trust_tier == TrustTier::Community {
"declared".to_owned()
} else {
"verified".to_owned()
},
value: trust_tier_string(&version.trust_tier).to_owned(),
}
}
pub(super) fn publisher_trust_signal(version: &RegistrySkillVersion) -> TrustSignal {
let attestation = version
.attestations
.iter()
.find(|attestation| attestation.kind == "publisher");
TrustSignal {
id: "publisher".to_owned(),
label: "Publisher identity".to_owned(),
status: attestation
.map_or("not_declared", |attestation| attestation.status.as_str())
.to_owned(),
value: publisher_label(&version.publisher).to_owned(),
}
}
pub(super) fn provenance_trust_signal(version: &RegistrySkillVersion) -> TrustSignal {
let provenance = source_provenance(version);
TrustSignal {
id: "provenance".to_owned(),
label: "Source provenance".to_owned(),
status: if provenance.is_some() {
"verified".to_owned()
} else {
"not_declared".to_owned()
},
value: provenance.unwrap_or_else(|| "no source attestation".to_owned()),
}
}
pub(super) fn source_type_trust_signal(version: &RegistrySkillVersion) -> TrustSignal {
TrustSignal {
id: "source_type".to_owned(),
label: "Execution source".to_owned(),
status: "declared".to_owned(),
value: version.source_type.clone(),
}
}
pub(super) fn scopes_trust_signal(version: &RegistrySkillVersion) -> TrustSignal {
TrustSignal {
id: "scopes".to_owned(),
label: "Required scopes".to_owned(),
status: declared_status(!version.required_scopes.is_empty()).to_owned(),
value: if version.required_scopes.is_empty() {
"none declared".to_owned()
} else {
version.required_scopes.join(", ")
},
}
}
pub(super) fn runtime_trust_signal(version: &RegistrySkillVersion) -> TrustSignal {
TrustSignal {
id: "runtime".to_owned(),
label: "Runtime requirements".to_owned(),
status: declared_status(version.runtime.is_some()).to_owned(),
value: if version.runtime.is_some() {
"declared in skill metadata".to_owned()
} else {
"none declared".to_owned()
},
}
}
pub(super) fn runner_metadata_trust_signal(version: &RegistrySkillVersion) -> TrustSignal {
TrustSignal {
id: "runner_metadata".to_owned(),
label: "Materialized binding".to_owned(),
status: if version.profile_digest.is_some() {
"verified".to_owned()
} else {
"not_declared".to_owned()
},
value: runner_metadata_value(version),
}
}
pub(super) fn publisher_label(publisher: &RegistryPublisher) -> &str {
publisher
.display_name
.as_ref()
.or(publisher.handle.as_ref())
.unwrap_or(&publisher.id)
}
pub(super) fn runner_metadata_value(version: &RegistrySkillVersion) -> String {
version.profile_digest.as_ref().map_or_else(
|| "portable agent runner".to_owned(),
|digest| {
format!(
"{} runner(s), binding {}",
version.runner_names.len(),
display_sha256(digest)
)
},
)
}
pub(super) fn declared_status(is_declared: bool) -> &'static str {
if is_declared {
"declared"
} else {
"not_declared"
}
}
pub(super) fn source_provenance(version: &RegistrySkillVersion) -> Option<String> {
if let Some(source_metadata) = &version.source_metadata {
return Some(format!(
"{}:{}@{}",
source_metadata.provider, source_metadata.repo, source_metadata.sha
));
}
version
.attestations
.iter()
.find(|attestation| attestation.kind == "source")
.map(|attestation| attestation.summary.clone())
}
pub(super) fn search_result_for_version(
version: &RegistrySkillVersion,
registry_url: Option<&str>,
) -> RegistrySearchResult {
let link = runx_link_for_version(version, registry_url);
RegistrySearchResult {
skill_id: version.skill_id.clone(),
name: version.name.clone(),
summary: version.description.clone(),
category: version.category.clone(),
source_category: version.source_category.clone(),
owner: version.owner.clone(),
version: Some(version.version.clone()),
digest: Some(version.digest.clone()),
source: Some("runx-registry".to_owned()),
source_label: Some("runx registry".to_owned()),
source_type: version.source_type.clone(),
profile_mode: if version.profile_document.is_some() {
ProfileMode::Profiled
} else {
ProfileMode::Portable
},
runner_names: version.runner_names.clone(),
profile_digest: version.profile_digest.clone(),
profile_trust_tier: version
.profile_document
.as_ref()
.map(|_| version.trust_tier.clone()),
required_scopes: version.required_scopes.clone(),
tags: version.tags.clone(),
trust_tier: version.trust_tier.clone(),
trust_signals: derive_trust_signals(version),
install_command: link.install_command,
run_command: link.run_command,
}
}
pub(super) fn detail_for_version(
version: &RegistrySkillVersion,
registry_url: Option<&str>,
) -> RegistrySkillDetail {
let link = runx_link_for_version(version, registry_url);
RegistrySkillDetail {
skill_id: version.skill_id.clone(),
owner: version.owner.clone(),
name: version.name.clone(),
description: version.description.clone(),
category: version.category.clone(),
source_category: version.source_category.clone(),
version: version.version.clone(),
digest: version.digest.clone(),
signed_manifest: version.signed_manifest.clone(),
markdown: version.markdown.clone(),
profile_digest: version.profile_digest.clone(),
package_files: version.package_files.clone(),
package_digest: version.package_digest.clone(),
runner_names: version.runner_names.clone(),
source_type: version.source_type.clone(),
trust_tier: version.trust_tier.clone(),
required_scopes: version.required_scopes.clone(),
tags: version.tags.clone(),
publisher: version.publisher.clone(),
source_metadata: version.source_metadata.clone(),
attestations: version.attestations.clone(),
install_command: link.install_command,
run_command: link.run_command,
}
}
pub(super) fn resolve_by_name(
store: &FileRegistryStore,
name: &str,
version: Option<&str>,
) -> Result<Option<RegistrySkillVersion>, LocalRegistryError> {
let normalized = slugify(name)?;
let matches = store
.list_skills()?
.into_iter()
.filter(|skill| {
skill.name == normalized || skill.skill_id.ends_with(&format!("/{normalized}"))
})
.collect::<Vec<_>>();
match matches.len() {
0 => Ok(None),
1 => store.get_version(&matches[0].skill_id, version),
_ => Err(LocalRegistryError::Ambiguous(name.to_owned())),
}
}
pub(super) fn searchable_text(version: &RegistrySkillVersion) -> String {
let mut parts = vec![
version.skill_id.clone(),
version.name.clone(),
version.owner.clone(),
version.source_type.clone(),
];
if let Some(description) = &version.description {
parts.push(description.clone());
}
if let Some(category) = &version.category {
parts.push(category.clone());
}
if let Some(source_category) = &version.source_category {
parts.push(source_category.clone());
}
parts.extend(version.runner_names.clone());
parts.extend(version.tags.clone());
normalize(&parts.join(" "))
}
pub(super) fn normalize(value: &str) -> String {
value.trim().to_lowercase()
}