zx icon indicating copy to clipboard operation
zx copied to clipboard

Feature request: redact secrets when logging

Open vikaspotluri123 opened this issue 2 years ago • 6 comments

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

vikaspotluri123 avatar Nov 20 '22 18:11 vikaspotluri123

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"`;

antonmedv avatar Nov 20 '22 19:11 antonmedv

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?

vikaspotluri123 avatar Nov 20 '22 20:11 vikaspotluri123

For fetch we need to add support.

antonmedv avatar Nov 20 '22 20:11 antonmedv

@antonmedv Can I work on this?

SoulPancake avatar Nov 23 '22 18:11 SoulPancake

Sure 👌🏻

antonmedv avatar Nov 23 '22 19:11 antonmedv

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.

wereHamster avatar Feb 27 '23 08:02 wereHamster

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.

kosciolek avatar Aug 08 '24 13:08 kosciolek