https://github.com/rgglez/go-bash-env-redact
Redact sensitive values in files containing environment variables.
https://github.com/rgglez/go-bash-env-redact
environment-variables golang obscure privacy-protection redaction utility
Last synced: 3 days ago
JSON representation
Redact sensitive values in files containing environment variables.
- Host: GitHub
- URL: https://github.com/rgglez/go-bash-env-redact
- Owner: rgglez
- License: gpl-3.0
- Created: 2026-06-12T02:37:52.000Z (5 days ago)
- Default Branch: main
- Last Pushed: 2026-06-12T03:04:00.000Z (5 days ago)
- Last Synced: 2026-06-12T04:17:48.763Z (5 days ago)
- Topics: environment-variables, golang, obscure, privacy-protection, redaction, utility
- Language: Go
- Homepage:
- Size: 30.3 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# redactenv
[](https://www.gnu.org/licenses/gpl-3.0)
[](https://pkg.go.dev/gitub.com/rgglez/go-bash-env-redact/v5)
[](https://goreportcard.com/report/github.com/rgglez/go-bash-env-redact/v5)


*redactenv* reads a bash/`.env`-style file where each line is either:
```bash
VARIABLE=value
export VARIABLE=value
```
and writes a copy with every sensitive VALUE replaced by a safe placeholder,
keeping the structure intact (variable names, comments, quoting style,
indentation, inline comments, blank lines, etc.).
The result is safe to paste into a chatbot or send over a messaging app.
## Usage
```bash
redactenv [flags]
```
- `` — file to read, or `-` for stdin.
- `-o ` — output file (default: stdout).
- `--strict` — redact everything, including booleans, numbers and common enums.
- `--strip-comments` — remove comments (they can contain secrets too).
- `--keep-private-ips` — do not redact RFC-1918 / loopback addresses.
- `--keep ` — comma-separated variable names to leave untouched.
- `--force ` — comma-separated variable names to always redact.
## Build
### Using Make
| Target | Output | Description |
|---|---|---|
| `make` / `make build` | `build/redactenv[.exe]` | Builds for the current OS/arch (auto-detected via `go env`) |
| `make linux` | `build/redactenv_linux` | Cross-compiles for `linux/amd64` |
| `make darwin` | `build/redactenv_mac` | Cross-compiles for `darwin/arm64` |
| `make windows` | `build/redactenv.exe` | Cross-compiles for `windows/amd64` |
| `make all-platforms` | all three above | Builds for all platforms in one step |
| `make clean` | — | Removes the `build/` directory |
Override OS or architecture: `make build GOOS=linux GOARCH=arm64`.
### Manually
```bash
go build -o redactenv redactenv.go
```
Cross-compile examples:
```bash
GOOS=linux GOARCH=amd64 go build -o redactenv_linux redactenv.go
GOOS=darwin GOARCH=arm64 go build -o redactenv_mac redactenv.go
GOOS=windows GOARCH=amd64 go build -o redactenv.exe redactenv.go
```
## Installation
Move the resulting executable to your preferred directory. For example:
```bash
sudo mv build/redactenv /usr/local/bin/
```
## Architecture
The program is a single-pass pipeline with six source files, each with a single
responsibility:
```
┌─────────────────────────────────────────────────────────┐
│ main.go │
│ Parse flags → read → process each line → write │
└───────┬─────────────────────────┬───────────────────────┘
│ │
▼ ▼
┌──────────┐ ┌─────────────┐
│ io.go │ │ parser.go │
│ readLines│ │ processLine │
│writeLines│ │ splitRHS │
└──────────┘ └──────┬──────┘
│
┌─────────────┴──────────────┐
▼ ▼
┌──────────────┐ ┌──────────────────┐
│ classify.go │ │ anonymiser.go │
│classifyValue │◄─────────│ Anonymiser │
│isSensitiveKey│ │ Redact() │
└──────────────┘ │ placeholder() │
└──────────────────┘
▲ ▲
└──────────┬─────────────────┘
│
┌───────────┴──────────┐
│ patterns.go │
│ sensitivePatterns │
│ safeTextValues │
│ boolLiterals │
└──────────────────────┘
▲
┌───────────┴──────────┐
│ regexps.go │
│ assignmentRE │
│ emailRE, schemeRE… │
└──────────────────────┘
```
### Processing pipeline
For each line in the input file:
1. **`parser.go` — `processLine`**
- Skip or strip pure comment lines (`# …`).
- Match the line against `assignmentRE` to extract `indent`, optional
`export` keyword, `key`, and `rest`.
- Call `splitRHS` to separate the raw value from its quoting style (`"`, `'`,
or unquoted) and any trailing inline comment.
- Check the `--keep` / `--force` override lists; otherwise delegate to
`Anonymiser.Redact`.
- Reconstruct the output line preserving original structure.
2. **`classify.go` — `classifyValue` + `isSensitiveKey`**
- `isSensitiveKey` does a case-insensitive substring search of the variable
name against `sensitivePatterns` (e.g. `password`, `token`, `key`…).
- `classifyValue` probes the value with compiled regexps and `net.ParseIP` to
return one of: `empty`, `bool`, `int`, `float`, `email`, `ip`, `url`,
`path`, `text`.
3. **`anonymiser.go` — `Anonymiser.Redact`**
- If `sensitive=false` and `strict=false`, harmless types (`bool`, `int`,
`float`, `safeTextValues`) pass through unchanged.
- Otherwise calls `placeholder(sensitive, type, rawValue)`.
- A `map[cacheKey]string` cache ensures the same raw value always maps to the
same placeholder (consistent substitution across the file).
- Type-specific generators produce realistic-looking but safe replacements:
RFC 5737 IPs, `@example.com` emails, sanitised URLs that keep scheme and
port, paths that keep file extension.
- If the generated placeholder contains shell metacharacters and the original
was unquoted, double-quotes are added automatically.
4. **`io.go`** — thin I/O layer; supports `-` (stdin/stdout) for pipe-friendly
use.
5. **`patterns.go` / `regexps.go`** — static data and pre-compiled regexps, kept
separate to make the heuristic lists easy to audit and extend.
## Value detection strategy
Each value is classified by type (bool, integer, float, email, IP, URL, path,
plain text) and replaced by a placeholder of the same type so the redacted file
still conveys enough context to be useful:
- A variable whose **name** suggests a secret (`PASSWORD`, `TOKEN`, `KEY`,
`SECRET`, `JWT`, …) is always redacted as `REDACTED_N`, regardless of the
value.
- Emails become `userN@example.com`.
- IPv4 addresses become addresses from `203.0.113.0/24` (RFC 5737 documentation
range). IPv6 becomes `2001:db8::` (RFC 3849).
- URLs keep their scheme and port but the host/path/credentials/query are
replaced.
- Filesystem paths keep their extension.
- Repeated identical values always map to the same placeholder (consistent
substitution), so relationships between variables are preserved.
In non-strict mode, boolean literals, numbers, and common configuration enums
(`production`, `debug`, `info`, …) are left as-is because they carry no personal
information.
### Limitations
* Sensitive pattern detection is based on English variable names only.
## License
Copyright (C) 2026 Rodolfo González González.
Released under the
[GNU General Public License v3.0](https://www.gnu.org/licenses/gpl-3.0.html).
Please read the [LICENSE](LICENSE) file.