test: setattr/delattr hardening - #7291
Open
fracasula wants to merge 8 commits into
Open
Conversation
…enforce blocks getattr and import guards now enforce unconditionally in the candidate rudder-pytransformer image, so SANDBOX_GETATTR_GUARD_ENFORCE and SANDBOX_IMPORT_GUARD_ENFORCE no longer exist. Drop both env args from the candidate startup in TestGetattrAndModuleGuardContract and update the two inline comments that referenced them; the existing assertBlockedOnCandidate subtests are unchanged since the blocks now happen by default. Add TestWriteGuardEnforceContract, a candidate-only sibling test that starts a second candidate with SANDBOX_WRITE_GUARD_ENFORCE=true and asserts a module write (json.loads = None) and a foreign-class write (setattr(requests.exceptions.HTTPError, ...)) are both blocked with a clean 400 mentioning "not allowed" and "non-user-owned". Both targets are reached by plain top-level import + attribute read, deliberately avoiding socket.socket, which the getattr guard already blocks at the read step (requests.utils.socket is not on the value guard's reachability allow-list) and would therefore exercise the wrong guard's error message. assertBlockedOnCandidate is promoted from a closure to a package-level helper (parameterized by *bcTestEnv) so both tests share one assertion definition.
fracasula
force-pushed
the
setattr-delattr-hardening-contract
branch
from
August 19, 2026 08:42
dea89a5 to
d75af2d
Compare
fracasula
marked this pull request as ready for review
August 26, 2026 11:25
itsmihir
approved these changes
Aug 28, 2026
ktgowtham
approved these changes
Aug 28, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Contract tests for this PR, which routes every sandbox write (
obj.attr = v,del obj.attr,setattr(),delattr()) through a new write guard.WARNING: The tests should pass once we have a new PYT release.
They live in
integration_test/pytransformer_contract/security_hardening_contract_test.goand must merge together with the pytransformer PR.What is pinned
The write guard defaults to shadow (record and allow), so both sides of the switch are covered across the container boundary:
TestWriteGuardShadowContract— at the shipping default the write lands, the transformation runs to completion,transformer_write_guard_unsafe_total{kind}records it, and the alerted-on security series stays at zero.TestWriteGuardEnforceContract/TestWriteGuardDelattrContract— underSANDBOX_WRITE_GUARD_ENFORCE=truea write to a module, a foreign class, or a reserved name is refused and lands ontransformer_security_violations_total.TestWriteGuardLibraryOwnershipContract— a transformation writing to its own library records nothing, the direction that decides whether the counter is readable at all.TestWriteGuardOwnershipRegistryContract— ownership is keyed by identity, so an unhashable class is not over-blocked and a forged__hash__/__eq__cannot launder ownership.TestWriteGuardCounterUnitContract— the counter counts refused writes, not failed transformations.TestTestFlowSecurityMetricsContract/TestTestFlowEnforceContract—/testand/testRunreplay their security signals onto thetransformer_test_flow_*twins, never the production series.TestGetattrAndModuleGuardContract— the getattr value guard and the raw__getattribute__/__getattr__block.TestFactoryReprRiskContract— the new shadow-only telemetry: a transformation that both builds a factory-made class (namedtuple, three-argumenttype()) and renders text is flagged ontransformer_factory_class_repr_risk_total, while a factory class that is never rendered stays quiet. It sizes the follow-up__module__work and changes no behaviour.The write-guard, preview-twin and factory-telemetry tests are candidate-only: the guard and those metrics are new, so no released baseline image exports them to compare against.
Linear Ticket
< Fixes PIPE-3322 >
Security
Test-only change. It locks the contract that the pytransformer sandbox blocks these escapes, that the write guard refuses non-user-owned writes under enforce while changing nothing at the shadow default, and that preview traffic never reaches the production security series.