zx
zx copied to clipboard
Feature request: redact secrets when logging
Current Behavior
If we make a call with a secret, it will be printed to stdout.
note: I'm only including shell examples for brevity, but this applies to most zx logging 🙂
If we wanted to go one step further, there could also be a $.redact(text: string)
method
Example:
const githubUrl = 'https://api.github.com/organizations';
const githubToken = 'ghs_xxxxxxxxx';
await $`curl --silent ${githubUrl} -H "Authorization: Bearer ${githubToken}"`;
// prints:
// $ curl --silent $'https://api.github.com/organizations' -H "Authorization: Bearer ghs_xxxxxxxxx"
// ^ exposed!
Requested Behavior
It would be cool if we could either redact or replace secrets.
For example, with blanket redaction:
const githubUrl = 'https://api.github.com/organizations';
const githubToken = 'ghs_xxxxxxxxx';
$.secrets.push(githubToken); // Example: Blanket redaction
await $`curl --silent ${githubUrl} -H "Authorization: Bearer ${githubToken}"`;
// prints:
// $ curl --silent $'https://api.github.com/organizations' -H "Authorization: Bearer **redacted**"
// ^ hidden
Or with contextual redaction:
const githubUrl = 'https://api.github.com/organizations';
const githubToken = 'ghs_xxxxxxxxx';
$.secrets.githubToken = githubToken; // Example: Contextual redaction
await $`curl --silent ${githubUrl} -H "Authorization: Bearer ${githubToken}"`;
// prints:
// $ curl --silent $'https://api.github.com/organizations' -H "Authorization: Bearer **githubToken**"
// ^ hidden with context
Steps to Reproduce the Problem
covered in Current Behavior
section
Specifications
- Version: 7.1.1
- Platform: Linux
Well, we already have such feature: use env:
$.env.GITHUB_TOKEN = 'ghs_xxxxxxxxx';
await $`curl --silent https://api.github.com/organizations -H "Authorization: Bearer $GITHUB_TOKEN"`;
Ahh yeah, that would work for shell commands! I'm not sure why I assumed zx would do variable interpolation instead of letting the shell handle it.
Is this something that could be expanded to other places, such as fetch requests?
For fetch we need to add support.
@antonmedv Can I work on this?
Sure 👌🏻
I can't use env variable, since the requests are sent by Octokit:
import { Octokit } from '@octokit/rest'
const octokit = new Octokit({
auth: (await $`security find-generic-password -a github-com-personal-access-token -w`).stdout.trim(),
})
await octokit.rest.repos.createDeployment({ … })
somehow zx dumps outgoing http requests, including headers, to the console.
Is there any progress? Why this got closed? Passing secrets via env vars works, but I don't think it's a good practice, it creates coupling which is not as easy to spot. The env var can disappear, but no compiler will yell that there's still an usage left.
Are you still open to contributions? I could implement it.
IMO the best API would be:
$`do-stuff --secret ${$.secret("some-secret")}`
I have some ideas for the function name: secret
, redact
.
It could produce an object like { type: "secret", contents: "some-secret" }
which would be handled later appropriately, this could also require a change in zurk
(perhaps in buildCmd
), I'm not sure how to implement it yet.