pub struct AdmittedTool { /* private fields */ }Expand description
An executable with a retained byte identity and an admitted exact version.
Self::admit requires a consumer-supplied digest. Self::admit_version
records the installed identity without authenticating it against a pin.
Every execution rechecks digest/permission before spawning. Consumers must
exclude concurrent writers to the executable and its parent directories:
filesystem checks and exec are separate operations. This is not a file
capability or verification of dynamic libraries, interpreters, or descendants.
Implementations§
Source§impl AdmittedTool
impl AdmittedTool
Sourcepub fn admit(
spec: &ToolSpec<'_>,
context: &ExecutionContext<'_>,
limits: OutputLimits,
) -> Result<Self, ToolError>
pub fn admit( spec: &ToolSpec<'_>, context: &ExecutionContext<'_>, limits: OutputLimits, ) -> Result<Self, ToolError>
Admit exact executable bytes before invoking the selected version command.
§Errors
Rejects invalid inputs, non-executable files, digest/size mismatch, process failures, non-UTF-8 stdout, and a different successful version identity.
Examples found in repository?
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5 use ic_host_process::provenance::{
6 IgnoreSubmodules, StatusOptions, UntrackedFiles, capture_git,
7 };
8 use ic_host_process::tool::{AdmittedTool, ExecutionContext, OutputLimits, ToolSpec};
9
10 use std::{ffi::OsString, io, path::PathBuf, time::Duration};
11
12 let invalid = |message| io::Error::new(io::ErrorKind::InvalidInput, message);
13 let mut args = std::env::args_os().skip(1);
14 let mut required = || {
15 args.next().ok_or_else(|| invalid(
16 "usage: inspect_git TOOL SHA256 VERSION WORKDIR MAX_TOOL_BYTES MAX_STDOUT_BYTES MAX_STDERR_BYTES TIMEOUT_MS UNTRACKED SUBMODULES",
17 ))
18 };
19 let executable = PathBuf::from(required()?);
20 let digest = required()?
21 .into_string()
22 .map_err(|_| invalid("digest must be UTF-8"))?
23 .parse()?;
24 let version = required()?
25 .into_string()
26 .map_err(|_| invalid("version must be UTF-8"))?;
27 let directory = PathBuf::from(required()?);
28 let mut number = || -> Result<u64, Box<dyn std::error::Error>> {
29 Ok(required()?
30 .to_str()
31 .ok_or_else(|| invalid("limits must be UTF-8"))?
32 .parse()?)
33 };
34 let executable_bytes = number()?;
35 let limits = OutputLimits {
36 stdout: ic_host_process::tool::OutputLimit::Terminate(usize::try_from(number()?)?),
37 stderr: ic_host_process::tool::OutputLimit::Terminate(usize::try_from(number()?)?),
38 timeout: Some(Duration::from_millis(number()?)),
39 };
40 let untracked = match required()?.to_str() {
41 Some("no") => UntrackedFiles::No,
42 Some("normal") => UntrackedFiles::Normal,
43 Some("all") => UntrackedFiles::All,
44 _ => return Err(invalid("untracked must be no, normal or all").into()),
45 };
46 let ignore_submodules = match required()?.to_str() {
47 Some("none") => IgnoreSubmodules::None,
48 Some("untracked") => IgnoreSubmodules::Untracked,
49 Some("dirty") => IgnoreSubmodules::Dirty,
50 Some("all") => IgnoreSubmodules::All,
51 _ => return Err(invalid("submodules must be none, untracked, dirty or all").into()),
52 };
53 if args.next().is_some() {
54 return Err(invalid("unexpected argument").into());
55 }
56 // The example explicitly selects an empty environment; the library never
57 // chooses environment exclusions or tool/version pins for a consumer.
58 let context = ExecutionContext {
59 current_dir: &directory,
60 environment: &[],
61 };
62 let git = AdmittedTool::admit(
63 &ToolSpec {
64 executable: &executable,
65 sha256: digest,
66 executable_bytes,
67 version_arguments: &[OsString::from("--version")],
68 version_identity: &version,
69 },
70 &context,
71 limits,
72 )?;
73 let observed = capture_git(
74 &git,
75 &context,
76 StatusOptions {
77 untracked,
78 ignore_submodules,
79 },
80 limits,
81 )?;
82 println!("revision={}", observed.revision);
83 println!("tree={}", observed.tree);
84 println!("dirty={}", observed.is_dirty());
85 println!("status_bytes={}", observed.status_identity.bytes);
86 println!("status_sha256={}", observed.status_identity.sha256);
87 Ok(())
88}Sourcepub fn admit_version(
spec: &VersionSpec<'_>,
context: &ExecutionContext<'_>,
limits: OutputLimits,
) -> Result<Self, ToolError>
pub fn admit_version( spec: &VersionSpec<'_>, context: &ExecutionContext<'_>, limits: OutputLimits, ) -> Result<Self, ToolError>
Admit an exact version and record the caller-trusted installed bytes.
For tools built locally, no portable published digest may exist. This
entry hashes the executable within the supplied budget before running
the version command. The resulting Self::identity is an observation,
not a trusted published pin. All later runs reject changed bytes using
the same verification and capture engine as Self::admit.
The caller must trust the installation before admission: the version command executes those bytes. Exact version output does not establish authenticity. No version ranges, tool installation or PATH search occur. The caller must exclude concurrent executable/directory writers.
§Errors
Rejects invalid inputs, non-executable or oversized files, process failures, non-UTF-8 stdout and a different successful version identity.
Sourcepub const fn identity(&self) -> ArtifactIdentity
pub const fn identity(&self) -> ArtifactIdentity
Retained raw executable identity.
With Self::admit_version, this is an observed identity, not proof of
a published binary pin or trusted installation provenance.
Sourcepub fn version_identity(&self) -> &str
pub fn version_identity(&self) -> &str
Successfully observed, trimmed version identity.
Sourcepub fn run(
&self,
arguments: &[OsString],
context: &ExecutionContext<'_>,
limits: OutputLimits,
) -> Result<ExecutionEvidence, ToolError>
pub fn run( &self, arguments: &[OsString], context: &ExecutionContext<'_>, limits: OutputLimits, ) -> Result<ExecutionEvidence, ToolError>
Run once with a cleared, explicitly supplied environment and null stdin.
Stdout/stderr are drained fairly through nonblocking pipes without reader threads. On overflow/deadline the direct child is killed and reaped; pipe handles are closed without waiting for descendants to close their copies. Descendant processes remain caller-owned. This must not be interpreted as a rollback or safe automatic retry of a command with external effects.
§Errors
Returns invalid-input or identity failures before execution, or an execution failure retaining bounded prefixes and cleanup outcomes.