Skip to content

docs: align README examples with current Pydantic API#336

Merged
izar merged 6 commits into
OWASP:masterfrom
izar:docs/readme-140-api-alignment
Jul 6, 2026
Merged

docs: align README examples with current Pydantic API#336
izar merged 6 commits into
OWASP:masterfrom
izar:docs/readme-140-api-alignment

Conversation

@izar

@izar izar commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • controls.isHardened: web.isHardened = True and db.isHardened = False changed to web.controls.isHardened = True / db.controls.isHardened = False. isHardened lives on Controls, not on Element. Because Element has extra="allow", the old form failed silently — it stored the value as an extra field and left controls.isHardened at its default.
  • controls.hasAccessControl: my_lambda.hasAccessControl = Truemy_lambda.controls.hasAccessControl = True. Same silent-failure mechanism.
  • db.type = DatastoreType.SQL: db.isSql = Truedb.type = DatastoreType.SQL. The actual field is isSQL (uppercase), not isSql; isSql was silently stored as an extra field. The shipped tm.py uses DatastoreType.SQL.
  • sourceFiles: web.sourceCode and db.sourceCodeweb.sourceFiles = [...] / db.sourceFiles = [...]. sourceFiles is a List[str] on Element; sourceCode was silently ignored.
  • DatastoreType import: Added to the sample import list (required by db.type = DatastoreType.SQL).
  • --describe block: Replaced stale hand-written output (showing pre-Pydantic fields that no longer exist) with verbatim output of ./tm.py --describe Server, which shows the full inherited attribute set including controls, sourceFiles, minTLSVersion, etc.
  • Usage block: Updated synopsis (added --colormap to synopsis line; changed optional arguments: to options: — Python 3.10+ argparse wording).
  • Threat condition example: f.sink.isSQLf.sink.type == DatastoreType.SQL. isSQL is a valid bool field (still exists, defaults True) but is non-discriminating for all Datastores by default; type == DatastoreType.SQL matches the idiom in the shipped tm.py.

Verified failure mode of old sample

extra="allow" on Pydantic models means every stale attribute set (web.isHardened, db.isSql, web.sourceCode, etc.) was silently stored in model_extra rather than raising a ValidationError. No error was raised; the intended fields were simply never set.

Validation

# Corrected sample
python /tmp/sample.py --dfd > /dev/null          # OK
python /tmp/sample.py --report docs/basic_template.md > /dev/null   # OK

# Test suite
uv run pytest tests/ -x -q   # 243 passed

# Diff touches only README.md
git diff --stat HEAD~1  # README.md | 93 +++...

Hypotheses that turned out wrong

  • The hypothesis stated the README uses from pytm.pytm import; it already used from pytm import correctly. Only the missing DatastoreType in the import list needed fixing.
  • docs/threats.md hits from the grep sweep (target.controls.isHardened, target.controls.hasAccessControl) are already in correct form — no changes needed there.

Out-of-scope finding

./tm.py --describe Element errors with "No such class to describe: Element" because Element is not added to _CLASS_REGISTRY in pytm/pytm.py (only its subclasses are added via _iter_subclasses). Tracked separately.

@izar izar merged commit 5e664f4 into OWASP:master Jul 6, 2026
5 checks passed
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