Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 0 additions & 10 deletions components.json
Original file line number Diff line number Diff line change
Expand Up @@ -1759,15 +1759,5 @@
"llama-server"
]
}
},
"model_catalog": {
"head_cid": "bafkreigidvbvotnjdljhqmao3jmtgdh56h6wveso6lv7mnsyvmhcmhjpfq",
"publisher_dids": [
"did:key:z6Mkjg9duxEF2nskEPR9F38eSfrY6F1GyWUq5aDbgsMqgcjA"
],
"local_use": {
"max_cache_bytes": 21474836480,
"max_model_memory_bytes": 8589934592
}
}
}
241 changes: 0 additions & 241 deletions docs/MODEL_PACKAGE_HANDOFF.md

This file was deleted.

11 changes: 11 additions & 0 deletions elastos/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,19 @@ All notable changes to the public ElastOS Runtime repository.

## [Unreleased]

### Removed

- Releases no longer pin or carry a model catalogue; with no pin, Home shows no
published models. Removed the model CAR retention and import path from release
preparation, signing and publication, `model-package-handoff.py`,
`fetch-model.sh` and their tests. Models return later as a separate signed
publication.

### Fixed

- Setup reads a pinned model catalogue over Carrier with its 128 KiB bound and
refuses a larger declared size before reading the body.

- Setup accepts passive content capsules from the signed release while retaining
provider role and icon checks. It refuses URL-only downloads and blank release
paths, including entries that also contain a CID. Explicit CID-only operator
Expand Down
34 changes: 1 addition & 33 deletions elastos/crates/elastos-server/src/api/capsule_inventory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ pub(in crate::api) mod preparation;
const DEV_CAPSULES_ROOT: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/../../../capsules");
const MODEL_CATALOG_FILE: &str = "model-catalog.json";
const MODEL_CATALOG_DOMAIN: &str = "elastos.model.catalog.v1";
const MAX_MODEL_CATALOG_BYTES: usize = 128 * 1024;
pub(crate) const MAX_MODEL_CATALOG_BYTES: usize = 128 * 1024;
const MAX_MODEL_CATALOG_ENTRIES: usize = 8;

pub(crate) struct VerifiedModelCatalogEntry {
Expand Down Expand Up @@ -834,36 +834,4 @@ pub(crate) mod tests {
BTreeSet::from(["object-provider".to_string()])
);
}

#[test]
fn checkout_permanent_catalog_matches_components_pin() {
let root = PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../../");
let components: crate::setup::ComponentsManifest =
serde_json::from_slice(&std::fs::read(root.join("components.json")).unwrap()).unwrap();
let trust = components
.model_catalog
.expect("matching install pins a signed model catalog");
let bytes = std::fs::read(root.join(MODEL_CATALOG_FILE)).unwrap();
let now = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
let entries = verify_model_catalog(&trust, &bytes, now).unwrap();
assert_eq!(entries.len(), 2);
assert_eq!(
entries[0].cid,
"bafybeid5l7gfgsqy2wozia2q7mtyux2wrbnlfehzz4at3ic3cngvyku6hi"
);
assert_eq!(entries[0].manifest.name, "qwen3-5-9b-q4-k-m-local");
assert_eq!(
entries[1].cid,
"bafybeidy5kfvqwg6g6pfgdfwslmhijosbeskt5b2duqdqxnc7e6fwmr72y"
);
assert_eq!(entries[1].manifest.name, "smollm2-135m-instruct-q8-0-local");
assert_eq!(
entries[0].publisher_did,
"did:key:z6Mkjg9duxEF2nskEPR9F38eSfrY6F1GyWUq5aDbgsMqgcjA"
);
assert_eq!(entries[1].publisher_did, entries[0].publisher_did);
}
}
25 changes: 19 additions & 6 deletions elastos/crates/elastos-server/src/carrier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8275,14 +8275,22 @@ impl CarrierClient {
}

pub async fn fetch_file(&self, path: &str) -> Result<Vec<u8>> {
self.fetch_file_bounded(path, 200 * 1024 * 1024).await
}

pub(crate) async fn fetch_file_bounded(&self, path: &str, max_bytes: usize) -> Result<Vec<u8>> {
let (mut send, mut recv) = self.conn.open_bi().await?;
let msg = serde_json::json!({"op":"file","path":path});
let mut bytes = serde_json::to_vec(&msg)?;
bytes.push(b'\n');
send.write_all(&bytes).await?;
send.finish()?;
read_carrier_len_prefixed_bytes(&mut recv, &format!("trusted source file fetch for {path}"))
.await
read_carrier_len_prefixed_bytes(
&mut recv,
&format!("trusted source file fetch for {path}"),
max_bytes,
)
.await
}

pub async fn fetch_content(&self, cid: &str, path: Option<&str>) -> Result<Vec<u8>> {
Expand All @@ -8298,7 +8306,7 @@ impl CarrierClient {
bytes.push(b'\n');
send.write_all(&bytes).await?;
send.finish()?;
read_carrier_len_prefixed_bytes(&mut recv, "content fetch").await
read_carrier_len_prefixed_bytes(&mut recv, "content fetch", 200 * 1024 * 1024).await
}

pub async fn invoke_provider(
Expand Down Expand Up @@ -8427,11 +8435,12 @@ impl CarrierClient {
async fn read_carrier_len_prefixed_bytes(
recv: &mut iroh::endpoint::RecvStream,
operation: &str,
max_bytes: usize,
) -> Result<Vec<u8>> {
let mut len_buf = [0u8; 8];
recv.read_exact(&mut len_buf).await?;
let len = u64::from_be_bytes(len_buf) as usize;
if len > 200 * 1024 * 1024 {
let len = u64::from_be_bytes(len_buf);
if len_buf[0] == b'{' {
let mut error_bytes = len_buf.to_vec();
let tail = recv.read_to_end(16 * 1024).await?;
error_bytes.extend_from_slice(&tail);
Expand All @@ -8447,7 +8456,11 @@ async fn read_carrier_len_prefixed_bytes(
}
anyhow::bail!("{operation} returned invalid byte reply ({len} bytes declared)");
}
let mut content = vec![0u8; len];
anyhow::ensure!(
len <= max_bytes as u64,
"{operation} exceeds its {max_bytes}-byte bound ({len} bytes declared)"
);
let mut content = vec![0u8; len as usize];
recv.read_exact(&mut content).await?;
Ok(content)
}
Expand Down
Loading
Loading