747513bc59
Fix broken escape hatch mechanism and address reviewer feedback: - Replace non-functional comment-based pattern-not clauses with Semgrep's native # nosemgrep mechanism for the escape hatch. Semgrep strips comments from the AST so pattern-not clauses matching inline comments never fire; # nosemgrep is the only reliable per-line suppression mechanism. - Require both # nosemgrep: <rule-id> AND # error-propagation: allow on the same line: the former is the actual suppression, the latter is the mandatory human-readable audit annotation. - Add raise $EXC from $CAUSE pattern-not entries for both Exception and BaseException variants to prevent false positives on legitimate exception chaining (raise ServiceError from e). - Switch nox -s lint Semgrep invocation to audit mode (no --error) for the phased rollout: the codebase has ~337 existing suppressions that must be triaged before enforcement mode is enabled. A comment in noxfile.py documents the migration path and references #9103. - Update CONTRIBUTING.md examples and enforcement description to reflect the dual-comment requirement.
187 lines
5.8 KiB
YAML
187 lines
5.8 KiB
YAML
rules:
|
|
- id: no-eval
|
|
pattern: eval(...)
|
|
message: >
|
|
Use of eval() is a security risk. Do not use eval() in production code.
|
|
Consider using ast.literal_eval() for safe evaluation of literals.
|
|
languages: [python]
|
|
severity: ERROR
|
|
paths:
|
|
include:
|
|
- src/
|
|
|
|
- id: no-exec
|
|
pattern: exec(...)
|
|
message: >
|
|
Use of exec() is a security risk. Do not use exec() in production code.
|
|
Find an alternative approach that does not require dynamic code execution.
|
|
languages: [python]
|
|
severity: ERROR
|
|
paths:
|
|
include:
|
|
- src/
|
|
exclude:
|
|
# Intentional controlled-sandbox exec in transform pipeline.
|
|
- src/cleveragents/tool/wrapping.py
|
|
|
|
- id: no-compile-exec
|
|
pattern: compile(..., ..., "exec")
|
|
message: >
|
|
Using compile() with exec mode is a security risk.
|
|
Avoid dynamic code compilation in production code.
|
|
languages: [python]
|
|
severity: ERROR
|
|
paths:
|
|
include:
|
|
- src/
|
|
exclude:
|
|
# Intentional controlled-sandbox compile in transform pipeline.
|
|
- src/cleveragents/tool/wrapping.py
|
|
|
|
- id: no-os-system
|
|
pattern: os.system(...)
|
|
message: >
|
|
Use of os.system() is insecure. Use subprocess.run() with shell=False instead.
|
|
languages: [python]
|
|
severity: WARNING
|
|
paths:
|
|
include:
|
|
- src/
|
|
|
|
- id: no-pickle-loads
|
|
pattern: pickle.loads(...)
|
|
message: >
|
|
Use of pickle.loads() on untrusted data is a security risk.
|
|
Consider using json or a safe serialization format.
|
|
languages: [python]
|
|
severity: WARNING
|
|
paths:
|
|
include:
|
|
- src/
|
|
|
|
- id: python-no-suppressed-exception
|
|
patterns:
|
|
- pattern-either:
|
|
- patterns:
|
|
- pattern: |
|
|
try:
|
|
...
|
|
except Exception:
|
|
...
|
|
- pattern-not: |
|
|
try:
|
|
...
|
|
except Exception:
|
|
raise
|
|
- pattern-not: |
|
|
try:
|
|
...
|
|
except Exception:
|
|
raise $EXC
|
|
- pattern-not: |
|
|
try:
|
|
...
|
|
except Exception:
|
|
raise $EXC from $CAUSE
|
|
- pattern-not: |
|
|
try:
|
|
...
|
|
except Exception as $VAR:
|
|
raise
|
|
- pattern-not: |
|
|
try:
|
|
...
|
|
except Exception as $VAR:
|
|
raise $VAR
|
|
- pattern-not: |
|
|
try:
|
|
...
|
|
except Exception as $VAR:
|
|
raise $VAR from $CAUSE
|
|
- patterns:
|
|
- pattern: |
|
|
try:
|
|
...
|
|
except BaseException:
|
|
...
|
|
- pattern-not: |
|
|
try:
|
|
...
|
|
except BaseException:
|
|
raise
|
|
- pattern-not: |
|
|
try:
|
|
...
|
|
except BaseException:
|
|
raise $EXC
|
|
- pattern-not: |
|
|
try:
|
|
...
|
|
except BaseException:
|
|
raise $EXC from $CAUSE
|
|
- pattern-not: |
|
|
try:
|
|
...
|
|
except BaseException as $VAR:
|
|
raise
|
|
- pattern-not: |
|
|
try:
|
|
...
|
|
except BaseException as $VAR:
|
|
raise $VAR
|
|
- pattern-not: |
|
|
try:
|
|
...
|
|
except BaseException as $VAR:
|
|
raise $VAR from $CAUSE
|
|
message: >
|
|
Broad exception suppression detected. Do not suppress Exception or BaseException
|
|
without re-raising or narrowing to a specific exception type.
|
|
|
|
CRITICAL: Let exceptions propagate to top-level execution (see CONTRIBUTING.md).
|
|
|
|
To suppress this rule for a justified case, add the following inline comment on
|
|
the except line:
|
|
# nosemgrep: python-no-suppressed-exception # error-propagation: allow
|
|
|
|
The '# nosemgrep' comment is the actual suppression mechanism (Semgrep native).
|
|
The '# error-propagation: allow' annotation is required for human auditability.
|
|
|
|
Example of allowed suppression:
|
|
try:
|
|
resource.cleanup()
|
|
except Exception: # nosemgrep: python-no-suppressed-exception # error-propagation: allow
|
|
pass # Resource already cleaned up; safe to ignore
|
|
languages: [python]
|
|
severity: ERROR
|
|
paths:
|
|
include:
|
|
- src/
|
|
|
|
- id: python-no-suppress-exception
|
|
patterns:
|
|
- pattern-either:
|
|
- pattern: contextlib.suppress(Exception)
|
|
- pattern: contextlib.suppress(BaseException)
|
|
message: >
|
|
Use of contextlib.suppress(Exception) or contextlib.suppress(BaseException)
|
|
is not allowed. Do not suppress broad exception types.
|
|
|
|
CRITICAL: Let exceptions propagate to top-level execution (see CONTRIBUTING.md).
|
|
|
|
To suppress this rule for a justified case, add the following inline comment on
|
|
the same line as the suppress call:
|
|
# nosemgrep: python-no-suppress-exception # error-propagation: allow
|
|
|
|
The '# nosemgrep' comment is the actual suppression mechanism (Semgrep native).
|
|
The '# error-propagation: allow' annotation is required for human auditability.
|
|
|
|
Example of allowed suppression:
|
|
with contextlib.suppress(Exception): # nosemgrep: python-no-suppress-exception # error-propagation: allow
|
|
resource.cleanup() # Resource already cleaned up; safe to ignore
|
|
languages: [python]
|
|
severity: ERROR
|
|
paths:
|
|
include:
|
|
- src/
|