Files
insights/.semgrep/rules/devex/prefer-frozen-dataclasses.yaml
zeekay bc4ddf332b chore: rebase the tree onto upstream master fa1a9a60
Mechanically re-derived: bin/debrand runs over a fresh import of
posthog/posthog@fa1a9a60d4 (2026-08-06).
The pipeline (.hanzo/workflows), the Dockerfiles and bin/docker*
entrypoints, compose files, LLM.md and the squashed initial migration
are restored from the shipped tree, same as the previous import.

The prune's import-closure guard kept 21 products the new core now
imports; dropping them is a refactor now, recorded rather than forced.
2026-08-06 01:25:36 -07:00

66 lines
2.5 KiB
YAML

rules:
- id: prefer-frozen-dataclasses
message: |
Bare `@dataclass` without an explicit `frozen=` choice.
House default for value/result objects is `@frozen` from `insights.dataclasses`
(frozen, kw_only, slots; every flag overridable, e.g. `@frozen(slots=False)`
for `functools.cached_property`):
from insights.dataclasses import frozen
@frozen
class BillingPeriod:
start: datetime
end: datetime
If mutability is intentional, say so explicitly with `@dataclass(frozen=False, ...)`.
The `insights/test/test_dataclass_defaults.py` ratchet blocks new undeclared uses;
existing ones are grandfathered in its baseline and migrated over time.
Informational, not blocking. For a genuine exception, add
`# nosemgrep: prefer-frozen-dataclasses -- <reason>` on the class line.
severity: WARNING
languages: [python]
paths:
include:
- 'common/**/*.py'
- 'dags/**/*.py'
- 'ee/**/*.py'
- 'insights/**/*.py'
- 'products/**/*.py'
exclude:
- '**/migrations/**'
- '**/.semgrep/**'
patterns:
- pattern-either:
# Bare @dataclass is ambiguous: skip it when pydantic's decorator
# (with its own validation semantics) is imported under that name.
- patterns:
- pattern-either:
- pattern: |
@dataclass
class $C: ...
- pattern: |
@dataclass(...)
class $C: ...
- pattern-not-inside: |
from pydantic.dataclasses import dataclass
...
# The module-attribute form is always the stdlib decorator.
- pattern: |
@dataclasses.dataclass
class $C: ...
- pattern: |
@dataclasses.dataclass(...)
class $C: ...
- pattern-not: |
@dataclass(..., frozen=$V, ...)
class $C: ...
- pattern-not: |
@dataclasses.dataclass(..., frozen=$V, ...)
class $C: ...
metadata:
category: best-practice
subcategory:
- audit