Skip to content

Fix encrypted-password anonymization to replace instead of scrub#234

Open
manonfgoo wants to merge 5 commits intointentionet:masterfrom
manonfgoo:feature/juniper-encrypted-password
Open

Fix encrypted-password anonymization to replace instead of scrub#234
manonfgoo wants to merge 5 commits intointentionet:masterfrom
manonfgoo:feature/juniper-encrypted-password

Conversation

@manonfgoo
Copy link
Copy Markdown
Contributor

@manonfgoo manonfgoo commented Mar 23, 2026

Summary

  • Change Juniper encrypted-password handling from line-scrubbing to hash
    replacement, preserving config structure while anonymizing the value
  • Add SHA-256 ($5$) hash format detection and anonymization alongside
    existing SHA-512 ($6$) and MD5 ($1$) support
  • Add catch-all regexes for $5$ and $6$ hashes in extra_password_regexes

What changed

netconan/default_pwd_regexes.py:

  • encrypted-password regex changed from scrub-line (None) to capture-group
    replacement (group 3), using a named (?P<prefix>...) group to preserve the
    line prefix

netconan/sensitive_item_removal.py:

  • Add sha256 format to _sensitive_item_formats enum
  • Add sha256_crypt import from passlib
  • Add SHA-256 hash detection in _check_sensitive_item_format()
  • Add SHA-256 anonymization in _anonymize_value()
  • Add $5$ and $6$ catch-all regexes to extra_password_regexes
  • Change encrypted-password extra regex from scrub (None) to replace (group 1)

Before/After

Before: encrypted-password "$6$hash..." → entire line replaced with
! netconan_scrubbed (breaks config structure)

After: encrypted-password "$6$hash..."encrypted-password "$6$new_hash..."
(config remains valid, only the hash value changes)

New test files to avoid merge conflicts with other feature branches:

  • tests/unit/test_encrypted_password.py (hash verification tests)
  • tests/end_to_end/test_e2e_encrypted_password.py (e2e test)

This change is Reviewable

Manon Goo added 2 commits March 23, 2026 02:11
Changes encrypted-password handling from line-scrubbing (sensitive_item_num=None)
to targeted replacement (capture group), preserving line context. Adds SHA-256
hash format support alongside existing SHA-512, and $5$/$6$ catch-all regexes.

New test files to avoid merge conflicts with other feature branches:
- tests/unit/test_encrypted_password.py (hash verification tests)
- tests/end_to_end/test_e2e_encrypted_password.py (e2e test)
…anch

Add improved encrypted-password regex (with capture group) before the
JUNOS comment block. The original scrub-only version is left in place
as dead code so the JUNOS section stays untouched, avoiding merge
conflicts with the SSH key branch that modifies the adjacent line.
@dhalperi
Copy link
Copy Markdown
Member

dhalperi commented Mar 23, 2026

I pushed in the merge fixups for this PR. - Thanks for letting admins resolve conflicts.

Copy link
Copy Markdown
Member

@dhalperi dhalperi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dhalperi reviewed 5 files and all commit messages, and made 3 comments.
Reviewable status: all files reviewed, 3 unresolved discussions (waiting on manonfgoo).


netconan/default_pwd_regexes.py line 127 at r1 (raw file):

    [(r"(wlccp \S+ username (\S+)( .*)? password( \d)?) (\S+)(.*)", None)],
    # Juniper encrypted-password with capture group (replaces scrub-only version below).
    # TODO: delete the original encrypted-password scrubber in the JUNOS section

what's the plan for this TODO?


tests/unit/test_encrypted_password.py line 5 at r1 (raw file):

import pytest

from netconan.sensitive_item_removal import _anonymize_value

We like tests of function <file>.py:<foo> to be in tests/test_<file>py. Any good reason to deviate here?


tests/unit/test_encrypted_password.py line 7 at r1 (raw file):

from netconan.sensitive_item_removal import _anonymize_value

SALT = "saltForTest"

Are these not redundant with the ones you added in the existing test_sensitive_item_removal.py?

Copy link
Copy Markdown
Member

@dhalperi dhalperi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dhalperi made 1 comment and resolved 1 discussion.
Reviewable status: all files reviewed, 2 unresolved discussions (waiting on manonfgoo).


tests/unit/test_encrypted_password.py line 7 at r1 (raw file):

Previously, dhalperi (Dan Halperin) wrote…

Are these not redundant with the ones you added in the existing test_sensitive_item_removal.py?

seems like they are not redundant, because those ones don't check the output value.

Copy link
Copy Markdown
Member

@dhalperi dhalperi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@dhalperi made 1 comment.
Reviewable status: all files reviewed, 3 unresolved discussions (waiting on manonfgoo).


tests/unit/test_sensitive_item_removal.py line 713 at r1 (raw file):

    processed_line = replace_matching_item(regexes, config_line, pwd_lookup, SALT)
    assert "SECRET" not in processed_line
    assert _LINE_SCRUBBED_MESSAGE not in processed_line

This change broke the test. We need a new test with LINE_SCRUBBED_MESSAGE in it.

Code quote:

    assert "SECRET" not in processed_line
    assert _LINE_SCRUBBED_MESSAGE not in processed_line

@manonfgoo manonfgoo force-pushed the feature/juniper-encrypted-password branch from c64acec to fb92f40 Compare March 23, 2026 20:41
@manonfgoo
Copy link
Copy Markdown
Contributor Author

@dhalperi reviewed 5 files and all commit messages, and made 3 comments.
Reviewable status: all files reviewed, 3 unresolved discussions (waiting on manonfgoo).

netconan/default_pwd_regexes.py line 127 at r1 (raw file):

    [(r"(wlccp \S+ username (\S+)( .*)? password( \d)?) (\S+)(.*)", None)],
    # Juniper encrypted-password with capture group (replaces scrub-only version below).
    # TODO: delete the original encrypted-password scrubber in the JUNOS section

resolved this, this is the new line:

    [(r"(wlccp \S+ username (\S+)( .*)? password( \d)?) (\S+)(.*)", 1)],
    # Juniper encrypted-password with capture group (replaces scrub-only version below).
    # TODO: delete the original encrypted-password scrubber in the JUNOS section

what's the plan for this TODO?
Done

tests/unit/test_encrypted_password.py line 5 at r1 (raw file):

import pytest

from netconan.sensitive_item_removal import _anonymize_value

We like tests of function <file>.py:<foo> to be in tests/test_<file>py. Any good reason to deviate here?

I'll have a look at this

tests/unit/test_encrypted_password.py line 7 at r1 (raw file):

from netconan.sensitive_item_removal import _anonymize_value

SALT = "saltForTest"

Are these not redundant with the ones you added in the existing test_sensitive_item_removal.py?

Manon Goo added 2 commits March 23, 2026 21:53
Changes encrypted-password handling from line-scrubbing (sensitive_item_num=None)
to targeted replacement (capture group), preserving line context. Adds SHA-256
hash format support alongside existing SHA-512, and $5$/$6$ catch-all regexes.

New test files to avoid merge conflicts with other feature branches:
- tests/unit/test_encrypted_password.py (hash verification tests)
- tests/end_to_end/test_e2e_encrypted_password.py (e2e test)
- Fix wlccp regex capture group index (None -> 1)
- Delete redundant scrub-only encrypted-password regex in JUNOS section,
  now that the hash-preserving regex handles all encrypted-password lines
- Move hash verification tests into test_sensitive_item_removal.py to
  follow test file naming convention (test_<module>.py)
- Delete tests/unit/test_encrypted_password.py
@manonfgoo
Copy link
Copy Markdown
Contributor Author

Addressed all three review comments:

  1. wlccp capture group: Fixed None → 1
  2. TODO for original encrypted-password scrubber: Deleted the duplicate scrub-only regex in the JUNOS section — the capture-group version above now handles all encrypted-password lines
  3. Test file location + redundancy: Moved hash verification tests into test_sensitive_item_removal.py to follow the test_.py naming convention. These tests are not redundant — existing tests check format preservation and uniqueness, but the moved tests uniquely verify that anonymized crypt
    hashes are valid using passlib. Deleted tests/unit/test_encrypted_password.py.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants