jobs/runner/src/accept.rs
//! **The caller's acceptance check**: the only way a job's result is believed.
use std::path::Path;
use heimdall_core::{JobResult, JobTicket, SignedResult, VerifyingKey};
use holger_errcode::ErrCode;
/// A result that is not believed, by name.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Rejected {
pub code: &'static ErrCode,
pub why: String,
}
impl std::fmt::Display for Rejected {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(&self.code.tag(&self.why))
}
}
impl std::error::Error for Rejected {}
/// ★ **Believe `signed`** only when it verifies with the PINNED key
/// ([`heimdall_core::verify`]: the format version, the key id, the signature over
/// Heimdall's canonical encoding, a well-formed result), it is the result of the job
/// `ticket` names (its id and its nonce: a result replayed from another run names
/// another), and `out` holds exactly the outputs it lists, each with its sha256 and size
/// ([`heimdall_core::check_outputs`]). Returns the result.
pub fn accept<'a>(
signed: &'a SignedResult,
key: &VerifyingKey,
ticket: &JobTicket,
out: &Path,
) -> Result<&'a JobResult, Rejected> {
use holger_errcode::{SANDBOX_JOB_OUTPUTS_INVALID, SANDBOX_JOB_RESULT_REFUSED};
let r = heimdall_core::verify(signed, key).map_err(|e| Rejected {
code: &SANDBOX_JOB_RESULT_REFUSED,
why: format!("the job's result is not believed: {e}"),
})?;
if r.job_id != ticket.job_id || r.nonce != ticket.nonce {
return Err(Rejected {
code: &SANDBOX_JOB_RESULT_REFUSED,
why: format!("the signed result is the one of job {}, not of job {} that was run: a replayed result is not believed", r.job_id, ticket.job_id),
});
}
heimdall_core::check_outputs(r, out).map_err(|e| Rejected {
code: &SANDBOX_JOB_OUTPUTS_INVALID,
why: e.to_string(),
})?;
Ok(r)
}