Skip to main content

runx_runtime/
registry.rs

1mod http;
2mod index;
3mod install;
4mod local;
5mod package_files;
6mod payload;
7mod refs;
8pub(crate) mod scopes;
9mod source_authority;
10mod trust_anchor;
11mod types;
12
13use runx_contracts::{JsonNumber, JsonObject, JsonValue};
14
15pub use http::{
16    AcquireOptions, DefaultRuntimeHttpTransport, HttpMethod, HttpRequest, HttpResponse,
17    RegistryClient, RegistryClientError, RuntimeHttpError, RuntimeHttpHeader, Transport,
18};
19pub use index::{
20    GithubRepoRef, IndexError, IndexGithubRepoOptions, IndexResponse, IndexWarning, IndexedListing,
21    IndexedRepo, index_github_repo, parse_github_repo_ref,
22};
23pub use install::{
24    InstallCandidate, InstallError, InstallLocalSkillOptions, InstallLocalSkillResult,
25    InstallStatus, install_local_skill,
26};
27pub use local::{
28    CreateRegistrySkillVersionResult, FileRegistryStore, IngestSkillOptions, LocalRegistryClient,
29    LocalRegistryError, PublishSkillMarkdownOptions, PutVersionOptions, RegistryResolveOptions,
30    RegistrySearchOptions, RegistrySkillVersionPayload, build_registry_skill_version,
31    build_skill_id, create_file_registry_store, create_local_registry_client,
32    create_registry_skill_version, ingest_skill_markdown, normalize_registry_skill_version,
33    publish_skill_markdown, read_registry_skill, resolve_registry_skill, resolve_runx_link,
34    runx_link_for_version, search_registry, search_registry_with_options, slugify, split_skill_id,
35};
36pub use refs::{
37    ParsedRegistryRef, RegistryResolveError, materialization_cache_path,
38    materialization_digest_marker, parse_registry_ref, safe_skill_package_parts,
39};
40pub use source_authority::{
41    RUNX_REGISTRY_SOURCE_AUTHORITY_ENV, RegistryManifestSourceAuthority,
42    is_official_runx_registry_url, registry_manifest_source_authority_from_env,
43    registry_manifest_source_authority_from_registry_dir,
44    registry_manifest_source_authority_from_registry_url, registry_manifest_source_key,
45};
46pub use trust_anchor::{
47    REGISTRY_SIGNED_MANIFEST_SCHEMA, RUNX_REGISTRY_MANIFEST_TRUST_KEY_ENV,
48    RUNX_REGISTRY_MANIFEST_TRUST_KEY_ID_ENV, RUNX_REGISTRY_MANIFEST_TRUST_OWNER_ENV,
49    RegistryManifestKeyError, RegistryManifestTrustEnvError, RegistryManifestTrustScope,
50    RegistryManifestVerificationFailure, TrustedRegistryManifestKey,
51    default_trusted_registry_manifest_keys, registry_manifest_key_allows,
52    trusted_registry_manifest_keys_from_env, trusted_registry_manifest_keys_from_env_with_source,
53    verify_registry_signed_manifest,
54};
55pub use types::{
56    AcquiredRegistrySkill, ProfileMode, PublishSkillMarkdownResult, PublishStatus,
57    RegistryAttestation, RegistryLinkResolution, RegistryManifestSignature, RegistryManifestSigner,
58    RegistryPackageFile, RegistryPublishHarnessReport, RegistryPublisher, RegistrySearchResult,
59    RegistrySignedManifest, RegistrySkill, RegistrySkillDetail, RegistrySkillResolution,
60    RegistrySkillVersion, RegistrySourceMetadata, ResolvedRegistryRef, TrustSignal, TrustTier,
61};
62
63#[derive(Clone, Copy, Debug)]
64pub struct RegistryInstallMetadataInput<'a> {
65    pub candidate: &'a InstallCandidate,
66    pub install: &'a InstallLocalSkillResult,
67    pub acquisition: Option<&'a AcquiredRegistrySkill>,
68}
69
70#[must_use]
71pub fn registry_install_receipt_metadata(input: RegistryInstallMetadataInput<'_>) -> JsonObject {
72    let mut metadata = JsonObject::new();
73    insert_string(&mut metadata, "ref", &input.candidate.r#ref);
74    insert_optional_string(&mut metadata, "skill_id", input.install.skill_id.as_deref());
75    insert_optional_string(&mut metadata, "version", input.install.version.as_deref());
76    insert_string(&mut metadata, "digest", &input.install.digest);
77    insert_optional_string(
78        &mut metadata,
79        "profile_digest",
80        input.install.profile_digest.as_deref(),
81    );
82    insert_optional_string(
83        &mut metadata,
84        "package_digest",
85        input.candidate.package_digest.as_deref(),
86    );
87    insert_optional_string(
88        &mut metadata,
89        "trust_tier",
90        input.install.trust_tier.as_ref().map(trust_tier_value),
91    );
92    if let Some(acquisition) = input.acquisition {
93        metadata.insert(
94            "publisher".to_owned(),
95            JsonValue::Object(publisher_metadata(&acquisition.publisher)),
96        );
97        metadata.insert(
98            "install_count".to_owned(),
99            JsonValue::Number(JsonNumber::U64(acquisition.install_count)),
100        );
101    }
102    insert_string(&mut metadata, "source_label", &input.install.source_label);
103    insert_string(
104        &mut metadata,
105        "destination",
106        &input.install.destination.display().to_string(),
107    );
108    insert_string(
109        &mut metadata,
110        "status",
111        match input.install.status {
112            InstallStatus::Installed => "installed",
113            InstallStatus::Unchanged => "unchanged",
114        },
115    );
116    metadata
117}
118
119fn publisher_metadata(publisher: &RegistryPublisher) -> JsonObject {
120    let mut metadata = JsonObject::new();
121    insert_string(&mut metadata, "kind", &publisher.kind);
122    insert_string(&mut metadata, "id", &publisher.id);
123    insert_optional_string(&mut metadata, "handle", publisher.handle.as_deref());
124    insert_optional_string(
125        &mut metadata,
126        "display_name",
127        publisher.display_name.as_deref(),
128    );
129    metadata
130}
131
132fn insert_string(metadata: &mut JsonObject, key: &str, value: &str) {
133    metadata.insert(key.to_owned(), JsonValue::String(value.to_owned()));
134}
135
136fn insert_optional_string(metadata: &mut JsonObject, key: &str, value: Option<&str>) {
137    if let Some(value) = value.filter(|value| !value.trim().is_empty()) {
138        insert_string(metadata, key, value);
139    }
140}
141
142fn trust_tier_value(value: &TrustTier) -> &'static str {
143    match value {
144        TrustTier::FirstParty => "first_party",
145        TrustTier::Verified => "verified",
146        TrustTier::Community => "community",
147    }
148}