feat: Further syft-restrict improvements and red-team hardening#9461
Conversation
- make markers the main UX - introduce strictness flags for local assignments and base class attributes
…y and documentation
…ulti-segment imports and add corresponding tests
There was a problem hiding this comment.
Pull request overview
This PR further hardens syft-restrict’s verifier/marker workflow against bypasses found in red-team passes, tightening import/call resolution and region enforcement while updating the public API, docs, examples, and tests to match the “markers-first” UX.
Changes:
- Close multiple verifier gaps (multi-segment import binding, boundary-straddling statements treated as private, star-imports banned, safer local-alias handling and new strictness flags).
- Make
run()markers-only and introduce internal_run()for explicit-range callers; strengthen marker parsing (block markers must be on their own line). - Expand/refresh tests, docs, and examples to reflect default-deny posture and updated behaviors.
Reviewed changes
Copilot reviewed 26 out of 26 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/syft-restrict/src/syft_restrict/astutil.py | Fix import-binding semantics and add overlap detection for boundary-straddling nodes. |
| packages/syft-restrict/src/syft_restrict/verifier.py | Add boundary-straddle enforcement, star-import ban, safe-local tracking changes, and new policy-flag wiring. |
| packages/syft-restrict/src/syft_restrict/policy.py | Add optional strictness flags and allow __post_init__ as an allowed hook. |
| packages/syft-restrict/src/syft_restrict/runner.py | Make run() markers-only; add internal _run() for explicit numeric ranges; plumb policy flags. |
| packages/syft-restrict/src/syft_restrict/markers.py | Tighten marker scanning: block markers must be on a line by themselves; clearer MarkerError messaging. |
| packages/syft-restrict/tests/verify/helpers.py | Update make_policy() helper to expose the two new strictness flags. |
| packages/syft-restrict/tests/verify/test_policy_flags.py | New tests pinning behavior when strictness flags are flipped off. |
| packages/syft-restrict/tests/verify/test_bypasses.py | Add regressions for tuple-unpack/for-loop rebind clearing, boundary straddles, and multi-segment import floors. |
| packages/syft-restrict/tests/verify/test_disallowed.py | Add star-import rejection tests; adjust disallowed dunder list consistent with allowed __post_init__. |
| packages/syft-restrict/tests/verify/test_whitelist.py | Add tests for comprehension scoping and fully-private multiline calls; expand allowed dunder hook test. |
| packages/syft-restrict/tests/test_run.py | Update tests to call _run() for explicit-range cases; enforce markers-only behavior for run(). |
| packages/syft-restrict/tests/test_markers.py | Add tests ensuring code-sharing block markers raise MarkerError. |
| packages/syft-restrict/tests/obfuscate/test_obfuscate.py | Switch fixture runs to _run() for explicit-range flows. |
| packages/syft-restrict/README.md | Update guidance to default-deny allowlists, markers-only run(), and document optional strictness flags. |
| packages/syft-restrict/docs/verify.md | Update marker semantics (markers required) and clarify public-import vs private-use enforcement; star-import policy. |
| packages/syft-restrict/docs/blacklist.md | Update hook allowlist to include __post_init__. |
| packages/syft-restrict/examples/generate.py | Update example to rely on marker-resolved private region (no hand-counted ranges). |
| packages/syft-restrict/examples/generate_ranges.py | Add explicit-range regeneration example via internal _run(). |
| packages/syft-restrict/examples/generate_marked.py | Remove obsolete generator (markers are now the primary run() UX). |
| packages/syft-restrict/examples/gemma_inference.py | Add syft-restrict markers to designate private/hidden regions in the canonical example. |
| packages/syft-restrict/examples/gemma_inference.obfuscated.py | Regenerated obfuscated output reflecting marker-based private ranges. |
| packages/syft-restrict/examples/gemma_inference.certificate.json | Update certificate for new marker-resolved ranges/policy id. |
| packages/syft-restrict/examples/gemma_inference_ranges.py | Remove markers (ranges example is now driven by _run() + hand-counted ranges). |
| packages/syft-restrict/examples/gemma_inference_ranges.obfuscated.py | Regenerated ranges-based obfuscated output. |
| packages/syft-restrict/examples/gemma_inference_ranges.certificate.json | Add certificate for the explicit-ranges example path. |
| packages/syft-restrict/examples/gemma_inference_marked.certificate.json | Remove obsolete certificate for removed marked-example variant. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- Ensure run and _run read the source only once. - Enhance `_Checker` to clear safe locals for `for` loops overlapping private ranges; add test for public loop headers over private bodies. - Ensure references to ast.TryStar and ast.Match don't crash on Python < 3.11
… corresponding tests
koenvanderveen
left a comment
There was a problem hiding this comment.
Reviewed: security-focused verifier hardening. Fixes are sound and well-tested (import-binding bypass, boundary straddle, star imports, safe-local clearing, dunder-in-call, own-line markers, policy_id includes new flags). Approving.
|
awesome! |
Summary
Finishes the loose ends from #9436 and closes the verifier gaps found across three independent red-team passes (kimi-k3, Grok 4.5, Opus 4.8).
Changes
Security
API / UX:
Docs / examples:
Testing
Asana task
https://app.asana.com/1/1185126988600652/project/1216249688888494/task/1216630823225716?focus=true