# # patch "ChangeLog" # from [3f00101d744edfa74a6e13237a395494ef80498f] # to [3a9cac4940c0d1c1b6281e6dad3b6c0f16ae4fc9] # # patch "automate.cc" # from [10270281421d377dedc2362ee2de520fbf1952e2] # to [affdba906ca8aa970749756f7eba5a3ae4e9efb8] # --- ChangeLog +++ ChangeLog @@ -1,5 +1,9 @@ 2005-05-24 Timothy Brownawell + * automate.cc: Put back lost "automate certs". + +2005-05-24 Timothy Brownawell + * automate.cc: Fix comment for automate stdio to match the code. * monotone.texi: Document ignored locations in automate stdio input as reserved. --- automate.cc +++ automate.cc @@ -792,6 +792,116 @@ } +// Name: certs +// Arguments: +// 1: a revision id +// Added in: 1.0 +// Purpose: Prints all certificates associated with the given revision ID. +// Each certificate is contained in a basic IO stanza. For each certificate, +// the following values are provided: +// +// 'key' : a string indicating the key used to sign this certificate. +// 'signature': a string indicating the status of the signature. Possible +// values of this string are: +// 'ok' : the signature is correct +// 'bad' : the signature is invalid +// 'unknown' : signature was made with an unknown key +// 'name' : the name of this certificate +// 'value' : the value of this certificate +// 'trust' : is this certificate trusted by the defined trust metric +// Possible values of this string are: +// 'trusted' : this certificate is trusted +// 'untrusted' : this certificate is not trusted +// +// Output format: All stanzas are formatted by basic_io. Stanzas are seperated +// by a blank line. Values will be escaped, '\' -> '\\' and '"' -> '\"'. +// +// Error conditions: If a certificate is signed with an unknown public key, a +// warning message is printed to stderr. If the revision specified is unknown +// or invalid prints an error message to stderr and exits with status 1. +static void +automate_certs(std::vector args, + std::string const & help_name, + app_state & app, + std::ostream & output) +{ + if (args.size() != 1) + throw usage(help_name); + + std::vector certs; + + transaction_guard guard(app.db); + + revision_id rid(idx(args, 0)()); + N(app.db.revision_exists(rid), F("No such revision %s") % rid); + hexenc ident(rid.inner()); + + std::vector< revision > ts; + app.db.get_revision_certs(rid, ts); + for (size_t i = 0; i < ts.size(); ++i) + certs.push_back(idx(ts, i).inner()); + + { + std::set checked; + for (size_t i = 0; i < certs.size(); ++i) + { + if (checked.find(idx(certs, i).key) == checked.end() && + !app.db.public_key_exists(idx(certs, i).key)) + P(F("warning: no public key '%s' found in database\n") + % idx(certs, i).key); + checked.insert(idx(certs, i).key); + } + } + + // Make the output deterministic; this is useful for the test suite, in + // particular. + sort(certs.begin(), certs.end()); + + basic_io::printer pr(output); + + for (size_t i = 0; i < certs.size(); ++i) + { + basic_io::stanza st; + cert_status status = check_cert(app, idx(certs, i)); + cert_value tv; + cert_name name = idx(certs, i).name(); + std::set signers; + + decode_base64(idx(certs, i).value, tv); + + rsa_keypair_id keyid = idx(certs, i).key(); + signers.insert(keyid); + + bool trusted = app.lua.hook_get_revision_cert_trust(signers, ident, + name, tv); + + st.push_str_pair("key", keyid()); + + std::string stat; + switch (status) + { + case cert_ok: + stat = "ok"; + break; + case cert_bad: + stat = "bad"; + break; + case cert_unknown: + stat = "unknown"; + break; + } + st.push_str_pair("signature", stat); + + st.push_str_pair("name", name()); + st.push_str_pair("value", tv()); + st.push_str_pair("trust", (trusted ? "trusted" : "untrusted")); + + pr.print_stanza(st); + } + + guard.commit(); +} + void automate_command(utf8 cmd, std::vector args, std::string const & root_cmd_name, @@ -1016,6 +1126,8 @@ automate_attributes(args, root_cmd_name, app, output); else if (cmd() == "stdio") automate_stdio(args, root_cmd_name, app, output); + else if (cmd() == "certs") + automate_certs(args, root_cmd_name, app, output); else throw usage(root_cmd_name); }