3 Package Development Security Best Practices
This work-in-progress chapter includes guidance about managing secrets in packages and links for further reading.
We recommend the article Ten quick tips for staying safe online by Danielle Smalls and Greg Wilson.
3.2 GitHub access security
We recommend you secure your GitHub account with two-factor (authentication) 2FA. It is compulsory for all ropensci GitHub organization members and outside collaborators so make sure to enable it before your package is approved.
We also recommend you regularly check who has access to your package repository, and that you prune any unused access (such as from former collaborators).
3.4 Secrets in packages
This section contains guidance for when you develop a package interacting with a web resource requiring credentials (API keys, tokens, etc.). Also refer to the
httr vignette about sharing secrets.
3.4.1 Secrets in packages and user protection
Say your package needs an API key for making requests on behalf of users of your package.
In your package documentation, guide the user so the API key doesn’t end up in the .Rhistory/script of users of your package.
Encourage the use of environment variables to store the API key (or even remove the possibility to pass it as an argument to the functions?). You could link to this intro to startup files and
Or your package could depend on, or encourage the use of,
keyringto help user store variables in the specific OS’ credential stores (more secure than .Renviron): i.e. you’d create a function for setting the key, and have another one for retrieving the key; or the user would write
Sys.setenv(SUPERSECRETKEY = keyring::key_get("myservice"))at the beginning of their script.
Do not print the API key even in verbose mode in any message, warning, error.
In the GitHub issue template, it should be stated not to share any credentials. If an user of your package accidentally shares credentials in an issue, make sure they’re aware of that so they can revoke the key (i.e. ask them explicitly in an answer whether they realized they shared their key).
3.4.2 Secrets in packages and development
You’ll need to protect your secrets as you protect secrets of users, but there’s more to take into account and keep in mind.
18.104.22.168 Secrets and recorded requests in tests
If you use
httptest in tests for caching API responses, you need to make sure the recorded requests / fixtures do not contain secrets. Refer to
vcr security guidance and
httptest guidance “Redacting and Modifying Recorded Requests”, and inspect your recorded requests / fixtures before committing them the first time to be sure you got the setup right.
vcr being an rOpenSci package, you can post any question you might have to rOpenSci forum.
22.214.171.124 Secrets and collaborations
What about pull requests from external contributors? Tests using your secrets will fail unless you use some sort of mocked/cached response, so you might want to skip them depending on the context. For instance, in your CI account you could create an environment variable called
THIS_IS_ME and then skip tests based on the presence of this variable. This obviously means the PR checks by the CI are not exhaustive, so you’ll need to check out the PR locally to run all tests.
Document the behavior of your package for external PRs in CONTRIBUTING.md for the sake of people making PRs and of people reviewing them (you in a few weeks, and other authors of the package).
3.4.3 Secrets and CRAN
On CRAN, skip any tests (
skip_on_cran()) and examples (
dontrun) requiring credentials.
Precompute vignettes requiring credentials.
3.5 Further reading
Useful security resources:
rOpenSci community call “Security for R” (recording, slides, etc. see in particular the list of resources);