Add a framework to format and test examples.
- The `--help` output for most subcommands includes one or more examples. - We should test these, like we test everything else. - Add a framework to format, and test the examples. - Fixes #190. - Also, fix some broken examples.
This commit is contained in:
parent
825f4463de
commit
0d1da78356
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,3 +5,4 @@
|
||||
.dir-locals.el
|
||||
/*.html
|
||||
/*.pdf
|
||||
writelock
|
37
Cargo.lock
generated
37
Cargo.lock
generated
@ -803,6 +803,17 @@ dependencies = [
|
||||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dircpy"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8466f8d28ca6da4c9dfbbef6ad4bff6f2fdd5e412d821025b0d3f0a9d74a8c1e"
|
||||
dependencies = [
|
||||
"jwalk",
|
||||
"log",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dirs"
|
||||
version = "5.0.1"
|
||||
@ -1783,6 +1794,16 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jwalk"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2735847566356cd2179a2a38264839308f7079fa96e6bd5a42d740460e003c56"
|
||||
dependencies = [
|
||||
"crossbeam",
|
||||
"rayon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lalrpop"
|
||||
version = "0.20.0"
|
||||
@ -2755,7 +2776,7 @@ dependencies = [
|
||||
"anyhow",
|
||||
"serde",
|
||||
"serde_yaml 0.8.26",
|
||||
"textwrap",
|
||||
"textwrap 0.15.2",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
@ -3081,6 +3102,7 @@ dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
"clap_complete",
|
||||
"dircpy",
|
||||
"dirs",
|
||||
"dot-writer",
|
||||
"fehler",
|
||||
@ -3104,7 +3126,7 @@ dependencies = [
|
||||
"tempfile",
|
||||
"termcolor",
|
||||
"terminal_size",
|
||||
"textwrap",
|
||||
"textwrap 0.16.0",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
@ -3575,6 +3597,17 @@ dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d"
|
||||
dependencies = [
|
||||
"smawk",
|
||||
"unicode-linebreak",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.56"
|
||||
|
@ -63,10 +63,12 @@ serde = { version = "1.0.137", features = ["derive"] }
|
||||
sequoia-openpgp = { version = "1.17", default-features = false }
|
||||
sequoia-net = { version = "0.28", default-features = false }
|
||||
subplot-build = { version = ">=0.7, <0.10", optional = true }
|
||||
textwrap = "0.16"
|
||||
cfg-if = "1"
|
||||
terminal_size = ">=0.2.6, <0.4"
|
||||
|
||||
[dev-dependencies]
|
||||
dircpy = "0.3"
|
||||
subplotlib = ">=0.7, <0.10"
|
||||
fehler = "1.0.0"
|
||||
assert_cmd = "2"
|
||||
|
@ -3,6 +3,70 @@ use clap::Parser;
|
||||
use sequoia_openpgp as openpgp;
|
||||
use openpgp::KeyHandle;
|
||||
|
||||
use crate::cli::examples;
|
||||
use examples::Action;
|
||||
use examples::Actions;
|
||||
use examples::Example;
|
||||
|
||||
const EXAMPLES: Actions = Actions {
|
||||
actions: &[
|
||||
Action::Example(Example {
|
||||
comment: "Exports all certificates.",
|
||||
command: &[
|
||||
"sq", "cert", "export",
|
||||
],
|
||||
}),
|
||||
Action::Example(Example {
|
||||
comment: "\
|
||||
Exports certificates with a matching User ID packet. The binding \
|
||||
signatures are checked, but the User IDs are not authenticated. \
|
||||
Note: this check is case sensitive.",
|
||||
command: &[
|
||||
"sq", "cert", "export",
|
||||
"--userid", "Alice <alice@example.org>",
|
||||
],
|
||||
}),
|
||||
Action::Example(Example {
|
||||
comment: "\
|
||||
Exports certificates with a User ID containing the email address. \
|
||||
The binding signatures are checked, but the User IDs are not \
|
||||
authenticated. Note: this check is case insensitive.",
|
||||
command: &[
|
||||
"sq", "cert", "export", "--email", "alice@example.org",
|
||||
],
|
||||
}),
|
||||
Action::Example(Example {
|
||||
comment: "\
|
||||
Exports certificates where the certificate (i.e., the primary key) \
|
||||
has the specified Key ID.",
|
||||
command: &[
|
||||
"sq", "cert", "export", "--cert", "6F0073F60FD0CBF0",
|
||||
],
|
||||
}),
|
||||
Action::Example(Example {
|
||||
comment: "\
|
||||
Exports certificates where the primary key or a subkey matches the \
|
||||
specified Key ID.",
|
||||
command: &[
|
||||
"sq", "cert", "export", "--key", "24F3955B0B8DECC8",
|
||||
],
|
||||
}),
|
||||
Action::Example(Example {
|
||||
comment: "\
|
||||
Exports certificates that contain a User ID with *either* (not both!) \
|
||||
email address. Note: this check is case insensitive.",
|
||||
command: &[
|
||||
"sq", "cert", "export",
|
||||
"--email", "alice@example.org",
|
||||
"--email", "bob@example.org",
|
||||
],
|
||||
}),
|
||||
],
|
||||
};
|
||||
|
||||
test_examples!(sq_cert_export, EXAMPLES);
|
||||
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(
|
||||
name = "export",
|
||||
@ -25,34 +89,7 @@ all certificates.
|
||||
Fails if search criteria are specified and none of them matches any
|
||||
certificates. Note: this means if the certificate store is empty and
|
||||
no search criteria are specified, then this will return success.",
|
||||
after_help =
|
||||
"EXAMPLES:
|
||||
|
||||
# Exports all certificates.
|
||||
$ sq cert export > all.pgp
|
||||
|
||||
# Exports certificates with a matching User ID packet. The binding
|
||||
# signatures are checked, but the User IDs are not authenticated.
|
||||
# Note: this check is case sensitive.
|
||||
$ sq cert export --userid 'Alice <alice@example.org>'
|
||||
|
||||
# Exports certificates with a User ID containing the email address.
|
||||
# The binding signatures are checked, but the User IDs are not
|
||||
# authenticated. Note: this check is case insensitive.
|
||||
$ sq cert export --email 'alice@example.org'
|
||||
|
||||
# Exports certificates where the certificate (i.e., the primary key)
|
||||
# has the specified Key ID.
|
||||
$ sq cert export --cert 1234567812345678
|
||||
|
||||
# Exports certificates where the primary key or a subkey matches the
|
||||
# specified Key ID.
|
||||
$ sq cert export --key 1234567812345678
|
||||
|
||||
# Exports certificates that contain a User ID with *either* (not
|
||||
# both!) email address. Note: this check is case insensitive.
|
||||
$ sq cert export --email alice@example.org --email bob@example.org
|
||||
",
|
||||
after_help = EXAMPLES,
|
||||
)]
|
||||
pub struct Command {
|
||||
#[clap(
|
||||
|
@ -2,6 +2,24 @@ use std::path::PathBuf;
|
||||
|
||||
use clap::Parser;
|
||||
|
||||
use crate::cli::examples;
|
||||
use examples::Action;
|
||||
use examples::Actions;
|
||||
use examples::Example;
|
||||
|
||||
const EXAMPLES: Actions = Actions {
|
||||
actions: &[
|
||||
Action::Example(Example {
|
||||
comment: "Imports a certificate.",
|
||||
command: &[
|
||||
"sq", "cert", "import", "juliet.pgp",
|
||||
],
|
||||
}),
|
||||
]
|
||||
};
|
||||
|
||||
test_examples!(sq_cert_import, EXAMPLES);
|
||||
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(
|
||||
name = "import",
|
||||
@ -9,12 +27,7 @@ use clap::Parser;
|
||||
long_about =
|
||||
"Imports certificates into the local certificate store
|
||||
",
|
||||
after_help =
|
||||
"EXAMPLES:
|
||||
|
||||
# Imports a certificate.
|
||||
$ sq cert import < juliet.pgp
|
||||
",
|
||||
after_help = EXAMPLES,
|
||||
)]
|
||||
pub struct Command {
|
||||
#[clap(value_name = "FILE", help = "Reads from FILE or stdin if omitted")]
|
||||
|
176
src/cli/examples.rs
Normal file
176
src/cli/examples.rs
Normal file
@ -0,0 +1,176 @@
|
||||
//! A framework to format and check examples.
|
||||
//!
|
||||
//! The help text for subcommands includes examples. That's great.
|
||||
//! But, it is even better when they are tested. This module defines
|
||||
//! data structures to describe the examples, mechanisms to format the
|
||||
//! examples, and infrastructure to execute the examples.
|
||||
|
||||
use clap::builder::IntoResettable;
|
||||
use clap::builder::Resettable;
|
||||
|
||||
/// A command that is executed by the integration test, but not shown
|
||||
/// in the manual pages.
|
||||
pub struct Setup<'a> {
|
||||
pub command: &'a [ &'a str ],
|
||||
}
|
||||
|
||||
/// A command that is executed by the integration test, and shown in
|
||||
/// the manual pages.
|
||||
pub struct Example<'a> {
|
||||
// A human-readable comment.
|
||||
pub comment: &'a str,
|
||||
pub command: &'a [ &'a str ],
|
||||
}
|
||||
|
||||
/// An action to execute.
|
||||
#[allow(dead_code)]
|
||||
pub enum Action<'a> {
|
||||
/// A command that is executed by the integration test, but not
|
||||
/// shown in the manual pages.
|
||||
Setup(Setup<'a>),
|
||||
|
||||
/// A command that is executed by the integration test, and shown
|
||||
/// in the manual pages.
|
||||
Example(Example<'a>),
|
||||
}
|
||||
|
||||
impl<'a> Action<'a> {
|
||||
/// Return the action's command, if any.
|
||||
#[allow(dead_code)]
|
||||
pub fn command(&self) -> Option<&'a [ &'a str ]> {
|
||||
match self {
|
||||
Action::Setup(Setup { command, .. }) => Some(command),
|
||||
Action::Example(Example { command, .. }) => Some(command),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A sequence of actions to execute.
|
||||
pub struct Actions<'a> {
|
||||
pub actions: &'a [Action<'a>],
|
||||
}
|
||||
|
||||
impl<'a> IntoResettable<clap::builder::StyledStr> for Actions<'a> {
|
||||
fn into_resettable(self) -> Resettable<clap::builder::StyledStr> {
|
||||
// Default width when we aren't connected to a terminal.
|
||||
let default_width = 72;
|
||||
|
||||
let terminal_size = terminal_size::terminal_size();
|
||||
let width = if let Some((width, _height)) = terminal_size {
|
||||
let width = width.0 as usize;
|
||||
|
||||
if width < 40 {
|
||||
// If the terminal is too narrow, then give up and use
|
||||
// the default.
|
||||
default_width
|
||||
} else {
|
||||
std::cmp::max(40, width)
|
||||
}
|
||||
} else {
|
||||
72
|
||||
};
|
||||
|
||||
let mut lines = vec![ "EXAMPLES:".to_string() ];
|
||||
|
||||
lines.extend(self.actions
|
||||
.iter()
|
||||
.filter_map(|action| {
|
||||
let example = if let Action::Example(example) = action {
|
||||
example
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
let comment = textwrap::indent(
|
||||
&textwrap::wrap(example.comment, width).join("\n"),
|
||||
"# ");
|
||||
|
||||
let command = example.command.iter()
|
||||
.fold(vec!["$".to_string()], |mut s, arg| {
|
||||
// Quote the argument, if necessary.
|
||||
let arg = if arg.contains(&[
|
||||
'\"',
|
||||
]) {
|
||||
format!("'{}'", arg)
|
||||
} else if arg.chars().any(char::is_whitespace)
|
||||
|| arg.contains(&[
|
||||
'`', '#', '$', '&', '*', '(', ')',
|
||||
'\\', '|', '[', ']', '{', '}',
|
||||
';', '\'', '<', '>', '?', '!',
|
||||
])
|
||||
{
|
||||
format!("\"{}\"", arg)
|
||||
} else {
|
||||
arg.to_string()
|
||||
};
|
||||
|
||||
let last = s.last_mut().expect("have one");
|
||||
|
||||
let last_chars = last.chars().count();
|
||||
let arg_chars = arg.chars().count();
|
||||
|
||||
// Our manpage generate complains if an
|
||||
// example is too long:
|
||||
//
|
||||
// warning: Command in example exceeds 64 chars:
|
||||
if last_chars + 1 + arg_chars <= width.min(64) {
|
||||
*last = format!("{} {}", last, arg);
|
||||
} else {
|
||||
*last = format!("{} \\", last);
|
||||
s.push(format!(" {}", arg));
|
||||
}
|
||||
|
||||
s
|
||||
})
|
||||
.join("\n");
|
||||
|
||||
Some(format!("{}\n{}", comment, command))
|
||||
}));
|
||||
|
||||
let text = lines.join("\n\n").into();
|
||||
|
||||
Resettable::Value(text)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! test_examples {
|
||||
($ident:ident, $actions:expr) => {
|
||||
#[test]
|
||||
fn $ident() {
|
||||
use std::path::PathBuf;
|
||||
|
||||
use tempfile::TempDir;
|
||||
use assert_cmd::Command;
|
||||
|
||||
|
||||
let fixtures = PathBuf::from(concat!(
|
||||
env!("CARGO_MANIFEST_DIR"),
|
||||
"/tests/data/examples"));
|
||||
|
||||
let tmp_dir = TempDir::new().unwrap();
|
||||
|
||||
dircpy::copy_dir(&fixtures, &tmp_dir)
|
||||
.expect(&format!("Copying {:?} to {:?}",
|
||||
fixtures, &tmp_dir));
|
||||
|
||||
let cert_store = tmp_dir.path().join("cert-store");
|
||||
|
||||
for action in $actions.actions {
|
||||
let command = if let Some(command) = action.command() {
|
||||
command
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
|
||||
eprintln!("Executing: {:?}", command);
|
||||
|
||||
Command::cargo_bin(command[0]).unwrap()
|
||||
.current_dir(&tmp_dir)
|
||||
.env("SQ_CERT_STORE", &cert_store)
|
||||
.args(&command[1..])
|
||||
.assert()
|
||||
.success();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
@ -86,6 +86,9 @@ pub mod autocrypt;
|
||||
use sequoia_openpgp as openpgp;
|
||||
use openpgp::Fingerprint;
|
||||
|
||||
#[macro_use]
|
||||
pub mod examples;
|
||||
|
||||
pub mod cert;
|
||||
pub mod decrypt;
|
||||
pub mod encrypt;
|
||||
|
191
src/cli/pki.rs
191
src/cli/pki.rs
@ -14,6 +14,12 @@ use crate::cli::types::TrustAmount;
|
||||
pub mod certify;
|
||||
pub mod link;
|
||||
|
||||
use crate::cli::examples;
|
||||
use examples::Action;
|
||||
use examples::Setup;
|
||||
use examples::Actions;
|
||||
use examples::Example;
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[clap(
|
||||
name = "pki",
|
||||
@ -54,6 +60,38 @@ pub enum Subcommands {
|
||||
Path(PathCommand),
|
||||
}
|
||||
|
||||
const AUTHENTICATE_EXAMPLES: Actions = Actions {
|
||||
actions: &[
|
||||
// Link Alice's certificate.
|
||||
Action::Setup(Setup {
|
||||
command: &[
|
||||
"sq", "pki", "link", "add",
|
||||
"EB28F26E2739A4870ECC47726F0073F60FD0CBF0", "--all",
|
||||
],
|
||||
}),
|
||||
Action::Example(Example {
|
||||
comment: "\
|
||||
Authenticate a specific binding.",
|
||||
command: &[
|
||||
"sq", "pki", "authenticate",
|
||||
"EB28F26E2739A4870ECC47726F0073F60FD0CBF0",
|
||||
"Alice <alice@example.org>",
|
||||
]
|
||||
}),
|
||||
Action::Example(Example {
|
||||
comment: "\
|
||||
Check whether we can authenticate any user ID with the specified email \
|
||||
address for the given certificate.",
|
||||
command: &[
|
||||
"sq", "pki", "authenticate",
|
||||
"EB28F26E2739A4870ECC47726F0073F60FD0CBF0",
|
||||
"--email", "alice@example.org",
|
||||
],
|
||||
}),
|
||||
]
|
||||
};
|
||||
test_examples!(sq_pki_authenticate, AUTHENTICATE_EXAMPLES);
|
||||
|
||||
/// Authenticate a binding.
|
||||
///
|
||||
/// Authenticate a binding (a certificate and User ID) by looking
|
||||
@ -72,20 +110,8 @@ pub enum Subcommands {
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(
|
||||
name = "authenticate",
|
||||
after_help =
|
||||
"EXAMPLES:
|
||||
|
||||
# Authenticate a binding.
|
||||
$ sq pki authenticate --partial \\
|
||||
C7966E3E7CE67DBBECE5FC154E2AD944CFC78C86 \\
|
||||
'Alice <alice@example.org>'
|
||||
|
||||
# Try and authenticate each binding where the User ID has the
|
||||
# specified email address.
|
||||
$ sq pki authenticate \\
|
||||
C7966E3E7CE67DBBECE5FC154E2AD944CFC78C86 \\
|
||||
--email alice@example.org
|
||||
")]
|
||||
after_help = AUTHENTICATE_EXAMPLES,
|
||||
)]
|
||||
pub struct AuthenticateCommand {
|
||||
#[command(flatten)]
|
||||
pub email: EmailArg,
|
||||
@ -106,6 +132,34 @@ pub struct AuthenticateCommand {
|
||||
pub userid: UserIDArg,
|
||||
}
|
||||
|
||||
const LOOKUP_EXAMPLES: Actions = Actions {
|
||||
actions: &[
|
||||
// Link Alice's certificate.
|
||||
Action::Setup(Setup {
|
||||
command: &[
|
||||
"sq", "pki", "link", "add",
|
||||
"EB28F26E2739A4870ECC47726F0073F60FD0CBF0", "--all",
|
||||
],
|
||||
}),
|
||||
Action::Example(Example {
|
||||
comment: "\
|
||||
Lookup certificates that can be authenticated for the given user ID.",
|
||||
command: &[
|
||||
"sq", "pki", "lookup", "Alice <alice@example.org>"
|
||||
],
|
||||
}),
|
||||
Action::Example(Example {
|
||||
comment: "\
|
||||
Lookup certificates that have a user ID with the specified email \
|
||||
address, and that user ID can be authenticated.",
|
||||
command: &[
|
||||
"sq", "pki", "lookup", "--email", "alice@example.org",
|
||||
],
|
||||
}),
|
||||
]
|
||||
};
|
||||
test_examples!(sq_pki_lookup, LOOKUP_EXAMPLES);
|
||||
|
||||
/// Lookup the certificates associated with a User ID.
|
||||
///
|
||||
/// Identifies authenticated bindings (User ID and certificate
|
||||
@ -121,15 +175,8 @@ pub struct AuthenticateCommand {
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(
|
||||
name = "lookup",
|
||||
after_help =
|
||||
"EXAMPLES:
|
||||
|
||||
# Lookup a certificate with the given User ID.
|
||||
$ sq pki lookup --partial 'Alice <alice@example.org>'
|
||||
|
||||
# Lookup a certificate with the given email address.
|
||||
$ sq pki lookup --email alice@example.org
|
||||
")]
|
||||
after_help = LOOKUP_EXAMPLES,
|
||||
)]
|
||||
pub struct LookupCommand {
|
||||
#[command(flatten)]
|
||||
pub email: EmailArg,
|
||||
@ -147,6 +194,35 @@ pub struct LookupCommand {
|
||||
pub userid: UserIDArg,
|
||||
}
|
||||
|
||||
const IDENTIFY_EXAMPLES: Actions = Actions {
|
||||
actions: &[
|
||||
// Link Alice's certificate.
|
||||
Action::Setup(Setup {
|
||||
command: &[
|
||||
"sq", "pki", "link", "add",
|
||||
"EB28F26E2739A4870ECC47726F0073F60FD0CBF0", "--all",
|
||||
],
|
||||
}),
|
||||
Action::Example(Example {
|
||||
comment: "\
|
||||
Identify the user IDs that can be authenticated for the certificate.",
|
||||
command: &[
|
||||
"sq", "pki", "identify",
|
||||
"EB28F26E2739A4870ECC47726F0073F60FD0CBF0",
|
||||
],
|
||||
}),
|
||||
Action::Example(Example {
|
||||
comment: "\
|
||||
List all user IDs that have that have been certified by anyone.",
|
||||
command: &[
|
||||
"sq", "pki", "identify", "--gossip",
|
||||
"511257EBBF077B7AEDAE5D093F68CB84CE537C9A",
|
||||
],
|
||||
}),
|
||||
]
|
||||
};
|
||||
test_examples!(sq_pki_identify, IDENTIFY_EXAMPLES);
|
||||
|
||||
/// Identify a certificate.
|
||||
///
|
||||
/// Identify a certificate by finding authenticated bindings (User
|
||||
@ -162,17 +238,8 @@ pub struct LookupCommand {
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(
|
||||
name = "identify",
|
||||
after_help =
|
||||
"EXAMPLES:
|
||||
|
||||
# Identify a certificate.
|
||||
$ sq pki identify --partial \\
|
||||
C7B1406CD2F612E9CE2136156F2DA183236153AE
|
||||
|
||||
# Get gossip about a certificate.
|
||||
$ sq pki identify --gossip \\
|
||||
3217C509292FC67076ECD75C7614269BDDF73B36
|
||||
")]
|
||||
after_help = IDENTIFY_EXAMPLES,
|
||||
)]
|
||||
pub struct IdentifyCommand {
|
||||
#[command(flatten)]
|
||||
pub gossip: GossipArg,
|
||||
@ -187,6 +254,26 @@ pub struct IdentifyCommand {
|
||||
pub cert: CertArg,
|
||||
}
|
||||
|
||||
const LIST_EXAMPLES: Actions = Actions {
|
||||
actions: &[
|
||||
Action::Setup(Setup {
|
||||
command: &[
|
||||
"sq", "pki", "link", "add",
|
||||
"EB28F26E2739A4870ECC47726F0073F60FD0CBF0", "--all",
|
||||
],
|
||||
}),
|
||||
Action::Example(Example {
|
||||
comment: "\
|
||||
List all bindings for user IDs containing an email address from \
|
||||
example.org, and that can be authenticated.",
|
||||
command: &[
|
||||
"sq", "pki", "list", "@example.org",
|
||||
],
|
||||
})
|
||||
]
|
||||
};
|
||||
test_examples!(sq_pki_list, LIST_EXAMPLES);
|
||||
|
||||
/// List all authenticated bindings (User ID and certificate
|
||||
/// pairs).
|
||||
///
|
||||
@ -204,13 +291,8 @@ pub struct IdentifyCommand {
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(
|
||||
name = "list",
|
||||
after_help =
|
||||
"EXAMPLES:
|
||||
|
||||
# List all bindings for example.org that are at least partially
|
||||
# authenticated.
|
||||
$ sq pki list --partial @example.org
|
||||
")]
|
||||
after_help = LIST_EXAMPLES,
|
||||
)]
|
||||
pub struct ListCommand {
|
||||
#[command(flatten)]
|
||||
pub email: EmailArg,
|
||||
@ -233,6 +315,22 @@ pub struct ListCommand {
|
||||
pub pattern: Option<String>,
|
||||
}
|
||||
|
||||
const PATH_EXAMPLES: Actions = Actions {
|
||||
actions: &[
|
||||
Action::Example(Example {
|
||||
comment: "\
|
||||
Verify that Alice ceritified a particular User ID for Bob's certificate.",
|
||||
command: &[
|
||||
"sq", "pki", "path",
|
||||
"EB28F26E2739A4870ECC47726F0073F60FD0CBF0",
|
||||
"511257EBBF077B7AEDAE5D093F68CB84CE537C9A",
|
||||
"Bob <bob@example.org>",
|
||||
],
|
||||
})
|
||||
],
|
||||
};
|
||||
test_examples!(sq_pki_path, PATH_EXAMPLES);
|
||||
|
||||
/// Verify the specified path.
|
||||
///
|
||||
/// A path is a sequence of certificates starting at the root, and
|
||||
@ -248,15 +346,8 @@ pub struct ListCommand {
|
||||
#[derive(Parser, Debug)]
|
||||
#[clap(
|
||||
name = "path",
|
||||
after_help =
|
||||
"EXAMPLES:
|
||||
|
||||
# Verify that Neal ceritified Justus's certificate for a particular User ID.
|
||||
$ sq pki path \\
|
||||
8F17777118A33DDA9BA48E62AACB3243630052D9 \\
|
||||
CBCD8F030588653EEDD7E2659B7DD433F254904A \\
|
||||
'Justus Winter <justus@sequoia-pgp.org>'
|
||||
")]
|
||||
after_help = PATH_EXAMPLES,
|
||||
)]
|
||||
pub struct PathCommand {
|
||||
#[command(flatten)]
|
||||
pub gossip: GossipArg,
|
||||
|
29
tests/data/examples/README.md
Normal file
29
tests/data/examples/README.md
Normal file
@ -0,0 +1,29 @@
|
||||
# Introduction
|
||||
|
||||
This directory contains data for the examples.
|
||||
|
||||
The test suite executes each subcommand's examples. Each subcommand
|
||||
has its own context (temporary directory), which is set to the current
|
||||
working directory. The contents of this directory are copied into
|
||||
that directory. If a subcommand has multiple examples, they are
|
||||
execute after each other in the same context.
|
||||
|
||||
By using static data, we can use known fingerprints in the examples.
|
||||
|
||||
# Contents
|
||||
|
||||
- alice-secret.pgp: A general-purpose certificate for Alice
|
||||
<alice@example.org>.
|
||||
|
||||
- Imported into the cert store.
|
||||
|
||||
- bob-secret.pgp: A general-purpose certificate for Bob
|
||||
<bob@example.org>.
|
||||
|
||||
- Imported into the cert store.
|
||||
- Certified by Alice.
|
||||
|
||||
- juliet.pgp: A general-purpose certificate for Juliet Capulet
|
||||
<juliet@example.org>.
|
||||
|
||||
- NOT imported into the cert store.
|
43
tests/data/examples/alice-secret.pgp
Normal file
43
tests/data/examples/alice-secret.pgp
Normal file
@ -0,0 +1,43 @@
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
Comment: EB28 F26E 2739 A487 0ECC 4772 6F00 73F6 0FD0 CBF0
|
||||
Comment: Alice <alice@example.org>
|
||||
|
||||
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
|
||||
=3xfI
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
13
tests/data/examples/alice.pgp.rev
Normal file
13
tests/data/examples/alice.pgp.rev
Normal file
@ -0,0 +1,13 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Comment: Revocation certificate for
|
||||
Comment: EB28 F26E 2739 A487 0ECC 4772 6F00 73F6 0FD0 CBF0
|
||||
Comment: Alice <alice@example.org>
|
||||
|
||||
xjMEZcT3URYJKwYBBAHaRw8BAQdASgo8UO9lxwMTZkkBrqzyUMjF4flY8YtRT+pk
|
||||
iSI2jlPCwAoEIBYKAH0FgmXE91EJEG8Ac/YP0MvwRxQAAAAAAB4AIHNhbHRAbm90
|
||||
YXRpb25zLnNlcXVvaWEtcGdwLm9yZ1F95aiZHzvfQFFbhbE0SsQy3vMeM+nfRves
|
||||
qRkHca4nDR0AVW5zcGVjaWZpZWQWIQTrKPJuJzmkhw7MR3JvAHP2D9DL8AAALnYA
|
||||
/24KMLbwtB17x6wo3b1dUu1WODBxQCJj28+hC+IBMhIaAPjYZbEum4myHuOPg/2v
|
||||
Y5dSMQaYBpYYcYRu7g5UfugE
|
||||
=+8np
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
43
tests/data/examples/bob-secret.pgp
Normal file
43
tests/data/examples/bob-secret.pgp
Normal file
@ -0,0 +1,43 @@
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
Comment: 5112 57EB BF07 7B7A EDAE 5D09 3F68 CB84 CE53 7C9A
|
||||
Comment: Bob <bob@example.org>
|
||||
|
||||
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
|
||||
=qucl
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
13
tests/data/examples/bob.pgp.rev
Normal file
13
tests/data/examples/bob.pgp.rev
Normal file
@ -0,0 +1,13 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Comment: Revocation certificate for
|
||||
Comment: 5112 57EB BF07 7B7A EDAE 5D09 3F68 CB84 CE53 7C9A
|
||||
Comment: Bob <bob@example.org>
|
||||
|
||||
xjMEZcT3SRYJKwYBBAHaRw8BAQdAlN1milRLfSk/XwgEuKeZ27kK1sZcfRroOqjZ
|
||||
+E+OJFLCwAsEIBYKAH0FgmXE90kJED9oy4TOU3yaRxQAAAAAAB4AIHNhbHRAbm90
|
||||
YXRpb25zLnNlcXVvaWEtcGdwLm9yZ4Bk7ktrmF8plMFxGXxG/UF8Ne49zSqaitah
|
||||
szsKnEQcDR0AVW5zcGVjaWZpZWQWIQRRElfrvwd7eu2uXQk/aMuEzlN8mgAAmB0A
|
||||
/0F03E1UJ8/iWMtc0U8a2KP0nKHLXQvdzZFTXYGQs+zBAQC/wldPhJ51fJucKrOh
|
||||
QpVC2oxC1IkcBewTXG9yhl4oCg==
|
||||
=iw4M
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
Binary file not shown.
Binary file not shown.
44
tests/data/examples/juliet-secret.pgp
Normal file
44
tests/data/examples/juliet-secret.pgp
Normal file
@ -0,0 +1,44 @@
|
||||
-----BEGIN PGP PRIVATE KEY BLOCK-----
|
||||
Comment: 7A58 B15E 3B94 5948 3D9F FA8D 40E2 99AC 5F2B 0872
|
||||
Comment: Juliet Capulet <juliet@example.org>
|
||||
|
||||
xVgEZcT8ehYJKwYBBAHaRw8BAQdA3lxROHivYEc3bXTGDtoMuhY3rPN9zitmSEsQ
|
||||
3uMawTcAAQDdqSYdugT8ZYiXwmQupew5ioqT2q+K72pViJjuwLg4tRIBwsALBB8W
|
||||
CgB9BYJlxPx6AwsJBwkQQOKZrF8rCHJHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMu
|
||||
c2VxdW9pYS1wZ3Aub3JnjVASiFqRzmkGe1LPiY4olToBnIdQ8Xx3b4kTwjJPj7kD
|
||||
FQoIApsBAh4BFiEEelixXjuUWUg9n/qNQOKZrF8rCHIAAP4TAPsG6HdFuXr9LEUk
|
||||
38Nms2/d38hoCdPfwsPnkZYg1bOK1QEAkJah86jp9JVSyAfBO5csKdNEf6R1dXY7
|
||||
9xu1Sw67xwjNI0p1bGlldCBDYXB1bGV0IDxqdWxpZXRAZXhhbXBsZS5vcmc+wsAO
|
||||
BBMWCgCABYJlxPx6AwsJBwkQQOKZrF8rCHJHFAAAAAAAHgAgc2FsdEBub3RhdGlv
|
||||
bnMuc2VxdW9pYS1wZ3Aub3Jn1FqFnmGhxznlWBLFoRa61r8XigiWHC5KrzWmtJ59
|
||||
u0oDFQoIApkBApsBAh4BFiEEelixXjuUWUg9n/qNQOKZrF8rCHIAACMeAQDZ/w4T
|
||||
bbmIkxk/BCaRMbnayahiHhfF0c3JjyTXgFdwpQEAvpr686uEUv6IAfLZ6hQHnYdm
|
||||
xbE+6lfSsEZDF/wiUQLHWARlxPx6FgkrBgEEAdpHDwEBB0A8syceHf01lFn79GP4
|
||||
MnatpXkNXtQYeH4FoDmzJ06oygABAKOJCYTCFGd/FuhSYS7Ft/9vvg5w+DBZotGq
|
||||
mJEY+afZENPCwL8EGBYKATEFgmXE/HoJEEDimaxfKwhyRxQAAAAAAB4AIHNhbHRA
|
||||
bm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZ4sTm8Sq4aSpl0VRIrZiftDohY9IikmW
|
||||
S6oMj2oFC1BuApsCvqAEGRYKAG8FgmXE/HoJEIMEhL2szEMlRxQAAAAAAB4AIHNh
|
||||
bHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZyjznJGJYDmjWouq93Q9UX+2FV6d
|
||||
siqY+4pueKLbnY4aFiEEzb/YfSE60fznV0XtgwSEvazMQyUAAG2+AP4u3zNN3FbO
|
||||
dh/s0qEomEKIxJjRzyh2IzSomjTpvubGSQD/clAoUe02I7OpI4va44Zpw05ggHDz
|
||||
fhdlJyEVeCY0+gQWIQR6WLFeO5RZSD2f+o1A4pmsXysIcgAAfXQA/jJw9jurz03j
|
||||
ZPRY6iHsKYCWsh9WHxUFLD1I4ToS2sqjAP49kjsXhsdp9TrIzmfmQc8hI03Nnmb7
|
||||
MmrGNu1QkUbrAsdYBGXE/HoWCSsGAQQB2kcPAQEHQP3mXvoWQpYwbd6xWnL8HpfU
|
||||
7gNra50ZxQ2h4pskKi3SAAEA0cWm7zsZgoNxyiSdK8oLZOQB0+bpYZXSkv5/ra+f
|
||||
nxgR9cLAvwQYFgoBMQWCZcT8egkQQOKZrF8rCHJHFAAAAAAAHgAgc2FsdEBub3Rh
|
||||
dGlvbnMuc2VxdW9pYS1wZ3Aub3Jnc0DfMNymRnpmuM1MysdH+VZ/X91dnrPjRqtR
|
||||
n1qM1tACmyC+oAQZFgoAbwWCZcT8egkQdruOXnrPkTxHFAAAAAAAHgAgc2FsdEBu
|
||||
b3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3JngrW/Tm58TweTDzESH30JAXNgDlm109eV
|
||||
FdZj+Cn0YfQWIQTf1CEOTUC++4f87+l2u45ees+RPAAAzcsBAPwPxVqIG1KvJ0ds
|
||||
h8RoYYUCef+R3Ax5vSsnObb3FXscAQDSgesDtTZMw+9NLA0jhK+AUxyqzBdaMlbx
|
||||
McG6gWuGDRYhBHpYsV47lFlIPZ/6jUDimaxfKwhyAAAr0wD/UVJZoEQNGYRfZ4X1
|
||||
1thogaYcem4o/ek1PxWUqn44eBQBAJguCPgRAU8xc1WaTTWXAKU12+jg/tfcEkBk
|
||||
dfP/Ru8Ox10EZcT8ehIKKwYBBAGXVQEFAQEHQLljeYVLH9L60OcEfd1zhUpRoWKf
|
||||
g2EoDZCtRTEcxLhWAwEIBwAA/2xY5dNDiFdUOu1ankI4u9sL6c0BSPU3HrenQtHO
|
||||
3hOoEUzCwAAEGBYKAHIFgmXE/HoJEEDimaxfKwhyRxQAAAAAAB4AIHNhbHRAbm90
|
||||
YXRpb25zLnNlcXVvaWEtcGdwLm9yZ5w4sR1zgA6dC58p7zNfpE3vdqfDkCl3qbbr
|
||||
UquoseL9ApsMFiEEelixXjuUWUg9n/qNQOKZrF8rCHIAAMBRAP4rF1TtU5MWY13d
|
||||
LDJIsrmrVhaVFO8eGkk11bu4DsGjsAD/TAeeh3DTER/zyUssCRFd2ihvLSWk+laL
|
||||
PCdvFL+YTwY=
|
||||
=iIGf
|
||||
-----END PGP PRIVATE KEY BLOCK-----
|
41
tests/data/examples/juliet.pgp
Normal file
41
tests/data/examples/juliet.pgp
Normal file
@ -0,0 +1,41 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Comment: 7A58 B15E 3B94 5948 3D9F FA8D 40E2 99AC 5F2B 0872
|
||||
Comment: Juliet Capulet <juliet@example.org>
|
||||
|
||||
xjMEZcT8ehYJKwYBBAHaRw8BAQdA3lxROHivYEc3bXTGDtoMuhY3rPN9zitmSEsQ
|
||||
3uMawTfCwAsEHxYKAH0FgmXE/HoDCwkHCRBA4pmsXysIckcUAAAAAAAeACBzYWx0
|
||||
QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmeNUBKIWpHOaQZ7Us+JjiiVOgGch1Dx
|
||||
fHdviRPCMk+PuQMVCggCmwECHgEWIQR6WLFeO5RZSD2f+o1A4pmsXysIcgAA/hMA
|
||||
+wbod0W5ev0sRSTfw2azb93fyGgJ09/Cw+eRliDVs4rVAQCQlqHzqOn0lVLIB8E7
|
||||
lywp00R/pHV1djv3G7VLDrvHCM0jSnVsaWV0IENhcHVsZXQgPGp1bGlldEBleGFt
|
||||
cGxlLm9yZz7CwA4EExYKAIAFgmXE/HoDCwkHCRBA4pmsXysIckcUAAAAAAAeACBz
|
||||
YWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfUWoWeYaHHOeVYEsWhFrrWvxeK
|
||||
CJYcLkqvNaa0nn27SgMVCggCmQECmwECHgEWIQR6WLFeO5RZSD2f+o1A4pmsXysI
|
||||
cgAAIx4BANn/DhNtuYiTGT8EJpExudrJqGIeF8XRzcmPJNeAV3ClAQC+mvrzq4RS
|
||||
/ogB8tnqFAedh2bFsT7qV9KwRkMX/CJRAs4zBGXE/HoWCSsGAQQB2kcPAQEHQDyz
|
||||
Jx4d/TWUWfv0Y/gydq2leQ1e1Bh4fgWgObMnTqjKwsC/BBgWCgExBYJlxPx6CRBA
|
||||
4pmsXysIckcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmeL
|
||||
E5vEquGkqZdFUSK2Yn7Q6IWPSIpJlkuqDI9qBQtQbgKbAr6gBBkWCgBvBYJlxPx6
|
||||
CRCDBIS9rMxDJUcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5v
|
||||
cmco85yRiWA5o1qLqvd0PVF/thVenbIqmPuKbnii252OGhYhBM2/2H0hOtH851dF
|
||||
7YMEhL2szEMlAABtvgD+Lt8zTdxWznYf7NKhKJhCiMSY0c8odiM0qJo06b7mxkkA
|
||||
/3JQKFHtNiOzqSOL2uOGacNOYIBw834XZSchFXgmNPoEFiEEelixXjuUWUg9n/qN
|
||||
QOKZrF8rCHIAAH10AP4ycPY7q89N42T0WOoh7CmAlrIfVh8VBSw9SOE6EtrKowD+
|
||||
PZI7F4bHafU6yM5n5kHPISNNzZ5m+zJqxjbtUJFG6wLOMwRlxPx6FgkrBgEEAdpH
|
||||
DwEBB0D95l76FkKWMG3esVpy/B6X1O4Da2udGcUNoeKbJCot0sLAvwQYFgoBMQWC
|
||||
ZcT8egkQQOKZrF8rCHJHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2VxdW9pYS1w
|
||||
Z3Aub3Jnc0DfMNymRnpmuM1MysdH+VZ/X91dnrPjRqtRn1qM1tACmyC+oAQZFgoA
|
||||
bwWCZcT8egkQdruOXnrPkTxHFAAAAAAAHgAgc2FsdEBub3RhdGlvbnMuc2VxdW9p
|
||||
YS1wZ3Aub3JngrW/Tm58TweTDzESH30JAXNgDlm109eVFdZj+Cn0YfQWIQTf1CEO
|
||||
TUC++4f87+l2u45ees+RPAAAzcsBAPwPxVqIG1KvJ0dsh8RoYYUCef+R3Ax5vSsn
|
||||
Obb3FXscAQDSgesDtTZMw+9NLA0jhK+AUxyqzBdaMlbxMcG6gWuGDRYhBHpYsV47
|
||||
lFlIPZ/6jUDimaxfKwhyAAAr0wD/UVJZoEQNGYRfZ4X11thogaYcem4o/ek1PxWU
|
||||
qn44eBQBAJguCPgRAU8xc1WaTTWXAKU12+jg/tfcEkBkdfP/Ru8OzjgEZcT8ehIK
|
||||
KwYBBAGXVQEFAQEHQLljeYVLH9L60OcEfd1zhUpRoWKfg2EoDZCtRTEcxLhWAwEI
|
||||
B8LAAAQYFgoAcgWCZcT8egkQQOKZrF8rCHJHFAAAAAAAHgAgc2FsdEBub3RhdGlv
|
||||
bnMuc2VxdW9pYS1wZ3Aub3JnnDixHXOADp0LnynvM1+kTe92p8OQKXeptutSq6ix
|
||||
4v0CmwwWIQR6WLFeO5RZSD2f+o1A4pmsXysIcgAAwFEA/isXVO1TkxZjXd0sMkiy
|
||||
uatWFpUU7x4aSTXVu7gOwaOwAP9MB56HcNMRH/PJSywJEV3aKG8tJaT6Vos8J28U
|
||||
v5hPBg==
|
||||
=K2JW
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
13
tests/data/examples/juliet.pgp.rev
Normal file
13
tests/data/examples/juliet.pgp.rev
Normal file
@ -0,0 +1,13 @@
|
||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Comment: Revocation certificate for
|
||||
Comment: 7A58 B15E 3B94 5948 3D9F FA8D 40E2 99AC 5F2B 0872
|
||||
Comment: Juliet Capulet <juliet@example.org>
|
||||
|
||||
xjMEZcT8ehYJKwYBBAHaRw8BAQdA3lxROHivYEc3bXTGDtoMuhY3rPN9zitmSEsQ
|
||||
3uMawTfCwAsEIBYKAH0FgmXE/HoJEEDimaxfKwhyRxQAAAAAAB4AIHNhbHRAbm90
|
||||
YXRpb25zLnNlcXVvaWEtcGdwLm9yZxxCMSrMAAjxv4PmtEkn5JBHwnxAVs3ncsRF
|
||||
3/T+EHBpDR0AVW5zcGVjaWZpZWQWIQR6WLFeO5RZSD2f+o1A4pmsXysIcgAAj+0B
|
||||
AK7rgH7a6EVFGJaKHEQ2bs4fBlZdb8kPH+8/88k74DExAQDIUvW6MgRaGttYe/jG
|
||||
W6J9FAXu+9cIkroYwCREOJYaCg==
|
||||
=TEVF
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
Loading…
Reference in New Issue
Block a user