pvsecret: Add -i -o option variants

All pvattest subcommands use the command line option -i <input> and -o
<output> to specify file input and output respectively. pvsecret however
uses mostly positional arguments for <input> and <output> exclusively,
e.g. pvattest check input.bin output.yaml

$ pvsecret add secret.bin

This provides an inconsistent user interface within the Secure
Execution tools and may confuse users.

Add the -i and -o option to the subcommands if applicable.
Input/output can then be specified like so:

$ pvsecret add -i secret.bin
$ pvsecret list -o list.yaml
$ pvsecret verify -i FILE -o out.yaml
$ pvsecret retrieve -i ID -o id.yaml

Reviewed-by: Jan Höppner <hoeppner@linux.ibm.com>
Signed-off-by: Steffen Eiden <seiden@linux.ibm.com>
Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
Steffen Eiden
2026-05-19 17:32:38 +02:00
committed by Jan Höppner
parent 1d6f7d0bec
commit 080a6678fb
6 changed files with 178 additions and 39 deletions
+145 -12
View File
@@ -292,8 +292,12 @@ impl Display for RetrieveableSecretInpKind {
#[derive(Args, Debug)]
pub struct AddSecretOpt {
/// Specify the request to be sent.
#[arg(value_name = "FILE", value_hint = ValueHint::FilePath,)]
pub input: String,
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
input: Option<String>,
/// Specify the request to be sent.
#[arg(value_name = "FILE", value_hint = ValueHint::FilePath, required_unless_present("input"), conflicts_with("input"))]
input_pos: Option<String>,
/// Force the addition of add-secret requests.
///
@@ -303,6 +307,27 @@ pub struct AddSecretOpt {
pub force: bool,
}
#[derive(Debug)]
pub struct AddSecretOptComb<'a> {
pub input: &'a str,
pub force: bool,
}
impl<'a> From<&'a AddSecretOpt> for AddSecretOptComb<'a> {
fn from(value: &'a AddSecretOpt) -> Self {
let input = match (&value.input, &value.input_pos) {
(None, Some(i)) => i.as_str(),
(Some(i), None) => i.as_str(),
(Some(_), Some(_)) => unreachable!(),
(None, None) => unreachable!(),
};
Self {
input,
force: value.force,
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum, Debug, Default)]
pub enum ListSecretOutputType {
/// Human-focused, non-parsable output format
@@ -317,19 +342,48 @@ pub enum ListSecretOutputType {
#[derive(Args, Debug)]
pub struct ListSecretOpt {
/// Store the result in FILE
#[arg(value_name = "FILE", default_value = STDOUT, value_hint = ValueHint::FilePath,)]
pub output: String,
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
output: Option<String>,
/// Store the result in FILE
#[arg(value_name = "FILE", default_value = STDOUT, value_hint = ValueHint::FilePath, required_unless_present("output"), conflicts_with("output"))]
output_pos: Option<String>,
/// Define the output format of the list.
#[arg(long, value_enum, default_value_t)]
pub format: ListSecretOutputType,
}
#[derive(Debug)]
pub struct ListSecretOptComb<'a> {
pub output: &'a str,
pub format: ListSecretOutputType,
}
impl<'a> From<&'a ListSecretOpt> for ListSecretOptComb<'a> {
fn from(value: &'a ListSecretOpt) -> Self {
let output = match (&value.output, &value.output_pos) {
(None, Some(o)) => o.as_str(),
(Some(o), None) => o.as_str(),
(Some(_), Some(_)) => unreachable!(),
(None, None) => unreachable!(),
};
Self {
output,
format: value.format,
}
}
}
#[derive(Args, Debug)]
pub struct VerifyOpt {
/// Specify the request to be checked.
#[arg(value_name = "FILE", value_hint = ValueHint::FilePath,)]
pub input: String,
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
input: Option<String>,
/// Specify the request to be checked.
#[arg(value_name = "FILE", value_hint = ValueHint::FilePath, required_unless_present("input"), conflicts_with("input"))]
input_pos: Option<String>,
/// Certificate containing a public key used to verify the user data signature.
///
@@ -345,8 +399,44 @@ pub struct VerifyOpt {
///
/// If the request contained abirtary user-data the output contains this user-data with padded
/// zeros if available.
#[arg(short, long, value_name = "FILE", default_value = STDOUT, value_hint = ValueHint::FilePath,)]
pub output: String,
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath,)]
output: Option<String>,
/// Store the result in FILE
///
/// If the request contained abirtary user-data the output contains this user-data with padded
/// zeros if available.
#[arg(value_name = "FILE", default_value = STDOUT, value_hint = ValueHint::FilePath, required_unless_present("output"), conflicts_with("output"))]
output_pos: Option<String>,
}
#[derive(Debug)]
pub struct VerifyOptComb<'a> {
pub input: &'a str,
pub user_cert: Option<&'a str>,
pub output: &'a str,
}
impl<'a> From<&'a VerifyOpt> for VerifyOptComb<'a> {
fn from(value: &'a VerifyOpt) -> Self {
let input = match (&value.input, &value.input_pos) {
(None, Some(i)) => i.as_str(),
(Some(i), None) => i.as_str(),
(Some(_), Some(_)) => unreachable!(),
(None, None) => unreachable!(),
};
let output = match (&value.output, &value.output_pos) {
(None, Some(o)) => o.as_str(),
(Some(o), None) => o.as_str(),
(Some(_), Some(_)) => unreachable!(),
(None, None) => unreachable!(),
};
Self {
input,
user_cert: value.user_cert.as_deref(),
output,
}
}
}
#[derive(Args, Debug)]
@@ -358,12 +448,26 @@ pub struct RetrSecretOptions {
/// handle encodes in hexadecimal. Leading zeros are required. If there are multiple secrets in
/// the store with the same Id there are no guarantees on which specific secret is retrieved.
/// Use --inform=idx to make sure a specific secret is retrieved.
#[arg(value_name = "ID", value_hint = ValueHint::FilePath)]
pub input: String,
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath)]
input: Option<String>,
/// Specify the secret ID to be retrieved.
///
/// Input type depends on '--inform'. If `yaml` (default) is specified, it must be a yaml
/// created by the create subcommand of this tool. If `hex` is specified, it must be a 32 byte
/// handle encodes in hexadecimal. Leading zeros are required. If there are multiple secrets in
/// the store with the same Id there are no guarantees on which specific secret is retrieved.
/// Use --inform=idx to make sure a specific secret is retrieved.
#[arg(value_name = "ID", value_hint = ValueHint::FilePath, required_unless_present("input"), conflicts_with("input"))]
input_pos: Option<String>,
/// Specify the output path to place the secret value
#[arg(short, long, value_name = "FILE", default_value = STDOUT, value_hint = ValueHint::FilePath)]
pub output: String,
#[arg(short, long, value_name = "FILE", value_hint = ValueHint::FilePath)]
output: Option<String>,
/// Specify the output path to place the secret value
#[arg(value_name = "FILE", default_value = STDOUT, value_hint = ValueHint::FilePath, required_unless_present("output"), conflicts_with("output"))]
output_pos: Option<String>,
/// Define input type for the Secret ID
#[arg(long, value_enum, default_value_t)]
@@ -400,6 +504,35 @@ pub enum RetrOutFmt {
Bin,
}
#[derive(Debug)]
pub struct RetrSecretOptionsComb<'a> {
pub input: &'a str,
pub output: &'a str,
pub inform: RetrInpFmt,
}
impl<'a> From<&'a RetrSecretOptions> for RetrSecretOptionsComb<'a> {
fn from(value: &'a RetrSecretOptions) -> Self {
let input = match (&value.input, &value.input_pos) {
(None, Some(i)) => i.as_str(),
(Some(i), None) => i.as_str(),
(Some(_), Some(_)) => unreachable!(),
(None, None) => unreachable!(),
};
let output = match (&value.output, &value.output_pos) {
(None, Some(o)) => o.as_str(),
(Some(o), None) => o.as_str(),
(Some(_), Some(_)) => unreachable!(),
(None, None) => unreachable!(),
};
Self {
input,
output,
inform: value.inform,
}
}
}
#[derive(Subcommand, Debug)]
pub enum Command {
/// Create a new add-secret request.