mkit_cli/commands/
verify.rs1use 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: 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}