Skip to main content

mkit_cli/commands/
verify.rs

1//! `mkit verify <rev>` — verify the signature on a commit, remix, or
2//! signed tag.
3
4use std::io::Write;
5
6use clap::Parser;
7use mkit_core::object::Object;
8use mkit_core::sign::{verify_commit, verify_remix, verify_tag};
9use mkit_core::store::ObjectStore;
10
11use crate::clap_shim;
12use crate::exit;
13
14#[derive(Debug, Parser)]
15#[command(
16    name = "mkit verify",
17    about = "Verify the signature on a commit, remix, or signed tag."
18)]
19struct VerifyOpts {
20    /// Revision to verify: an object hash (full or short), a branch /
21    /// tag name, or `HEAD`. A tag name resolves to its annotated-tag
22    /// object when one exists.
23    revision: String,
24}
25
26#[must_use]
27pub fn run(args: &[String]) -> u8 {
28    let opts = match clap_shim::parse::<VerifyOpts>("mkit verify", args) {
29        Ok(o) => o,
30        Err(code) => return code,
31    };
32    let cwd = match std::env::current_dir() {
33        Ok(p) => p,
34        Err(e) => return emit_err(&format!("cwd: {e}"), exit::NOINPUT),
35    };
36    let store = match ObjectStore::open(&cwd) {
37        Ok(s) => s,
38        Err(e) => return emit_err(&format!("not a mkit repo: {e}"), exit::GENERAL_ERROR),
39    };
40    let mkit_dir = cwd.join(mkit_core::MKIT_DIR);
41    let h = match super::revspec::resolve_revision(&store, &mkit_dir, &opts.revision) {
42        Ok(h) => h,
43        Err(e) => return emit_err(&format!("{e}"), exit::DATAERR),
44    };
45    let obj = match store.read_object(&h) {
46        Ok(o) => o,
47        Err(e) => return emit_err(&format!("read: {e}"), exit::NOINPUT),
48    };
49    let res = match &obj {
50        Object::Commit(c) => verify_commit(c),
51        Object::Remix(r) => verify_remix(r),
52        Object::Tag(t) => verify_tag(t),
53        _ => {
54            return emit_err(
55                "object is not a commit, remix, or signed tag",
56                exit::DATAERR,
57            );
58        }
59    };
60    let mut stdout = std::io::stdout().lock();
61    match res {
62        Ok(()) => {
63            let _ = writeln!(stdout, "ok: signature valid");
64            exit::OK
65        }
66        Err(e) => {
67            let _ = writeln!(stdout, "bad: {e}");
68            exit::DATAERR
69        }
70    }
71}
72
73fn emit_err(msg: &str, code: u8) -> u8 {
74    let mut stderr = std::io::stderr().lock();
75    let _ = writeln!(stderr, "error: {msg}");
76    code
77}