Skip to content
640 changes: 580 additions & 60 deletions elastos/crates/elastos-runtime/src/provider/bridge.rs

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
fn main() {
let paths = std::env::args_os().skip(1).collect::<Vec<_>>();
if paths.first().is_some_and(|path| path == "--child") {
return;
}
for path in paths {
if std::fs::canonicalize(path).is_err() {
std::process::exit(1);
}
}
let result = std::process::Command::new(std::env::current_exe().unwrap())
.arg("--child")
.stdin(std::process::Stdio::piped())
.stdout(std::process::Stdio::null())
.stderr(std::process::Stdio::null())
.spawn();
let Ok(mut child) = result else {
std::process::exit(2);
};
if !child.wait().is_ok_and(|status| status.success()) {
std::process::exit(2);
}
}
189 changes: 189 additions & 0 deletions elastos/crates/elastos-runtime/tests/fixtures/model_seatbelt_probe.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
#include <arpa/inet.h>
#include <errno.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>

static int opened(const char *path, int flags) {
int fd = open(path, flags);
if (fd < 0) return errno;
close(fd);
return 0;
}

static int inet_result(const char *ip, unsigned short port) {
int fd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in addr = {.sin_family = AF_INET, .sin_port = htons(port)};
inet_pton(AF_INET, ip, &addr.sin_addr);
int result = connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0 ? 0 : errno;
close(fd);
return result;
}

static int unix_result(const char *path) {
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un addr = {.sun_family = AF_UNIX};
snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", path);
int result = connect(fd, (struct sockaddr *)&addr, sizeof(addr)) == 0 ? 0 : errno;
close(fd);
return result;
}

int main(void) {
int inherited_writable_regular_fds = 0;
for (int fd = 3; fd < 256; fd++) {
struct stat metadata;
int flags = fcntl(fd, F_GETFL);
if (flags >= 0 && fstat(fd, &metadata) == 0 && S_ISREG(metadata.st_mode) &&
(flags & O_ACCMODE) != O_RDONLY) inherited_writable_regular_fds++;
}
char line[8192];
while (fgets(line, sizeof(line), stdin)) {
if (strstr(line, "\"op\":\"init\"")) {
puts("{\"status\":\"ok\"}"); fflush(stdout);
continue;
}
if (strstr(line, "\"op\":\"shutdown\"")) {
puts("{\"status\":\"ok\"}"); fflush(stdout);
return 0;
}
char *field = strstr(line, "\"path\":\"");
if (!field) return 2;
field += strlen("\"path\":\"");
char *end = strchr(field, '"');
if (!end) return 3;
*end = 0;
char *save = NULL;
char *selected = strtok_r(field, "|", &save);
char *port_text = strtok_r(NULL, "|", &save);
char *other = strtok_r(NULL, "|", &save);
char *model = strtok_r(NULL, "|", &save);
char *canary = strtok_r(NULL, "|", &save);
char *journal = strtok_r(NULL, "|", &save);
char *base = strtok_r(NULL, "|", &save);
if (!selected || !port_text || !other || !model || !canary || !journal || !base) return 4;
char resolved[4096];
int base_canonical = realpath(base, resolved) ? 0 : errno;
unsigned short port = (unsigned short)strtoul(port_text, NULL, 10);
int external = inet_result("203.0.113.1", 443);
int unrelated = inet_result("127.0.0.1", port);
int other_socket = unix_result(other);
int selected_socket = unix_result(selected);
char engine_socket[4096];
snprintf(engine_socket, sizeof(engine_socket), "%.*s.engine.sock",
(int)strlen(selected) - 5, selected);
struct stat engine_metadata;
int engine_preflight = lstat(engine_socket, &engine_metadata) == 0 ? 0 : errno;
int engine_fd = socket(AF_UNIX, SOCK_STREAM, 0);
struct sockaddr_un engine_addr = {.sun_family = AF_UNIX};
snprintf(engine_addr.sun_path, sizeof(engine_addr.sun_path), "%s", engine_socket);
int engine_bind = bind(engine_fd, (struct sockaddr *)&engine_addr,
sizeof(engine_addr)) == 0 ? 0 : errno;
int engine_stat = lstat(engine_socket, &engine_metadata) == 0 ? 0 : errno;
int engine_unlink = unlink(engine_socket) == 0 ? 0 : errno;
close(engine_fd);
int system_read = opened("/usr/bin", O_RDONLY);
int canary_read = opened(canary, O_RDONLY);
char data_alias[4096];
snprintf(data_alias, sizeof(data_alias), "/System/Volumes/Data%s", canary);
int data_alias_read = opened(data_alias, O_RDONLY);
int model_read = opened(model, O_RDONLY);
char namespace_probe[4096];
snprintf(namespace_probe, sizeof(namespace_probe), "%s/model-preparation/stage/canary", base);
int stage_read = opened(namespace_probe, O_RDONLY);
snprintf(namespace_probe, sizeof(namespace_probe), "%s/model-preparation/state.json", base);
int inventory_read = opened(namespace_probe, O_RDONLY);
snprintf(namespace_probe, sizeof(namespace_probe), "%s/model-preparation/worker", base);
int worker_read = opened(namespace_probe, O_RDONLY);
snprintf(namespace_probe, sizeof(namespace_probe), "%s/libexec/llama.cpp/fixture/darwin-arm64/late-engine", base);
int late_engine_read = opened(namespace_probe, O_RDONLY);
int late_engine_write = opened(namespace_probe, O_WRONLY | O_TRUNC);
snprintf(namespace_probe, sizeof(namespace_probe), "%s.external", model);
int admitted_alias_read = opened(namespace_probe, O_RDONLY);
snprintf(namespace_probe, sizeof(namespace_probe), "%s/model-preparation/admitted-%063d/canary", base, 0);
int short_admission_read = opened(namespace_probe, O_RDONLY);
snprintf(namespace_probe, sizeof(namespace_probe), "%s/model-preparation/admitted-%064d-extra/canary", base, 0);
int suffixed_admission_read = opened(namespace_probe, O_RDONLY);
snprintf(namespace_probe, sizeof(namespace_probe), "%s/libexec/llama.cpp/other/darwin-arm64/canary", base);
int other_engine_read = opened(namespace_probe, O_RDONLY);
int model_write = opened(model, O_WRONLY | O_TRUNC);
char alias[4096];
snprintf(alias, sizeof(alias), "%s/probe-link", journal);
int model_link = link(model, alias) == 0 ? 0 : errno;
snprintf(alias, sizeof(alias), "%s/probe-symlink", journal);
int symlink_create = symlink(model, alias) == 0 ? 0 : errno;
int alias_write = opened(alias, O_WRONLY | O_TRUNC);
snprintf(alias, sizeof(alias), "%s/probe-write", journal);
int journal_write = opened(alias, O_WRONLY | O_CREAT | O_EXCL);
int pipes[2];
if (pipe(pipes) != 0) return 5;
pid_t pid = fork();
if (pid < 0) return 6;
if (pid == 0) {
close(pipes[0]);
char child_alias[4096];
snprintf(child_alias, sizeof(child_alias), "%s/child-link", journal);
int child_link = link(model, child_alias) == 0 ? 0 : errno;
snprintf(child_alias, sizeof(child_alias), "%s/child-moved", journal);
int child_rename = rename(model, child_alias) == 0 ? 0 : errno;
int descendant[9] = {inet_result("203.0.113.1", 443),
inet_result("127.0.0.1", port), unix_result(other),
unix_result(selected), opened("/usr/bin", O_RDONLY),
opened(canary, O_RDONLY),
opened(model, O_WRONLY | O_TRUNC), child_link,
child_rename};
int wrote = (int)write(pipes[1], descendant, sizeof(descendant));
_exit(wrote == sizeof(descendant) ? 0 : 7);
}
close(pipes[1]);
int descendant[9] = {0};
if (read(pipes[0], descendant, sizeof(descendant)) != sizeof(descendant)) return 8;
close(pipes[0]);
int status;
if (waitpid(pid, &status, 0) != pid || !WIFEXITED(status) || WEXITSTATUS(status)) return 9;
snprintf(alias, sizeof(alias), "%s/probe-moved", journal);
int model_rename = rename(model, alias) == 0 ? 0 : errno;
printf("{\"status\":\"ok\",\"data\":{\"direct_errno\":%d,\"descendant_errno\":%d,"
"\"unrelated_errno\":%d,\"descendant_unrelated_errno\":%d,"
"\"other_socket_errno\":%d,\"descendant_other_socket_errno\":%d,"
"\"selected_socket_errno\":%d,"
"\"descendant_selected_socket_errno\":%d,\"system_read_errno\":%d,"
"\"descendant_system_read_errno\":%d,\"canary_read_errno\":%d,"
"\"descendant_canary_read_errno\":%d,\"model_read_errno\":%d,"
"\"model_write_errno\":%d,\"descendant_model_write_errno\":%d,"
"\"model_link_errno\":%d,\"descendant_model_link_errno\":%d,"
"\"model_rename_errno\":%d,\"descendant_model_rename_errno\":%d,"
"\"journal_alias_create_errno\":%d,\"journal_alias_write_errno\":%d,"
"\"journal_write_errno\":%d,\"base_canonical_errno\":%d,"
"\"engine_preflight_errno\":%d,\"engine_bind_errno\":%d,"
"\"engine_stat_errno\":%d,\"engine_unlink_errno\":%d,"
"\"stage_read_errno\":%d,\"inventory_read_errno\":%d,"
"\"worker_read_errno\":%d,\"late_engine_read_errno\":%d,"
"\"other_engine_read_errno\":%d,"
"\"late_engine_write_errno\":%d,\"admitted_alias_read_errno\":%d,"
"\"short_admission_read_errno\":%d,\"suffixed_admission_read_errno\":%d,"
"\"data_alias_read_errno\":%d,"
"\"inherited_writable_regular_fds\":%d}}\n",
external, descendant[0], unrelated, descendant[1], other_socket,
descendant[2], selected_socket, descendant[3], system_read,
descendant[4], canary_read, descendant[5], model_read, model_write,
descendant[6], model_link, descendant[7], model_rename, descendant[8],
symlink_create, alias_write, journal_write, base_canonical,
engine_preflight, engine_bind, engine_stat, engine_unlink,
stage_read, inventory_read, worker_read, late_engine_read,
other_engine_read,
late_engine_write, admitted_alias_read,
short_admission_read, suffixed_admission_read,
data_alias_read,
inherited_writable_regular_fds);
fflush(stdout);
}
return 0;
}
6 changes: 5 additions & 1 deletion elastos/crates/elastos-server/src/api/capsule_inventory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,11 @@ struct ModelCatalogEntry {
object_manifest: Value,
}

fn read_model_catalog_file(data_dir: &Path, name: &str, limit: usize) -> anyhow::Result<Vec<u8>> {
pub(crate) fn read_model_catalog_file(
data_dir: &Path,
name: &str,
limit: usize,
) -> anyhow::Result<Vec<u8>> {
let root = std::fs::symlink_metadata(data_dir)?;
if !root.is_dir() || root.file_type().is_symlink() {
anyhow::bail!("model catalog requires a real data directory");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const MAX_RECORDS: usize = 64;
const RESERVATION_SECONDS: u64 = 3600;
const MAX_PACKAGE_BYTES: u64 = 16 * 1024 * 1024 * 1024;
const CAPACITY_WINDOW_BYTES: u64 = 1024 * 1024;
const ADMITTED_MODEL_CONTEXT_SIZE: u32 = 4096;

// Static checkpoints retain a useful cause after cleanup without retaining
// provider text, host paths, credentials or media bytes in the inventory.
Expand Down Expand Up @@ -2285,7 +2286,7 @@ fn local_model_startup_profile(platform: &str) -> anyhow::Result<serde_json::Val
_ => anyhow::bail!("admitted model host profile is unavailable"),
};
Ok(serde_json::json!({
"context_size":4096, "parallel":1, "threads":threads, "batch_threads":threads,
"context_size":ADMITTED_MODEL_CONTEXT_SIZE, "parallel":1, "threads":threads, "batch_threads":threads,
"gpu_layers":gpu_layers, "health_timeout_ms":120000,
"shutdown_timeout_ms":5000, "enable_thinking":false
}))
Expand Down Expand Up @@ -2442,7 +2443,8 @@ impl ModelActivation {
}

// The saved activation binds execution identity and policy. The live provider
// owns wire-schema capabilities; old descriptors keep their original bytes.
// owns wire-schema capabilities and reports context limits for that profile;
// old descriptors keep their original bytes.
fn model_offer_matches(actual: &serde_json::Value, expected: &serde_json::Value) -> bool {
let mut identity = actual.clone();
let Some(object) = identity.as_object_mut() else {
Expand All @@ -2466,6 +2468,18 @@ fn model_offer_matches(actual: &serde_json::Value, expected: &serde_json::Value)
return false;
}
}
if let Some(context) = object.remove("context") {
// Every admitted startup profile has one slot. These public limits
// describe its settings without adding fields to the saved descriptor.
if context
!= serde_json::json!({
"context_window_tokens":ADMITTED_MODEL_CONTEXT_SIZE,
"max_output_tokens":(ADMITTED_MODEL_CONTEXT_SIZE / 4).clamp(1, 1024)
})
{
return false;
}
}
identity == *expected
}

Expand Down Expand Up @@ -3576,9 +3590,25 @@ mod tests {
let mut live = expected.clone();
live["input_schemas"] = schemas;
assert!(model_offer_matches(&live, &expected));
live["context"] = serde_json::json!({
"context_window_tokens":4096,"max_output_tokens":1024
});
assert!(model_offer_matches(&live, &expected));
live["policy"]["input_bytes_limit"] = serde_json::json!(1);
assert!(!model_offer_matches(&live, &expected));
}
for context in [
serde_json::json!(null),
serde_json::json!({}),
serde_json::json!({"context_window_tokens":8192,"max_output_tokens":1024}),
serde_json::json!({"context_window_tokens":4096,"max_output_tokens":4096}),
serde_json::json!({"context_window_tokens":"4096","max_output_tokens":1024}),
serde_json::json!({"context_window_tokens":4096,"max_output_tokens":1024,"adapter":{}}),
] {
let mut live = expected.clone();
live["context"] = context;
assert!(!model_offer_matches(&live, &expected));
}
for schemas in [
serde_json::json!([]),
serde_json::json!(null),
Expand Down Expand Up @@ -3624,6 +3654,9 @@ mod tests {
elastos_model_contract::TEXT_INPUT_V2_SCHEMA
]);
offer["policy"]["schema"] = serde_json::json!("elastos.model.policy/v1");
offer["context"] = serde_json::json!({
"context_window_tokens":4096,"max_output_tokens":1024
});
let mut response = serde_json::json!({"status":"ok", "data":{
"schema":"elastos.model.offers-list/v1", "provider":"model-provider",
"protocol_version":"elastos.model-provider/v1",
Expand Down Expand Up @@ -3781,6 +3814,9 @@ mod tests {
elastos_model_contract::TEXT_INPUT_V2_SCHEMA
]);
offer["policy"]["schema"] = serde_json::json!("elastos.model.policy/v1");
offer["context"] = serde_json::json!({
"context_window_tokens":4096,"max_output_tokens":1024
});
let mut response = serde_json::json!({"status":"ok", "data":{
"schema":"elastos.model.offers-list/v1", "provider":"model-provider",
"protocol_version":"elastos.model-provider/v1", "offers":[offer.clone()],
Expand Down Expand Up @@ -5763,6 +5799,9 @@ mod tests {
Some(&record.operation_id),
)
.await;
// Explicit Use keeps A. Release that intent before capacity pressure
// may select A for retirement after the catalog moves to B.
retention_intent(root.path(), &context(), &record.package_cid, false).unwrap();
// A remains active in this real provider after the one-entry signed
// catalog moves to B. Its retirement cannot use B's catalog facts.
let (mut next_catalog, _) = package_fixture(b"GGUF\x03\0\0\0fixture".to_vec());
Expand Down Expand Up @@ -6686,6 +6725,11 @@ class Handler(http.server.BaseHTTPRequestHandler):
self.wfile.write(json.dumps(body).encode())
def do_POST(self):
body = json.loads(self.rfile.read(int(self.headers['Content-Length'])))
if self.path == '/v1/chat/completions/input_tokens':
self.send_response(200)
self.end_headers()
self.wfile.write(json.dumps({'input_tokens': 1}).encode())
return
assert self.path == '/v1/chat/completions' and body['model'] == alias
assert body['chat_template_kwargs'] == {'enable_thinking': False}
prompt = body['messages'][0]['content']
Expand Down Expand Up @@ -6873,6 +6917,8 @@ server.serve_forever()
)
.await
.unwrap();
// Let pressure reach the unknown-run gate rather than the Keep gate.
retention_intent(root.path(), &context(), &record.package_cid, false).unwrap();
let (mut next_catalog, _) = package_fixture(b"GGUF\x03\0\0\0fixture".to_vec());
let next_cid = "bafybeihgnsjhpoktqbyspaqv6moblyny3txs5nkjdxfx7wm346odxkhlrm";
next_catalog["entries"][0]["cid"] = serde_json::json!(next_cid);
Expand Down
2 changes: 2 additions & 0 deletions elastos/crates/elastos-server/src/api/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ mod model_provider_config;
pub mod model_provider_egress;
#[cfg(unix)]
mod model_provider_egress_decision;
#[cfg(target_os = "macos")]
pub use model_provider_config::model_provider_engine_bundle;
#[cfg(test)]
pub(crate) use model_provider_config::seed_model_provider_operator_offers_for_test;
pub(crate) use model_provider_config::{
Expand Down
13 changes: 13 additions & 0 deletions elastos/crates/elastos-server/src/api/model_provider_config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,19 @@ fn model_provider_journal_dir(data_dir: &Path) -> PathBuf {
model_provider_root_dir(data_dir).join("journal")
}

/// Declare the installed component's engine read boundary for macOS startup.
/// Activation still verifies its full receipt and payload closure before Init.
#[cfg(target_os = "macos")]
pub fn model_provider_engine_bundle(data_dir: &Path) -> anyhow::Result<Option<PathBuf>> {
let bytes = super::capsule_inventory::read_model_catalog_file(
data_dir,
"components.json",
4 * 1024 * 1024,
)?;
let manifest = serde_json::from_slice(&bytes)?;
crate::setup::local_model_engine_confinement_bundle(data_dir, &manifest)
}

pub fn model_provider_bridge_config(
data_dir: &Path,
) -> anyhow::Result<provider::BridgeProviderConfig> {
Expand Down
Loading
Loading