Draft: add -m/--mask flag to dotenv list (sensitivity-gated) - #688
Closed
maorq08 wants to merge 1 commit into
Closed
Draft: add -m/--mask flag to dotenv list (sensitivity-gated)#688maorq08 wants to merge 1 commit into
maorq08 wants to merge 1 commit into
Conversation
Masks displayed values whose key looks sensitive (case-insensitive substring match against a keyword list: KEY, SECRET, TOKEN, PASSWORD, PASSWD, PWD, CREDENTIAL, AUTH, PRIVATE, ACCESS, CERT, DSN, CONNECTION_STRING, CONN_STRING - the convention used by mise-en-place, Airflow, and gitleaks). Values longer than 4 chars show first/last 2 chars with **** in between, values of 4 chars or fewer become **** entirely. Non-sensitive keys and None/unset values are left untouched. The transform is applied once to the values dict before the --format branch, so simple/shell/export/json output are all masked consistently.
Author
|
Closing - this was a draft opened for internal review only, not an upstream contribution proposal. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This is a draft PR opened for internal review only. It is not being proposed as an
official contribution to
python-dotenvand is not ready to merge. Please do not reviewor merge it as an upstream contribution.
What this adds
A
-m/--maskflag ondotenv listthat redacts values whose key looks sensitive,so secrets don't get printed in plaintext by
dotenv list(e.g. in a terminal recording,CI log, or screen share).
Masking rule
Two independent pieces, both gated per-key:
_is_sensitive_key(key)does a case-insensitive substringmatch against a fixed keyword list:
KEY,SECRET,TOKEN,PASSWORD,PASSWD,PWD,CREDENTIAL,AUTH,PRIVATE,ACCESS,CERT,DSN,CONNECTION_STRING,CONN_STRING. This is the same substring-match convention used by mise-en-place,Apache Airflow's keyword-based masking, and gitleaks' keyword list — e.g.
MY_API_KEYmatches on
KEY,DB_PASSWORDmatches onPASSWORD. A key that doesn't match printsits value completely unchanged, even with
--maskon._mask_value(value), applied only to values whosekey matched the heuristic:
MY_SECRET_KEY→MY****EY****entirelyNone/unset values (a bare key with no=valuein the.envfile) are left untouchedeither way, so
--format=json'snulloutput and the plain formats' existing"skip if value is None" behavior are unchanged.
Format-agnostic by construction
The masking transform is applied once, to the
valuesdict returned bydotenv_values(stream=stream), immediately after that call and before the--formatbranch in
list_values(src/dotenv/cli.py). That meanssimple(default),json,shell, andexportoutput are all masked consistently — the transform isn'tduplicated per format branch.
Tests
Added to
tests/test_cli.py, following the file's existingcli/dotenv_pathfixtureand
CliRunner-based style:test_list_masktable extended across all four--formatvalues (valuestest_list_mask_non_sensitive_key_unmasked— the key case proving the heuristicactually gates masking rather than masking everything (
PORT=8080prints unmasked).test_list_mask_short_flag— covers the-malias.test_list_mask_empty_value— an explicitKEY=(empty string, distinct from a barekey with no
=at all) masks to****.test_list_mask_five_char_boundary— a 5-character value is the first to cross intothe partial-reveal branch.
test_list_mask_custom_file—--maskcombined with an explicit non-default--filepath.test_list_mask_mixed_sensitive_and_non_sensitive(+ a--format=jsonvariant) — asensitive and a non-sensitive key in the same file, so per-key gating is visible in
one result rather than only single-key cases.
Full suite: 266 passed, 1 skipped locally (plus 3 pre-existing failures in
test_run_with_invalid_cmd/test_run_with_version/test_run_with_command_flagsthatreproduce identically on unmodified
main— they're a macOS BSD-printenvenvironmentincompatibility, unrelated to this change).
ruff checkandmypyare clean on bothchanged files.
CHANGELOG
Added an
## [Unreleased] / ### Addedentry describing the sensitivity-gated behavior.