Skip to main content

extract_candid/
extract_candid.rs

1//! Explicitly admitted extractor with bounded input/output and no file publication.
2
3#[cfg(unix)]
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    use ic_host_tools::{
6        candid::extract,
7        tool::{AdmittedTool, ExecutionContext, OutputLimits, ToolSpec},
8    };
9    use std::{
10        ffi::OsString,
11        io::{self, Write as _},
12        path::PathBuf,
13        time::Duration,
14    };
15
16    let mut args = std::env::args_os().skip(1);
17    let mut required = || {
18        args.next().ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "usage: extract_candid TOOL SHA256 VERSION WASM WORKDIR MAX_TOOL_BYTES MAX_WASM_BYTES MAX_STDOUT_BYTES MAX_STDERR_BYTES TIMEOUT_MS"))
19    };
20    let executable = PathBuf::from(required()?);
21    let digest = required()?
22        .into_string()
23        .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "digest must be UTF-8"))?
24        .parse()?;
25    let version = required()?
26        .into_string()
27        .map_err(|_| io::Error::new(io::ErrorKind::InvalidInput, "version must be UTF-8"))?;
28    let source = PathBuf::from(required()?);
29    let directory = PathBuf::from(required()?);
30    let mut number = || -> Result<u64, Box<dyn std::error::Error>> {
31        Ok(required()?
32            .to_str()
33            .ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "limits must be UTF-8"))?
34            .parse()?)
35    };
36    let executable_bytes = number()?;
37    let source_bytes = number()?;
38    let limits = OutputLimits {
39        stdout_bytes: usize::try_from(number()?)?,
40        stderr_bytes: usize::try_from(number()?)?,
41        timeout: Duration::from_millis(number()?),
42    };
43    if args.next().is_some() {
44        return Err(io::Error::new(io::ErrorKind::InvalidInput, "unexpected argument").into());
45    }
46    // This example selects a credential-free empty environment explicitly.
47    let context = ExecutionContext {
48        current_dir: &directory,
49        environment: &[],
50    };
51    let tool = AdmittedTool::admit(
52        &ToolSpec {
53            executable: &executable,
54            sha256: digest,
55            executable_bytes,
56            version_arguments: &[OsString::from("--version")],
57            version_identity: &version,
58        },
59        &context,
60        limits,
61    )?;
62    let candid = extract(&tool, &source, &context, source_bytes, limits)?;
63    io::stdout().lock().write_all(candid.text.as_bytes())?;
64    Ok(())
65}
66
67#[cfg(not(unix))]
68fn main() -> Result<(), std::io::Error> {
69    Err(std::io::Error::new(
70        std::io::ErrorKind::Unsupported,
71        "verified extractor execution requires a supported Unix host",
72    ))
73}