Skip to content

Commit 6242dff

Browse files
committed
refactor(branding): Rename rule prefixes from LM to PL
Updates all rule and finding codes from the legacy 'LM' (LogMaster) prefix to 'PL' (Privlog) for complete brand consistency. This change affects the Semgrep rules, the AST checker, the runner, and the documentation.
1 parent 3f9e5f1 commit 6242dff

5 files changed

Lines changed: 32 additions & 28 deletions

File tree

CONTRIBUTING.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Contributing to privlog
1+
# Contributing to Privlog
22

33
This guide is for developers who want to contribute to the `privlog` project. It explains the project's architecture and where key logic lives.
44

@@ -47,10 +47,10 @@ This guide is for developers who want to contribute to the `privlog` project. It
4747
4. **Heuristic Analysis**: Flags risky patterns like logging with `extra=...` or `json.dumps()`.
4848
5. **Custom Wrapper Analysis**: Receives the `PrivlogConfig` object and inspects function calls to see if they match a name in the `custom_wrappers` configuration, checking their keyword arguments accordingly.
4949
- **Finding Codes**:
50-
- `LM2101`: A direct sensitive identifier was found in a logging call.
51-
- `LM2201-2203`: A heuristic pattern (like `extra=...` or `json.dumps`) was found in a logging call.
52-
- `LM2301-2303`: A sensitive identifier or heuristic pattern was found in a `print()` call.
53-
- `LM2401`: A sensitive argument was passed to a custom logging wrapper defined in the user's configuration.
50+
- `PL2101`: A direct sensitive identifier was found in a logging call.
51+
- `PL2201-2203`: A heuristic pattern (like `extra=...` or `json.dumps`) was found in a logging call.
52+
- `PL2301-2303`: A sensitive identifier or heuristic pattern was found in a `print()` call.
53+
- `PL2401`: A sensitive argument was passed to a custom logging wrapper defined in the user's configuration.
5454

5555
- `privlog/rules/privlog.yml`
5656
- **Purpose:** The core Semgrep ruleset, which complements the AST checker.

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
# privlog
1+
# Privlog
2+
3+
[![PyPI](https://img.shields.io/pypi/v/privlog)](https://pypi.org/project/privlog/)
4+
[![Python](https://img.shields.io/pypi/pyversions/privlog)](https://pypi.org/project/privlog)
5+
[![License](https://img.shields.io/github/license/privlog-dev/privlog)](https://github.com/privlog-dev/privlog/blob/main/LICENSE)
26

37
A privacy-aware linter for Python projects, designed to catch accidental leaks of sensitive data in logs and `print` statements before they reach production.
48

privlog/ast_checks.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ def visit_Call(self, node: ast.Call) -> None:
179179
for arg in args_to_check:
180180
severity = _get_expr_sensitivity(arg)
181181
if severity:
182-
code = "LM2301" if is_print else "LM2101"
182+
code = "PL2301" if is_print else "PL2101"
183183
call_type = "print()" if is_print else "log"
184184
self._add_finding(node, code, f"Sensitive identifier passed to {call_type}. Hash/pseudonymize or omit.", severity)
185185
break
@@ -188,7 +188,7 @@ def visit_Call(self, node: ast.Call) -> None:
188188
if is_log:
189189
for keyword in node.keywords:
190190
if keyword.arg == 'extra':
191-
self._add_finding(node, "LM2201", "Logging with 'extra' can hide sensitive data. Review manually.", "WARNING")
191+
self._add_finding(node, "PL2201", "Logging with 'extra' can hide sensitive data. Review manually.", "WARNING")
192192
break
193193

194194
# Check 3: Custom wrapper checks
@@ -197,16 +197,16 @@ def visit_Call(self, node: ast.Call) -> None:
197197
for kw in node.keywords:
198198
if kw.arg in wrapper_rules:
199199
severity = wrapper_rules[kw.arg]
200-
self._add_finding(node, "LM2401", f"Sensitive argument '{kw.arg}' passed to custom wrapper '{func_name}'.", severity)
200+
self._add_finding(node, "PL2401", f"Sensitive argument '{kw.arg}' passed to custom wrapper '{func_name}'.", severity)
201201

202202
# Common heuristic checks for all call types
203203
for arg in node.args:
204204
if isinstance(arg, ast.Call) and isinstance(arg.func, ast.Attribute):
205205
if isinstance(arg.func.value, ast.Name) and arg.func.value.id == 'json' and arg.func.attr == 'dumps':
206-
code = "LM2302" if is_print else "LM2202"
206+
code = "PL2302" if is_print else "PL2202"
207207
self._add_finding(node, code, "Object serialized as JSON may be sensitive. Review manually.", "WARNING")
208208
if arg.func.attr == 'to_dict':
209-
code = "LM2303" if is_print else "LM2203"
209+
code = "PL2303" if is_print else "PL2203"
210210
self._add_finding(node, code, "Object converted to dict may be sensitive. Review manually.", "WARNING")
211211

212212
self.generic_visit(node)

privlog/rules/privlog.yml

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
rules:
22
#
33
# ==========================================================
4-
# privlog (LM) — Privacy/Log Hygiene "F-like" checks
4+
# privlog (PL) — Privacy/Log Hygiene "F-like" checks
55
# Focus: High-signal findings with low false positives.
66
# ==========================================================
77
#
88

99
#
10-
# LM110x — Direct identifier logging (ERROR)
10+
# PL110x — Direct identifier logging (ERROR)
1111
#
1212

13-
- id: LM1101.no-direct-wix-user-id-in-logs
13+
- id: PL1101.no-direct-wix-user-id-in-logs
1414
message: "Do not log raw wix_user_id. Use get_salted_identifier(wix_user_id) (or equivalent) before logging."
1515
severity: ERROR
1616
languages: [python]
@@ -24,7 +24,7 @@ rules:
2424
- pattern-not: logging.$L(..., get_salted_identifier($WIXID), ...)
2525
- pattern-not: logger.$L(..., get_salted_identifier($WIXID), ...)
2626

27-
- id: LM1102.no-direct-email-in-logs
27+
- id: PL1102.no-direct-email-in-logs
2828
message: "Do not log raw emails. Hash/pseudonymize (e.g., get_salted_identifier(email)) or omit."
2929
severity: ERROR
3030
languages: [python]
@@ -38,7 +38,7 @@ rules:
3838
- pattern-not: logging.$L(..., get_salted_identifier($EMAIL), ...)
3939
- pattern-not: logger.$L(..., get_salted_identifier($EMAIL), ...)
4040

41-
- id: LM1103.no-raw-ip-in-logs
41+
- id: PL1103.no-raw-ip-in-logs
4242
message: "Do not log raw IP addresses. Prefer hashed_ip / salted hash."
4343
severity: ERROR
4444
languages: [python]
@@ -56,10 +56,10 @@ rules:
5656
regex: "(?i)^(hashed_ip|salted_hash|ip_hash|identifier_hash)$"
5757

5858
#
59-
# LM120x — Secrets and auth artifacts (ERROR/WARNING)
59+
# PL120x — Secrets and auth artifacts (ERROR/WARNING)
6060
#
6161

62-
- id: LM1201.no-auth-headers-in-logs
62+
- id: PL1201.no-auth-headers-in-logs
6363
message: "Do not log Authorization/Cookie headers."
6464
severity: ERROR
6565
languages: [python]
@@ -79,10 +79,10 @@ rules:
7979
- pattern: logger.$L(..., $H.get('Set-Cookie'), ...)
8080

8181
#
82-
# LM130x — Payload dumping (ERROR)
82+
# PL130x — Payload dumping (ERROR)
8383
#
8484

85-
- id: LM1301.no-request-body-logging
85+
- id: PL1301.no-request-body-logging
8686
message: "Do not log request body/json/payload content."
8787
severity: ERROR
8888
languages: [python]
@@ -96,7 +96,7 @@ rules:
9696
- pattern: logger.$L(..., await request.json(), ...)
9797
- pattern: logger.$L(..., await request.body(), ...)
9898

99-
- id: LM1302.no-headers-dict-logging
99+
- id: PL1302.no-headers-dict-logging
100100
message: "Avoid logging full request headers (may contain cookies/tokens). Log minimal safe fields."
101101
severity: ERROR
102102
languages: [python]
@@ -107,7 +107,7 @@ rules:
107107
- pattern: logger.$L(..., dict(request.headers), ...)
108108

109109
#
110-
# LM140x — Exception logging hygiene (ERROR)
110+
# PL140x — Exception logging hygiene (ERROR)
111111
#
112112
# Goal: Encourage your privacy-safe exception pattern:
113113
# except Exception:
@@ -116,15 +116,15 @@ rules:
116116
# Flag patterns that often leak sensitive objects.
117117
#
118118

119-
- id: LM1401.no-logger-exception-with-object
119+
- id: PL1401.no-logger-exception-with-object
120120
message: "Avoid logger.exception(e) / logging.exception(e). Exception objects may contain sensitive data."
121121
severity: ERROR
122122
languages: [python]
123123
pattern-either:
124124
- pattern: logging.exception($E, ...)
125125
- pattern: logger.exception($E, ...)
126126

127-
- id: LM1402.no-error-logging-exception-object
127+
- id: PL1402.no-error-logging-exception-object
128128
message: "Avoid logging.error(e) with raw exception objects; log a generic message + safe identifiers."
129129
severity: WARNING
130130
languages: [python]
@@ -138,13 +138,13 @@ rules:
138138
regex: "^(e|err|error|exc|exception)$"
139139

140140
#
141-
# LM150x — Vendor response logging (WARNING)
141+
# PL150x — Vendor response logging (WARNING)
142142
#
143143
# Your pattern is: status_code + response.text[:200]
144144
# That's generally OK if truncated. Flag only if response.text is logged unbounded.
145145
#
146146

147-
- id: LM1501.no-unbounded-response-text
147+
- id: PL1501.no-unbounded-response-text
148148
message: "Avoid logging full vendor response.text; truncate (e.g., response.text[:200])."
149149
severity: WARNING
150150
languages: [python]

privlog/runner.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,8 +92,8 @@ def _run_semgrep(path: Path, config: Path | None, rules: Path | None, verbose: b
9292
data = json.loads(raw)
9393
for r in data.get("results", []):
9494
raw_rid = r.get("check_id", "UNKNOWN")
95-
lm_index = raw_rid.find("LM")
96-
rid = raw_rid[lm_index:] if lm_index != -1 else raw_rid
95+
pl_index = raw_rid.find("PL")
96+
rid = raw_rid[pl_index:] if pl_index != -1 else raw_rid
9797

9898
findings.append(
9999
Finding(

0 commit comments

Comments
 (0)