diff --git a/docs/_build/QPC_VAR_PROGRAM_NAME.1 b/docs/_build/QPC_VAR_PROGRAM_NAME.1 index fc174e0b..7e2ba693 100644 --- a/docs/_build/QPC_VAR_PROGRAM_NAME.1 +++ b/docs/_build/QPC_VAR_PROGRAM_NAME.1 @@ -160,7 +160,7 @@ When a scan runs, it uses a source that contains information such as the host na .sp To create a credential, supply the type of credential and supply SSH credentials as either a username\-password pair, a username\-key pair, or an access token. The QPC_VAR_PROJECT tool stores each set of credentials in a separate credential entry. .sp -\fBQPC_VAR_PROGRAM_NAME cred add \-\-name=\fP \fIname\fP \fB\-\-type=\fP \fI(network | vcenter | satellite | openshift | rhacs | ansible)\fP { \fB\-\-username=\fP \fIusername\fP (\fB\-\-password\fP | \fB\-\-sshkeyfile\fP \fI(ssh_keyfile | \-)\fP | \fB\-\-token\fP) | \fB\-\-vault\-secret\-path=\fP \fIpath\fP [\fB\-\-vault\-mount\-point=\fP \fImount_point\fP] } \fB[\-\-sshpassphrase]\fP \fB\-\-become\-method=\fP \fI(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )\fP \fB\-\-become\-user=\fP \fIuser\fP \fB[\-\-become\-password]\fP +\fBQPC_VAR_PROGRAM_NAME cred add \-\-name=\fP \fIname\fP \fB\-\-type=\fP \fI(network | vcenter | satellite | openshift | rhacs | ansible)\fP { \fB\-\-username=\fP \fIusername\fP (\fB\-\-password\fP | \fB\-\-sshkeyfile\fP \fI(ssh_keyfile | \-)\fP | \fB\-\-token\fP) | \fB\-\-vault\-secret\-path=\fP \fIpath\fP \fB\-\-vault\-secret\-key=\fP \fIkey\fP [\fB\-\-vault\-mount\-point=\fP \fImount_point\fP] } \fB[\-\-sshpassphrase]\fP \fB\-\-become\-method=\fP \fI(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )\fP \fB\-\-become\-user=\fP \fIuser\fP \fB[\-\-become\-password]\fP .sp \fB\-\-name=name\fP .INDENT 0.0 @@ -235,7 +235,14 @@ Prompts for the access token for authentication. Mutually exclusive with the \fB \fB\-\-vault\-secret\-path=path\fP .INDENT 0.0 .INDENT 3.5 -Sets the HashiCorp Vault secret path for credential storage. Only valid for \fBopenshift\fP and \fBansible\fP credential types. When this option is used, credentials are retrieved from the configured HashiCorp Vault server instead of being stored in the QPC database. Mutually exclusive with the \fB\-\-username\fP, \fB\-\-password\fP, \fB\-\-sshkeyfile\fP, and \fB\-\-token\fP options. +Sets the HashiCorp Vault secret path for credential storage. Only valid for \fBopenshift\fP and \fBansible\fP credential types. When this option is used, credentials are retrieved from the configured HashiCorp Vault server instead of being stored in the QPC database. Mutually exclusive with the \fB\-\-username\fP, \fB\-\-password\fP, \fB\-\-sshkeyfile\fP, and \fB\-\-token\fP options. Requires \fB\-\-vault\-secret\-key\fP\&. +.UNINDENT +.UNINDENT +.sp +\fB\-\-vault\-secret\-key=key\fP +.INDENT 0.0 +.INDENT 3.5 +Required when \fB\-\-vault\-secret\-path\fP is specified. Sets the key within the HashiCorp Vault secret from which the credential value is retrieved. .UNINDENT .UNINDENT .sp @@ -248,7 +255,7 @@ Sets the HashiCorp Vault mount point. Only valid when \fB\-\-vault\-secret\-path .sp The information in a credential might change, including passwords, become passwords, SSH keys, the become_method, tokens or even the username. For example, your local security policies might require you to change passwords periodically. Use the \fBQPC_VAR_PROGRAM_NAME cred edit\fP command to change credential information. The parameters for \fBQPC_VAR_PROGRAM_NAME cred edit\fP are the same as those for \fBQPC_VAR_PROGRAM_NAME cred add\fP\&. .sp -\fBQPC_VAR_PROGRAM_NAME cred edit \-\-name=\fP \fIname\fP \fB\-\-username=\fP \fIusername\fP (\fB\-\-password\fP | \fB\-\-sshkeyfile\fP \fI(ssh_keyfile | \-)\fP \fB| \-\-token | \-\-vault\-secret\-path\fP \fIpath\fP) \fB[\-\-sshpassphrase]\fP \fB\-\-become\-method=\fP \fI(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )\fP \fB\-\-become\-user=\fP \fIuser\fP \fB[\-\-become\-password]\fP \fB[\-\-vault\-mount\-point\fP \fImount_point\fP \fB]\fP +\fBQPC_VAR_PROGRAM_NAME cred edit \-\-name=\fP \fIname\fP \fB\-\-username=\fP \fIusername\fP (\fB\-\-password\fP | \fB\-\-sshkeyfile\fP \fI(ssh_keyfile | \-)\fP \fB| \-\-token | \-\-vault\-secret\-path\fP \fIpath\fP \fB\-\-vault\-secret\-key\fP \fIkey\fP) \fB[\-\-sshpassphrase]\fP \fB\-\-become\-method=\fP \fI(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )\fP \fB\-\-become\-user=\fP \fIuser\fP \fB[\-\-become\-password]\fP \fB[\-\-vault\-mount\-point\fP \fImount_point\fP \fB]\fP .SS Listing and Showing Credentials .sp The \fBQPC_VAR_PROGRAM_NAME cred list\fP command returns the details for every credential that is configured for QPC_VAR_PROJECT. This output includes the name and username for each entry. Secret values such as passwords and tokens are never displated in the output. @@ -1020,7 +1027,7 @@ Creating a new openshift type credential with a password .IP \(bu 2 Creating a new openshift type credential using a HashiCorp Vault secret .sp -\fBQPC_VAR_PROGRAM_NAME cred add \-\-name ocp_cred3 \-\-type openshift \-\-vault\-secret\-path ocp3_secret\fP +\fBQPC_VAR_PROGRAM_NAME cred add \-\-name ocp_cred3 \-\-type openshift \-\-vault\-secret\-path ocp3_secret \-\-vault\-secret\-key ocp3_key\fP .IP \(bu 2 Creating a new vcenter type credential .sp diff --git a/docs/_build/man-qpc.rst b/docs/_build/man-qpc.rst index 46c68658..64308c34 100644 --- a/docs/_build/man-qpc.rst +++ b/docs/_build/man-qpc.rst @@ -143,7 +143,7 @@ Creating and Editing Credentials To create a credential, supply the type of credential and supply SSH credentials as either a username-password pair, a username-key pair, or an access token. The Quipucords tool stores each set of credentials in a separate credential entry. -**qpc cred add --name=** *name* **--type=** *(network | vcenter | satellite | openshift | rhacs | ansible)* { **--username=** *username* (**--password** | **--sshkeyfile** *(ssh_keyfile | -)* | **--token**) | **--vault-secret-path=** *path* [**--vault-mount-point=** *mount_point*] } **[--sshpassphrase]** **--become-method=** *(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )* **--become-user=** *user* **[--become-password]** +**qpc cred add --name=** *name* **--type=** *(network | vcenter | satellite | openshift | rhacs | ansible)* { **--username=** *username* (**--password** | **--sshkeyfile** *(ssh_keyfile | -)* | **--token**) | **--vault-secret-path=** *path* **--vault-secret-key=** *key* [**--vault-mount-point=** *mount_point*] } **[--sshpassphrase]** **--become-method=** *(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )* **--become-user=** *user* **[--become-password]** ``--name=name`` @@ -188,7 +188,11 @@ To create a credential, supply the type of credential and supply SSH credentials ``--vault-secret-path=path`` - Sets the HashiCorp Vault secret path for credential storage. Only valid for ``openshift`` and ``ansible`` credential types. When this option is used, credentials are retrieved from the configured HashiCorp Vault server instead of being stored in the QPC database. Mutually exclusive with the ``--username``, ``--password``, ``--sshkeyfile``, and ``--token`` options. + Sets the HashiCorp Vault secret path for credential storage. Only valid for ``openshift`` and ``ansible`` credential types. When this option is used, credentials are retrieved from the configured HashiCorp Vault server instead of being stored in the QPC database. Mutually exclusive with the ``--username``, ``--password``, ``--sshkeyfile``, and ``--token`` options. Requires ``--vault-secret-key``. + +``--vault-secret-key=key`` + + Required when ``--vault-secret-path`` is specified. Sets the key within the HashiCorp Vault secret from which the credential value is retrieved. ``--vault-mount-point=mount_point`` @@ -196,7 +200,7 @@ To create a credential, supply the type of credential and supply SSH credentials The information in a credential might change, including passwords, become passwords, SSH keys, the become_method, tokens or even the username. For example, your local security policies might require you to change passwords periodically. Use the ``qpc cred edit`` command to change credential information. The parameters for ``qpc cred edit`` are the same as those for ``qpc cred add``. -**qpc cred edit --name=** *name* **--username=** *username* (**--password** | **--sshkeyfile** *(ssh_keyfile | -)* **| --token | --vault-secret-path** *path*) **[--sshpassphrase]** **--become-method=** *(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )* **--become-user=** *user* **[--become-password]** **[--vault-mount-point** *mount_point* **]** +**qpc cred edit --name=** *name* **--username=** *username* (**--password** | **--sshkeyfile** *(ssh_keyfile | -)* **| --token | --vault-secret-path** *path* **--vault-secret-key** *key*) **[--sshpassphrase]** **--become-method=** *(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )* **--become-user=** *user* **[--become-password]** **[--vault-mount-point** *mount_point* **]** Listing and Showing Credentials ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -823,7 +827,7 @@ Examples * Creating a new openshift type credential using a HashiCorp Vault secret - ``qpc cred add --name ocp_cred3 --type openshift --vault-secret-path ocp3_secret`` + ``qpc cred add --name ocp_cred3 --type openshift --vault-secret-path ocp3_secret --vault-secret-key ocp3_key`` * Creating a new vcenter type credential diff --git a/docs/_build/qpc.1 b/docs/_build/qpc.1 index a3a8e5ba..4c44764a 100644 --- a/docs/_build/qpc.1 +++ b/docs/_build/qpc.1 @@ -27,7 +27,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]] .\" new: \\n[rst2man-indent\\n[rst2man-indent-level]] .in \\n[rst2man-indent\\n[rst2man-indent-level]]u .. -.TH "qpc" "1" "April 27, 2026" "" "qpc" +.TH "qpc" "1" "May 13, 2026" "" "qpc" .SH NAME .sp qpc \- Inspect and report on product entitlement metadata from various sources, including networks and systems management solutions. @@ -160,7 +160,7 @@ When a scan runs, it uses a source that contains information such as the host na .sp To create a credential, supply the type of credential and supply SSH credentials as either a username\-password pair, a username\-key pair, or an access token. The Quipucords tool stores each set of credentials in a separate credential entry. .sp -\fBqpc cred add \-\-name=\fP \fIname\fP \fB\-\-type=\fP \fI(network | vcenter | satellite | openshift | rhacs | ansible)\fP { \fB\-\-username=\fP \fIusername\fP (\fB\-\-password\fP | \fB\-\-sshkeyfile\fP \fI(ssh_keyfile | \-)\fP | \fB\-\-token\fP) | \fB\-\-vault\-secret\-path=\fP \fIpath\fP [\fB\-\-vault\-mount\-point=\fP \fImount_point\fP] } \fB[\-\-sshpassphrase]\fP \fB\-\-become\-method=\fP \fI(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )\fP \fB\-\-become\-user=\fP \fIuser\fP \fB[\-\-become\-password]\fP +\fBqpc cred add \-\-name=\fP \fIname\fP \fB\-\-type=\fP \fI(network | vcenter | satellite | openshift | rhacs | ansible)\fP { \fB\-\-username=\fP \fIusername\fP (\fB\-\-password\fP | \fB\-\-sshkeyfile\fP \fI(ssh_keyfile | \-)\fP | \fB\-\-token\fP) | \fB\-\-vault\-secret\-path=\fP \fIpath\fP \fB\-\-vault\-secret\-key=\fP \fIkey\fP [\fB\-\-vault\-mount\-point=\fP \fImount_point\fP] } \fB[\-\-sshpassphrase]\fP \fB\-\-become\-method=\fP \fI(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )\fP \fB\-\-become\-user=\fP \fIuser\fP \fB[\-\-become\-password]\fP .sp \fB\-\-name=name\fP .INDENT 0.0 @@ -235,7 +235,14 @@ Prompts for the access token for authentication. Mutually exclusive with the \fB \fB\-\-vault\-secret\-path=path\fP .INDENT 0.0 .INDENT 3.5 -Sets the HashiCorp Vault secret path for credential storage. Only valid for \fBopenshift\fP and \fBansible\fP credential types. When this option is used, credentials are retrieved from the configured HashiCorp Vault server instead of being stored in the QPC database. Mutually exclusive with the \fB\-\-username\fP, \fB\-\-password\fP, \fB\-\-sshkeyfile\fP, and \fB\-\-token\fP options. +Sets the HashiCorp Vault secret path for credential storage. Only valid for \fBopenshift\fP and \fBansible\fP credential types. When this option is used, credentials are retrieved from the configured HashiCorp Vault server instead of being stored in the QPC database. Mutually exclusive with the \fB\-\-username\fP, \fB\-\-password\fP, \fB\-\-sshkeyfile\fP, and \fB\-\-token\fP options. Requires \fB\-\-vault\-secret\-key\fP\&. +.UNINDENT +.UNINDENT +.sp +\fB\-\-vault\-secret\-key=key\fP +.INDENT 0.0 +.INDENT 3.5 +Required when \fB\-\-vault\-secret\-path\fP is specified. Sets the key within the HashiCorp Vault secret from which the credential value is retrieved. .UNINDENT .UNINDENT .sp @@ -248,7 +255,7 @@ Sets the HashiCorp Vault mount point. Only valid when \fB\-\-vault\-secret\-path .sp The information in a credential might change, including passwords, become passwords, SSH keys, the become_method, tokens or even the username. For example, your local security policies might require you to change passwords periodically. Use the \fBqpc cred edit\fP command to change credential information. The parameters for \fBqpc cred edit\fP are the same as those for \fBqpc cred add\fP\&. .sp -\fBqpc cred edit \-\-name=\fP \fIname\fP \fB\-\-username=\fP \fIusername\fP (\fB\-\-password\fP | \fB\-\-sshkeyfile\fP \fI(ssh_keyfile | \-)\fP \fB| \-\-token | \-\-vault\-secret\-path\fP \fIpath\fP) \fB[\-\-sshpassphrase]\fP \fB\-\-become\-method=\fP \fI(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )\fP \fB\-\-become\-user=\fP \fIuser\fP \fB[\-\-become\-password]\fP \fB[\-\-vault\-mount\-point\fP \fImount_point\fP \fB]\fP +\fBqpc cred edit \-\-name=\fP \fIname\fP \fB\-\-username=\fP \fIusername\fP (\fB\-\-password\fP | \fB\-\-sshkeyfile\fP \fI(ssh_keyfile | \-)\fP \fB| \-\-token | \-\-vault\-secret\-path\fP \fIpath\fP \fB\-\-vault\-secret\-key\fP \fIkey\fP) \fB[\-\-sshpassphrase]\fP \fB\-\-become\-method=\fP \fI(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )\fP \fB\-\-become\-user=\fP \fIuser\fP \fB[\-\-become\-password]\fP \fB[\-\-vault\-mount\-point\fP \fImount_point\fP \fB]\fP .SS Listing and Showing Credentials .sp The \fBqpc cred list\fP command returns the details for every credential that is configured for Quipucords. This output includes the name and username for each entry. Secret values such as passwords and tokens are never displated in the output. @@ -1020,7 +1027,7 @@ Creating a new openshift type credential with a password .IP \(bu 2 Creating a new openshift type credential using a HashiCorp Vault secret .sp -\fBqpc cred add \-\-name ocp_cred3 \-\-type openshift \-\-vault\-secret\-path ocp3_secret\fP +\fBqpc cred add \-\-name ocp_cred3 \-\-type openshift \-\-vault\-secret\-path ocp3_secret \-\-vault\-secret\-key ocp3_key\fP .IP \(bu 2 Creating a new vcenter type credential .sp diff --git a/docs/source/man-template.rst b/docs/source/man-template.rst index e9f08532..987cfe21 100644 --- a/docs/source/man-template.rst +++ b/docs/source/man-template.rst @@ -143,7 +143,7 @@ Creating and Editing Credentials To create a credential, supply the type of credential and supply SSH credentials as either a username-password pair, a username-key pair, or an access token. The QPC_VAR_PROJECT tool stores each set of credentials in a separate credential entry. -**QPC_VAR_PROGRAM_NAME cred add --name=** *name* **--type=** *(network | vcenter | satellite | openshift | rhacs | ansible)* { **--username=** *username* (**--password** | **--sshkeyfile** *(ssh_keyfile | -)* | **--token**) | **--vault-secret-path=** *path* [**--vault-mount-point=** *mount_point*] } **[--sshpassphrase]** **--become-method=** *(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )* **--become-user=** *user* **[--become-password]** +**QPC_VAR_PROGRAM_NAME cred add --name=** *name* **--type=** *(network | vcenter | satellite | openshift | rhacs | ansible)* { **--username=** *username* (**--password** | **--sshkeyfile** *(ssh_keyfile | -)* | **--token**) | **--vault-secret-path=** *path* **--vault-secret-key=** *key* [**--vault-mount-point=** *mount_point*] } **[--sshpassphrase]** **--become-method=** *(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )* **--become-user=** *user* **[--become-password]** ``--name=name`` @@ -188,7 +188,11 @@ To create a credential, supply the type of credential and supply SSH credentials ``--vault-secret-path=path`` - Sets the HashiCorp Vault secret path for credential storage. Only valid for ``openshift`` and ``ansible`` credential types. When this option is used, credentials are retrieved from the configured HashiCorp Vault server instead of being stored in the QPC database. Mutually exclusive with the ``--username``, ``--password``, ``--sshkeyfile``, and ``--token`` options. + Sets the HashiCorp Vault secret path for credential storage. Only valid for ``openshift`` and ``ansible`` credential types. When this option is used, credentials are retrieved from the configured HashiCorp Vault server instead of being stored in the QPC database. Mutually exclusive with the ``--username``, ``--password``, ``--sshkeyfile``, and ``--token`` options. Requires ``--vault-secret-key``. + +``--vault-secret-key=key`` + + Required when ``--vault-secret-path`` is specified. Sets the key within the HashiCorp Vault secret from which the credential value is retrieved. ``--vault-mount-point=mount_point`` @@ -196,7 +200,7 @@ To create a credential, supply the type of credential and supply SSH credentials The information in a credential might change, including passwords, become passwords, SSH keys, the become_method, tokens or even the username. For example, your local security policies might require you to change passwords periodically. Use the ``QPC_VAR_PROGRAM_NAME cred edit`` command to change credential information. The parameters for ``QPC_VAR_PROGRAM_NAME cred edit`` are the same as those for ``QPC_VAR_PROGRAM_NAME cred add``. -**QPC_VAR_PROGRAM_NAME cred edit --name=** *name* **--username=** *username* (**--password** | **--sshkeyfile** *(ssh_keyfile | -)* **| --token | --vault-secret-path** *path*) **[--sshpassphrase]** **--become-method=** *(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )* **--become-user=** *user* **[--become-password]** **[--vault-mount-point** *mount_point* **]** +**QPC_VAR_PROGRAM_NAME cred edit --name=** *name* **--username=** *username* (**--password** | **--sshkeyfile** *(ssh_keyfile | -)* **| --token | --vault-secret-path** *path* **--vault-secret-key** *key*) **[--sshpassphrase]** **--become-method=** *(sudo | su | pbrun | pfexec | doas | dzdo | ksu | runas )* **--become-user=** *user* **[--become-password]** **[--vault-mount-point** *mount_point* **]** Listing and Showing Credentials ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -823,7 +827,7 @@ Examples * Creating a new openshift type credential using a HashiCorp Vault secret - ``QPC_VAR_PROGRAM_NAME cred add --name ocp_cred3 --type openshift --vault-secret-path ocp3_secret`` + ``QPC_VAR_PROGRAM_NAME cred add --name ocp_cred3 --type openshift --vault-secret-path ocp3_secret --vault-secret-key ocp3_key`` * Creating a new vcenter type credential diff --git a/qpc/cred/add.py b/qpc/cred/add.py index 815c9716..8f703402 100644 --- a/qpc/cred/add.py +++ b/qpc/cred/add.py @@ -85,6 +85,13 @@ def __init__(self, subparsers): metavar="VAULT_SECRET_PATH", help=_(messages.CRED_VAULT_SECRET_PATH_HELP), ) + self.parser.add_argument( + "--vault-secret-key", + dest="vault_secret_key", + metavar="VAULT_SECRET_KEY", + help=_(messages.CRED_VAULT_SECRET_KEY_HELP), + required=False, + ) self.parser.add_argument( "--vault-mount-point", dest="vault_mount_point", diff --git a/qpc/cred/edit.py b/qpc/cred/edit.py index a6edcd66..89d589d0 100644 --- a/qpc/cred/edit.py +++ b/qpc/cred/edit.py @@ -69,6 +69,13 @@ def __init__(self, subparsers): metavar="VAULT_SECRET_PATH", help=_(messages.CRED_VAULT_SECRET_PATH_HELP), ) + self.parser.add_argument( + "--vault-secret-key", + dest="vault_secret_key", + metavar="VAULT_SECRET_KEY", + help=_(messages.CRED_VAULT_SECRET_KEY_HELP), + required=False, + ) self.parser.add_argument( "--vault-mount-point", dest="vault_mount_point", @@ -114,6 +121,7 @@ def _validate_args(self): # Get vault options (use getattr for legacy test compatibility) vault_secret_path = getattr(self.args, "vault_secret_path", None) + vault_secret_key = getattr(self.args, "vault_secret_key", None) vault_mount_point = getattr(self.args, "vault_mount_point", None) if not ( @@ -126,6 +134,7 @@ def _validate_args(self): or self.args.become_password or self.args.token or vault_secret_path + or vault_secret_key or vault_mount_point ): logger.error(_(messages.CRED_EDIT_NO_ARGS), self.args.name) diff --git a/qpc/cred/utils.py b/qpc/cred/utils.py index a0688633..39ccf2d9 100644 --- a/qpc/cred/utils.py +++ b/qpc/cred/utils.py @@ -129,6 +129,8 @@ def build_credential_payload(args, cred_type, add_none=True): req_payload["become_user"] = args.become_user if "vault_secret_path" in args and args.vault_secret_path: req_payload["vault_secret_path"] = args.vault_secret_path + if "vault_secret_key" in args and args.vault_secret_key: + req_payload["vault_secret_key"] = args.vault_secret_key if "vault_mount_point" in args and args.vault_mount_point: req_payload["vault_mount_point"] = args.vault_mount_point @@ -170,6 +172,7 @@ def validate_vault_args(args, cred_type=None): """ # Get vault options (use getattr for legacy test compatibility) vault_secret_path = getattr(args, "vault_secret_path", None) + vault_secret_key = getattr(args, "vault_secret_key", None) vault_mount_point = getattr(args, "vault_mount_point", None) if vault_secret_path: @@ -191,6 +194,16 @@ def validate_vault_args(args, cred_type=None): logger.error(_(messages.CRED_VAULT_EXCLUSIVE_WITH_CREDS)) sys.exit(1) + # vault_secret_key is required when vault_secret_path is specified + if not vault_secret_key: + logger.error(_(messages.CRED_VAULT_SECRET_KEY_REQUIRED)) + sys.exit(1) + + # vault_secret_key can only be specified if vault_secret_path is specified + if vault_secret_key and not vault_secret_path: + logger.error(_(messages.CRED_VAULT_SECRET_KEY_REQUIRES_PATH)) + sys.exit(1) + # vault_mount_point can only be specified if vault_secret_path is specified if vault_mount_point and not vault_secret_path: logger.error(_(messages.CRED_VAULT_MOUNT_REQUIRES_PATH)) diff --git a/qpc/messages.py b/qpc/messages.py index 7d7a0a9e..8f17da66 100644 --- a/qpc/messages.py +++ b/qpc/messages.py @@ -63,6 +63,10 @@ "Only valid for openshift and ansible credential types. " "Cannot be used with --username, --password, --sshkeyfile, or --token." ) +CRED_VAULT_SECRET_KEY_HELP = ( + "HashiCorp Vault key within the secret. " + "Required when --vault-secret-path is specified." +) CRED_VAULT_MOUNT_POINT_HELP = ( "Optional HashiCorp Vault mount point. " "Only valid when --vault-secret-path is specified." @@ -79,6 +83,13 @@ "The --vault-mount-point option can only be specified " "when --vault-secret-path is also specified." ) +CRED_VAULT_SECRET_KEY_REQUIRED = ( + "The --vault-secret-key option is required when --vault-secret-path is specified." +) +CRED_VAULT_SECRET_KEY_REQUIRES_PATH = ( + "The --vault-secret-key option can only be specified " + "when --vault-secret-path is also specified." +) SOURCE_NAME_HELP = "Source name." SOURCES_NAME_HELP = "List of source names." diff --git a/qpc/tests/cred/test_vault_cred_add.py b/qpc/tests/cred/test_vault_cred_add.py index 829e25ee..927c7c29 100644 --- a/qpc/tests/cred/test_vault_cred_add.py +++ b/qpc/tests/cred/test_vault_cred_add.py @@ -37,6 +37,8 @@ def test_add_vault_openshift_green_path( OPENSHIFT_CRED_TYPE, "--vault-secret-path", "secret/data/my-creds", + "--vault-secret-key", + "my-key", ] CLI().main() assert caplog.messages[-1] == messages.CRED_ADDED % "openshift_vault_credential" @@ -63,6 +65,8 @@ def test_add_vault_ansible_green_path( ANSIBLE_SOURCE_TYPE, "--vault-secret-path", "secret/data/my-creds", + "--vault-secret-key", + "my-key", ] CLI().main() assert caplog.messages[-1] == messages.CRED_ADDED % "ansible_vault_credential" @@ -70,6 +74,7 @@ def test_add_vault_ansible_green_path( # Validate outgoing request payload payload = requests_mock.last_request.json() assert payload["vault_secret_path"] == "secret/data/my-creds" + assert payload["vault_secret_key"] == "my-key" # Mount point should not be present when not provided assert "vault_mount_point" not in payload @@ -95,6 +100,8 @@ def test_add_vault_with_mount_point( OPENSHIFT_CRED_TYPE, "--vault-secret-path", "secret/data/my-creds", + "--vault-secret-key", + "my-key", "--vault-mount-point", "custom-mount", ] @@ -104,6 +111,7 @@ def test_add_vault_with_mount_point( # Validate outgoing request payload includes mount point when provided payload = requests_mock.last_request.json() assert payload["vault_secret_path"] == "secret/data/my-creds" + assert payload["vault_secret_key"] == "my-key" assert payload["vault_mount_point"] == "custom-mount" def test_add_vault_invalid_type( @@ -127,6 +135,27 @@ def test_add_vault_invalid_type( out, err = capsys.readouterr() assert messages.CRED_VAULT_INVALID_TYPE in err + def test_add_vault_missing_key( + self, + capsys, + ): + """Test that vault secret path without vault key fails.""" + sys.argv = [ + "/bin/qpc", + "cred", + "add", + "--name", + "openshift_vault_credential", + "--type", + OPENSHIFT_CRED_TYPE, + "--vault-secret-path", + "secret/data/my-creds", + ] + with pytest.raises(SystemExit): + CLI().main() + out, err = capsys.readouterr() + assert messages.CRED_VAULT_SECRET_KEY_REQUIRED in err + @patch("sys.stdin.isatty") def test_add_vault_with_username( self, @@ -156,6 +185,28 @@ def test_add_vault_with_username( out, err = capsys.readouterr() assert messages.CRED_VAULT_EXCLUSIVE_WITH_CREDS in err + def test_add_vault_secret_key_without_path( + self, + capsys, + ): + """Test that vault key without vault secret path fails.""" + sys.argv = [ + "/bin/qpc", + "cred", + "add", + "--name", + "openshift_vault_credential", + "--type", + OPENSHIFT_CRED_TYPE, + "--password", + "--vault-secret-key", + "my-key", + ] + with pytest.raises(SystemExit): + CLI().main() + out, err = capsys.readouterr() + assert messages.CRED_VAULT_SECRET_KEY_REQUIRES_PATH in err + @patch("sys.stdin.isatty") def test_add_vault_mount_without_path( self, diff --git a/qpc/tests/cred/test_vault_cred_edit.py b/qpc/tests/cred/test_vault_cred_edit.py index b5551bc4..a90d60c6 100644 --- a/qpc/tests/cred/test_vault_cred_edit.py +++ b/qpc/tests/cred/test_vault_cred_edit.py @@ -46,6 +46,8 @@ def test_edit_vault_openshift_green_path( "openshift_cred", "--vault-secret-path", "secret/data/my-creds", + "--vault-secret-key", + "my-key", ] CLI().main() assert caplog.messages[-1] == messages.CRED_UPDATED % "openshift_cred" @@ -80,6 +82,8 @@ def test_edit_vault_ansible_green_path( "ansible_cred", "--vault-secret-path", "secret/data/my-creds", + "--vault-secret-key", + "my-key", ] CLI().main() assert caplog.messages[-1] == messages.CRED_UPDATED % "ansible_cred" @@ -87,6 +91,7 @@ def test_edit_vault_ansible_green_path( # Validate outgoing request payload payload = requests_mock.last_request.json() assert payload["vault_secret_path"] == "secret/data/my-creds" + assert payload["vault_secret_key"] == "my-key" # Mount point should not be present when not provided assert "vault_mount_point" not in payload @@ -122,6 +127,8 @@ def test_edit_vault_with_mount_point( "openshift_cred", "--vault-secret-path", "secret/data/my-creds", + "--vault-secret-key", + "my-key", "--vault-mount-point", "custom-mount", ] @@ -131,8 +138,40 @@ def test_edit_vault_with_mount_point( # Validate outgoing request payload includes mount point when provided payload = requests_mock.last_request.json() assert payload["vault_secret_path"] == "secret/data/my-creds" + assert payload["vault_secret_key"] == "my-key" assert payload["vault_mount_point"] == "custom-mount" + def test_edit_vault_missing_key( + self, + capsys, + requests_mock, + ): + """Test that vault secret path without vault key fails.""" + url = get_server_location() + CREDENTIAL_URI + requests_mock.get( + url, + status_code=200, + json={ + "count": 1, + "results": [ + {"id": 1, "name": "openshift_cred", "cred_type": "openshift"} + ], + }, + ) + sys.argv = [ + "/bin/qpc", + "cred", + "edit", + "--name", + "openshift_cred", + "--vault-secret-path", + "secret/data/my-creds", + ] + with pytest.raises(SystemExit): + CLI().main() + out, err = capsys.readouterr() + assert messages.CRED_VAULT_SECRET_KEY_REQUIRED in err + def test_edit_vault_invalid_type( self, capsys, @@ -261,3 +300,34 @@ def test_edit_vault_mount_without_path( CLI().main() out, err = capsys.readouterr() assert messages.CRED_VAULT_MOUNT_REQUIRES_PATH in err + + def test_edit_vault_secret_key_without_path( + self, + capsys, + requests_mock, + ): + """Test that vault key without vault secret path fails.""" + url = get_server_location() + CREDENTIAL_URI + requests_mock.get( + url, + status_code=200, + json={ + "count": 1, + "results": [ + {"id": 1, "name": "openshift_cred", "cred_type": "openshift"} + ], + }, + ) + sys.argv = [ + "/bin/qpc", + "cred", + "edit", + "--name", + "openshift_cred", + "--vault-secret-key", + "my-key", + ] + with pytest.raises(SystemExit): + CLI().main() + out, err = capsys.readouterr() + assert messages.CRED_VAULT_SECRET_KEY_REQUIRES_PATH in err