diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 000000000..48ad4ab77
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @jenkinsci/script-security-plugin-developers
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index f3f604548..2e90055d3 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -4,10 +4,6 @@ updates:
directory: "/"
schedule:
interval: "daily"
- ignore:
- # Caffeine 3.x requires Java 11, so we cannot update until Jenkins requires Java 11
- - dependency-name: "com.github.ben-manes.caffeine:caffeine"
- versions: ["[3.0.0,)"]
- package-ecosystem: github-actions
directory: /
schedule:
diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml
deleted file mode 100644
index 0d0b1c994..000000000
--- a/.github/release-drafter.yml
+++ /dev/null
@@ -1 +0,0 @@
-_extends: .github
diff --git a/.github/workflows/cd.yaml b/.github/workflows/cd.yaml
index 8fa03bb92..0279984d7 100644
--- a/.github/workflows/cd.yaml
+++ b/.github/workflows/cd.yaml
@@ -8,52 +8,8 @@ on:
- completed
jobs:
- validate:
- runs-on: ubuntu-latest
- outputs:
- should_release: ${{ steps.verify-ci-status.outputs.result == 'success' && steps.interesting-categories.outputs.interesting == 'true' }}
- steps:
- - name: Verify CI status
- uses: jenkins-infra/verify-ci-status-action@v1.2.0
- id: verify-ci-status
- with:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- output_result: true
-
- - name: Release Drafter
- uses: release-drafter/release-drafter@v5
- if: steps.verify-ci-status.outputs.result == 'success'
- with:
- name: next
- tag: next
- version: next
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- - name: Check interesting categories
- uses: jenkins-infra/interesting-category-action@v1.0.0
- id: interesting-categories
- if: steps.verify-ci-status.outputs.result == 'success'
- with:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
-
- release:
- runs-on: ubuntu-latest
- needs: [validate]
- if: needs.validate.outputs.should_release == 'true'
- steps:
- - name: Check out
- uses: actions/checkout@v3
- with:
- fetch-depth: 0
- - name: Set up JDK 8
- uses: actions/setup-java@v3
- with:
- distribution: 'temurin'
- java-version: 8
- - name: Release
- uses: jenkins-infra/jenkins-maven-cd-action@v1.2.0
- with:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
- MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }}
+ maven-cd:
+ uses: jenkins-infra/github-reusable-workflows/.github/workflows/maven-cd.yml@v1
+ secrets:
+ MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
+ MAVEN_TOKEN: ${{ secrets.MAVEN_TOKEN }}
diff --git a/.github/workflows/jenkins-security-scan.yml b/.github/workflows/jenkins-security-scan.yml
new file mode 100644
index 000000000..c7b41fc29
--- /dev/null
+++ b/.github/workflows/jenkins-security-scan.yml
@@ -0,0 +1,21 @@
+name: Jenkins Security Scan
+
+on:
+ push:
+ branches:
+ - master
+ pull_request:
+ types: [ opened, synchronize, reopened ]
+ workflow_dispatch:
+
+permissions:
+ security-events: write
+ contents: read
+ actions: read
+
+jobs:
+ security-scan:
+ uses: jenkins-infra/jenkins-security-scan/.github/workflows/jenkins-security-scan.yaml@v2
+ with:
+ java-cache: 'maven' # Optionally enable use of a build dependency cache. Specify 'maven' or 'gradle' as appropriate.
+ # java-version: 21 # Optionally specify what version of Java to set up for the build, or remove to use a recent default.
diff --git a/.gitignore b/.gitignore
index 75bad940c..d055f499a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
target
work
-
+/.classpath
+/.project
+/.settings/
.idea
*.iml
.*.sw*
diff --git a/.mvn/extensions.xml b/.mvn/extensions.xml
index a65d82e1b..4e0774d51 100644
--- a/.mvn/extensions.xml
+++ b/.mvn/extensions.xml
@@ -2,6 +2,6 @@
io.jenkins.tools.incrementalsgit-changelist-maven-extension
- 1.3
+ 1.8
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index ce33869b3..000000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,704 +0,0 @@
-# Changelog
-
-From of version 1.77 see [GitHub Releases](https://github.com/jenkinsci/script-security-plugin/releases)
-
-## Version 1.76
-
-Release date: 2021-02-01
-
-* Improvement: Add the following to the default list of approved signatures ([PR #308](https://github.com/jenkinsci/script-security-plugin/pull/308), [PR #310](https://github.com/jenkinsci/script-security-plugin/pull/310)):
- * All static methods and fields in `java.lang.Math`
- * All methods related to `java.lang.StringBuilder` and `java.lang.StringBuffer`
- * All methods related to `java.lang.CharSequence` and `java.lang.String` apart from `String.intern()`
- * All static methods and fields in `java.nio.charset.Charset`
- * All methods related to `java.util.Base64`, `java.util.Base64.Decoder`, and `java.util.Base64.Encoder`
-* Internal: Update dependencies and parent POM ([PR #311](https://github.com/jenkinsci/script-security-plugin/pull/311), [PR #313](https://github.com/jenkinsci/script-security-plugin/pull/313), [PR #314](https://github.com/jenkinsci/script-security-plugin/pull/314), [PR #316](https://github.com/jenkinsci/script-security-plugin/pull/316), [PR #317](https://github.com/jenkinsci/script-security-plugin/pull/317), [PR #321](https://github.com/jenkinsci/script-security-plugin/pull/321), [PR #323](https://github.com/jenkinsci/script-security-plugin/pull/323), [PR #324](https://github.com/jenkinsci/script-security-plugin/pull/324), [PR #326](https://github.com/jenkinsci/script-security-plugin/pull/326))
-
-## Version 1.75
-
-Release date: 2020-09-23
-
-* [Fix sandbox bypass vulnerability](https://jenkins.io/security/advisory/2020-09-23/#SECURITY-2020)
-* Improvement: Add the following to the default list of approved signatures:
- * `DefaultGroovyMethods.and(Boolean, Boolean)`
- * `DefaultGroovyMethods.toBoolean(Boolean)`
- * `DefaultGroovyMethods.toDouble(String)`
- * `StringGroovyMethods.toBoolean(String)`
- * `StringGroovyMethods.toDouble(CharSequence)`
- * `StringGroovyMethods.toDouble(String)`
- * `StringGroovyMethods.toInteger(CharSequence)`
- * `StringGroovyMethods.toInteger(String)`
-
-## Version 1.74
-
-Release date: 2020-06-30
-
-* Improvement: On the Manage Jenkins page in Jenkins 2.226 and newer, display the link to the In-process Script Approval page under "Security" instead of "Uncategorized". ([PR 302](https://github.com/jenkinsci/script-security-plugin/pull/302))
-* Improvement: Add the following to the list of approved Jenkins-related signatures:
- * `BallColor.getHtmlBaseColor`
- * `Result.color`
- * `Result.fromString(String)`
-
-## Version 1.73
-
-Release date: 2020-06-03
-
-* Fix security vulnerability. ([SECURITY-1866](https://www.jenkins.io/security/advisory/2020-06-03/#SECURITY-1866))
-
-## Version 1.72
-
-Release date: 2020-05-11
-
-* This plugin now requires Jenkins 2.176.4 or newer.
-* Improvement: Add various methods to the default list of approved signatures: ([JENKINS-61952](https://issues.jenkins-ci.org/browse/JENKINS-61952), [PR 242](https://github.com/jenkinsci/script-security-plugin/pull/242), [PR 295](https://github.com/jenkinsci/script-security-plugin/pull/295), [PR 296](https://github.com/jenkinsci/script-security-plugin/pull/296))
- * Remaining `java.util.regex.Matcher` methods
- * Methods related to `java.time.Instant`
- * Methods and fields defined on `java.text.DateFormat`
- * Most methods defined on `java.text.Format`
- * Methods and fields defined on `java.util.Calendar`
- * `Boolean.booleanValue`
- * `Collection.containsAll(Collection)`
- * `List.indexOf(Object)`
- * Various extension methods defined in `DefaultGroovyMethods`
-* Improvement: Make `SecureGroovyScript` and `ClasspathEntry` serializable so that they can be used by Active Choices Plugin. ([JENKINS-39742](https://issues.jenkins-ci.org/browse/JENKINS-39742))
-* Fix: Clear static field signatures correctly when signature approvals are reset. ([PR 290](https://github.com/jenkinsci/script-security-plugin/pull/290))
-* Internal: Update parent POM and minimum required Jenkins version to fix build errors when testing against new versions of Jenkins. ([PR 293](https://github.com/jenkinsci/script-security-plugin/pull/293))
-* Internal: Update caffeine dependency to 2.8.2. ([PR 294](https://github.com/jenkinsci/script-security-plugin/pull/294))
-
-## Version 1.71
-
-Release date: 2020-03-09
-
-* [Fix sandbox bypass vulnerability](https://jenkins.io/security/advisory/2020-03-09/#SECURITY-1754)
-
-## Version 1.70
-
-Release date: 2020-03-18
-
-* [Fix sandbox bypass vulnerability](https://jenkins.io/security/advisory/2020-02-12/#SECURITY-1713)
-
-## Version 1.69
-
-Release date: 2020-01-27
-
-* Improvement: Add various methods to the default list of approved signatures: ([PR 280](https://github.com/jenkinsci/script-security-plugin/pull/280), [PR 281](https://github.com/jenkinsci/script-security-plugin/pull/281), [PR 283](https://github.com/jenkinsci/script-security-plugin/pull/283))
- * All remaining static methods in the `java.util.Collections` class
- * Groovy's `List.getAt(Collection)` extension method
- * Groovy's `List.transpose()` extension method
- * `Integer.parse(String, int)`
- * All of the fields in the `java.time.DayOfWeek` enum
-* Internal: Add better logging for issues encountered in tests, update test-scope dependencies. ([PR 279](https://github.com/jenkinsci/script-security-plugin/pull/279), [PR 284](https://github.com/jenkinsci/script-security-plugin/pull/284))
-
-## Version 1.68
-
-Release date: 2019-11-21
-
-* [Fix sandbox bypass vulnerability](https://jenkins.io/security/advisory/2019-11-21/#SECURITY-1658)
-
-## Version 1.67
-
-Release date: 2019-11-13
-
-* Fix: Remove approved signatures that did not correspond to real signatures. ([PR 268](https://github.com/jenkinsci/script-security-plugin/pull/268))
-* Improvement: Add the following to the default list of approved signatures:
- * `Object[].getAt(IntRange)`
- * All remaining methods in the `java.util.regex` package
- * Getters/setters on `Date`
- * Various extension methods defined in `DateGroovyMethods`
-* Internal: Migrate Wiki content to GitHub. ([PR 264](https://github.com/jenkinsci/script-security-plugin/pull/264))
-
-## Version 1.66
-
-Release date: 2019-10-01
-
-* [JENKINS-59587](https://issues.jenkins-ci.org/browse/JENKINS-59587) - Fix issue that caused a cache used by the class loader for sandboxed Groovy scripts to be cleared out by the garbage collector when it should not have been. This could lead to performance issues for complex sandboxed scripts.
-
-## Version 1.65
-
-Release date: 2019-10-01
-
-* [Fix sandbox bypass vulnerability](https://jenkins.io/security/advisory/2019-10-01/#SECURITY-1579)
-
-## Version 1.64
-
-Release date: 2019-09-13
-
-* [JENKINS-57563](https://issues.jenkins-ci.org/browse/JENKINS-57563) - Add support for configuring script approvals using [Jenkins Configuration as Code Plugin](https://plugins.jenkins.io/configuration-as-code).
-
-## Version 1.63
-
-Release date: 2019-09-12
-
-* [Fix sandbox bypass security vulnerabilities](https://jenkins.io/security/advisory/2019-09-12/#SECURITY-1538)
-
-## Version 1.62
-
-Release date: 2019-07-31
-
-* [Fix sandbox bypass security vulnerabilities](https://jenkins.io/security/advisory/2019-07-31/)
-
-## Version 1.61
-
-Release date: 2019-07-05
-
-* [JENKINS-56682](https://issues.jenkins-ci.org/browse/JENKINS-56682) - Fix the use of script-level initializers in sandboxed Groovy scripts, which was a regression from version 1.54.
-* [JENKINS-47430](https://issues.jenkins-ci.org/browse/JENKINS-47430) - Replace Guava cache used in for sandbox class loading with Caffeine to fix some performance issues and deadlocks.
-* Add the following methods to the default list of approved signatures:
- * `Number.times(Closure)`
- * `new PrintWriter(Writer)`
- * `Reader.read()`
- * `Reader.read(char[])`
- * `Reader.read(char[], int, int)`
- * `Reader.reset()`
- * `Reader.skip(long)`
- * `Writer.write(char[])`
- * `Writer.write(char[], int, int)`
- * `Writer.write(int)`
- * `Writer.write(String)`
- * `Writer.write(String, int, int)`
- * `Appendable.append(char)`
- * `Appendable.append(CharSequence)`
- * `Appendable.append(CharSequence, int, int)`
- * `AutoCloseable.close()`
- * `Flushable.flush()`
- * `new LinkedHashSet()`
- * `List.add(int, Object)`
- * `Matcher.find()`
- * `DefaultGroovyMethods.getAt(Object[], Range)`
- * `DefaultGroovyMethods.reverse(List)`
-
-## Version 1.60
-
-Release date: 2019-05-31
-
-* SandboxResolvingClassLoader.parentClassCache could leak loaders in a different way ([PR 253](https://github.com/jenkinsci/script-security-plugin/pull/253))
-
-## Version 1.59
-
-Release date: 2019-04-18
-
-* SandboxResolvingClassLoader.parentClassCache could leak loaders ([PR 252](https://github.com/jenkinsci/script-security-plugin/pull/252))
-* [JENKINS-57299](https://issues.jenkins-ci.org/browse/JENKINS-57299) - Add the following methods to the default list of approved signatures:
- * `DefaultGroovyMethods.drop(Iterable, int)`
- * `DefaultGroovyMethods.drop(List, int)`
- * `DefaultGroovyMethods.dropRight(Iterable, int)`
- * `DefaultGroovyMethods.dropRight(List, int)`
- * `DefaultGroovyMethods.take(List, int)`
- * `DefaultGroovyMethods.takeRight(Iterable, int)`
- * `DefaultGroovyMethods.takeRight(List, int)`
-
-## Version 1.58
-
-Release date: 2019-04-18
-
-* Always block `System.exit(int)` , `Runtime#halt(int)` , and `Runtime#exit(int)`
-* [JENKINS-34973](https://issues.jenkins-ci.org/browse/JENKINS-34973) - Add script approvals from within `try/catch` blocks.
-
-## Version 1.57
-
-Release date: 2019-04-11
-
-* Add the following methods to the default list of approved signatures:
- * `Map.getOrDefault(Object, Object)`
- * `Map.putIfAbsent(Object, Object)`
- * `Map.replace(Object, Object)`
- * `Map.replace(Object, Object, Object)`
-
-## Version 1.56
-
-Release date: 2019-03-25
-
-* [Fix security issue](https://jenkins.io/security/advisory/2019-03-25/#SECURITY-1353)
-
-## Version 1.55
-
-Release date: 2019-03-18
-
-* [JENKINS-55303](https://issues.jenkins-ci.org/browse/JENKINS-55303) - Internal: Update tests and test-scope dependencies so that the plugin can build with all tests passing on Java 11.
-
-## Version 1.54
-
-Release date: 2019-03-06
-
-* [Fix security issue](https://jenkins.io/security/advisory/2019-03-06/#SECURITY-1336%20(1))
-
-## Version 1.53
-
-Release date: 2019-02-19
-
-* [Fix security issue](https://jenkins.io/security/advisory/2019-02-19/#SECURITY-1320)
-
-## Version 1.52
-
-Release date: 2019-02-13
-
-* Add the following methods to the default list of approved signatures:
- * `DateTimeFormatter.ofPattern(String)`
- * `Iterable.take(int)`
- * `List.subList(int, int)`
-
-## Version 1.51
-
-Release date: 2019-01-28
-
-* [Fix security issue](https://jenkins.io/security/advisory/2019-01-28/)
-
-## Version 1.50
-
-Release date: 2019-01-08
-
-* [Fix security vulnerability](https://jenkins.io/security/advisory/2019-01-08/)
-
-## Version 1.49
-
-Release date: 2018-11-30
-
-* Make sure expensive log lines are only created if the appropriate logging level is enabled ([PR #232](https://github.com/jenkinsci/script-security-plugin/pull/232))
-* Add the following methods to the default list of approved signatures:
-
- * `String#indexOf(int)`
- * `String#indexOf(int, int)`
- * `String#indexOf(String, int)`
- * `String#lastIndexOf(int)`
- * `String#lastIndexOf(int, int)`
- * `String#lastIndexOf(String, int)`
-
-## Version 1.48
-
-Release date: 2018-10-29
-
-* [Fix security issue](https://jenkins.io/security/advisory/2018-10-29/)
-
-## Version 1.47
-
-Release date: 2018-10-17
-
-* Add the following methods to the default list of approved signatures:
- * `DefaultGroovyMethods#leftShift(Writer, Object)`
- * `Class#isInstance(Object)`
- * `Throwable#getCause()`
- * `Arrays#asList(Object[])`
- * `Matcher#group(String)`
- * `DefaultGroovyMethods#minus(List, Collection)`
- * `DefaultGroovyMethods#asBoolean(CharSequence)`
- * Various methods in the `java.time` package
-* Thanks, open source contributors TobiX, haridsv, kevinkjt2000!
-
-## Version 1.46
-
-Release date: 2018-09-05
-
-* [JENKINS-53420](https://issues.jenkins-ci.org/browse/JENKINS-53420) - Fix `MissingPropertyException` when executing Pipeline steps.
-
-## Version 1.45
-
-Release date: 2018-09-04
-
-* [JENKINS-50843](https://issues.jenkins-ci.org/browse/JENKINS-50843) - Allow calling `Closure` elements of a `Map` as methods.
-* [JENKINS-51332](https://issues.jenkins-ci.org/browse/JENKINS-51332) - Add `Calendar` constants for days of the week and months (such as `MONDAY` and `APRIL`) to the default list of approved signatures.
-* [JENKINS-50906](https://issues.jenkins-ci.org/browse/JENKINS-50906) - Allow `this.foo()` for closure variables.
-* Downgrade logging level for message about slow class loading increase threshold from 250ms to 1s.
-* Add the following methods to the default list of approved signatures:
-
- * `DefaultGroovyMethods#addAll(Collection, Object[])`
- * `DefaultGroovyMethods#asImmutable(Map)`
- * `DefaultGroovyMethods#flatten(List)`
- * `DefaultGroovyMethods#getAt(List, Range)`
- * `DefaultGroovyMethods#subMap(Map, Object[])`
- * `DefaultGroovyMethods#subMap(Map, Collection)`
-
-## Version 1.44
-
-Release date: 2018-04-27
-
-* Add `DefaultGroovyMethods.toLong(String)` to the default list of approved signatures.
-* [JENKINS-50470](https://issues.jenkins-ci.org/browse/JENKINS-50470) - fix handling of `ArrayList.someField` to behave as a spread operation.
-* [JENKINS-46882](https://issues.jenkins-ci.org/browse/JENKINS-46882) - Add `new Exception(String)` to the default list of approved signatures.
-
-## Version 1.43
-
-Release date: 2018-03-28
-
-* Add `DefaultGroovyMethods.collate` methods to the default list of approved signatures.
-* [JENKINS-50380](https://issues.jenkins-ci.org/browse/JENKINS-50380) - Stop going through `checkedCast` process for objects that can be assigned to the target class and just return them instead.
-* Add `Collection#remove(int)` and `List#remove(int)` to the default list of approved signatures.
-* Add `DefaultGroovyMethods` for `sort`, `toSorted`, `unique`, `max`, `min`, and `abs` to the default list of approved signatures. Note that using these (other than `abs`) in Pipeline code will not work until [JENKINS-44924](https://issues.jenkins-ci.org/browse/JENKINS-44924) is resolved.
-* Slightly improved error messages replacing `unclassified ...` for cases where we couldn't find a method, field, constructor, etc matching the signature.
-
-## Version 1.42
-
-Release date: 2018-03-12
-
-* [JENKINS-45982](https://issues.jenkins-ci.org/browse/JENKINS-45982) - Fix an issue with calling `super` for a CPS-transformed method.
-* [JENKINS-49542](https://issues.jenkins-ci.org/browse/JENKINS-49542) - add `Map#isEmpty()` to the default list of approved signatures.
-* Add `DefaultGroovyMethods.multiply(String,Number)`, `DefaultGroovyMethods.with(Object,Closure)`, `Object#hashCode()`, `Objects.hash(Object[])`, `DefaultGroovyMethods.first(...)`, and `DefaultGroovyMethods.last(...)` to the default list of approved signatures.
-
-## Version 1.41
-
-Release date: 2018-02-08
-
-* **Major improvement**: greatly reduce time required to check whether signatures are approved for some implementations of `Whitelist`
-* **Major improvement**: allow permission checks to multithread - elliminate lock contention with concurrent calls
-* Improve UX for clearing dangerous signatures [JENKINS-22660](https://issues.jenkins-ci.org/browse/JENKINS-22660)
-* Add Integer.toString(int, int) to the default list of approved signatures
-* Add DefaultGroovyMethods toListString and toMapString to the default list of approved signatures
-
-## Version 1.40
-
-Release date: 2018-01-10
-
-* Block `System.getNanoTime()` to prevent Spectre/Meltdown exploits.
-* Add `DefaultGroovyMethods#contains(Iterable,Object)` to the default list of approved signatures.
-
-## Version 1.39
-
-Release date: 2017-12-12
-
-* [JENKINS-48501](https://issues.jenkins-ci.org/browse/JENKINS-48501) - Fix NPE regression caused by fix for JENKINS-48364 and JENKINS-46213.
-
-## Version 1.38
-
-Release date: 2017-12-11
-
-* [JENKINS-46764](https://issues.jenkins-ci.org/browse/JENKINS-46764) - Log useful message when `scriptApproval.xml` is malformed.
-* [JENKINS-48364](https://issues.jenkins-ci.org/browse/JENKINS-48364) - Treat null first vararg param properly.
-* [JENKINS-46213](https://issues.jenkins-ci.org/browse/JENKINS-46213) - Treat trailing array parameters as varargs when appropriate.
-
-## Version 1.37
-
-Release date: 2017-12-11
-
-* [Fix security issue](https://jenkins.io/security/advisory/2017-12-11/)
-
-## Version 1.36
-
-Release date: 2017-11-29
-
-* [JENKINS-47159](https://issues.jenkins-ci.org/browse/JENKINS-47159), [JENKINS-47893](https://issues.jenkins-ci.org/browse/JENKINS-47893) - Fix two issues with varargs handling.
-* Add more collection methods to the default list of approved signatures.
-* Hide `ScriptApproval` link if there are no pending or approved signatures.
-* Introduced support for `SystemCommandLanguage`
-
-## Version 1.35
-
-Release date: 2017-11-02
-
-* [JENKINS-47758](https://issues.jenkins-ci.org/browse/JENKINS-47758) - New feature: plugins using the SecureGroovyScript.evaluate method are automatically protected against Groovy memory leaks (most plugins)
-
- * Notable plugin exceptions: email-ext, matrix-project, ontrack (may be covered by a later enhancement), job-dsl (needs a bespoke implementation) and splunk-devops plugins (can't cover - doesn't use enough script-security APIs)
- * Pipeline offered its own leak protection mechanism (this is based on that)
-* [JENKINS-35294](https://issues.jenkins-ci.org/browse/JENKINS-35294) - VarArgs support for enums
-* Add map.get, List, minus, padLeft and padRight to the default list of approved signatures (thanks to community contributions from Github users [ryankillory](https://github.com/ryankillory), [Ignition](https://github.com/Ignition), and [andrey-fomin](https://github.com/andrey-fomin) !)
-* [JENKINS-47666](https://issues.jenkins-ci.org/browse/JENKINS-47666) - Add math.max and math.min to the default list of approved signatures
-* [JENKINS-44557](https://issues.jenkins-ci.org/browse/JENKINS-44557) - Properly cast GString (Groovy dynamic/templated string) in varargs
-
-## Version 1.34
-
-Release date: 2017-09-05
-
-* [JENKINS-46391](https://issues.jenkins-ci.org/browse/JENKINS-46391) - Properly handle `~/foo/` regexp declarations and some other `Pattern` methods.
-* [JENKINS-46358](https://issues.jenkins-ci.org/browse/JENKINS-46358) - Add `StringGroovyMethods` including `replaceAll`, and `findAll` to the default list of approved signatures.
-
-## Version 1.33
-
-Release date: 2017-08-16
-
-* [JENKINS-46088](https://issues.jenkins-ci.org/browse/JENKINS-46088) Fix problems caused by double sandbox transformation of right-hand-side of declarations.
-* [JENKINS-33468](https://issues.jenkins-ci.org/browse/JENKINS-33468) Allow use of `it` implicit closure parameter.
-* [JENKINS-45776](https://issues.jenkins-ci.org/browse/JENKINS-45776) Better handling of scoping of closure local variables.
-* [JENKINS-46191](https://issues.jenkins-ci.org/browse/JENKINS-46191) Fix compilation of empty declarations, such as `String foo;`, in sandbox.
-
-## Version 1.32
-
-Release date: 2017-08-16
-
-* Failed release due to repository permissions issues; replaced by 1.33.
-
-## Version 1.31
-
-Release date: 2017-08-07
-
-* [Multiple security fixes](https://jenkins.io/security/advisory/2017-08-07/)
-
-## Version 1.30
-
-Release date: 2017-07-25
-
-Now requires Jenkins 2.7.x or later, i.e., versions of Jenkins running Groovy 2.x.
-
-* Add signatures to the lists of approved and dangerous signatures.
-* [JENKINS-42563](https://issues.jenkins-ci.org/browse/JENKINS-42563) Handling `super` calls to methods.
-
-* Be explicit about classpath directory rejection reason.
-* [JENKINS-45117](https://issues.jenkins-ci.org/browse/JENKINS-45117) Apply specificity comparisons to constructors, not just methods.
-
-* [JENKINS-37129](https://issues.jenkins-ci.org/browse/JENKINS-37129) Throw a more helpful `MissingMethodException` rather than an “unclassified” error.
-
-* Cleanup of math operations.
-* [JENKINS-34599](https://issues.jenkins-ci.org/browse/JENKINS-34599) Allow `final` fields to be set.
-
-* [JENKINS-45629](https://issues.jenkins-ci.org/browse/JENKINS-45629) Field initializers could produce a `NullPointerException` during script transformation.
-
-## Version 1.29.1
-
-Release date: 2017-07-10
-
-* [Fix security issue](https://jenkins.io/security/advisory/2017-07-10/)
-
-## Version 1.29
-
-Release date: 2017-06-15
-
-* Add various signatures to the default list of approved signatures, particularly for `DefaultGroovyMethods`.
-
-## Version 1.28
-
-Release date: 2017-06-05
-
-* [JENKINS-34741](https://issues.jenkins-ci.org/browse/JENKINS-34741) Unclassified error when using Groovy struct constructors.
-
-* Update the default list of approved signatures.
-
-## Version 1.27
-
-Release date: 2017-02-27
-
-* [JENKINS-41797](https://issues.jenkins-ci.org/browse/JENKINS-41797) Race condition could corrupt internal metadata used to check whether signatures are approved.
-* [JENKINS-39159](https://issues.jenkins-ci.org/browse/JENKINS-39159) File handle leak when using custom script classpath could lead to unwanted locks on Windows or NFS.
-* Update the default list of approved signatures.
-
-## Version 1.26
-
-Release date: 2017-02-13
-
-* Update the default list of approved signatures.
-
-## Version 1.25
-
-Release date: 2017-01-03
-
-* Update the lists of approved and dangerous signatures.
-* Display a warning about previously approved signatures which are now in the list of dangerous signatures.
-
-## Version 1.24
-
-Release date: 2016-10-20
-
-* [JENKINS-38908](https://issues.jenkins-ci.org/browse/JENKINS-38908) Improper handling of some varargs methods.
-* Update the default list of approved signatures.
-
-## Version 1.23
-
-Release date: 2016-09-21
-
-* Better report [JENKINS-37599](https://issues.jenkins-ci.org/browse/JENKINS-37599), a bug in core tickled by the [Promoted Builds Plugin](https://wiki.jenkins.io/display/JENKINS/Promoted+Builds+Plugin).
-* Update the lists of approved and dangerous signatures.
-
-## Version 1.22
-
-Release date: 2016-08-15
-
-* Introduce a class loader caching layer for the Groovy sandbox to work around core performance limitations such as [JENKINS-23784](https://issues.jenkins-ci.org/browse/JENKINS-23784).
-* [JENKINS-37344](https://issues.jenkins-ci.org/browse/JENKINS-37344) Add collection-related signatures to the default list of approved signatures.
-
-## Version 1.21
-
-Release date: 2016-07-11
-
-* Add build changelog-related signatures to the default list of approved Jenkins-related signatures ([JENKINS-30412](https://issues.jenkins-ci.org/browse/JENKINS-30412)).
-
-## Version 1.20
-
-Release date: 2016-06-20
-
-* Update the default list of approved signatures.
-* [JENKINS-34739](https://issues.jenkins-ci.org/browse/JENKINS-34739) Support for varargs methods.
-* [JENKINS-33023](https://issues.jenkins-ci.org/browse/JENKINS-33023) `enum` initializer fixes.
-* Add `RunWrapper.getRawBuild` to the list of dangerous signatures.
-
-## Version 1.19
-
-Release date: 2016-04-26
-
-* [JENKINS-24399](https://issues.jenkins-ci.org/browse/JENKINS-24399) Prohibit class directories from being approved classpath entries.
-* [JENKINS-33023](https://issues.jenkins-ci.org/browse/JENKINS-33023) Support `enum` initializers.
-* Permit metaclass methods to be run.
-* Update the lists of approved and dangerous signatures.
-
-## Version 1.18.1
-
-Release date: 2016-04-11
-
-* Security release (CVE-2016-3102). [advisory](https://wiki.jenkins-ci.org/display/SECURITY/Jenkins+Security+Advisory+2016-04-11)
-
-## Version 1.18
-
-Release date: 2016-04-04
-
-* Groovy prefers a getter/setter to a field access, so act accordingly, particularly when suggesting signatures to approve.
-* [JENKINS-27725](https://issues.jenkins-ci.org/browse/JENKINS-27725) Various fixes to handling of GDK methods.
-* Update the lists of approved and dangerous signatures.
-* [JENKINS-26481](https://issues.jenkins-ci.org/browse/JENKINS-26481) Supporting fix to GDK method handling necessary to support calls such as `Object.each(Closure)` from `groovy-cps` Pipeline.
-
-## Version 1.17
-
-Release date: 2016-01-25
-
-* `obj.prop` should interpret `boolean TheClass.isProp()`, not just `boolean TheClass.getProp()`.
-
-## Version 1.16
-
-Release date: 2016-01-19
-
-* Update the default list of approved signatures, including standard Groovy operators and GDK methods.
-* [JENKINS-30432](https://issues.jenkins-ci.org/browse/JENKINS-30432) Warn about dangerous signatures.
-* [JENKINS-31234](https://issues.jenkins-ci.org/browse/JENKINS-31234) Groovy allows `Singleton.instance` as an alias for `Singleton.getInstance()`; handled.
-* [JENKINS-31701](https://issues.jenkins-ci.org/browse/JENKINS-31701) Misclassification of a method taking `long` and being passed an `int`.
-
-## Version 1.15
-
-Release date: 2015-08-20
-
-* Update the default list of approved signatures.
-* Properly classify pseudofields of a `Map`.
-* [JENKINS-29541](https://issues.jenkins-ci.org/browse/JENKINS-29541) Methods on a `GString` may really be called on a `String`.
-* Corrected classification of methods ambiguous between `GroovyDefaultMethods` and `invokeMethod`.
-* [JENKINS-28586](https://issues.jenkins-ci.org/browse/JENKINS-28586) Corrected handling of receivers inside a `Closure`.
-* [JENKINS-28154](https://issues.jenkins-ci.org/browse/JENKINS-28154) Fixing handling of Groovy operators.
-
-## Version 1.14
-
-Release date: 2015-04-22
-
-* Better error message when you mistype a method name on a Groovy class.
-* Default to using sandbox mode when the current user is not an administrator.
-
-## Version 1.13
-
-Release date: 2015-02-02
-
-* Testability fix only.
-
-## Version 1.12
-
-Release date: 2014-12-04
-
-* [JENKINS-25914](https://issues.jenkins-ci.org/browse/JENKINS-25914) Allow `env` in Pipeline plugins with a special implementation of `Whitelist`.
-* Add `Collection.contains` to the default list of approved signatures.
-
-## Version 1.11
-
-Release date: 2014-12-03
-
-* Handling some more Groovy constructs, such as the `=~` operator, and GDK methods like `Iterable.join(String)`.
-
-## Version 1.10
-
-Release date: 2014-11-14
-
-* [JENKINS-25524](https://issues.jenkins-ci.org/browse/JENKINS-25524) Handle ambiguous method overloads better.
-
-## Version 1.9
-
-Release date: 2014-11-04
-
-* Code can escape sandbox if there are multiple copies of `groovy-sandbox.jar` in Jenkins ([JENKINS-25348](https://issues.jenkins-ci.org/browse/JENKINS-25348))
-
-## Version 1.8
-
-Release date: 2014-10-29
-
-* `groovy-sandbox` 1.8 has a few fixes.
-
-## Version 1.7
-
-Release date: 2014-10-13
-
-* [JENKINS-25118](https://issues.jenkins-ci.org/browse/JENKINS-25118) Handle methods with primitive arguments.
-
-## Version 1.6
-
-Release date: 2014-10-02
-
-* Handle `GroovyObject.invokeMethod(String,Object)` correctly during call site selecction.
-
-## Version 1.5
-
-Release date: 2014-08-19
-
-* [JENKINS-22834](https://issues.jenkins-ci.org/browse/JENKINS-22834) Added support for custom classpaths.
-
-## Version 1.4
-
-Release date: 2014-06-08
-
-* Do not bother enforcing whole-script approval when Jenkins is unsecured anyway.
-* Some changes to make writing acceptance tests easier.
-
-## Version 1.3
-
-Release date: 2014-05-13
-
-* Fixing some regressions from 1.2.
-
-## Version 1.2
-
-Release date: 2014-05-13
-
-* Updated Groovy sandbox library for better language coverage.
-
-## Version 1.1
-
-Release date: 2014-05-06
-
-* Making it possible to use Groovy functions with `def` syntax.
-* Added `GroovySandbox.run` so that methods defined in the script itself are always allowed.
-
-## Version 1.0
-
-Release date: 2014-04-15
-
-* String concatenation fix in sandbox.
-* Preapprove the empty script.
-* Support for static fields in sandbox.
-* Changed package of `AbstractWhitelist`.
-
-## Version 1.0 beta 6
-
-Release date: 2014-03-31
-
-* Added `SecureGroovyScript` convenience class.
-
-## Version 1.0 beta 5
-
-Release date: 2014-03-13
-
-* Fixed various bugs in the Groovy sandbox.
-* Added `AbstractWhitelist`.
-
-## Version 1.0 beta 4
-
-Release date: 2014-03-12
-
-* Refactored `Whitelist` to support `GString` and more
-
-## Version 1.0 beta 3
-
-Release date: 2014-03-01
-
-* Reverted GString fix for now
-
-## Version 1.0 beta 2
-
-Release date: 2014-02-28
-
-* @Whitelisted
-* initialization bug fix
-* Groovy GString fix
-
-## Version 1.0 beta 1
-
-Release date: 2014-02-28
-
-* Initial version.
-
diff --git a/Jenkinsfile b/Jenkinsfile
index 3765128a6..52525eb3a 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -1,4 +1,6 @@
-buildPlugin(useAci: true, configurations: [
- [ platform: "windows", jdk: "11" ],
- [ platform: "linux", jdk: "11" ]
+buildPlugin(
+ useContainerAgent: true,
+ configurations: [
+ [platform: 'linux', jdk: 21],
+ [platform: 'windows', jdk: 17],
])
diff --git a/README.md b/README.md
index 41bc7f93d..00c335a39 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,5 @@
# Script Security Plugin
-[![Jenkins Plugin](https://img.shields.io/jenkins/plugin/v/script-security)](https://plugins.jenkins.io/script-security)
-[![Changelog](https://img.shields.io/github/v/tag/jenkinsci/script-security-plugin?label=changelog)](https://github.com/jenkinsci/script-security-plugin/releases)
-[![Jenkins Plugin Installs](https://img.shields.io/jenkins/plugin/i/script-security?color=blue)](https://plugins.jenkins.io/script-security)
## User’s guide
(adapted from information on [Template plugin in CloudBees Plugins guide](https://docs.cloudbees.com/docs/admin-resources/latest/plugins/template#template-sect-script-approval))
@@ -25,17 +22,17 @@ The first, and simpler, security system is to allow any kind of script to be run
with an administrator’s approval. There is a globally maintained list of approved scripts
which are judged to not perform any malicious actions.
-When an administrator saves some kind of configuration (for example, a job), those scripts
-that were edited by admin are automatically approved and are ready to run with no further
-intervention. For scripts that were submitted by lower privileged users there will be
+When a user saves some kind of configuration (for example, a job), there will be
appropriate warnings indicating that approval is required. Administrators may approve those
-scripts using the Script Approval configuration page or by editing the script and saving it.
-In previous versions of Script Security Plugin, administrators could automatically approve
-scripts submitted by unprivileged users by saving them without making any changes, but this
-functionality was disabled to prevent social engineering-based attacks. (“Saving” usually
-means from the web UI, but could also mean uploading a new XML configuration via REST or CLI.)
-
-When a non-administrator saves a template configuration, a check is done whether any
+scripts using the Script Approval configuration page or following the approval link in the
+configuration.
+In previous versions of Script Security Plugin, scripts saved by administrators where
+automatically approved when saving them, but this functionality was disabled to prevent
+a variety of social engineering-based attacks. (“Saving” usually means from the web UI, but
+could also mean uploading a new XML configuration via REST or CLI.) or merely by creating a
+new item copying an existing one.
+
+When a user saves a template configuration, a check is done whether any
contained scripts have been edited from an approved text. (More precisely, whether the
requested content has ever been approved before.) If it has not been approved, a request
for approval of this script is added to a queue. (A warning is also displayed in the
@@ -193,4 +190,6 @@ whitelist methods used by your tests -- either generally for real users, or usin
## Version history
-See [the changelog](CHANGELOG.md)
+
+From of version 1.77 see [GitHub Releases](https://github.com/jenkinsci/script-security-plugin/releases).
+[Archives](https://github.com/jenkinsci/script-security-plugin/blob/71755e3bd5cf0f04acfcb5afc27b5a29252fca7e/CHANGELOG.md)
diff --git a/pom.xml b/pom.xml
index 783f0ea2d..a519762d2 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,20 +4,18 @@
org.jenkins-ci.pluginsplugin
- 4.47
-
+ 4.87
+ script-security${changelist}hpiScript Security Plugin
- Allows Jenkins administrators to control what in-process scripts can be run by less-privileged users.https://github.com/jenkinsci/${project.artifactId}-plugin999999-SNAPSHOT
-
- 2.366-rc32795.df5b_49c75b_0e
+ 2.440.3jenkinsci/${project.artifactId}-plugin
@@ -51,8 +49,8 @@
io.jenkins.tools.bom
- bom-2.361.x
- 1607.va_c1576527071
+ bom-2.440.x
+ 3334.v18e2a_2f48356importpom
@@ -63,7 +61,7 @@
org.kohsukegroovy-sandbox
- 1.27
+ 1.34org.codehaus.groovy
diff --git a/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/ClassLoaderWhitelist.java b/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/ClassLoaderWhitelist.java
index 517f7a145..cab90aa19 100644
--- a/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/ClassLoaderWhitelist.java
+++ b/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/ClassLoaderWhitelist.java
@@ -1,10 +1,12 @@
package org.jenkinsci.plugins.scriptsecurity.sandbox.groovy;
+import edu.umd.cs.findbugs.annotations.NonNull;
import org.jenkinsci.plugins.scriptsecurity.sandbox.Whitelist;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
/**
* {@link Whitelist} that allows everything defined from a specific classloader.
@@ -22,31 +24,82 @@ private boolean permits(Class> declaringClass) {
return declaringClass.getClassLoader() == scriptLoader;
}
- @Override public boolean permitsMethod(Method method, Object receiver, Object[] args) {
- return permits(method.getDeclaringClass());
+ @Override public boolean permitsMethod(@NonNull Method method, @NonNull Object receiver, @NonNull Object[] args) {
+ return permits(method.getDeclaringClass()) && !isIllegalSyntheticMethod(method);
}
- @Override public boolean permitsConstructor(Constructor> constructor, Object[] args) {
- return permits(constructor.getDeclaringClass());
+ @Override public boolean permitsConstructor(@NonNull Constructor> constructor, @NonNull Object[] args) {
+ return permits(constructor.getDeclaringClass()) && !isIllegalSyntheticConstructor(constructor);
}
- @Override public boolean permitsStaticMethod(Method method, Object[] args) {
- return permits(method.getDeclaringClass());
+ @Override public boolean permitsStaticMethod(@NonNull Method method, @NonNull Object[] args) {
+ return permits(method.getDeclaringClass()) && !isIllegalSyntheticMethod(method);
}
- @Override public boolean permitsFieldGet(Field field, Object receiver) {
- return permits(field.getDeclaringClass());
+ @Override public boolean permitsFieldGet(@NonNull Field field, @NonNull Object receiver) {
+ return permits(field.getDeclaringClass()) && !isIllegalSyntheticField(field);
}
- @Override public boolean permitsFieldSet(Field field, Object receiver, Object value) {
- return permits(field.getDeclaringClass());
+ @Override public boolean permitsFieldSet(@NonNull Field field, @NonNull Object receiver, Object value) {
+ return permits(field.getDeclaringClass()) && !isIllegalSyntheticField(field);
}
- @Override public boolean permitsStaticFieldGet(Field field) {
- return permits(field.getDeclaringClass());
+ @Override public boolean permitsStaticFieldGet(@NonNull Field field) {
+ return permits(field.getDeclaringClass()) && !isIllegalSyntheticField(field);
}
- @Override public boolean permitsStaticFieldSet(Field field, Object value) {
- return permits(field.getDeclaringClass());
+ @Override public boolean permitsStaticFieldSet(@NonNull Field field, Object value) {
+ return permits(field.getDeclaringClass()) && !isIllegalSyntheticField(field);
+ }
+
+ /**
+ * Checks whether a given field was synthetically created by the Groovy compiler and should be inaccessible even if
+ * it is declared by a class defined by the specified class loader.
+ */
+ private static boolean isIllegalSyntheticField(Field field) {
+ if (!field.isSynthetic()) {
+ return false;
+ }
+ Class> declaringClass = field.getDeclaringClass();
+ Class> enclosingClass = declaringClass.getEnclosingClass();
+ if (field.getType() == enclosingClass && field.getName().startsWith("this$")) {
+ // Synthetic field added to inner classes to reference the outer class.
+ return false;
+ } else if (declaringClass.isEnum() && Modifier.isStatic(field.getModifiers()) && field.getName().equals("$VALUES")) {
+ // Synthetic field added by Groovy to enum classes to hold the enum constants.
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Checks whether a given method was synthetically created by the Groovy compiler and should be inaccessible even
+ * if it is declared by a class defined by the specified class loader.
+ */
+ private static boolean isIllegalSyntheticMethod(Method method) {
+ if (!method.isSynthetic()) {
+ return false;
+ } else if (Modifier.isStatic(method.getModifiers()) && method.getDeclaringClass().isEnum() && method.getName().equals("$INIT")) {
+ // Synthetic method added by Groovy to enum classes used to initialize the enum constants.
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Checks whether a given constructor was created by the Groovy compiler (or groovy-sandbox) and
+ * should be inaccessible even if it is declared by a class defined by the specified class loader.
+ */
+ private static boolean isIllegalSyntheticConstructor(Constructor constructor) {
+ if (!constructor.isSynthetic()) {
+ return false;
+ }
+ Class> declaringClass = constructor.getDeclaringClass();
+ Class> enclosingClass = declaringClass.getEnclosingClass();
+ if (enclosingClass != null && constructor.getParameters().length > 0 && constructor.getParameterTypes()[0] == enclosingClass) {
+ // Synthetic constructor added by Groovy to anonymous classes.
+ return false;
+ }
+ return true;
}
}
diff --git a/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/GroovyCallSiteSelector.java b/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/GroovyCallSiteSelector.java
index 0c3a04f2b..768f7c570 100644
--- a/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/GroovyCallSiteSelector.java
+++ b/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/GroovyCallSiteSelector.java
@@ -31,9 +31,12 @@
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Predicate;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
import org.apache.commons.lang.ClassUtils;
@@ -43,7 +46,8 @@
* Assists in determination of which method or other JVM element is actually about to be called by Groovy.
* Most of this just duplicates what {@link java.lang.invoke.MethodHandles.Lookup} and {@link java.lang.invoke.MethodHandle#asType} do,
* but {@link org.codehaus.groovy.vmplugin.v7.TypeTransformers} shows that there are Groovy-specific complications.
- * Comments in https://github.com/kohsuke/groovy-sandbox/issues/7 note that it would be great for the sandbox itself to just tell us what the call site is so we would not have to guess.
+ * Comments in groovy-sandbox #7 note that it would be
+ * great for the sandbox itself to just tell us what the call site is so we would not have to guess.
*/
class GroovyCallSiteSelector {
@@ -198,6 +202,41 @@ private static boolean isInstancePrimitive(@NonNull Class> type, @NonNull Obje
return findMatchingMethod(receiver, method, args);
}
+ /**
+ * Like {@link #method}, but returns all methods with the given name that match the given predicate.
+ */
+ public static List methods(@NonNull Object receiver, @NonNull String method, Predicate filter) {
+ Set> types = types(receiver);
+ if (types.contains(GroovyInterceptable.class) && !"invokeMethod".equals(method)) {
+ return methods(receiver, "invokeMethod", m -> true);
+ }
+ List candidates = new ArrayList<>();
+ for (Class> c : types) {
+ for (Method candidate : c.getDeclaredMethods()) {
+ if (candidate.getName().equals(method) && filter.test(candidate)) {
+ candidates.add(candidate);
+ }
+ }
+ }
+ if (receiver instanceof GString) { // cf. GString.invokeMethod
+ candidates.addAll(methods(String.class, method, filter));
+ }
+ return candidates;
+ }
+
+ /**
+ * Like {@link #staticMethod}, but returns all methods with the given name that match the given predicate.
+ */
+ public static List staticMethods(@NonNull Class> receiver, @NonNull String method, Predicate filter) {
+ List candidates = new ArrayList<>();
+ for (Method candidate : receiver.getDeclaredMethods()) {
+ if (candidate.getName().equals(method) && filter.test(candidate)) {
+ candidates.add(candidate);
+ }
+ }
+ return candidates;
+ }
+
private static Method findMatchingMethod(@NonNull Class> receiver, @NonNull String method, @NonNull Object[] args) {
Method candidate = null;
diff --git a/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/GroovySandbox.java b/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/GroovySandbox.java
index 58a85dd17..9323071fe 100644
--- a/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/GroovySandbox.java
+++ b/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/GroovySandbox.java
@@ -26,20 +26,28 @@
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import groovy.grape.GrabAnnotationTransformation;
+import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
+import groovy.lang.GroovyCodeSource;
+import groovy.lang.GroovyObject;
+import groovy.lang.GroovyRuntimeException;
import groovy.lang.GroovyShell;
import static groovy.lang.GroovyShell.DEFAULT_CODE_BASE;
+import groovy.lang.MissingPropertyException;
import groovy.lang.Script;
import hudson.ExtensionList;
import hudson.model.RootAction;
import hudson.model.TaskListener;
import hudson.util.FormValidation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.CodeSource;
import java.security.cert.Certificate;
import java.util.Collections;
import java.util.HashSet;
+import java.util.Map;
import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -49,6 +57,8 @@
import org.codehaus.groovy.control.CompilationUnit;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.Phases;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.syntax.Types;
import org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException;
import org.jenkinsci.plugins.scriptsecurity.sandbox.Whitelist;
import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.ProxyWhitelist;
@@ -58,6 +68,7 @@
import org.jenkinsci.plugins.scriptsecurity.scripts.ScriptApprovalNote;
import org.kohsuke.groovy.sandbox.GroovyInterceptor;
import org.kohsuke.groovy.sandbox.SandboxTransformer;
+import org.kohsuke.groovy.sandbox.impl.Checker;
/**
* Allows Groovy scripts (including Groovy Templates) to be run inside a sandbox.
@@ -143,6 +154,17 @@ public Scope enter() {
@FunctionalInterface
public interface Scope extends AutoCloseable {
+ /**
+ * Variant of {@link GroovyShell#parse(String)} that intercepts potentially unsafe calls when the script is created.
+ *
+ *
{@link GroovySandbox#runScript(GroovyShell, String)} should be used instead of this method in most cases.
+ */
+ default Script parse(GroovyShell shell, GroovyCodeSource codeSource) {
+ Class> scriptClass = shell.getClassLoader().parseClass(codeSource, false);
+ Script script = checkedCreateScript(scriptClass, shell.getContext());
+ return script;
+ }
+
@Override void close();
}
@@ -150,24 +172,96 @@ public interface Scope extends AutoCloseable {
/**
* Compiles and runs a script within the sandbox.
* @param shell the shell to be used; see {@link #createSecureCompilerConfiguration} and similar methods
- * @param script the script to run
+ * @param scriptText the script to run
* @return the return value of the script
*/
- public Object runScript(@NonNull GroovyShell shell, @NonNull String script) {
+ public Object runScript(@NonNull GroovyShell shell, @NonNull String scriptText) {
GroovySandbox derived = new GroovySandbox().
withApprovalContext(context).
withTaskListener(listener).
withWhitelist(new ProxyWhitelist(new ClassLoaderWhitelist(shell.getClassLoader()), whitelist()));
try (Scope scope = derived.enter()) {
- return shell.parse(script).run();
+ // GroovyShell does not expose any public APIs that allow us to access the generated Script class before InvokerHelper.createScript is called.
+ String scriptFileName = "Script0.groovy";
+ try {
+ Method generateScriptName = shell.getClass().getDeclaredMethod("generateScriptName");
+ generateScriptName.setAccessible(true); // Method is protected.
+ scriptFileName = (String) generateScriptName.invoke(shell);
+ } catch (ReflectiveOperationException e) {
+ LOGGER.log(Level.WARNING, null, e);
+ }
+ GroovyCodeSource codeSource = new GroovyCodeSource(scriptText, scriptFileName, DEFAULT_CODE_BASE);
+ Script script = scope.parse(shell, codeSource);
+ return script.run();
+ }
+ }
+
+ /**
+ * Variant of {@link InvokerHelper#createScript} that intercepts potentially unsafe reflective behaviors.
+ *
+ *
{@link GroovySandbox#runScript(GroovyShell, String)} or {@link Scope#parse} should be used instead of this method in most cases.
+ *
+ * @see InvokerHelper#createScript
+ */
+ private static Script checkedCreateScript(Class> scriptClass, Binding context) {
+ Script script;
+ try {
+ if (Script.class.isAssignableFrom(scriptClass)) {
+ try {
+ script = InvokerHelper.newScript(scriptClass, context);
+ } catch (InvocationTargetException e) {
+ throw e.getCause(); // Typically RejectedAccessException.
+ }
+ } else {
+ // TODO: Could we just throw a SecurityException instead and tell users to extend Script or not have a
+ // class definition as the only top-level content in their script?
+ final GroovyObject object = (GroovyObject) scriptClass.newInstance();
+ // it could just be a class, so let's wrap it in a Script
+ // wrapper; though the bindings will be ignored
+ script = new Script(context) {
+ public Object run() {
+ Object[] argsToPass = new Object[0];
+ try {
+ Object args = getProperty("args");
+ if (args instanceof String[]) {
+ argsToPass = (String[])args;
+ }
+ } catch (MissingPropertyException e) {
+ // They'll get empty args since none exist in the context.
+ }
+ try {
+ Checker.checkedCall(object, false, false, "main", argsToPass);
+ } catch (Throwable t) {
+ throw new GroovyRuntimeException(t);
+ }
+ return null;
+ }
+ };
+ Map variables = context.getVariables();
+ for (Object o : variables.entrySet()) {
+ Map.Entry entry = (Map.Entry) o;
+ String key = entry.getKey().toString();
+ // assume underscore variables are for the wrapper script
+ try {
+ Checker.checkedSetProperty(key.startsWith("_") ? script : object, key, true, false, Types.ASSIGN, entry.getValue());
+ } catch (MissingPropertyException e) {
+ // Swallow MissingPropertyException to match Groovy behavior in this case.
+ }
+ }
+ }
+ } catch (Throwable e) {
+ throw new GroovyRuntimeException(
+ "Failed to create Script instance for class: "
+ + scriptClass + ". Reason: " + e, e);
}
+ return script;
}
/**
* Prepares a compiler configuration the sandbox.
*
- *
CAUTION
*
+ * CAUTION:
* When creating {@link GroovyShell} with this {@link CompilerConfiguration},
* you also have to use {@link #createSecureClassLoader(ClassLoader)} to wrap
* a classloader of your choice into sandbox-aware one.
diff --git a/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/SandboxInterceptor.java b/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/SandboxInterceptor.java
index f5a67ec1c..4a46bf5b1 100644
--- a/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/SandboxInterceptor.java
+++ b/src/main/java/org/jenkinsci/plugins/scriptsecurity/sandbox/groovy/SandboxInterceptor.java
@@ -30,23 +30,26 @@
import groovy.lang.MissingMethodException;
import groovy.lang.MissingPropertyException;
import groovy.lang.Script;
-import hudson.Functions;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import edu.umd.cs.findbugs.annotations.CheckForNull;
import edu.umd.cs.findbugs.annotations.NonNull;
+import java.lang.reflect.Modifier;
import org.codehaus.groovy.runtime.DateGroovyMethods;
import org.codehaus.groovy.runtime.DefaultGroovyMethods;
import org.codehaus.groovy.runtime.EncodingGroovyMethods;
import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.MetaClassHelper;
import org.codehaus.groovy.runtime.ProcessGroovyMethods;
import org.codehaus.groovy.runtime.SqlGroovyMethods;
import org.codehaus.groovy.runtime.StringGroovyMethods;
@@ -54,12 +57,14 @@
import org.codehaus.groovy.runtime.XmlGroovyMethods;
import org.codehaus.groovy.runtime.metaclass.ClosureMetaMethod;
import org.codehaus.groovy.runtime.typehandling.NumberMathModificationInfo;
+import org.codehaus.groovy.syntax.Types;
import org.codehaus.groovy.tools.DgmConverter;
import org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException;
import org.jenkinsci.plugins.scriptsecurity.sandbox.Whitelist;
import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.EnumeratingWhitelist;
import org.jenkinsci.plugins.scriptsecurity.sandbox.whitelists.StaticWhitelist;
import org.kohsuke.groovy.sandbox.GroovyInterceptor;
+import org.kohsuke.groovy.sandbox.impl.Checker;
@SuppressWarnings("rawtypes")
final class SandboxInterceptor extends GroovyInterceptor {
@@ -131,7 +136,7 @@ final class SandboxInterceptor extends GroovyInterceptor {
Script s = (Script) receiver;
if (s.getBinding().hasVariable(method)) {
Object var = s.getBinding().getVariable(method);
- if (!InvokerHelper.getMetaClass(var).respondsTo(var, "call", (Object[]) args).isEmpty()) {
+ if (!InvokerHelper.getMetaClass(var).respondsTo(var, "call", args).isEmpty()) {
return onMethodCall(invoker, var, "call", args);
}
}
@@ -154,12 +159,12 @@ final class SandboxInterceptor extends GroovyInterceptor {
throw new MissingMethodException(method, receiver.getClass(), args);
} else if (StaticWhitelist.isPermanentlyBlacklistedMethod(m)) {
throw StaticWhitelist.rejectMethod(m);
- } else if (whitelist.permitsMethod(m, receiver, args)) {
+ } else if (permitsMethod(whitelist, m, receiver, args)) {
return super.onMethodCall(invoker, receiver, method, args);
} else if (method.equals("invokeMethod") && args.length == 2 && args[0] instanceof String && args[1] instanceof Object[]) {
throw StaticWhitelist.rejectMethod(m, EnumeratingWhitelist.getName(receiver.getClass()) + " " + args[0] + printArgumentTypes((Object[]) args[1]));
} else {
- throw StaticWhitelist.rejectMethod(m);
+ throw rejectMethod(m);
}
}
@@ -170,6 +175,24 @@ final class SandboxInterceptor extends GroovyInterceptor {
} else if (StaticWhitelist.isPermanentlyBlacklistedConstructor(c)) {
throw StaticWhitelist.rejectNew(c);
} else if (whitelist.permitsConstructor(c, args)) {
+ if (c.getParameterCount() == 0 && args.length == 1 && args[0] instanceof Map) {
+ // c.f. https://github.com/apache/groovy/blob/41b990d0a20e442f29247f0e04cbed900f3dcad4/src/main/groovy/lang/MetaClassImpl.java#L1728-L1738
+ // We replace the arguments that the invoker will use to construct the object with the empty array to
+ // bypass Groovy's default handling for implicit map constructors.
+ Object newInstance = super.onNewInstance(invoker, receiver, new Object[0]);
+ if (newInstance == null) {
+ // We were called by Checker.preCheckedCast. Our options here are limited, so we just reject everything.
+ throw new UnsupportedOperationException("Groovy map constructors may only be invoked using the 'new' keyword in the sandbox (attempted to construct " + receiver + " via a Groovy cast)");
+ }
+ // The call to Map.entrySet below may be on a user-defined type, which could be a problem if we iterated
+ // over it here to pre-check the property assignments and then let Groovy iterate over it again to
+ // actually perform them, so we only iterate over it once and perform the property assignments
+ // ourselves using sandbox-aware methods.
+ for (Map.Entry