vaultr includes some machinery for using
vault and vaultr within packages, and within
tests in particular. They are designed to work well with testthat
but should be easily adapted to work with any other testing
framework.
In order to use this, you must set some environment variables:
-
VAULTR_TEST_SERVER_BIN_PATHmust be set to a directory where thevaultbinary can be found, the path to the vault executable, or to the stringautoto find vault on thePATH -
VAULTR_TEST_SERVER_PORTcan be set to the port where we start creating vault servers (by default this is 18200 but any high port number can be selected - we’ll create servers starting at this port number and incrementing - see below for details)
To create a vault server, run:
srv <- vaultr::vault_test_server()## ...waiting for Vault to start
As soon as srv goes out of scope and is garbage
collected, the vault server will be stopped. So keep srv
within the scope of your tests.
This object contains
-
addr: which is vault’s address -
token: a root token for this vault -
keys: a vector of unseal keys
By default the vault server is stared in “Dev”
server mode in which we run with http (not https), a single unseal
key and in-memory storage. It is not suited for any production
use.
You can create clients using vaultr::vault_client() and
passing in appropriate parameters, but it may be more convenient to use
srv$client():
vault <- srv$client()
vault## <vault: client>
## Command groups:
## audit: Interact with vault's audit devices
## auth: administer vault's authentication methods
## operator: Administration commands for vault operators
## policy: Interact with policies
## secrets: Interact with secret engines
## token: Interact and configure vault's token support
## tools: General tools provided by vault
## Commands:
## api()
## delete(path)
## help()
## list(path, full_names = FALSE)
## login(..., method = "token", mount = NULL, renew = FALSE,
## quiet = FALSE, token_only = FALSE, use_cache = TRUE)
## read(path, field = NULL, metadata = FALSE)
## status()
## unwrap(token)
## wrap_lookup(token)
## write(path, data)
vault$list("secret")## character(0)
By default the client is logged in, but you can pass
login = FALSE to create a client that needs to log in:
vault <- srv$client(login = FALSE)
vault$list("secret")## Error: Have not authenticated against vault
vault$login(token = srv$token)## Verifying token
vault$list("secret")## character(0)
You can use $export to export appropriate environment
variables to connect to your vault:
srv$export()
Sys.getenv("VAULT_ADDR")## [1] "http://127.0.0.1:18200"
Sys.getenv("VAULT_TOKEN")## [1] "2a346bc0-516b-67d8-f337-d28af0aac8d0"
Handling lack of vault gracefully
The vaultr::vault_test_server function takes an argument
if_disabled which is a callback function that will be
called on failure to start a vault server. This could be for reasons
such as:
- the user has not opted in by setting
VAULTR_TEST_SERVER_BIN_PATH - the binary is not in place
- a port could not be opened
By default this calls testthat::skip, which
interactively will appear to cause an error but if called within a
test_that block in a test will gracefully skip a test
srv <- vaultr::vault_test_server()
## Error: vault is not enabledAlternatively, provide your own handler:
srv <- vaultr::vault_test_server(if_disabled = message)In this case, vaultr::vault_test_server will return
NULL and you might wrap vault-requiring tests with:
if (!is.null(srv)) {
# ... vault requiring code here ...
}All together (and assuming testthat), use of vault
within tests might look like this example from the vaultr
tests:
test_that("list", {
srv <- vault_test_server()
cl <- srv$client()
cl$write("secret/a", list(key = 1))
cl$write("secret/b/c", list(key = 2))
cl$write("secret/b/d/e", list(key = 2))
expect_setequal(cl$list("secret"), c("a", "b/"))
expect_setequal(cl$list("secret", TRUE), c("secret/a", "secret/b/"))
expect_setequal(cl$list("secret/b"), c("c", "d/"))
expect_setequal(cl$list("secret/b", TRUE), c("secret/b/c", "secret/b/d/"))
})If you use one vault per test, as here, there’s no need to clean up - we can assume that the vault is empty at the start of the test block and not worry about cleanup at the end. If vault is not enabled this test will be skipped over gracefully.
Installing vault
To develop your package, you will need vault installed; please see the official vault docs for this.
If you use github actions, you can follow the same approach as
vaultr itself; add the environment variables
VAULTR_TEST_SERVER_BIN_PATH and
VAULTR_TEST_SERVER_PORT:
env:
...
VAULTR_TEST_SERVER_BIN_PATH: auto
VAULTR_TEST_SERVER_PORT: 18200then use the eLco/setup-vault
action to install a suitable vault binary:
- uses: eLco/setup-vault@v1See the
vaultr actions for full details.