Skip to main content

runx_runtime/registry/
types.rs

1// rust-style-allow: large-file - registry wire/domain types are kept together so
2// local, hosted, install, publish, trust, and signed-manifest envelopes evolve
3// under one serialization contract.
4use runx_contracts::JsonValue;
5use runx_contracts::maturity::MaturityTier;
6use serde::{Deserialize, Serialize};
7
8#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
9pub struct RegistryLinkResolution {
10    pub link: String,
11    pub skill_id: String,
12    pub version: String,
13    pub digest: String,
14    #[serde(skip_serializing_if = "Option::is_none")]
15    pub registry_url: Option<String>,
16    pub install_command: String,
17    pub run_command: String,
18}
19
20#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
21#[serde(rename_all = "snake_case")]
22pub enum TrustTier {
23    FirstParty,
24    Verified,
25    Community,
26}
27
28#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
29#[serde(rename_all = "snake_case")]
30pub enum ProfileMode {
31    Portable,
32    Profiled,
33}
34
35#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
36pub struct RegistryPublisher {
37    pub kind: String,
38    pub id: String,
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub handle: Option<String>,
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub display_name: Option<String>,
43}
44
45#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
46pub struct RegistryManifestSigner {
47    pub id: String,
48    pub key_id: String,
49}
50
51#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
52pub struct RegistryManifestSignature {
53    pub alg: String,
54    pub value: String,
55}
56
57#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
58pub struct RegistrySignedManifest {
59    pub schema: String,
60    pub skill_id: String,
61    pub version: String,
62    pub digest: String,
63    #[serde(skip_serializing_if = "Option::is_none")]
64    pub profile_digest: Option<String>,
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub package_digest: Option<String>,
67    pub signer: RegistryManifestSigner,
68    pub signature: RegistryManifestSignature,
69}
70
71#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
72pub struct RegistryPackageFile {
73    pub path: String,
74    pub content: String,
75}
76
77#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
78pub struct RegistryAttestation {
79    pub kind: String,
80    pub id: String,
81    pub status: String,
82    pub summary: String,
83    #[serde(skip_serializing_if = "Option::is_none")]
84    pub source: Option<String>,
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub issued_at: Option<String>,
87    #[serde(skip_serializing_if = "Option::is_none")]
88    pub metadata: Option<JsonValue>,
89}
90
91#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
92pub struct RegistrySourceMetadata {
93    pub provider: String,
94    pub repo: String,
95    pub repo_url: String,
96    pub skill_path: String,
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub profile_path: Option<String>,
99    pub r#ref: String,
100    pub sha: String,
101    pub default_branch: String,
102    pub event: String,
103    pub immutable: bool,
104    pub live: bool,
105    #[serde(skip_serializing_if = "Option::is_none")]
106    pub tombstoned: Option<bool>,
107    #[serde(skip_serializing_if = "Option::is_none")]
108    pub tag: Option<String>,
109    #[serde(skip_serializing_if = "Option::is_none")]
110    pub publisher_handle: Option<String>,
111}
112
113#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
114pub struct TrustSignal {
115    pub id: String,
116    pub label: String,
117    pub status: String,
118    pub value: String,
119}
120
121#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
122pub struct RegistrySearchResult {
123    pub skill_id: String,
124    pub name: String,
125    #[serde(skip_serializing_if = "Option::is_none")]
126    pub summary: Option<String>,
127    #[serde(skip_serializing_if = "Option::is_none")]
128    pub category: Option<String>,
129    #[serde(skip_serializing_if = "Option::is_none")]
130    pub source_category: Option<String>,
131    pub owner: String,
132    #[serde(skip_serializing_if = "Option::is_none")]
133    pub version: Option<String>,
134    #[serde(skip_serializing_if = "Option::is_none")]
135    pub digest: Option<String>,
136    #[serde(skip_serializing_if = "Option::is_none")]
137    pub source: Option<String>,
138    #[serde(skip_serializing_if = "Option::is_none")]
139    pub source_label: Option<String>,
140    pub source_type: String,
141    pub profile_mode: ProfileMode,
142    pub runner_names: Vec<String>,
143    #[serde(skip_serializing_if = "Option::is_none")]
144    pub profile_digest: Option<String>,
145    #[serde(skip_serializing_if = "Option::is_none")]
146    pub profile_trust_tier: Option<TrustTier>,
147    pub required_scopes: Vec<String>,
148    pub tags: Vec<String>,
149    pub trust_tier: TrustTier,
150    #[serde(default, skip_serializing_if = "Vec::is_empty")]
151    pub trust_signals: Vec<TrustSignal>,
152    pub install_command: String,
153    pub run_command: String,
154}
155
156#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
157pub struct RegistrySkillVersion {
158    pub skill_id: String,
159    pub owner: String,
160    pub name: String,
161    #[serde(skip_serializing_if = "Option::is_none")]
162    pub description: Option<String>,
163    #[serde(skip_serializing_if = "Option::is_none")]
164    pub category: Option<String>,
165    #[serde(skip_serializing_if = "Option::is_none")]
166    pub source_category: Option<String>,
167    pub version: String,
168    pub digest: String,
169    #[serde(skip_serializing_if = "Option::is_none")]
170    pub signed_manifest: Option<RegistrySignedManifest>,
171    pub markdown: String,
172    #[serde(skip_serializing_if = "Option::is_none")]
173    pub profile_document: Option<String>,
174    #[serde(skip_serializing_if = "Option::is_none")]
175    pub profile_digest: Option<String>,
176    #[serde(default, skip_serializing_if = "Vec::is_empty")]
177    pub package_files: Vec<RegistryPackageFile>,
178    #[serde(skip_serializing_if = "Option::is_none")]
179    pub package_digest: Option<String>,
180    pub runner_names: Vec<String>,
181    pub source_type: String,
182    pub trust_tier: TrustTier,
183    #[serde(default)]
184    pub maturity: MaturityTier,
185    #[serde(skip_serializing_if = "Option::is_none")]
186    pub catalog_kind: Option<String>,
187    #[serde(skip_serializing_if = "Option::is_none")]
188    pub catalog_audience: Option<String>,
189    #[serde(skip_serializing_if = "Option::is_none")]
190    pub catalog_visibility: Option<String>,
191    #[serde(skip_serializing_if = "Option::is_none")]
192    pub source_metadata: Option<RegistrySourceMetadata>,
193    #[serde(default, skip_serializing_if = "Vec::is_empty")]
194    pub attestations: Vec<RegistryAttestation>,
195    pub required_scopes: Vec<String>,
196    #[serde(skip_serializing_if = "Option::is_none")]
197    pub runtime: Option<JsonValue>,
198    #[serde(skip_serializing_if = "Option::is_none")]
199    pub auth: Option<JsonValue>,
200    #[serde(skip_serializing_if = "Option::is_none")]
201    pub risk: Option<JsonValue>,
202    #[serde(skip_serializing_if = "Option::is_none")]
203    pub runx: Option<runx_contracts::JsonObject>,
204    pub tags: Vec<String>,
205    pub publisher: RegistryPublisher,
206    pub created_at: String,
207    pub updated_at: String,
208}
209
210#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
211pub struct RegistrySkill {
212    pub skill_id: String,
213    pub owner: String,
214    pub name: String,
215    #[serde(skip_serializing_if = "Option::is_none")]
216    pub description: Option<String>,
217    #[serde(skip_serializing_if = "Option::is_none")]
218    pub category: Option<String>,
219    #[serde(skip_serializing_if = "Option::is_none")]
220    pub source_category: Option<String>,
221    pub latest_version: String,
222    pub latest_digest: String,
223    pub versions: Vec<RegistrySkillVersion>,
224}
225
226#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
227pub struct RegistrySkillResolution {
228    pub markdown: String,
229    #[serde(skip_serializing_if = "Option::is_none")]
230    pub profile_document: Option<String>,
231    #[serde(skip_serializing_if = "Option::is_none")]
232    pub profile_digest: Option<String>,
233    #[serde(default, skip_serializing_if = "Vec::is_empty")]
234    pub package_files: Vec<RegistryPackageFile>,
235    #[serde(skip_serializing_if = "Option::is_none")]
236    pub package_digest: Option<String>,
237    pub runner_names: Vec<String>,
238    pub skill_id: String,
239    pub name: String,
240    pub version: String,
241    pub digest: String,
242    #[serde(skip_serializing_if = "Option::is_none")]
243    pub signed_manifest: Option<RegistrySignedManifest>,
244    pub source: String,
245    pub source_label: String,
246    pub source_type: String,
247    pub trust_tier: TrustTier,
248    #[serde(skip_serializing_if = "Option::is_none")]
249    pub registry_url: Option<String>,
250    pub install_command: String,
251    pub run_command: String,
252}
253
254#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
255pub struct PublishSkillMarkdownResult {
256    pub status: PublishStatus,
257    pub skill_id: String,
258    pub name: String,
259    pub version: String,
260    pub digest: String,
261    #[serde(skip_serializing_if = "Option::is_none")]
262    pub signed_manifest: Option<RegistrySignedManifest>,
263    #[serde(skip_serializing_if = "Option::is_none")]
264    pub profile_digest: Option<String>,
265    pub runner_names: Vec<String>,
266    pub source_type: String,
267    #[serde(skip_serializing_if = "Option::is_none")]
268    pub registry_url: Option<String>,
269    #[serde(default)]
270    pub harness: RegistryPublishHarnessReport,
271    pub link: RegistryLinkResolution,
272    pub record: RegistrySkillVersion,
273}
274
275#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
276pub struct RegistryPublishHarnessReport {
277    pub status: String,
278    pub case_count: usize,
279    pub assertion_error_count: usize,
280    pub assertion_errors: Vec<String>,
281    pub case_names: Vec<String>,
282    pub receipt_ids: Vec<String>,
283    pub graph_case_count: usize,
284}
285
286impl RegistryPublishHarnessReport {
287    #[must_use]
288    pub fn not_declared() -> Self {
289        Self {
290            status: "not_declared".to_owned(),
291            case_count: 0,
292            assertion_error_count: 0,
293            assertion_errors: Vec::new(),
294            case_names: Vec::new(),
295            receipt_ids: Vec::new(),
296            graph_case_count: 0,
297        }
298    }
299
300    #[must_use]
301    pub fn failed(&self) -> bool {
302        self.status == "failed"
303    }
304}
305
306impl Default for RegistryPublishHarnessReport {
307    fn default() -> Self {
308        Self::not_declared()
309    }
310}
311
312#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
313#[serde(rename_all = "snake_case")]
314pub enum PublishStatus {
315    Published,
316    Unchanged,
317}
318
319#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
320pub struct RegistrySkillDetail {
321    pub skill_id: String,
322    pub owner: String,
323    pub name: String,
324    #[serde(skip_serializing_if = "Option::is_none")]
325    pub description: Option<String>,
326    #[serde(skip_serializing_if = "Option::is_none")]
327    pub category: Option<String>,
328    #[serde(skip_serializing_if = "Option::is_none")]
329    pub source_category: Option<String>,
330    pub version: String,
331    pub digest: String,
332    #[serde(skip_serializing_if = "Option::is_none")]
333    pub signed_manifest: Option<RegistrySignedManifest>,
334    pub markdown: String,
335    #[serde(skip_serializing_if = "Option::is_none")]
336    pub profile_digest: Option<String>,
337    #[serde(default, skip_serializing_if = "Vec::is_empty")]
338    pub package_files: Vec<RegistryPackageFile>,
339    #[serde(skip_serializing_if = "Option::is_none")]
340    pub package_digest: Option<String>,
341    pub runner_names: Vec<String>,
342    pub source_type: String,
343    pub trust_tier: TrustTier,
344    pub required_scopes: Vec<String>,
345    pub tags: Vec<String>,
346    pub publisher: RegistryPublisher,
347    #[serde(skip_serializing_if = "Option::is_none")]
348    pub source_metadata: Option<RegistrySourceMetadata>,
349    pub attestations: Vec<RegistryAttestation>,
350    pub install_command: String,
351    pub run_command: String,
352}
353
354#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
355pub struct AcquiredRegistrySkill {
356    pub skill_id: String,
357    pub owner: String,
358    pub name: String,
359    pub version: String,
360    pub digest: String,
361    #[serde(skip_serializing_if = "Option::is_none")]
362    pub signed_manifest: Option<RegistrySignedManifest>,
363    pub markdown: String,
364    #[serde(skip_serializing_if = "Option::is_none")]
365    pub profile_document: Option<String>,
366    #[serde(skip_serializing_if = "Option::is_none")]
367    pub profile_digest: Option<String>,
368    #[serde(default, skip_serializing_if = "Vec::is_empty")]
369    pub package_files: Vec<RegistryPackageFile>,
370    #[serde(skip_serializing_if = "Option::is_none")]
371    pub package_digest: Option<String>,
372    pub runner_names: Vec<String>,
373    pub trust_tier: TrustTier,
374    pub publisher: RegistryPublisher,
375    #[serde(skip_serializing_if = "Option::is_none")]
376    pub source_metadata: Option<RegistrySourceMetadata>,
377    pub attestations: Vec<RegistryAttestation>,
378    pub install_count: u64,
379}
380
381#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
382pub struct ResolvedRegistryRef {
383    pub skill_id: String,
384    pub version: Option<String>,
385}