Copilot commented on code in PR #2779:
URL: https://github.com/apache/groovy/pull/2779#discussion_r3753644298


##########
src/test/groovy/org/codehaus/groovy/control/customizers/SecureASTCustomizerTest.groovy:
##########
@@ -754,4 +754,171 @@ final class SecureASTCustomizerTest {
             '''
         }
     }
+
+    
//--------------------------------------------------------------------------
+    // code outside method bodies: constructors and initializers
+
+    private void disallowSystemReceiver() {
+        customizer.disallowedReceivers = ['java.lang.System']
+    }
+
+    @Test
+    void testDisallowedReceiverInScriptBody() {
+        disallowSystemReceiver()
+        def shell = new GroovyShell(configuration)
+        assert hasSecurityException {
+            shell.evaluate "System.getProperty('java.version')"
+        }
+    }
+
+    @Test
+    void testDisallowedReceiverInConstructor() {
+        disallowSystemReceiver()
+        def shell = new GroovyShell(configuration)
+        assert hasSecurityException {
+            shell.evaluate '''
+                class A { A() { System.getProperty('java.version') } }
+                new A()
+            '''
+        }
+    }
+
+    @Test
+    void testDisallowedReceiverInStaticInitializer() {
+        disallowSystemReceiver()
+        def shell = new GroovyShell(configuration)
+        assert hasSecurityException {
+            shell.evaluate '''
+                class A { static { System.getProperty('java.version') } }
+                new A()
+            '''
+        }
+    }
+
+    @Test
+    void testDisallowedReceiverInObjectInitializer() {
+        disallowSystemReceiver()
+        def shell = new GroovyShell(configuration)
+        assert hasSecurityException {
+            shell.evaluate '''
+                class A { { System.getProperty('java.version') } }
+                new A()
+            '''
+        }
+    }
+
+    @Test
+    void testDisallowedReceiverInFieldInitializer() {
+        disallowSystemReceiver()
+        def shell = new GroovyShell(configuration)
+        assert hasSecurityException {
+            shell.evaluate '''
+                class A { def f = System.getProperty('java.version') }
+                new A()
+            '''
+        }
+    }
+
+    @Test
+    void testDisallowedReceiverInStaticFieldInitializer() {
+        disallowSystemReceiver()
+        def shell = new GroovyShell(configuration)
+        assert hasSecurityException {
+            shell.evaluate '''
+                class A { static def f = System.getProperty('java.version') }
+                new A()
+            '''
+        }
+    }
+
+    @Test
+    void testGeneratedScriptConstructorsAreNotChecked() {
+        // every script class has generated constructors which call 
super(Binding); they are not
+        // written by the author of the script, so they must not be subject to 
the restrictions
+        customizer.with {
+            disallowedReceivers = ['java.lang.System']
+            allowedExpressions = [BinaryExpression, ConstantExpression]
+        }
+        def shell = new GroovyShell(configuration)
+        shell.evaluate '1 + 1'
+        // no error means success
+    }
+
+    @Test
+    void testDisallowedReceiverMovedIntoGeneratedConstructor() {
+        // @TupleConstructor(pre=...) relocates the closure body into the 
constructor it generates;
+        // the statements keep their original source position, so they are 
still the author's code
+        disallowSystemReceiver()
+        def shell = new GroovyShell(configuration)
+        assert hasSecurityException {
+            shell.evaluate '''
+                @groovy.transform.TupleConstructor(pre={ 
System.getProperty('java.version') })
+                class A { String a }
+                new A('x')
+            '''
+        }
+    }
+
+    @Test
+    void testDisallowedReceiverMovedIntoGeneratedMapConstructor() {
+        disallowSystemReceiver()
+        def shell = new GroovyShell(configuration)
+        assert hasSecurityException {
+            shell.evaluate '''
+                @groovy.transform.MapConstructor(pre={ 
System.getProperty('java.version') })
+                class A { String a }
+                null
+            '''
+        }
+    }
+
+    @Test
+    void testDisallowedReceiverMovedIntoSyntheticMethod() {
+        // @ConditionalInterrupt lifts its closure into a synthetic method and 
calls it at every
+        // method start and every loop; the closure is still code the script 
author wrote
+        disallowSystemReceiver()
+        def shell = new GroovyShell(configuration)
+        assert hasSecurityException {
+            shell.evaluate '''
+                import groovy.transform.ConditionalInterrupt
+                @ConditionalInterrupt({ System.getProperty('java.version') != 
null })
+                class A { def m() { 1 } }
+                null
+            '''
+        }
+    }
+
+    @Test
+    void testGeneratedSyntheticMethodsAreNotChecked() {
+        // the compiler emits a great many synthetic methods -- property 
accessors, delegate
+        // forwarders, record components, enum machinery, trait bridges. Their 
contents carry no
+        // source position and must stay exempt, otherwise the filter is doing 
nothing
+        disallowSystemReceiver()
+        def shell = new GroovyShell(configuration)
+        shell.evaluate '''
+            trait T { def hi() { 1 } }
+            class A implements T { String p; int q }
+            class B { @Delegate List l = [] }
+            record R(String a, int b) {}
+            enum E { X, Y }
+            new A(); new B(); new R('s', 1); E.X
+        '''
+        // no error means success
+    }

Review Comment:
   `testGeneratedSyntheticMethodsAreNotChecked` doesn’t currently validate the 
behavior described in its comment: it only sets `disallowedReceivers` to 
`java.lang.System`, but the evaluated script never references `System`, so the 
test will pass even if synthetic methods were inadvertently checked. Consider 
making the test fail-fast if any generated synthetic method statements 
unexpectedly carry a source position (e.g., by using a very restrictive 
`allowedExpressions` set and a script with no authored expressions beyond a 
constant).



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to