Skip to content

Python: Replace eval with safer alternatives - #7709

Merged
cwhite911 merged 3 commits into
OSGeo:mainfrom
cwhite911:python-eval-cleanup
Sep 2, 2026
Merged

cwhite911 merged 3 commits into
OSGeo:mainfrom
cwhite911:python-eval-cleanup

Conversation

@cwhite911

Copy link
Copy Markdown
Contributor

Fixes the 14 Bandit B307 (eval) code scanning alerts in non-vendored code. All flagged inputs are local (GRASS-shipped XML, parser tokens, model files), so this is a code quality cleanup rather than a vulnerability fix; eval is simply unnecessary at most of these sites.

  • grass.temporal (temporal_algebra.py, 9 alerts): eval_datetime_str() evaluated eval(str(a < b)) for each operator, which round-trips a bool through a string; it now compares directly. The td(A) == 1 and start_day() > 5 style comparisons built Python source by string concatenation and eval'd it; they now call the same comparison helper with float(value). The one remaining eval (boolean expression string assembled from isinstance(x, bool)-checked values and grammar tokens) is documented and marked # nosec B307.
  • wxGUI: menutree.py resolved <id> menu XML entries with eval("wx." + text), now getattr(wx, text) (verified: every <id> in the shipped menu XMLs resolves); gui_core/menu.py resolved menu handlers with eval, now getattr (all <handler> entries in the shipped XMLs are plain attribute names), which also removes the one pre-existing # nosec B307. The gmodeler loop-condition eval stays (a model's loop expression is authored by the model creator; evaluating it is equivalent to running the model) and is now documented and suppressed.
  • i.tasscap: dispatched calc1bands<N> via eval of a formatted call string, now a globals() lookup with a normal call.

Verification: the three temporal algebra testsuites (unittests_temporal_algebra.py, unittests_temporal_raster_algebra.py, unittests_temporal_vector_algebra.py) pass against nc_spm; i.tasscap runs end-to-end on synthetic bands; bandit 1.9.4 reports no B307 findings in the touched files.

This is part of a larger effort to work through the open code scanning alerts, grouped into small PRs by issue type.

Written with the assistance of Claude Code.

In temporal algebra, compare values directly instead of eval of
stringified comparisons, and route the td and global-variable
comparisons through the same helper; the remaining eval of the
internally built boolean string is documented and marked nosec. In
the wxGUI, resolve wx ids and menu handlers with getattr instead of
eval, and document the gmodeler loop-condition eval, which runs the
model author's own expression. In i.tasscap, dispatch to the band
combination function via globals() lookup.

Fixes 14 Bandit B307 (eval) alerts.
@github-actions github-actions Bot added GUI wxGUI related Python Related code is in Python libraries module imagery labels Jul 14, 2026
Comment thread gui/wxpython/core/menutree.py Resolved
@cwhite911 cwhite911 self-assigned this Jul 15, 2026
@cwhite911
cwhite911 requested a review from wenzeslaus July 15, 2026 21:17
@cwhite911
cwhite911 requested a review from wenzeslaus July 17, 2026 11:46

@wenzeslaus wenzeslaus left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The temporal expressions require further care and I didn't have time to explore it more fully before. The tests are still critical, but there are other issues which surfaced when I co-reviewed that with AI. See the individual comments.

Comment thread gui/wxpython/gui_core/menu.py Resolved
- Rename eval_datetime_str to compare_values (it no longer evals or
  takes strings) and keep a deprecated alias; add an explicit raise for
  an unknown operator instead of falling through to UnboundLocalError.
- Drop the unnecessary float()/str() coercions at both call sites so
  integer comparisons stay int-exact, matching the old eval semantics
  and the documented direction of t_var comp_op t_var.
- Add a unit test exercising all six operators over int/float/date,
  including != which no expression-level test reaches.
- gui menu: use str.removeprefix('self.') instead of lstrip, which
  strips a character set rather than a prefix (latent bug).
- Tighten the B307 nosec justification by guarding the seed condition
  value as a bool, so the claim that only booleans are evaluated holds.
@cwhite911

cwhite911 commented Jul 17, 2026 •

Copy link
Copy Markdown
Contributor Author

Addressed in the latest push:

  • Rename + alias: eval_datetime_str -> compare_values(self, left, comp, right), with eval_datetime_str kept as a .. deprecated:: 8.6.0 alias delegating to it. Added an explicit raise ValueError("Unknown comparison operator: ...") so an unrecognized operator no longer falls through to UnboundLocalError.
  • Dropped the float() (and the str() round-trip): both call sites now pass the value through unchanged. t_INT/t_FLOAT already yield real int/float, so start_year(A) == 2001 and A # B == 2 stay integer-exact, matching the old eval semantics and leaving room for the t_var comp_op t_var direction in the TODO. In eval_global_var the two branches now converge on a single compare_values(...) call after the date conversion.
  • Coverage / !=: added python/grass/temporal/tests/temporal_algebra_compare_values_test.py, asserting all six operators against int, float, and date values (equal and unequal), the int-exactness, and the unknown-operator raise. It builds the parser via __new__ (no DB connection needed since compare_values uses no instance state), so it stays a fast unit test. This makes the != branch observable.
  • menu.py lstrip: switched to str.removeprefix("self.").
  • # nosec at build_...: guarded the seed leftbool with an isinstance(..., bool) check that raises otherwise, so the "only booleans are evaluated" justification is now enforced rather than asserted, and updated the comment to match.

The except in the td/# handler dropped ValueError (no more float() to raise it) and keeps IndexError, AttributeError, TypeError.

@cwhite911
cwhite911 requested a review from wenzeslaus July 17, 2026 19:33
@github-actions github-actions Bot added the tests Related to Test Suite label Jul 18, 2026
@cwhite911

Copy link
Copy Markdown
Contributor Author

@wenzeslaus take another look at this when you get a chance. I would like to merge or close these automated codeQL so I don't have so many open PRs.

@cwhite911
cwhite911 merged commit 6990dad into OSGeo:main Sep 2, 2026
26 checks passed
@github-actions github-actions Bot added this to the 8.6.0 milestone Sep 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

GUI wxGUI related imagery libraries module Python Related code is in Python tests Related to Test Suite

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants