Skip to main content

mur_common/deps/
registry.rs

1//! MUR-curated program registry. URLs + pinned SHA-256 are MUR-owned, so a
2//! shared bundle can only *reference* a key — it cannot substitute the source.
3
4use serde::{Deserialize, Serialize};
5use std::collections::BTreeMap;
6
7const MANIFEST: &str = include_str!("registry_manifest.yaml");
8
9#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
10pub struct CuratedRecipe {
11    #[serde(default)]
12    pub description: String,
13    pub url: String,
14    pub sha256: String,
15    /// For a bare-binary recipe; `None` when `archive` is set.
16    #[serde(default)]
17    pub install_to: Option<String>,
18    #[serde(default)]
19    pub executable: bool,
20    /// For a multi-file tarball (e.g. obscura's two binaries).
21    #[serde(default)]
22    pub archive: Option<ArchiveSpec>,
23}
24
25#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
26pub struct ArchiveSpec {
27    pub members: Vec<RecipeMember>,
28}
29
30#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, schemars::JsonSchema)]
31pub struct RecipeMember {
32    pub path_in_archive: String,
33    pub install_to: String,
34    #[serde(default)]
35    pub executable: bool,
36}
37
38#[derive(Debug, Deserialize)]
39struct Entry {
40    #[serde(default)]
41    description: String,
42    platforms: BTreeMap<String, PlatformRaw>,
43}
44
45#[derive(Debug, Deserialize)]
46struct PlatformRaw {
47    url: String,
48    sha256: String,
49    #[serde(default)]
50    install_to: Option<String>,
51    #[serde(default)]
52    executable: bool,
53    #[serde(default)]
54    archive: Option<ArchiveSpec>,
55}
56
57fn load() -> BTreeMap<String, Entry> {
58    serde_yaml::from_str(MANIFEST).expect("embedded registry_manifest.yaml is valid")
59}
60
61/// Resolve a curated recipe for `key` on `platform` (`<arch>-<os>`).
62pub fn recipe(key: &str, platform: &str) -> Option<CuratedRecipe> {
63    let map = load();
64    let entry = map.get(key)?;
65    let p = entry.platforms.get(platform)?;
66    Some(CuratedRecipe {
67        description: entry.description.clone(),
68        url: p.url.clone(),
69        sha256: p.sha256.clone(),
70        install_to: p.install_to.clone(),
71        executable: p.executable,
72        archive: p.archive.clone(),
73    })
74}
75
76/// True if `key` names a curated program (on any platform).
77pub fn is_curated(key: &str) -> bool {
78    load().contains_key(key)
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84
85    #[test]
86    fn lightpanda_recipe_resolves_per_platform() {
87        let r = recipe("lightpanda", "aarch64-macos");
88        assert!(r.is_some(), "lightpanda/aarch64-macos should exist");
89        let r = r.unwrap();
90        assert!(!r.url.is_empty() && r.sha256.len() == 64);
91        assert!(
92            r.install_to
93                .as_ref()
94                .map_or(false, |p| p.starts_with("aura/"))
95        );
96        assert!(is_curated("lightpanda"));
97        assert!(!is_curated("totally-unknown-key"));
98        assert!(recipe("lightpanda", "sparc-solaris").is_none());
99    }
100
101    #[test]
102    fn obscura_recipe_is_an_archive_with_two_members() {
103        let r = recipe("obscura", "aarch64-macos").expect("obscura/aarch64-macos");
104        let a = r.archive.expect("obscura ships an archive");
105        assert_eq!(a.members.len(), 2, "obscura + obscura-worker");
106        assert!(a.members.iter().any(|m| m.install_to == "aura/obscura"));
107        assert!(
108            a.members
109                .iter()
110                .any(|m| m.install_to == "aura/obscura-worker")
111        );
112    }
113}