diff --git a/.asf.yaml b/.asf.yaml new file mode 100644 index 00000000000..c61f8071517 --- /dev/null +++ b/.asf.yaml @@ -0,0 +1,41 @@ +# https://cwiki.apache.org/confluence/display/INFRA/.asf.yaml+features+for+git+repositories + +github: + description: "Apache JMeter open-source load testing tool for analyzing and measuring the performance of a variety of services" + homepage: https://jmeter.apache.org/ + labels: + - performance + - test + - java + + dependabot_alerts: true + dependabot_updates: false + + enabled_merge_buttons: + squash: true + merge: false + rebase: true + + features: + wiki: false + issues: true + projects: false + + rulesets: + - name: "Default Branch Protection" + type: branch + branches: + includes: + - "~DEFAULT_BRANCH" + - "release/*" + - "rel/*" + excludes: [] + bypass_teams: + - root + restrict_deletion: true + restrict_force_push: true +notifications: + commits: commits@jmeter.apache.org + issues: dev@jmeter.apache.org + pullrequests: dev@jmeter.apache.org + jira_options: link label diff --git a/.editorconfig b/.editorconfig index 018a717cc91..5f44ca2b086 100644 --- a/.editorconfig +++ b/.editorconfig @@ -5,6 +5,12 @@ trim_trailing_whitespace = true insert_final_newline = true charset = utf-8 indent_style = space +max_line_length = 120 +ij_any_align_multiline_parameters = false +ij_any_do_while_brace_force = always +ij_any_for_brace_force = always +ij_any_if_brace_force = always +ij_any_while_brace_force = always [{*.sh,gradlew}] end_of_line = lf @@ -16,9 +22,17 @@ end_of_line = crlf ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL ij_kotlin_name_count_to_use_star_import = 999 ij_kotlin_name_count_to_use_star_import_for_members = 999 +# Kotlin code style does not use double-continuation indents +# Revise this when the following issues are resolved: +# https://youtrack.jetbrains.com/issue/KTIJ-17907 +# https://github.com/pinterest/ktlint/issues/805 +ij_kotlin_continuation_indent_size = 4 [*.java] # Doc: https://youtrack.jetbrains.com/issue/IDEA-170643#focus=streamItem-27-3708697.0-0 #"static ", "java.", "javax", "org", "net", "com", "" ij_java_imports_layout = $*,|,java.**,|,javax.**,|,org.**,|,net.**,|,com.**,|,* ij_java_use_single_class_imports = true + +[*.xml] +indent_size = 2 diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml new file mode 100644 index 00000000000..502aadfbe82 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -0,0 +1,59 @@ +name: Bug report +description: Create a report and help us improve +labels: + - defect + - to-triage +body: + - type: markdown + attributes: + value: | + Please fill in all required fields with as many details as possible. + Read the [User manual](https://jmeter.apache.org/usermanual/index.html) and/or [Reference documentation](https://jmeter.apache.org/usermanual/component_reference.html) + - type: textarea + id: expected + attributes: + label: Expected behavior + description: | + Describe what you were expecting JMeter to do + placeholder: | + Here you can also attach log files, screenshots or a video + - type: textarea + id: actual + attributes: + label: Actual behavior + description: | + Describe what you observed JMeter did instead + placeholder: | + Here you can also attach log files (e.g. jmeter.log), screenshots or a video + - type: textarea + id: steps + attributes: + label: Steps to reproduce the problem + description: | + - If the problem relates to a third-party plugin, consider removing them first + placeholder: | + Here you can also attach log files, screenshots or a video + validations: + required: true + - type: input + id: jmeter-version + attributes: + label: JMeter Version + description: | + What JMeter version and edition did you use? + Note: While you can obviously continue using older versions of JMeter, it may well be that your bug is already fixed. If you're using an older version, please also try to reproduce the bug in the latest version of JMeter before reporting it. + placeholder: ex. 5.6 + validations: + required: true + - type: input + id: java-version + attributes: + label: Java Version + description: What JDK version and distribution did you use (use `java -version`) + placeholder: ex. openjdk version "17" 2021-09-14 + - type: input + id: os-version + attributes: + label: OS Version + description: What operating system version and distribution did you use (use e.g. `ver` on Windows) + placeholder: ex. Microsoft Windows [Version 10.0.22000.856] diff --git a/.github/ISSUE_TEMPLATE/config.yaml b/.github/ISSUE_TEMPLATE/config.yaml new file mode 100644 index 00000000000..04a0fb026db --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yaml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: JMeter users mailing list + url: https://jmeter.apache.org/mail2.html + about: Please ask questions on JMeter usage on users mailing list (note that you need to subscribe first) diff --git a/.github/ISSUE_TEMPLATE/documentation.yaml b/.github/ISSUE_TEMPLATE/documentation.yaml new file mode 100644 index 00000000000..66192ff73e6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/documentation.yaml @@ -0,0 +1,27 @@ +name: Feedback about the manual +description: Found an issue with the documentation? +labels: + - documentation + - to-triage +body: + - type: markdown + attributes: + value: | + Please fill in all required fields with as many details as possible. + - type: input + id: url + attributes: + label: The documentation URL + placeholder: ex. https://jmeter.apache.org/usermanual/best-practices.html + validations: + required: true + - type: textarea + id: feedback + attributes: + label: Feedback + description: | + Describe what issue with the documentation you've found + placeholder: | + Here you can also attach log files, screenshots or a video + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml new file mode 100644 index 00000000000..85fc221b752 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -0,0 +1,58 @@ +name: Feature Request +description: Suggest an idea +labels: + - enhancement + - to-triage +body: + - type: markdown + attributes: + value: | + Please describe the use-case you have. This will better help us understand the context in which you're looking for a new feature. + - type: textarea + id: use-case + attributes: + label: Use case + description: | + Please describe the use-case you have. This will better help us understand the context in which you're looking for a new feature. + placeholder: Describe the use-case here + validations: + required: true + - type: textarea + id: solution + attributes: + label: Possible solution + description: | + Please describe a possible solution you'd like to see in JMeter, ideally with example code. + Please note, it's not always easy to describe a good solution. Describing the use-case above is much more important to us. + placeholder: Describe the possible solution here. + validations: + required: false + - type: textarea + id: workarounds + attributes: + label: Possible workarounds + description: | + Please describe the possible workarounds you've implemented to work around the lacking functionality. + placeholder: Describe the possible workarounds here. + validations: + required: false + - type: input + id: jmeter-version + attributes: + label: JMeter Version + description: What JMeter version and edition did you use? + placeholder: ex. 5.6 + validations: + required: true + - type: input + id: java-version + attributes: + label: Java Version + description: What JDK version and distribution did you use (use `java -version`) + placeholder: ex. openjdk version "17" 2021-09-14 + - type: input + id: os-version + attributes: + label: OS Version + description: What operating system version and distribution did you use (use e.g. `ver` on Windows) + placeholder: ex. Microsoft Windows [Version 10.0.22000.856] diff --git a/.github/ISSUE_TEMPLATE/regression.yaml b/.github/ISSUE_TEMPLATE/regression.yaml new file mode 100644 index 00000000000..d27609c5810 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/regression.yaml @@ -0,0 +1,59 @@ +name: Regression +description: Report a problem about something that used to work +labels: + - regression + - to-triage +body: + - type: markdown + attributes: + value: | + Please fill in all required fields with as many details as possible. + Read the [User manual](https://jmeter.apache.org/usermanual/index.html) and/or [Reference documentation](https://jmeter.apache.org/usermanual/component_reference.html) + - type: textarea + id: expected + attributes: + label: Expected behavior + description: | + Describe what you were expecting JMeter to do + placeholder: | + Here you can also attach log files, screenshots or a video + - type: textarea + id: actual + attributes: + label: Actual behavior + description: | + Describe what you observed JMeter did instead + placeholder: | + Here you can also attach log files (e.g. jmeter.log), screenshots or a video + - type: textarea + id: steps + attributes: + label: Steps to reproduce the problem + description: | + - If the problem relates to a third-party plugin, consider removing them first + placeholder: | + Here you can also attach log files, screenshots or a video + validations: + required: true + - type: input + id: jmeter-version + attributes: + label: JMeter Version + description: | + What JMeter version and edition did you use? + Note: While you can obviously continue using older versions of JMeter, it may well be that your bug is already fixed. If you're using an older version, please also try to reproduce the bug in the latest version of JMeter before reporting it. + placeholder: ex. 5.6 + validations: + required: true + - type: input + id: java-version + attributes: + label: Java Version + description: What JDK version and distribution did you use (use `java -version`) + placeholder: ex. openjdk version "17" 2021-09-14 + - type: input + id: os-version + attributes: + label: OS Version + description: What operating system version and distribution did you use (use e.g. `ver` on Windows) + placeholder: ex. Microsoft Windows [Version 10.0.22000.856] diff --git a/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md similarity index 100% rename from PULL_REQUEST_TEMPLATE.md rename to .github/PULL_REQUEST_TEMPLATE.md diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml new file mode 100644 index 00000000000..0a09f1b3941 --- /dev/null +++ b/.github/release-drafter.yml @@ -0,0 +1,72 @@ +# See https://github.com/release-drafter/release-drafter#configuration-options +name-template: 'v$RESOLVED_VERSION' +tag-template: 'rel/v$RESOLVED_VERSION' +exclude-labels: + - 'skip-changelog' +categories: + - title: '🚀 Features' + labels: + - 'feature' + - 'enhancement' + - title: '🐛 Bug Fixes' + labels: + - 'fix' + - 'bugfix' + - 'bug' + - 'defect' + - title: '📝 Documentation' + labels: + - 'documentation' + - title: '🧰 Maintenance' + label: 'chore' + - title: '⬆️ Dependencies' + collapse-after: 8 + labels: + - 'dependencies' +change-template: '- $TITLE @$AUTHOR (#$NUMBER)' +change-title-escapes: '\<*_&' # You can add # and @ to disable mentions, and add ` to disable code blocks. +version-resolver: + major: + labels: + - 'major' + minor: + labels: + - 'minor' + patch: + labels: + - 'patch' + default: patch +template: | + ## Changes + + $CHANGES +# See https://github.com/release-drafter/release-drafter#autolabeler +# This is more like a reference, since auto-labelling PRs seems to require too much privileges +autolabeler: + - label: 'dependencies' + files: + - 'gradle-wrapper.properties' + title: + - '/^fix\(deps\)/i' + - '/^chore:\s*bump/i' + - label: 'chore' + files: + - '*gradle*' + branch: + - '/docs{0,1}\/.+/' + title: + - '/^chore/i' + - label: 'documentation' + files: + - '*.md' + - 'docs/**' + - label: 'bug' + branch: + - '/fix\/.+/' + title: + - '/^fix/i' + - label: 'enhancement' + branch: + - '/feature\/.+/' + title: + - '/^feat/i' diff --git a/.github/workflows/gradle-dependency-submit.yaml b/.github/workflows/gradle-dependency-submit.yaml new file mode 100644 index 00000000000..45ff462e8bd --- /dev/null +++ b/.github/workflows/gradle-dependency-submit.yaml @@ -0,0 +1,31 @@ +name: Dependency Submission + +# See https://github.com/gradle/actions/blob/768a17f3488dc3fe0155ff431553e1f53d57e22e/dependency-submission/README.md#the-dependency-submission-action +# The action allows GitHub to alert about reported vulnerabilities in the project +on: + push: + branches: + - master + +# Declare default permissions as read-only. +permissions: read-all + +jobs: + dependency-submission: + name: Submit dependencies + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout sources + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + persist-credentials: false + - name: Set up JDK 21 + uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5 + with: + distribution: zulu + java-version: 21 + server-id: central + - name: Generate and submit dependency graph + uses: gradle/actions/dependency-submission@0723195856401067f7a2779048b490ace7a47d7c # v5 diff --git a/.github/workflows/gradle-wrapper-validation.yml b/.github/workflows/gradle-wrapper-validation.yml index 405a2b30659..78ee9d201e9 100644 --- a/.github/workflows/gradle-wrapper-validation.yml +++ b/.github/workflows/gradle-wrapper-validation.yml @@ -6,5 +6,5 @@ jobs: name: "Validation" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: gradle/wrapper-validation-action@v1 + - uses: actions/checkout@v6 + - uses: gradle/actions/wrapper-validation@0723195856401067f7a2779048b490ace7a47d7c # v5.0.2 diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 4bc32698f00..4a44114626c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -10,58 +10,100 @@ on: # https://help.github.com/en/actions/automating-your-workflow-with-github-actions/software-installed-on-github-hosted-runners +concurrency: + # On master/release, we don't want any jobs cancelled so the sha is used to name the group + # On PR branches, we cancel the job if new commits are pushed + # More info: https://stackoverflow.com/a/68422069/253468 + group: ${{ (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/release' ) && format('ci-main-{0}', github.sha) || format('ci-main-{0}', github.ref) }} + cancel-in-progress: true + jobs: - windows: - name: 'Windows (JDK 14)' - runs-on: windows-latest + matrix_prep: + name: Matrix Preparation + runs-on: ubuntu-latest + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + env: + # Number of jobs to generate in matrix.js + MATRIX_JOBS: 4 steps: - - uses: actions/checkout@v1.1.0 - with: - fetch-depth: 50 - - name: 'Set up JDK 14' - uses: actions/setup-java@v1 - with: - java-version: 14 - - uses: burrunan/gradle-cache-action@v1 - name: Test - with: - job-id: jdk14 - multi-cache-enabled: false - # An explicit skip for Sha512 tasks is required due to https://github.com/gradle/gradle/issues/16789 - arguments: --scan --no-parallel build -x distTar -x distTarSource -x distTarSha512 -x distTarSourceSha512 + - uses: actions/checkout@v6 + - id: set-matrix + run: | + npm ci --prefix .github/workflows + node .github/workflows/matrix.mjs - mac: - name: 'macOS (JDK 14)' - runs-on: macos-latest + test: + needs: matrix_prep + name: '${{ matrix.name }}' + runs-on: ${{ matrix.os }} + env: + TZ: ${{ matrix.tz }} + strategy: + matrix: ${{fromJson(needs.matrix_prep.outputs.matrix)}} + fail-fast: false + # max-parallel: 4 steps: - - uses: actions/checkout@v1.1.0 + - uses: actions/checkout@v6 with: fetch-depth: 50 - - name: 'Set up JDK 14' - uses: actions/setup-java@v1 + - name: Set up Java ${{ matrix.java_version }}, oracle + if: ${{ matrix.oracle_java_website != '' }} + uses: oracle-actions/setup-java@fff43251af9936a0e6a4d5d0946e14f1680e9b6b # v1.5.0 + with: + website: ${{ matrix.oracle_java_website }} + release: ${{ matrix.java_version }} + - name: Set up Java 21 and ${{ matrix.non_ea_java_version }}, ${{ matrix.java_distribution }} + uses: actions/setup-java@v5 + with: + # The latest one will be the default, so we use Java 21 for launching Gradle + java-version: | + ${{ matrix.non_ea_java_version }} + 21 + distribution: ${{ matrix.java_distribution }} + architecture: x64 + - name: Steps to reproduce + uses: actions/github-script@v8 with: - java-version: 14 - - uses: burrunan/gradle-cache-action@v1 + script: | + console.log('The following command might help reproducing CI results, use Java ${{ matrix.java_version }}') + console.log('TZ="${{ matrix.tz }}" _JAVA_OPTIONS="${{ matrix.extraJvmArgs }}" ./gradlew build -x distTar -x distTarSource -x distTarSha512 -x distTarSourceSha512 ${{ matrix.extraGradleArgs }} -PtestExtraJvmArgs="${{ matrix.testExtraJvmArgs }}" -PtestDisableCaching="${{ matrix.testDisableCaching }}"') + - uses: burrunan/gradle-cache-action@v3 name: Test with: - job-id: jdk14 + job-id: jdk${{ matrix.java_version }} multi-cache-enabled: false - arguments: --scan --no-parallel build -x distTar -x distTarSource -x distTarSha512 -x distTarSourceSha512 -Dskip.test_TestDNSCacheManager.testWithCustomResolverAnd1Server=true + # An explicit skip for Sha512 tasks is required due to https://github.com/gradle/gradle/issues/16789 + arguments: --scan --no-parallel build -x distTar -x distTarSource -x distTarSha512 -x distTarSourceSha512 ${{ matrix.extraGradleArgs }} + properties: | + testExtraJvmArgs=${{ matrix.testExtraJvmArgs }} + testDisableCaching=${{ matrix.testDisableCaching }} + jdkBuildVersion=21 + jdkTestVersion=${{ matrix.java_version }} + jdkTestVendor=${{ matrix.java_vendor }} + # We have a separate job with Errorprone verifications, so avoid duplicate warnings + enableErrorprone=false + # We provision JDKs with GitHub Actions for caching purposes, so Gradle should rather fail in case JDK is not found + org.gradle.java.installations.auto-download=false + env: + _JAVA_OPTIONS: ${{ matrix.extraJvmArgs }} + DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} errorprone: - name: 'Error Prone (JDK 11)' + name: 'Error Prone (JDK 21)' runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - with: - fetch-depth: 50 - - name: 'Set up JDK 11' - uses: actions/setup-java@v1 + - uses: actions/checkout@v6 + - name: 'Set up JDK 21' + uses: actions/setup-java@v5 with: - java-version: 11 - - uses: burrunan/gradle-cache-action@v1 + java-version: 21 + distribution: 'zulu' + - uses: burrunan/gradle-cache-action@v3 name: Test with: job-id: errprone multi-cache-enabled: false - arguments: --scan --no-parallel --no-daemon -PenableErrorprone classes + arguments: --scan --no-parallel --no-daemon classes + env: + DEVELOCITY_ACCESS_KEY: ${{ secrets.DEVELOCITY_ACCESS_KEY }} diff --git a/.github/workflows/matrix.mjs b/.github/workflows/matrix.mjs new file mode 100644 index 00000000000..fa4f79ca9db --- /dev/null +++ b/.github/workflows/matrix.mjs @@ -0,0 +1,170 @@ +// The script generates a random subset of valid jdk, os, timezone, and other axes. +// You can preview the results by running "node matrix.mjs" +// See https://github.com/vlsi/github-actions-random-matrix +import { appendFileSync } from 'fs'; +import { EOL } from 'os'; +import { createGitHubMatrixBuilder } from '@vlsi/github-actions-random-matrix/github'; +const { matrix, random } = createGitHubMatrixBuilder(); +matrix.addAxis({ + name: 'java_distribution', + values: [ + {value: 'corretto', vendor: 'amazon', weight: 1}, + {value: 'liberica', vendor: 'bellsoft', weight: 1}, + {value: 'microsoft', vendor: 'microsoft', weight: 1}, + {value: 'oracle', vendor: 'oracle', weight: 1}, + // There are issues running Semeru JDK with Gradle 8.5 + // See https://github.com/gradle/gradle/issues/27273 + // {value: 'semeru', vendor: 'ibm', weight: 4}, + {value: 'temurin', vendor: 'eclipse', weight: 1}, + {value: 'zulu', vendor: 'azul', weight: 1}, + ] +}); + +const eaJava = '22'; + +matrix.addAxis({ + name: 'java_version', + // Strings allow versions like 18-ea + values: [ + '17', + '21', + '25', + eaJava, + ] +}); + +matrix.addAxis({ + name: 'tz', + values: [ + 'America/New_York', + 'Pacific/Chatham', + 'UTC' + ] +}); + +matrix.addAxis({ + name: 'os', + title: x => x.replace('-latest', ''), + values: [ + // TODO: X11 is not available. Un-comment when https://github.com/burrunan/gradle-cache-action/issues/48 is resolved + // 'ubuntu-latest', + 'windows-latest', + 'macos-latest' + ] +}); + +// Test cases when Object#hashCode produces the same results +// It allows capturing cases when the code uses hashCode as a unique identifier +matrix.addAxis({ + name: 'hash', + values: [ + {value: 'regular', title: '', weight: 42}, + {value: 'same', title: 'same hashcode', weight: 1} + ] +}); +matrix.addAxis({ + name: 'locale', + title: x => x.language + '_' + x.country, + values: [ + {language: 'de', country: 'DE'}, + {language: 'fr', country: 'FR'}, + // TODO: fix :src:dist-check:batchBUG_62847 + // Fails with "ERROR o.a.j.u.JMeterUtils: Could not find resources for 'ru_EN'" + // {language: 'ru', country: 'RU'}, + {language: 'tr', country: 'TR'}, + ] +}); + +matrix.setNamePattern(['java_version', 'java_distribution', 'hash', 'os', 'tz', 'locale']); + +// Semeru uses OpenJ9 jit which has no option for making hash codes the same +matrix.exclude({java_distribution: {value: 'semeru'}, hash: {value: 'same'}}); +// MacOS and Oracle Java does not work currently. No JAVA_HOME_${VERSION}_x64 set and thus no java found +matrix.exclude({os: 'macos-latest', java_distribution: {value: 'oracle'}}) +// Ignore builds with JAVA EA for now, see https://github.com/apache/jmeter/issues/6114 +matrix.exclude({java_version: eaJava}) +matrix.imply({java_version: eaJava}, {java_distribution: {value: 'oracle'}}) +// Oracle JDK is only supported for JDK 21 and later +matrix.imply({java_distribution: {value: 'oracle'}}, {java_version: v => v === eaJava || v >= 21}); +// TODO: Semeru does not ship Java 21 builds yet +matrix.exclude({java_distribution: {value: 'semeru'}, java_version: '21'}); +// Ensure at least one job with "same" hashcode exists +matrix.generateRow({hash: {value: 'same'}}); +// Ensure at least one Windows and at least one Linux job is present (macOS is almost the same as Linux) +matrix.generateRow({os: 'windows-latest'}); +// TODO: un-comment when xvfb will be possible +// matrix.generateRow({os: 'ubuntu-latest'}); +// Ensure there will be at least one job with Java 17 +matrix.generateRow({java_version: "17"}); +// Ensure there will be at least one job with Java 25 +matrix.generateRow({java_version: "25"}); +// Ensure there will be at least one job with Java EA +// matrix.generateRow({java_version: eaJava}); +const include = matrix.generateRows(process.env.MATRIX_JOBS || 5); +if (include.length === 0) { + throw new Error('Matrix list is empty'); +} +include.sort((a, b) => a.name.localeCompare(b.name, undefined, {numeric: true})); +include.forEach(v => { + // Pass locale via Gradle arguments in case it won't be inherited from _JAVA_OPTIONS + // In fact, _JAVA_OPTIONS is non-standard and might be ignored by some JVMs + let gradleArgs = [ + `-Duser.country=${v.locale.country}`, + `-Duser.language=${v.locale.language}`, + ]; + v.extraGradleArgs = gradleArgs.join(' '); +}); +include.forEach(v => { + let jvmArgs = []; + // Extra JVM arguments passed to test execution + let testJvmArgs = []; + if (v.hash.value === 'same') { + testJvmArgs.push('-XX:+UnlockExperimentalVMOptions', '-XX:hashCode=2'); + } + // Gradle does not work in tr_TR locale, so pass locale to test only: https://github.com/gradle/gradle/issues/17361 + jvmArgs.push(`-Duser.country=${v.locale.country}`); + jvmArgs.push(`-Duser.language=${v.locale.language}`); + v.java_distribution = v.java_distribution.value; + v.java_vendor = v.java_distribution.vendor; + if (v.java_distribution === 'oracle') { + v.oracle_java_website = v.java_version === eaJava ? 'jdk.java.net' : 'oracle.com'; + } + v.non_ea_java_version = v.java_version === eaJava ? '' : v.java_version; + if (v.java_distribution !== 'semeru' && random() > 0.5) { + // The following options randomize instruction selection in JIT compiler + // so it might reveal missing synchronization + v.name += ', stress JIT'; + v.testDisableCaching = 'JIT randomization should not be cached'; + jvmArgs.push('-XX:+UnlockDiagnosticVMOptions'); + if (v.java_version >= 8) { + // Randomize instruction scheduling in GCM + // share/opto/c2_globals.hpp + jvmArgs.push('-XX:+StressGCM'); + // Randomize instruction scheduling in LCM + // share/opto/c2_globals.hpp + jvmArgs.push('-XX:+StressLCM'); + } + if (v.java_version >= 16) { + // Randomize worklist traversal in IGVN + // share/opto/c2_globals.hpp + jvmArgs.push('-XX:+StressIGVN'); + } + if (v.java_version >= 17) { + // Randomize worklist traversal in CCP + // share/opto/c2_globals.hpp + jvmArgs.push('-XX:+StressCCP'); + } + } + v.extraJvmArgs = jvmArgs.join(' '); + v.testExtraJvmArgs = testJvmArgs.join(' ::: '); + delete v.hash; +}); + +console.log(include); + +let filePath = process.env['GITHUB_OUTPUT'] || ''; +if (filePath) { + appendFileSync(filePath, `matrix<=16" + } + } + } +} diff --git a/.github/workflows/package.json b/.github/workflows/package.json new file mode 100644 index 00000000000..a66b1aa6f43 --- /dev/null +++ b/.github/workflows/package.json @@ -0,0 +1,7 @@ +{ + "private": true, + "type": "module", + "dependencies": { + "@vlsi/github-actions-random-matrix": "2.0.0" + } +} diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml new file mode 100644 index 00000000000..0ffcc9b1bdd --- /dev/null +++ b/.github/workflows/release-drafter.yml @@ -0,0 +1,53 @@ +name: Release Drafter + +on: + push: + # branches to consider in the event; optional, defaults to all + branches: + - master + - 'release/**' + # pull_request_target allows PR from forks to access secrets, so please NEVER add pull_request_target + +# Declare default permissions as read-only. +permissions: read-all + +jobs: + update_release_draft: + # Skip release drafts in forks + if: vars.RUN_RELEASE_DRAFTER == 'true' + name: Update Release Draft + runs-on: ubuntu-latest + permissions: + # write permission is required to create a github release + contents: write + steps: + - name: Get the current version + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8 + id: current_version + with: + # language=javascript + script: | + const response = await github.rest.repos.getContent({ + owner: context.repo.owner, + repo: context.repo.repo, + path: 'gradle.properties', + ref: context.sha + }); + const content = Buffer.from(response.data.content, 'base64').toString(); + const version = content.match(/^jmeter\.version=(.+)$/m)[1]; + console.log(`Version is ${version}`); + return version; + + # Drafts your next Release notes as Pull Requests are merged into "master" + - name: Update release body draft + uses: release-drafter/release-drafter@6a93d829887aa2e0748befe2e808c66c0ec6e4c7 # v6 + id: prepare_release + # (Optional) specify config name to use, relative to .github/. Default: release-drafter.yml + with: + # config-name: my-config.yml + disable-autolabeler: true + publish: false + latest: ${{ github.ref_name == github.event.repository.default_branch }} + version: ${{ steps.current_version.outputs.result }} + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/renovate-config-lint.yaml b/.github/workflows/renovate-config-lint.yaml new file mode 100644 index 00000000000..a4160ad2d3a --- /dev/null +++ b/.github/workflows/renovate-config-lint.yaml @@ -0,0 +1,27 @@ +name: Validate Renovate Config + +on: + push: + paths: + - renovate.json + - .github/workflows/renovate-config-lint.yaml + pull_request: + paths: + - renovate.json + - .github/workflows/renovate-config-lint.yaml + +# Declare default permissions as read-only. +permissions: read-all + +jobs: + validate-renovate-config: + name: Validate renovate.json + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + with: + persist-credentials: false + + - name: Validate renovate.json + run: docker run --rm -v "$PWD":/work -w /work renovate/renovate:latest renovate-config-validator renovate.json diff --git a/.gitignore b/.gitignore index 21abad60e4b..31dc34b4b3d 100644 --- a/.gitignore +++ b/.gitignore @@ -14,9 +14,13 @@ /src/protocol/*/build/ /src/protocol/*/bin/ /src/protocol/*/out/ +# This folder is generated by running one of the tests (HTML report?), so ignore it for now +# See https://github.com/apache/jmeter/issues/5762 +/src/dist-check/temp/ /dist/ /docs/ /local/ +# We no longer use printable_docs folder, however, keep it here so everybody else do not acidentally commit it /printable_docs/ /reports/ /site/ @@ -29,6 +33,9 @@ # Ignore Gradle project-specific cache directory .gradle +# burrunan/gradle-cache-action creates this folder, so ignore it until the folder moved to another location +/.cache-proxy + # macOS .DS_Store @@ -77,6 +84,10 @@ jmeter-fb.* *.iml # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +node_modules hs_err_pid* # other jvm related files .attach_* + +# npm/node dependencies and generated web assets +/xdocs/node_modules/ diff --git a/.ratignore b/.ratignore index 4f0ca3e960a..bde628007ed 100644 --- a/.ratignore +++ b/.ratignore @@ -1,8 +1,9 @@ -checksum.xml -buildSrc/checksum.xml gradle/wrapper/gradle-wrapper.jar -.* +gradle/verification-keyring.keys +gradle/verification-metadata.xml +**/.* .*/** +AGENTS.md CODE_OF_CONDUCT.md CONTRIBUTING.md eclipse.md @@ -10,6 +11,9 @@ gradle.md ISSUE_TEMPLATE.md PULL_REQUEST_TEMPLATE.md README.md +SECURITY.md +THREAT_MODEL.md +renovate.json **/*.jmx bin/examples/** bin/report-output/** @@ -25,7 +29,6 @@ lib/aareadme.txt lib/opt/README.txt src/licenses/licenses/*/CC0-1.0.txt #local/** -#printable_docs/** #reports/** src/launcher/src/main/resources/org/apache/jmeter/jmeter_as_ascii_art.txt src/core/src/main/resources/org/apache/jmeter/help.txt @@ -35,6 +38,10 @@ test/resources/** #**/*.log **/download_jmeter.cgi xdocs/extending/HTML_REPORT_README.TXT +xdocs/node_modules/** +xdocs/package.json +xdocs/package-lock.json +xdocs/yarn.lock # Rat should automatically detect below files as binary, however it fails **/*.sxi **/*.sxw diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a299afa596d..00000000000 --- a/.travis.yml +++ /dev/null @@ -1,99 +0,0 @@ -language: java - -# skip default "install" command -install: true - -# We can clean the caches via web at https://travis-ci.org/apache/jmeter/caches -before_cache: - - F=CleanupGradleCache sh -x -c 'curl -O https://raw.githubusercontent.com/vlsi/cleanup-gradle-cache/v1.x/$F.java && javac -J-Xmx128m $F.java && java -Xmx128m $F' - - rm -rf $HOME/.m2/repository/org/apache/jmeter - -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ - - $HOME/.m2/repository - -env: - global: - - SKIP_TAR="-x distTar -x distTarSource -x distTarSha512 -x distTarSourceSha512" - - ORG_GRADLE_PROJECT_checksumFailOn=build_finish - - ORG_GRADLE_PROJECT_checksumPrint=true - -matrix: - allow_failures: - # j-m-p does not seem to download all the dependencies: https://github.com/jmeter-maven-plugin/jmeter-maven-plugin/issues/187 - - name: jmeter-maven-plugin tests - - name: jmeter-maven-plugin tests on s390x - - name: Tests with OpenJDK 11 on s390x - include: - - name: Tests with OpenJDK 8 + code coverage - jdk: openjdk8 - script: - - xvfb-run ./gradlew build jacocoReport $SKIP_TAR - after_success: - - bash <(curl -s https://codecov.io/bash) - - name: Tests with OpenJDK 11 - jdk: openjdk11 - addons: - apt: - packages: - - language-pack-fr - env: - - TZ=Pacific/Chatham # flips between +12:45 and +13:45 - - LANG=fr_FR.UTF-8 - - LC_ALL=fr_FR.UTF-8 - script: - # This job verifies headless mode to ensure Apache JMeter is workable in headless as well - # Spotless and Checkstyle are skipped here to save some time. They are verified anyway in Java 8 and Java 13 builds, so skipping them for Java 11 does not harm - - ./gradlew build -Djava.awt.headless=true -Duser.language=fr -Duser.country=FR -PskipCheckstyle -PskipSpotless $SKIP_TAR - - name: Tests with OpenJDK 11 on s390x - os: linux - arch: s390x - dist: bionic - jdk: openjdk11 - addons: - apt: - packages: - - language-pack-fr - script: - - sudo apt-get install -y openjdk-11-jdk - - export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-s390x/ - - export PATH=$JAVA_HOME/bin:$PATH - - ./gradlew build -Djava.awt.headless=true -PskipCheckstyle -PskipSpotless $SKIP_TAR - # Java 12 is not here because it has been superceeded by Java 13 - # Tests with Java 12 do not surface much new, so Java 11 (LTS) and Java 13 (non-LTS) are enough for "post Java 9" testing - - name: Tests with OpenJDK 14 - jdk: openjdk14 - addons: - apt: - packages: - - language-pack-fr - env: - - TZ=America/New_York # flips between −05:00 and −04:00 - - LANG=fr_FR.UTF-8 - - LC_ALL=fr_FR.UTF-8 - script: - # Spotless, Checkstyle, and JaCoCo are verified here to ensure they all work with the latest supported Java - - xvfb-run ./gradlew build jacocoReport -Duser.language=fr -Duser.country=FR $SKIP_TAR - - name: jmeter-maven-plugin tests - jdk: openjdk8 - script: - - ./gradlew -PskipJavadoc publishToMavenLocal -Pjmeter.version=42.0 -PchecksumIgnore - - cd .. - - git clone --depth 100 https://github.com/jmeter-maven-plugin/jmeter-maven-plugin.git - - cd jmeter-maven-plugin - - mvn verify -Djmeter.version=42.0-SNAPSHOT - - name: jmeter-maven-plugin tests on s390x - os: linux - arch: s390x - jdk: openjdk11 - script: - - wget http://www.eu.apache.org/dist/maven/maven-3/3.6.3/binaries/apache-maven-3.6.3-bin.tar.gz - - tar -xvzf apache-maven-3.6.3-bin.tar.gz - - export PATH=`pwd`/apache-maven-3.6.3/bin/:$PATH - - ./gradlew -PskipJavadoc publishToMavenLocal -Pjmeter.version=42.0 -PchecksumIgnore - - cd .. - - git clone --depth 100 https://github.com/jmeter-maven-plugin/jmeter-maven-plugin.git - - cd jmeter-maven-plugin - - mvn verify -Djmeter.version=42.0-SNAPSHOT diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000000..8c32763d3da --- /dev/null +++ b/AGENTS.md @@ -0,0 +1 @@ +Security model: [SECURITY.md](./SECURITY.md) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 14a1c8ce40e..94ac90745a9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,16 +4,17 @@ Want to show Apache JMeter some love? Help out by contributing! ## :beetle: Found a bug -Log it in our bugzilla: +Log it in GitHub issues: + +* https://github.com/apache/jmeter/issues +* or send a note to the [user mailing list](https://jmeter.apache.org/mail2.html#JMeterUser). -* ** -* or send a note to the *user mailing list*. Be sure to include all relevant information, like the versions of JMeter you’re using as long as Java version. A Test plan that caused the issue as well as any error messages are also very helpful. ## :question: Need help -Simply contact: +Contact: * [Our users mailing list](https://jmeter.apache.org/mail2.html#JMeterUser) * or ask question on [stackoverflow](https://stackoverflow.com/questions/tagged/jmeter). @@ -22,8 +23,8 @@ Simply contact: See: -* [Open bug entries for JMeter](https://bz.apache.org/bugzilla/buglist.cgi?bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_status=NEEDINFO&bug_severity=Blocker&bug_severity=Critical&bug_severity=Major&bug_severity=Normal&bug_severity=Regression&bug_severity=Minor&bug_severity=Trivial&product=JMeter&order=Bug%20Number&list_id=164231) -* [Enhancement requests for JMeter](https://bz.apache.org/bugzilla/buglist.cgi?bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&bug_status=NEEDINFO&bug_severity=Enhancement&product=JMeter&order=Bug%20Number&list_id=164232) +* [Open issues for JMeter](https://github.com/apache/jmeter/issues) +* [Enhancement requests for JMeter](https://github.com/apache/jmeter/issues?q=is%3Aopen+label%3Aenhancement) ## Development setup @@ -52,9 +53,8 @@ Optionally you can generate an Eclipse project by running The steps to import the sources (based on Eclipse 2019-06) into Eclipse are as follows: 1. Install `Eclipse IDE for Java Developers` -1. Install the Groovy Eclipse plugin and select Groovy Compiler 2.4 (some tests are written in Groovy) -1. Install `Kotlin for Eclipse` plugin (builds scripts are written in Kotlin) -1. Make sure you have a Java 8 compatible JDK configured in your workspace +1. Install `Kotlin for Eclipse` plugin (JMeter code uses Java and Kotlin) +1. Make sure you have a Java 17 compatible JDK configured in your workspace 1. Open `File->Import...` 1. Select `Existing Gradle Project` and click `Next` 1. Read `How to experience the best Gradle integration` and click `Next` @@ -66,7 +66,7 @@ The best way to make sure your issue or feature is addressed is to submit a patc We accept patches through: * pull requests -* patch attached to bugzilla. +* patch attached to [JMeter developers mailing list](https://jmeter.apache.org/mail2.html#JMeterDev). However, before sending a patch, please make sure that the following applies: diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md deleted file mode 100644 index d24c0af1d5f..00000000000 --- a/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,15 +0,0 @@ -# Reporting an issue: - -- Mention JVM implementation (OpenJDK, Oracle JDK, ...), versions of Java, Apache JMeter -- Provide anonymized and as simple as possible test plan helping reproduce the issue -- Provide jmeter.log -- If it's a bug, explain clearly how to reproduce: - - What should happen (OK Case) - - What happens (KO Case) -- If it's an enhancement request, explain what you want, why you need it and the clear use case -- Answer to questions of the person who handles your case - -Issue are related to bug or enhancements, it is not the right place to ask questions about usage, for the latter: - -- Read the [User manual](https://jmeter.apache.org/usermanual/index.html) and/or [Reference documentation](https://jmeter.apache.org/usermanual/component_reference.html) -- Ask questions on the [user mailing list](https://jmeter.apache.org/mail2.html). *Note you need to subscribe first* diff --git a/NOTICE b/NOTICE index 0f5314e48c8..75b927c8e74 100644 --- a/NOTICE +++ b/NOTICE @@ -1,5 +1,5 @@ Apache JMeter -Copyright 1998-2021 The Apache Software Foundation +Copyright 1998-2024 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). diff --git a/README.md b/README.md index a5703ea1cce..f844e232837 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ By The Apache Software Foundation [![codecov](https://codecov.io/gh/apache/jmeter/branch/master/graph/badge.svg)](https://codecov.io/gh/apache/jmeter) [![License](https://img.shields.io/:license-apache-brightgreen.svg)](https://www.apache.org/licenses/LICENSE-2.0.html) [![Stack Overflow](https://img.shields.io/:stack%20overflow-jmeter-brightgreen.svg)](https://stackoverflow.com/questions/tagged/jmeter) -[![Maven Central](https://maven-badges.herokuapp.com/maven-central/org.apache.jmeter/ApacheJMeter/badge.svg)](https://maven-badges.herokuapp.com/maven-central/org.apache.jmeter/ApacheJMeter) +[![Maven Central](https://img.shields.io/maven-central/v/org.apache.jmeter/ApacheJMeter.svg?label=Maven%20Central)](https://search.maven.org/artifact/org.apache.jmeter/ApacheJMeter) [![Javadocs](https://www.javadoc.io/badge/org.apache.jmeter/ApacheJMeter_core.svg)](https://www.javadoc.io/doc/org.apache.jmeter/ApacheJMeter_core) [![Twitter](https://img.shields.io/twitter/url/https/github.com/apache/jmeter.svg?style=social)](https://twitter.com/intent/tweet?text=Powerful%20load%20testing%20with%20Apache%20JMeter:&url=https://jmeter.apache.org) @@ -92,7 +92,7 @@ The following requirements exist for running Apache JMeter: - Java Interpreter: - A fully compliant Java 8 Runtime Environment is required + A fully compliant Java 17 Runtime Environment is required for Apache JMeter to execute. A JDK with `keytool` utility is better suited for Recording HTTPS websites. @@ -136,8 +136,8 @@ a JMX file onto: ## Documentation The documentation available as of the date of this release is -also included, in HTML format, in the [printable_docs](printable_docs) directory, -and it may be browsed starting from the file called [index.html](printable_docs/index.html). +also included, in HTML format, in the [docs](docs) directory, +and it may be browsed starting from the file called [index.html](docs/index.html). ## Reporting a bug/enhancement @@ -175,7 +175,12 @@ systemProp.https.proxyPassword=your_password ### Test builds -JMeter is built using Gradle. +JMeter is built using Gradle, and it uses [Gradle's Toolchains for JVM projects](https://docs.gradle.org/current/userguide/toolchains.html) +for provisioning JDKs. It means the code would search for the needed JDKs locally, or download them +if they are not found. + +By default, the code would use JDK 17 for build purposes, however it would set the target release to 8, +so the resulting artifacts would be compatible with Java 8. The following command builds and tests JMeter: @@ -183,6 +188,15 @@ The following command builds and tests JMeter: ./gradlew build ``` +If you want to use a custom JDK for building you can set `-PjdkBuildVersion=11`, +and you can select `-PjdkTestVersion=21` if you want to use a different JDK for testing. + +You can list the available build parameters by executing + +```sh +./gradlew parameters +``` + If the system does not have a GUI display then: ```sh @@ -196,7 +210,7 @@ The following command would compile the application and enable you to run `jmete from the `bin` directory. > **Note** that it completely refreshes `lib/` contents, -so it would remove custom plugins should you have them installed. +so it would remove custom plugins should you have them installed to `lib/`. However, it would keep `lib/ext/` plugins intact. ```sh ./gradlew createDist @@ -266,3 +280,11 @@ Apache JMeter does not include any implementation of JSSE or JCE. ## Thanks **Thank you for using Apache JMeter.** + +### Third party notices + +* Notice for mxparser: + + > This product includes software developed by the Indiana + > University Extreme! Lab. For further information please visit + > http://www.extreme.indiana.edu/ diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000000..dabb96e8b32 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +## Reporting a Vulnerability + +`apache/jmeter` follows the [Apache Software Foundation security process](https://www.apache.org/security/). Please report suspected +vulnerabilities privately to `security@apache.org`; do not open public +GitHub issues or pull requests for security reports. + +## Threat Model + +What the project treats as in scope and out of scope, the security +properties it provides and disclaims, the adversary model, and how +findings are triaged are documented in [THREAT_MODEL.md](./THREAT_MODEL.md). diff --git a/THREAT_MODEL.md b/THREAT_MODEL.md new file mode 100644 index 00000000000..7add8cbcc8b --- /dev/null +++ b/THREAT_MODEL.md @@ -0,0 +1,216 @@ +# Apache JMeter — Threat Model (v1 draft) + +> Built on Apache JMeter's existing security policy at +> . That page's "Security Model" +> statements are lifted here verbatim as the *(documented)* core; this +> document adds the threat-model structure around them (adversary model, +> in/out scope, properties, known non-findings, triage dispositions). + +## §1 Header + +- **Project:** Apache JMeter (`apache/jmeter`), `master`, against which this draft was written. +- **Date:** 2026-06-02 (v0); **revised 2026-06-04** incorporating the full JMeter PMC review (vlsi, milamberspace). **Status:** draft v1 — Wave-1/2 questions ratified by the PMC; remaining items are tracked follow-ups (XStream allowlist enforcement; `security.html` backlink) flagged in §14. **Author:** ASF Security team (drafted via the Scovetta threat-model rubric, building on JMeter's `security.html`), for PMC ratification. +- **Version binding:** versioned with the project; a report against version *N* is triaged against the model as it stood at *N*. +- **Reporting cross-reference:** §8-property violations → report privately per ASF process (`security@apache.org` → `private@jmeter.apache.org`); §3/§9 findings are closed citing this document and `security.html`. +- **Provenance legend:** *(documented)* = JMeter's own docs/`security.html`/repo; *(maintainer)* = confirmed by a JMeter PMC member through this process; *(inferred)* = reasoned from architecture, not yet confirmed — each has a matching §14 open question. +- **Coexistence:** this model is a strict superset of `security.html`; nothing there is weakened. `security.html` stays the canonical reporting/policy page and should link here for the expanded model (the `xdocs/security.xml` backlink is a tracked follow-up — see §14 Q8). *(maintainer)* +- **Draft confidence:** ~10 documented / ~20 maintainer / ~6 inferred. The RMI-SSL posture, the open-vs-run line, the XStream policy gap, the Security-Manager/JDK-24 status, the HTTPS-recording-proxy surface, and the SUT scope were all confirmed from JMeter source by the PMC (vlsi, milamberspace) on 2026-06-03/04. +- **What JMeter is:** Apache JMeter is a Java load-/performance-testing tool. A user builds a **test plan** (a `.jmx` file) in the GUI or by hand, then runs it — in the GUI, in non-GUI/CLI mode, or distributed across a controller and remote engines — to drive load at a *system under test* and collect results. Test plans may contain scripting (JSR223/Groovy/BeanShell) and therefore arbitrary code. *(documented — README, security.html)* + +## §2 Scope and intended use + +- **Primary use:** a **user-run tool** — the person running JMeter authors (or obtains) the `.jmx`, points it at a target they are authorised to test, and runs it locally or across machines they control. *(documented — security.html)* +- **Secondary / dual-use — authorized penetration testing.** JMeter is used (and distributed in pentest toolkits) by security professionals for **authorized** security assessments — rate-limit testing, parameterized enumeration, fuzzing, and custom scenarios via scripting (JSR223/Groovy/BeanShell), parameterized datasets (CSV Dataset Config), and broad protocol support (HTTP/JDBC/LDAP/JMS/…). This is a recognised legitimate use; the operator-trust model is unchanged (the operator is still the trusted party, running a `.jmx` they control against a target they are authorised to test). Conducting such tests **without authorization** is a legal/ethical violation, already covered by §11. *(maintainer, milamberspace 2026-06-04)* +- **The user is the trusted operator.** The central design statement: *"The purpose of JMeter is to execute the workload specified in the input jmx file, which may include arbitrary code"* — so JMeter running the plan it is given is the intended behaviour, not an attack. *(documented — security.html)* +- **Roles** (a tool, but distributed mode and the recording proxy introduce network/trust surfaces): + - **user/operator** — supplies the `.jmx`, runs JMeter. **Trusted.** *(documented)* + - **distributed remote engine** (`jmeter-server`) — a node that accepts a test plan from a controller over RMI and executes it. A **listening network surface** in distributed mode. *(documented — distributed testing guidance)* + - **HTTPS recording proxy** (`ProxyControl`) — a user-initiated local proxy that MITMs the operator's own HTTPS traffic to record it, backed by a locally-generated Root CA. A **local trust boundary** (the CA private key on disk). *(maintainer, milamberspace 2026-06-04)* + - **system under test (SUT)** — the target JMeter sends requests to and whose responses it parses. JMeter is the *client* here; the SUT is the operator's own/authorised target. *(maintainer — SUT scope confirmed 2026-06-04)* + +**Component-family table:** + +| Family | Entry point | Touches outside process | In model? | +| --- | --- | --- | --- | +| Test-plan load + execution (GUI / non-GUI) | open/run a `.jmx`; JSR223/Groovy/BeanShell elements | runs arbitrary code **by design** | **In, but see §9 — executing the plan is by-design** *(documented)* | +| Distributed / remote testing | `jmeter-server` RMI controller↔engine | network (listens) | **In — the real network boundary** *(documented)* | +| HTTPS recording proxy | `ProxyControl` (GUI or CLI) | local filesystem (CA keystore) + MITM on local HTTPS traffic | **In — local trust boundary (CA private key)** *(maintainer)* | +| Protocol client + response processing | HTTP/JDBC/JMS/etc. samplers; XPath/JSON/regex extractors | network (egress to SUT); parses responses | **In as a client, but hostile-SUT response handling is out of model (§3/§9)** *(maintainer)* | +| Report/results generation | listeners, dashboard | filesystem | **In (parsing result files)** *(inferred)* | +| Plugins / properties / functions | `user.properties`, plugins, `__function` calls | varies | **In core; third-party plugins out** *(maintainer)* | +| `examples/`, test resources, demos | — | — | **Out** *(maintainer — see §3)* | + +## §3 Out of scope (explicit non-goals) + +- **Executing the test plan the user gives it** — including arbitrary scripting in that plan. This is the whole purpose of the tool. A report that "a `.jmx` / JSR223 element can run code" is **not a vulnerability**; it is the documented design. *(documented — security.html)* +- **Isolating untrusted `.jmx` files** — explicitly delegated to the user: *"If you want to use JMeter to evaluate untrusted jmx files, it is up to you to provide the required isolation."* *(documented — security.html)* +- **Attackers who already control the machine JMeter runs on, its `user.properties`, its plugins, or the controller in a distributed run.** Operator-trusted. *(inferred)* +- **The security of the system under test, and robustness against a *hostile* SUT.** JMeter drives load at a target the operator owns/is authorised to test; defending the SUT, and hardening JMeter's parsers against a malicious SUT's crafted responses (XXE/ReDoS/size bombs), is not a claimed property. *(maintainer, vlsi + milamberspace 2026-06-04)* +- **Unauthorized use.** Pointing JMeter at systems the operator is not authorised to test (load-testing/pentesting a third party without permission) is a legal/ethical violation, not a JMeter vulnerability (§11). *(maintainer, milamberspace 2026-06-04)* +- **`examples/`, demo/test resources, and third-party plugins.** *(maintainer, vlsi + milamberspace 2026-06-04)* + +## §4 Trust boundaries and data flow + +- **The `.jmx` is NOT a trust boundary for the code the operator chose to run — it is trusted input by design** (§3). The user vouches for the plan they run. The one in-model caveat is the *open*-time deserialization path (see the open-vs-run boundary below and §8). *(documented + maintainer)* +- **The distributed-testing RMI surface IS a trust boundary** — and one whose defaults are protective. `jmeter-server` accepts a serialized test plan + commands from a controller over RMI. Per the PMC's source review (`RmiUtils.java`): RMI-over-SSL is **on by default** (`server.rmi.ssl.disable=false`), the server hard-codes `setNeedClientAuth(true)` (**mutual TLS required**), the keystore (`rmi_keystore.jks`) is **not shipped** so the engine **won't start** until the operator generates one (or explicitly disables SSL). So an attacker cannot reach an unprotected engine **unless the operator has explicitly opted out** with `server.rmi.ssl.disable=true`. *(maintainer, 2026-06-03 — vlsi + milamberspace, from source)* The historical no-SSL RMI-deserialization exposure (CVE-2019-0187) is what these defaults close. (Interface-binding nuance: the RMI port is **not** restricted to a single interface by default — see §5a.) +- **The HTTPS-recording-proxy CA private key IS a local trust boundary.** In recording mode JMeter generates a local Root CA (`ApacheJMeterTemporaryRootCA.*`) stored in a keystore on the operator's machine, dynamically issues per-host certs signed by that CA, and requires the operator to install the CA into their OS/browser trust store. This is analogous to running a private CA on the workstation: if the CA private key is compromised while the CA is still trusted, an attacker could mint certs for any domain accepted silently by the browser (MITM). The default `proxy.cert.validity=7` days limits the exposure window (a sound default; long validity is an opt-in misconfiguration). *(maintainer, milamberspace 2026-06-04 — from `ProxyControl.java`)* +- **The SUT→JMeter response path is *not* an in-model boundary.** The model assumes the tester points JMeter only at systems they own/are authorised to test (§2, §10); a *hostile* SUT crafting responses to exploit JMeter's extractors (XXE/ReDoS/size bombs) is therefore **out of model** — robustness there is hardening, not a claimed security property. *(maintainer, vlsi + milamberspace 2026-06-04)* Classifying it in-model would amount to claiming "JMeter is safe to point at attacker-controlled infrastructure", which is not the intended use case. +- **The open-vs-run boundary.** *Opening/browsing* a `.jmx` deserializes the plan and calls getters/setters on the **existing** control/logic classes JMeter ships — that is safe **provided you trust all existing classes in the JMeter distribution**. What would be a **vulnerability** is opening (not running) a file that causes a class **outside** the JMeter distribution to be instantiated/executed (an XStream gadget chain or a "jmx trick" synthesising and running new code before the user clicks Run). See §8/§9 for the current implementation gap. *(maintainer, vlsi + milamberspace 2026-06-03/04)* +- **Reachability precondition:** a finding is **in-model** if it is reachable (a) by a network party against the distributed-RMI surface **with the default SSL/mutual-TLS protections in place** (i.e. without the operator having set `server.rmi.ssl.disable=true`), (b) pre-execution by *opening* a file that triggers instantiation/execution of a class **outside** the JMeter distribution (the open-vs-run boundary above), or (c) against the recording-proxy CA-key local boundary. Anything that requires the user to run a `.jmx` they chose to run, or a hostile SUT, is `OUT-OF-MODEL`/`BY-DESIGN`. *(maintainer 2026-06-04)* + +## §5 Assumptions about the environment + +- **Runtime:** JVM (JMeter 6.0 sets JDK 17 as the minimum; users may run on JDK 24+); runs as a desktop GUI app, a CLI process, or `jmeter-server` remote engine. *(documented — README; maintainer for the JDK-floor detail)* +- **The user controls the host, the `.jmx`, `user.properties`, installed plugins, and (in distributed mode) the controller and engines.** *(inferred)* +- **Java Security Manager — removed on modern JDKs; NOT the forward defense.** `security.html` historically recommends the Security Manager for distributed runs, but it is gone on the JDKs JMeter now targets and **cannot** be relied on going forward *(maintainer, milamberspace 2026-06-04 — the recommendation in `security.html` should be updated)*: + + | JDK | Security Manager status | + | --- | --- | + | 17 | Deprecated for removal (JEP 411) | + | 18–23 | Deprecated, still functional (startup warning) | + | **24+** | **Fully removed (JEP 486) — not available at all** | + + Since JMeter 6.0's minimum is JDK 17 and operators may run on JDK 24+, the documented Security-Manager isolation recommendation is **not actionable on JDK 24+**. The equivalent isolation must now come from **outside** the JVM (see §9 / §10 for the recommended OS-level replacements). The actual distributed-mode defense is the RMI-over-SSL + mutual-client-auth posture (§4), not the Security Manager. +- **Negative side-effects inventory:** JMeter makes outbound network requests to the SUT by design; in distributed mode it listens for RMI; in recording mode it listens on a local proxy port and writes a CA keystore; it reads/writes test plans, results, and properties on the local filesystem; it executes user-supplied scripting. *(maintainer / documented)* + +## §5a Build-time and configuration variants + +Security-relevant configuration *(documented unless noted):* + +- **`server.rmi.ssl.disable`** — default **`false`**: RMI-over-SSL is on by default, and the server requires **mutual** client auth (`setNeedClientAuth(true)`). The keystore is not shipped, so the engine won't start until the operator provides one or sets this to `true`. *(maintainer, 2026-06-03)* +- **`jmeter-server` bind interface — *not* restricted by default.** The RMI registry and server socket bind to the address `java.rmi.server.hostname` resolves to (typically the machine's primary hostname/IP via `getLocalHost()`), **not** a loopback-only or single-interface binding. On a multi-homed or public-IP host this can expose the RMI port on all interfaces. Operators limit exposure with `java.rmi.server.hostname` (set to `127.0.0.1` for loopback-only) and/or perimeter firewall rules — especially important when SSL is disabled. *(maintainer, milamberspace 2026-06-04 — corrects the earlier "refuses loopback" wording)* + + | Property | Default | Purpose | + | --- | --- | --- | + | `java.rmi.server.hostname` | (machine hostname) | Which IP the RMI server advertises/binds to; set `127.0.0.1` for loopback-only | + | `server.rmi.port` | `1099` | RMI registry port | + | `server.rmi.localport` | (dynamic) | Server socket port for the remote engine object; fix it for precise firewall rules | + +- **`proxy.cert.validity`** — default **`7`** days (`ProxyControl.java`): the recording-proxy CA's per-host certs are short-lived by default, limiting MITM-key exposure. A long value (e.g. `3650`) is an opt-in misconfiguration, not the default. *(maintainer, milamberspace 2026-06-04)* +- **Scripting elements** (JSR223/Groovy/BeanShell, `__groovy`/`__BeanShell` functions) — always available; gated only by who controls the `.jmx` (the user). *(documented design)* +- **XStream `.jmx` deserialization policy** — `setupXStreamSecurityPolicy()` currently sets `NoTypePermission.NONE` then immediately overrides it with `AnyTypePermission.ANY`, i.e. the effective policy is a **no-op** (any JVM class may be instantiated on open). A package-scoped allowlist is the intended fix but is complicated by third-party plugins (see §8/§9/§12). *(maintainer, milamberspace + vlsi 2026-06-04)* + +**Insecure-default ruling (resolved):** the distributed-mode defaults are **secure** — an unprotected engine requires the operator to actively set `server.rmi.ssl.disable=true`. A report that "jmeter-server is unauthenticated / RCE-by-default" is therefore **not** `VALID` (the defaults refuse to run without SSL + keystore + client-auth). An exposed engine reached after the operator disabled SSL is `OUT-OF-MODEL: non-default-config` — note **config**, not *build*: it's a runtime property opt-out, no rebuild involved *(maintainer, vlsi 2026-06-03)*. (This closes the CVE-2019-0187 class.) + +## §6 Assumptions about inputs + +Per-surface trust table *(maintainer unless noted):* + +| Surface | Input | Attacker-controllable? | Caller/operator must enforce | +| --- | --- | --- | --- | +| `.jmx` test plan (run) | plan XML + embedded scripts | **no — trusted by design**; **yes only if** the user runs an untrusted plan, which they must isolate | don't run untrusted `.jmx` without OS/JVM isolation | +| `.jmx` test plan (open/browse) | plan XML deserialized via XStream | **bounded** — safe w.r.t. *existing* distribution classes; an `OUT-OF-distribution` class instantiated on open is in-model (currently under-enforced, §8) | treat opening untrusted `.jmx` as not fully safe until the XStream allowlist lands | +| Distributed RMI (`jmeter-server`) | controller commands + serialized plan | **no by default** (SSL + mutual client-auth required, keystore not shipped → won't start unprotected); **yes only if** the operator set `server.rmi.ssl.disable=true` | keep `server.rmi.ssl.disable=false`; generate the keystore; restrict the bind interface; never expose an engine after disabling SSL | +| Recording-proxy CA keystore | local CA private key on disk | local — operator-trusted; risk is a stolen key while the CA stays trusted | keep `proxy.cert.validity` short; remove the CA from the trust store after recording | +| SUT responses | HTTP/JDBC/etc. response bodies | **out of model** — the tester points JMeter at systems they own/are authorised to test | test only systems you trust/own (hostile-SUT parser robustness is hardening, not a claimed property) | +| `user.properties` / plugins | local config | no — operator-trusted | vet plugins | +| Result/JTL files (re-opened) | results to render | **yes if a result file is from an untrusted source** | don't open untrusted result files | + +- **Size/shape/rate:** response/result-file size handling and recursion (XML/regex) bounds are open as *hardening* against a hostile SUT (out of model — see §3/§9). *(maintainer)* + +## §7 Adversary model + +- **Distributed-mode network attacker** — can reach a `jmeter-server` RMI port or MITM the controller↔engine link; goal: code execution on a remote engine. The primary in-model adversary, but defeated by the default SSL + mutual-TLS posture (§4/§8). *(maintainer)* +- **Crafted-`.jmx`-on-open attacker** — supplies a `.jmx` that, when merely *opened*, instantiates a class outside the JMeter distribution (XStream gadget chain) to execute code before the user runs the plan. In-model; see §8/§9 for the current enforcement gap. *(maintainer, vlsi + milamberspace 2026-06-04)* +- **Recording-proxy CA-key thief** — obtains the locally-stored CA private key while the CA is still trusted by the operator's browser/OS, to MITM the operator's traffic. In-model as a local boundary; mitigated by short `proxy.cert.validity` and removing the CA after use. *(maintainer, milamberspace 2026-06-04)* +- **Malicious-`.jmx` social-engineering (run)** — tricks a user into *running* a hostile plan. JMeter's stance: this executes by design; isolation is the user's responsibility. An *acknowledged, disclaimed* threat, not a defended one. *(documented — security.html)* +- **Out of scope — malicious SUT.** A target server returning hostile responses to exploit JMeter's extractors is **not** in the adversary model: the tester chooses the target and is expected to test only systems they own/are authorised to test. Parser robustness against a hostile SUT is hardening, not a defended property. *(maintainer, vlsi + milamberspace 2026-06-04)* +- **Out of scope:** anyone with control of the JMeter host, the controller, `user.properties`, or installed plugins. *(inferred)* + +## §8 Security properties the project provides + +- **Distributed-mode network protection (by default).** `jmeter-server` requires RMI-over-SSL with **mutual** client auth and won't start without a keystore the operator generates — so a network party cannot drive a remote engine to execute code in the default configuration. *Violation symptom:* RCE on a `jmeter-server` engine by an unauthenticated/MITM network party **while SSL is enabled** (i.e. without `server.rmi.ssl.disable=true`). *Severity:* security-critical. *(maintainer, 2026-06-03 — confirmed from source)* +- **No unintended code execution from *opening* a non-executed file (aspirational; partially enforced).** + - *Result/JTL files:* opening for display should not instantiate arbitrary classes — the stronger guarantee. *(inferred)* + - *`.jmx` files:* the in-model guarantee is "opening is safe **with respect to the *existing* JMeter distribution classes**" (deserialization drives existing control/logic getters/setters, which you trust by trusting the distribution). If a crafted `.jmx` triggers instantiation of a class **outside** the JMeter distribution (an XStream gadget chain, or dynamically-generated/-compiled code) before the user clicks Run, that is treated as a **`VALID`** vulnerability. **Current status — not yet enforced:** `setupXStreamSecurityPolicy()` is effectively `AnyTypePermission.ANY` (a no-op, carrying a 12-year-old `CVE-2013-7285` TODO), so XStream will instantiate any classpath class during `.jmx` deserialization. The boundary is therefore **aspirational, not enforced**; a package/classloader-scoped allowlist is a tracked improvement (§12), complicated by the need to keep third-party-plugin classes deserializable (a static `org.apache.jmeter.**` allowlist would break plugin test plans — §12). *Violation symptom:* opening (not running) a `.jmx`/result file instantiates or executes a class outside the JMeter distribution. *Severity:* security-critical. *(maintainer, vlsi + milamberspace 2026-06-04)* +- **HTTPS-recording-proxy default exposure window is bounded.** The recording proxy issues short-lived per-host certs (`proxy.cert.validity=7` days by default), limiting the window in which a stolen CA key is useful. *(maintainer, milamberspace 2026-06-04)* This is a *default-hygiene* property, not a guarantee against a stolen-and-still-trusted CA key (§4/§10). +- **Hostile-SUT response handling is *not* a claimed property** — see §3/§7/§9. The SUT is the tester's own/authorised target; hardening the extractors against a malicious SUT is desirable (`VALID-HARDENING` on an internal-audit track) but not a security guarantee. *(maintainer, vlsi + milamberspace 2026-06-04)* + +## §9 Security properties the project does *not* provide + +- **JMeter does not isolate or sandbox the test plan it runs.** *"The JMeter security model assumes you trust jmx input files."* Running a `.jmx` runs its code, including scripting. *(documented — security.html)* **This is the single most important statement for triage.** +- **JMeter does not protect a user who opens/runs an untrusted `.jmx`** — *"it is up to you to provide the required isolation."* *(documented)* +- **XStream class-loading boundary not yet enforced.** `setupXStreamSecurityPolicy()` applies `NoTypePermission.NONE` then immediately overrides it with `AnyTypePermission.ANY`, allowing instantiation of any JVM class during `.jmx` deserialization. A scoped allowlist (classloader-based, or manifest-declared per plugin, or a targeted gadget denylist — to avoid breaking third-party plugins) is a tracked improvement (§12); until it lands, the §8 "opening is safe given trust in existing classes" property is aspirational, not enforced. A *secondary* item: `BeanShellTestElement.readResolve()` instantiates a BeanShell interpreter on open (it does not compile/run the script); making it lazy would shrink the open-time surface. (`JSR223TestElement` is already clean.) *(maintainer, milamberspace + vlsi 2026-06-04)* +- **JMeter does not defend the system under test, and does not claim hardened response-parsing against a *hostile* SUT.** The tester points JMeter at systems they own/are authorised to test; a malicious SUT crafting responses to exploit the extractors (XXE on the XPath Extractor, ReDoS on regex patterns, unbounded response sizes) is out of model — `VALID-HARDENING` at most, not a vulnerability. §8 "safe response handling — best-effort, not a claimed property" is the framing. *(maintainer, vlsi + milamberspace 2026-06-04)* +- **No reliance on the Java Security Manager.** It is fully removed on JDK 24+ (JEP 486) and not a forward defense; the `security.html` recommendation predates that and should be updated. **On JDK 24+, the Security Manager is unavailable; OS-level isolation (container, systemd hardening, or dedicated OS user) is the recommended replacement** (see §10). Distributed-mode protection comes from RMI-over-SSL + mutual client auth (§4/§8), not the Security Manager. *(maintainer, milamberspace 2026-06-04)* +- **JMeter does not guarantee the recording-proxy CA key cannot be misused if stolen while still trusted.** The operator must remove the CA from their trust store after recording and keep `proxy.cert.validity` short. *(maintainer, milamberspace 2026-06-04)* +- **False friend:** loading a `.jmx` in the GUI is *not* a guaranteed-safe "preview" — opening it deserializes the plan and, given the current XStream policy, "may in some cases trigger code execution". *(documented + maintainer)* + +## §10 Downstream responsibilities (the user/operator) + +- **Only open and run `.jmx` files you trust**; isolate (separate OS user / container / VM) if you must evaluate an untrusted plan. Treat *opening* an untrusted `.jmx` as not fully safe until the XStream allowlist lands (§8/§9). *(documented + maintainer)* +- **For distributed testing, keep the secure defaults** — leave `server.rmi.ssl.disable=false`, generate the RMI keystore (`create-rmi-keystore.sh`), restrict the bind interface (`java.rmi.server.hostname`, firewall `server.rmi.port`/`server.rmi.localport`), and do **not** set `server.rmi.ssl.disable=true` to "simplify setup" on an engine reachable from an untrusted network. *(maintainer, 2026-06-03/04)* +- **For distributed-mode isolation on JDK 24+ (Security Manager gone), use OS-level isolation**, in order of preference: (1) **container** (`docker`/`podman` with non-root user, `--read-only` root FS, `--tmpfs /tmp`, `--cap-drop=ALL`, network scoped to the controller); (2) **systemd hardening** (`NoNewPrivileges=true`, `CapabilityBoundingSet=`, `PrivateTmp=true`, `ProtectSystem=strict`, `ReadWritePaths=…`); (3) **dedicated locked-down OS user** (least privilege). A reference `Dockerfile`/unit for `jmeter-server` is a suggested PMC deliverable (tracked — §14 Q8). *(maintainer, milamberspace 2026-06-04)* +- **For HTTPS recording:** remove the JMeter CA certificate from your OS/browser trust store after recording sessions; do not set `proxy.cert.validity` longer than the session needs. *(maintainer, milamberspace 2026-06-04)* +- **Only point JMeter at systems you are authorised to test**, and treat responses from untrusted targets as potentially hostile to the parsers (hardening posture, not a guarantee). *(maintainer)* +- **Vet third-party plugins** before installing. *(inferred)* +- **Don't open untrusted result/JTL files.** *(inferred)* + +## §11 Known misuse patterns + +- Running a `.jmx` obtained from an untrusted source without isolation. *(documented as the user's risk)* +- **Disabling RMI SSL (`server.rmi.ssl.disable=true`) to simplify distributed setup, then exposing `jmeter-server` on an untrusted network** — a widespread quick-start/tutorial antipattern that turns off the default mutual-TLS protection. *(maintainer, milamberspace 2026-06-03)* +- **Leaving the JMeter recording-proxy CA certificate permanently installed in the OS/browser trust store** after a recording session, or setting `proxy.cert.validity` to a long duration (e.g. years) — both widen the MITM exposure of a stolen CA key. *(maintainer, milamberspace 2026-06-04)* +- Treating "open in GUI" as a safe way to inspect an untrusted plan (especially while the XStream allowlist is unenforced). *(documented + maintainer)* +- Load-testing or pentesting a third party's system **without authorisation** (a legal/ethical violation, not just a security risk; the negative counterpart of the §2 authorized dual-use). *(maintainer, milamberspace 2026-06-04)* + +## §11a Known non-findings (recurring false positives) + +*(The highest-leverage scan-suppression input; the `.jmx` items are documented.)* + +- "A `.jmx` / JSR223 / BeanShell element can execute arbitrary code" — **by-design**; JMeter executes the plan it is given (§3/§9, security.html). `BY-DESIGN`, not a finding. +- "Opening a `.jmx` triggers code execution" — **split into two cases:** (a) execution via *existing* JMeter distribution classes during deserialization/UI initialisation is `BY-DESIGN`, consistent with `security.html`; (b) execution via a class *outside* the JMeter distribution (XStream gadget chain, dynamically-compiled script triggered before Run) is `VALID` — the boundary the model intends to hold (currently under-enforced; §8/§9). *(maintainer, vlsi + milamberspace 2026-06-04)* +- "Scripting/reflection/`Runtime.exec` present in the codebase" — needed to execute test plans; `Runtime.exec()` is used by the OS Process Sampler (by design — it runs commands the user configured) and by `KeyToolUtils` to invoke `keytool` for proxy keystore management; reflection is required for plugin loading and test-element instantiation. `BY-DESIGN`/`KNOWN-NON-FINDING` unless reachable from the distributed-RMI surface or the open-a-file-instantiates-an-out-of-distribution-class path. *(maintainer, milamberspace 2026-06-04)* +- "JMeter listens on a local port (proxy)" — that is the user-initiated HTTPS recording proxy (`ProxyControl`), `BY-DESIGN`; not an unintended listening service. *(maintainer, milamberspace 2026-06-04)* +- "Keystore default password `changeit` in properties" — scanners flag the `changeit` value in commented-out lines of `user.properties`/`jmeter.properties`; the `rmi_keystore.jks` is not shipped (operator-generated via `create-rmi-keystore.sh/bat`), so the comment is a `KNOWN-NON-FINDING` (operators should pick a strong password for their generated keystore). *(maintainer, milamberspace 2026-06-04)* +- "RMI deserialization in distributed mode / jmeter-server is unauthenticated" — **not** `VALID`: SSL + mutual client-auth are on by default and the engine won't start without a keystore. It only becomes reachable if the operator set `server.rmi.ssl.disable=true` → `OUT-OF-MODEL: non-default-config` (closes CVE-2019-0187). *(maintainer, 2026-06-03)* +- "Hostile SUT response (XXE/ReDoS/size bomb) crashes/exploits JMeter" — out of model; test only systems you own/are authorised to test (§3/§9). At most a `VALID-HARDENING` on the internal-audit track. *(maintainer, vlsi + milamberspace 2026-06-04)* +- "XML external-entity (XXE) configuration in JMeter's XML processors (XPath Extractor, XStream)" — relevant only against a hostile SUT (out of model) or as part of the open-time XStream boundary (§8/§9). A targeted audit of whether `FEATURE_SECURE_PROCESSING` is enforced everywhere is a `VALID-HARDENING` candidate, not an in-model external-reporter finding. *(maintainer, milamberspace 2026-06-04)* +- "JMeter makes outbound requests / can be pointed anywhere" — by-design; it is a load generator (§3). + +## §12 Conditions that would change this model + +- A change to the distributed-mode RMI/SSL defaults, or the JDK removing/altering an isolation primitive the model relies on. *(maintainer/inferred)* +- **Merging an XStream class-loading allowlist** (replacing `AnyTypePermission.ANY` with a classloader-based / manifest-declared / targeted-denylist scheme that still admits third-party-plugin classes) — would upgrade the §8 `.jmx`-open guarantee from aspirational to enforced and tighten the §11a open-time triage split. *(maintainer, vlsi + milamberspace 2026-06-04)* +- A new way to *open* (not run) a file that triggers instantiation/execution of a class outside the distribution. *(maintainer)* +- A decision to bring hostile-SUT response parsing **into** the model (currently out of model, §3/§9) — would add a new §8 claimed property. *(maintainer)* +- A change to the recording-proxy CA/cert-validity defaults. *(maintainer)* +- A report that cannot be routed to one §13 disposition → revise the model. + +## §13 Triage dispositions + +| Disposition | Meaning | Licensed by | +| --- | --- | --- | +| `VALID` | Violates a §8 property via an in-scope adversary (RCE on a distributed engine despite the documented protections; code exec from *opening* a non-run file via an out-of-distribution class; misuse of a stolen recording-proxy CA key as a local boundary). | §8, §6, §7 | +| `VALID-HARDENING` | No §8 property broken, but a §11 misuse / hostile-SUT parser robustness is worth hardening on an internal-audit track (XXE/ReDoS/size-limits; louder open-time warnings; safer parser defaults). | §11, §9 | +| `OUT-OF-MODEL: trusted-input` | Requires the user to run a `.jmx` they chose to run, or control of host/controller/properties/plugins. | §3, §6, §7 | +| `OUT-OF-MODEL: adversary-not-in-scope` | Requires a capability the model excludes (e.g. a hostile SUT). | §7 | +| `OUT-OF-MODEL: unsupported-component` | Lands in `examples/` / demos / third-party plugins. | §3 | +| `OUT-OF-MODEL: non-default-config` | Only manifests after the operator changed a runtime property away from its secure default — above all `server.rmi.ssl.disable=true` (turning off the default RMI mutual-TLS), or a very long `proxy.cert.validity`. No rebuild involved. | §5a | +| `OUT-OF-MODEL: non-default-build` | Only manifests under a non-default build/compile-time setting (distinct from the runtime config opt-out above). | §5a | +| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property — above all, "JMeter executes the (trusted) test plan, including its code". | §9 | +| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a | +| `MODEL-GAP` | Cannot be cleanly routed — triggers §12. | §12 | + +## §14 Open questions for the maintainers + +Waves 1 and 2 were answered by the PMC (vlsi, milamberspace) on 2026-06-03/04 from a JMeter source review; the resolutions are folded into the sections above and the tags promoted to *(maintainer)*. Retained here as a ratification record. + +**Wave 1 — security.html core + distributed defaults ✅ ANSWERED (2026-06-03/04)** +1. security.html core (trusted `.jmx`; opening may execute; untrusted-plan isolation is the user's job) — confirmed canonical; "`.jmx`/scripting runs code" is `BY-DESIGN`. → §3/§9/§11a. +2. **Distributed defaults** — confirmed from `RmiUtils.java`: `server.rmi.ssl.disable=false`, mutual client-auth (`setNeedClientAuth(true)`), keystore **not shipped** (engine won't start unprotected). The bind interface is **not** restricted by default (binds to the resolved `java.rmi.server.hostname`, can expose all interfaces on a multi-homed/public host). An unprotected engine requires the explicit `server.rmi.ssl.disable=true` opt-out → `OUT-OF-MODEL: non-default-config`. → §4/§5a/§8/§13. *(maintainer, vlsi + milamberspace)* +3. `examples/` / demos / third-party plugins out of scope — confirmed. → §2/§3. *(maintainer, vlsi + milamberspace)* + +**Wave 2 — in-model boundaries ✅ ANSWERED (2026-06-03/04)** +4. **Opening vs running** — opening a `.jmx` is safe given trust in the distribution's **existing** classes (it deserializes + drives existing control/logic getters/setters); the in-model line is opening that instantiates/executes a class **outside** the distribution. The current `setupXStreamSecurityPolicy()` is effectively `AnyTypePermission.ANY` (a no-op), so this boundary is aspirational, not yet enforced — a scoped allowlist that still admits plugin classes is the tracked fix (Q8). → §4/§8/§9/§11a/§12. *(maintainer, vlsi + milamberspace)* +5. **Hostile SUT** — **out of model**, fully confirmed: the tester targets only systems they own/are authorised to test, so hostile-SUT parser robustness is `VALID-HARDENING` (internal audit), not a claimed property; no in-model carve-out. → §3/§7/§8/§9/§11a. *(maintainer, vlsi + milamberspace 2026-06-04)* +6. **Security Manager** — removed on JDK 24+ (JEP 486; deprecated JEP 411 from JDK 17), **not** the forward defense; `security.html` should be updated. The replacement on JDK 24+ is OS-level isolation (container / systemd hardening / dedicated OS user). Distributed protection is RMI-over-SSL + mutual client-auth. → §5/§9/§10. *(maintainer, milamberspace 2026-06-04)* +7. **HTTPS recording proxy** — modeled as a local trust boundary (CA private key on disk); default `proxy.cert.validity=7` days is a sound default; risk is a stolen-and-still-trusted CA key. → §2/§4/§5a/§8/§10/§11/§11a. *(maintainer, milamberspace 2026-06-04)* + +**Wave 3 — tracked follow-ups (open; do not block the doc)** +8. **Tracked engineering/doc follow-ups** (GitHub issues, not threat-model blockers, per the PMC): + - **XStream allowlist** — replace `AnyTypePermission.ANY` with a classloader-based / manifest-declared / targeted-denylist policy that still deserializes third-party-plugin classes (a static `org.apache.jmeter.**` list would break plugin test plans — vlsi). Closes the 12-year-old `CVE-2013-7285` TODO. Upgrades the §8 open-time property from aspirational to enforced. *(maintainer — direction agreed; exact mechanism open.)* + - **`security.html` backlink** — add the THREAT_MODEL.md link to `xdocs/security.xml` (the Velocity source for `security.html`); without it the model is not discoverable from the canonical reporting page. *(maintainer, milamberspace — track via PR/issue.)* + - **Reference `Dockerfile` / systemd unit** for hardened `jmeter-server` on JDK 24+ (the post-Security-Manager isolation deliverable). *(maintainer, milamberspace.)* +9. Any further recurring scanner/fuzzer false positives to seed §11a beyond those now listed (scripting engines, reflection, `Runtime.exec`, proxy port, `changeit`, XXE)? → §11a. *(inferred — kept open for future scan output.)* +10. **Residual operator-trust / result-file assumptions** — confirm the still-*(inferred)* items: that the operator fully controls the host / `user.properties` / plugins / (distributed) controller and engines, that those host-controlling parties are out of the adversary model, that result/JTL-file *display* does not instantiate arbitrary classes, and that re-opening an untrusted result/JTL file is the operator's responsibility. These are reasoned from architecture and not yet PMC-confirmed. → §2/§3/§5/§7/§8/§10. diff --git a/bin/jmeter b/bin/jmeter index 055b2bafcbe..56550598ec8 100755 --- a/bin/jmeter +++ b/bin/jmeter @@ -115,18 +115,19 @@ if [ -z "$JAVA_HOME" ]; then JAVA_HOME="$JRE_HOME" fi -#--add-opens if JAVA 9 -JAVA9_OPTS= +# Module access for modern Java versions (required for JMeter components) +JAVA_OPTS="--add-opens java.desktop/sun.awt=ALL-UNNAMED --add-opens java.desktop/sun.swing=ALL-UNNAMED --add-opens java.desktop/javax.swing.text.html=ALL-UNNAMED --add-opens java.desktop/java.awt=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.text=ALL-UNNAMED --add-opens=java.desktop/sun.awt.X11=ALL-UNNAMED --add-opens=java.desktop/sun.awt.shell=ALL-UNNAMED" # Minimal version to run JMeter -MINIMAL_VERSION=8 +MINIMAL_VERSION=17 -# Check if version is from OpenJDK or Oracle Hotspot JVM prior to 9 containing 1.${version}.x +# Check if version meets the minimal requirement CURRENT_VERSION=`"${JAVA_HOME}/bin/java" -version 2>&1 | awk -F'"' '/version/ {gsub("^1[.]", "", $2); gsub("[^0-9].*$", "", $2); print $2}'` -# Check if Java is present and the minimal version requirement -if [ "$CURRENT_VERSION" -gt "$MINIMAL_VERSION" ]; then - JAVA9_OPTS="--add-opens java.desktop/sun.awt=ALL-UNNAMED --add-opens java.desktop/sun.swing=ALL-UNNAMED --add-opens java.desktop/javax.swing.text.html=ALL-UNNAMED --add-opens java.desktop/java.awt=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.text=ALL-UNNAMED --add-opens=java.desktop/sun.awt.X11=ALL-UNNAMED --add-opens=java.desktop/sun.awt.shell=ALL-UNNAMED" +# Check if Java is present and meets the minimal version requirement +if [ "$CURRENT_VERSION" -lt "$MINIMAL_VERSION" ]; then + echo "ERROR: Java version $CURRENT_VERSION is too low. JMeter requires Java $MINIMAL_VERSION or higher." + exit 1 fi : "${JMETER_OPTS:=""}" @@ -169,15 +170,19 @@ esac # Default to en_EN : "${JMETER_LANGUAGE:="-Duser.language=en -Duser.region=EN"}" -# Uncomment this to generate GC verbose file with Java prior to 9 -# VERBOSE_GC="-verbose:gc -Xloggc:gc_jmeter_%p.log -XX:+PrintGCDetails -XX:+PrintGCCause -XX:+PrintTenuringDistribution -XX:+PrintHeapAtGC -XX:+PrintGCApplicationConcurrentTime -XX:+PrintAdaptiveSizePolicy -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps" +# Legacy GC verbose options removed (Java 8/9 support discontinued) + +# Optimized GC logging for Java 17 with structured output and performance analysis +# Uncomment to enable comprehensive GC logging with rotation and detailed metrics +# VERBOSE_GC="-Xlog:gc,gc+heap,gc+regions,gc+refine,gc+phases:gc_jmeter_%p_%t.log:time,level,tags:filecount=5,filesize=50M" + +# Alternative: Minimal GC logging for production (uncomment if needed) +# VERBOSE_GC="-Xlog:gc:gc_jmeter_%p.log:time" -# Uncomment this to generate GC verbose file with Java 9 and above -# VERBOSE_GC="-Xlog:gc*,gc+age=trace,gc+heap=debug:file=gc_jmeter_%p.log" +# Docker support for Java 17+ +# Modern container memory detection is automatic in Java 17+ +# RUN_IN_DOCKER="-XX:+UseContainerSupport" -# Uncomment this if you run JMeter in DOCKER (need Java SE 8u131 or JDK 9) -# see https://blogs.oracle.com/java-platform-group/java-se-support-for-docker-cpu-and-memory-limits -# RUN_IN_DOCKER="-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap" # Finally, some tracing to help in case things go astray: # You may want to add those settings: @@ -191,7 +196,7 @@ SYSTEM_PROPS="-Djava.security.egd=file:/dev/urandom" SERVER="-server" if [ -z "${JMETER_COMPLETE_ARGS}" ]; then - ARGS="$JAVA9_OPTS $SERVER $DUMP $HEAP $VERBOSE_GC $GC_ALGO $SYSTEM_PROPS $JMETER_LANGUAGE $RUN_IN_DOCKER" + ARGS="$JAVA_OPTS $SERVER $DUMP $HEAP $VERBOSE_GC $GC_ALGO $SYSTEM_PROPS $JMETER_LANGUAGE $RUN_IN_DOCKER" else ARGS="" fi diff --git a/bin/jmeter.bat b/bin/jmeter.bat index e39153dab5b..7a6dae72b3c 100644 --- a/bin/jmeter.bat +++ b/bin/jmeter.bat @@ -78,12 +78,19 @@ if not defined JMETER_LANGUAGE ( ) rem Minimal version to run JMeter -set MINIMAL_VERSION=1.8.0 +set MINIMAL_VERSION=17.0.0 -rem --add-opens if JAVA 9 -set JAVA9_OPTS= +rem Optimized GC logging for Java 17 with structured output and performance analysis +rem Uncomment to enable comprehensive GC logging with rotation and detailed metrics +rem set VERBOSE_GC=-Xlog:gc,gc+heap,gc+regions,gc+refine,gc+phases:gc_jmeter_%%p_%%t.log:time,level,tags:filecount=5,filesize=50M +rem Alternative: Minimal GC logging for production (uncomment if needed) +rem set VERBOSE_GC=-Xlog:gc:gc_jmeter_%%p.log:time + + +rem Module access for modern Java versions (required for JMeter components) +set JAVA_OPTS=--add-opens java.desktop/sun.awt=ALL-UNNAMED --add-opens java.desktop/sun.swing=ALL-UNNAMED --add-opens java.desktop/javax.swing.text.html=ALL-UNNAMED --add-opens java.desktop/java.awt=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.text=ALL-UNNAMED --add-opens=java.desktop/sun.awt.shell=ALL-UNNAMED for /f "tokens=3" %%g in ('java -version 2^>^&1 ^| findstr /i "version"') do ( rem @echo Debug Output: %%g @@ -95,36 +102,24 @@ if not defined JAVAVER ( goto pause ) - - -rem Check if version is from OpenJDK or Oracle Hotspot JVM prior to 9 containing 1.${version}.x -rem JAVAVER will be equal to "9.0.4" (quotes are part of the value) for Oracle Java 9 -rem JAVAVER will be equal to "1.8.0_161" (quotes are part of the value) for Oracle Java 8 -rem so we extract 2 chars starting from index 1 -IF "%JAVAVER:~1,2%"=="1." ( - set JAVAVER=%JAVAVER:"=% - for /f "delims=. tokens=1-3" %%v in ("%JAVAVER%") do ( - set current_minor=%%w +rem Extract major version number from Java version string +for /f "delims=. tokens=1" %%v in ("%JAVAVER:~1,-1%") do ( + set current_major=%%v ) -) else ( - rem Java 9 at least - set current_minor=9 - set JAVA9_OPTS=--add-opens java.desktop/sun.awt=ALL-UNNAMED --add-opens java.desktop/sun.swing=ALL-UNNAMED --add-opens java.desktop/javax.swing.text.html=ALL-UNNAMED --add-opens java.desktop/java.awt=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.text=ALL-UNNAMED --add-opens=java.desktop/sun.awt.shell=ALL-UNNAMED -) - -for /f "delims=. tokens=1-3" %%v in ("%MINIMAL_VERSION%") do ( - set minimal_minor=%%w +rem Extract minimal major version +for /f "delims=. tokens=1" %%v in ("%MINIMAL_VERSION%") do ( + set minimal_major=%%v ) -if not defined current_minor ( +if not defined current_major ( @echo Not able to find Java executable or version. Please check your Java installation. set ERRORLEVEL=2 goto pause ) -rem @echo Debug: CURRENT=%current_minor% - MINIMAL=%minimal_minor% -if %current_minor% LSS %minimal_minor% ( - @echo Error: Java version -- %JAVAVER% -- is too low to run JMeter. Needs a Java version greater than or equal to %MINIMAL_VERSION% + +if %current_major% LSS %minimal_major% ( + @echo Error: Java version -- %JAVAVER% -- is too low to run JMeter. Needs Java %MINIMAL_VERSION% or higher. set ERRORLEVEL=3 goto pause ) @@ -151,13 +146,7 @@ if not defined HEAP ( set HEAP=-Xms1g -Xmx1g -XX:MaxMetaspaceSize=256m ) -rem Uncomment this to generate GC verbose file with Java prior to 9 -rem set VERBOSE_GC=-verbose:gc -Xloggc:gc_jmeter_%%p.log -XX:+PrintGCDetails -XX:+PrintGCCause -XX:+PrintTenuringDistribution -XX:+PrintHeapAtGC -XX:+PrintGCApplicationConcurrentTime -XX:+PrintGCApplicationStoppedTime -XX:+PrintGCDateStamps -XX:+PrintAdaptiveSizePolicy - -rem Uncomment this to generate GC verbose file with Java 9 and above -rem set VERBOSE_GC=-Xlog:gc*,gc+age=trace,gc+heap=debug:file=gc_jmeter_%%p.log -rem You may want to add those settings -rem -XX:+ParallelRefProcEnabled -XX:+PerfDisableSharedMem +rem Legacy GC verbose options removed (Java 8/9 support discontinued) if not defined GC_ALGO ( set GC_ALGO=-XX:+UseG1GC -XX:MaxGCPauseMillis=100 -XX:G1ReservePercent=20 ) @@ -167,9 +156,9 @@ set SYSTEM_PROPS=-Djava.security.egd=file:/dev/urandom rem Always dump on OOM (does not cost anything unless triggered) set DUMP=-XX:+HeapDumpOnOutOfMemoryError -rem Uncomment this if you run JMeter in DOCKER (need Java SE 8u131 or JDK 9) -rem see https://blogs.oracle.com/java-platform-group/java-se-support-for-docker-cpu-and-memory-limits -rem set RUN_IN_DOCKER=-XX:+UnlockExperimentalVMOptions -XX:+UseCGroupMemoryLimitForHeap +rem Docker support for Java 17+ +rem Modern container memory detection is automatic in Java 17+ +rem set RUN_IN_DOCKER=-XX:+UseContainerSupport rem Additional settings that might help improve GUI performance on some platforms rem See: http://www.oracle.com/technetwork/java/perf-graphics-135933.html @@ -188,7 +177,7 @@ if not defined DDRAW ( rem Collect the settings defined above if not defined JMETER_COMPLETE_ARGS ( - set ARGS=%JAVA9_OPTS% %DUMP% %HEAP% %VERBOSE_GC% %GC_ALGO% %DDRAW% %SYSTEM_PROPS% %JMETER_LANGUAGE% %RUN_IN_DOCKER% + set ARGS=%JAVA_OPTS% %DUMP% %HEAP% %VERBOSE_GC% %GC_ALGO% %DDRAW% %SYSTEM_PROPS% %JMETER_LANGUAGE% %RUN_IN_DOCKER% ) else ( set ARGS= ) diff --git a/bin/jmeter.properties b/bin/jmeter.properties index 4953cbd9ad8..dd4dd7eaacd 100644 --- a/bin/jmeter.properties +++ b/bin/jmeter.properties @@ -33,7 +33,7 @@ # JMeter properties are described in the file # http://jmeter.apache.org/usermanual/properties_reference.html # A local copy can be found in -# printable_docs/usermanual/properties_reference.html +# docs/usermanual/properties_reference.html #Preferred GUI language. Comment out to use the JVM default locale's language. #language=en @@ -202,9 +202,9 @@ #Components to not display in JMeter GUI (GUI class name or static label) # These elements are deprecated and will be removed in next version: -# MongoDB Script, MongoDB Source Config, Monitor Results +# Monitor Results # BSF Elements -not_in_menu=org.apache.jmeter.protocol.mongodb.sampler.MongoScriptSampler,org.apache.jmeter.protocol.mongodb.config.MongoSourceElement,\ +not_in_menu=\ org.apache.jmeter.timers.BSFTimer,org.apache.jmeter.modifiers.BSFPreProcessor,org.apache.jmeter.extractor.BSFPostProcessor,org.apache.jmeter.assertions.BSFAssertion,\ org.apache.jmeter.visualizers.BSFListener,org.apache.jmeter.protocol.java.sampler.BSFSampler,\ org.apache.jmeter.protocol.http.control.gui.SoapSamplerGui @@ -403,6 +403,10 @@ remote_hosts=127.0.0.1 # for SPNEGO authentication #kerberos.spnego.strip_port=true +# Should the host name for constructing SPN be canonicalized +# for SPNEGO authentication +#kerberos.spnego.use_canonical_host_name=true + # Should credentials be delegated to webservers when using # SPNEGO authentication #kerberos.spnego.delegate_cred=false @@ -803,7 +807,7 @@ wmlParser.types=text/vnd.wap.wml # Database validation query # based in https://stackoverflow.com/questions/10684244/dbcp-validationquery-for-different-databases list jdbc.config.check.query=select 1 from INFORMATION_SCHEMA.SYSTEM_USERS|select 1 from dual|select 1 from sysibm.sysdummy1|select 1|select 1 from rdb$database -jdbc.config.jdbc.driver.class=com.mysql.jdbc.Driver|org.postgresql.Driver|oracle.jdbc.OracleDriver|com.ingres.jdbc.IngresDriver|com.microsoft.sqlserver.jdbc.SQLServerDriver|com.microsoft.jdbc.sqlserver.SQLServerDriver|org.apache.derby.jdbc.ClientDriver|org.hsqldb.jdbc.JDBCDriver|com.ibm.db2.jcc.DB2Driver|org.apache.derby.jdbc.ClientDriver|org.h2.Driver|org.firebirdsql.jdbc.FBDriver|org.mariadb.jdbc.Driver|org.sqlite.JDBC|net.sourceforge.jtds.jdbc.Driver|com.exasol.jdbc.EXADriver +jdbc.config.jdbc.driver.class=com.mysql.cj.jdbc.Driver|com.mysql.jdbc.Driver|org.postgresql.Driver|oracle.jdbc.OracleDriver|com.ingres.jdbc.IngresDriver|com.microsoft.sqlserver.jdbc.SQLServerDriver|com.microsoft.jdbc.sqlserver.SQLServerDriver|org.apache.derby.jdbc.ClientDriver|org.hsqldb.jdbc.JDBCDriver|com.ibm.db2.jcc.DB2Driver|org.apache.derby.jdbc.ClientDriver|org.h2.Driver|org.firebirdsql.jdbc.FBDriver|org.mariadb.jdbc.Driver|org.sqlite.JDBC|net.sourceforge.jtds.jdbc.Driver|com.exasol.jdbc.EXADriver #--------------------------------------------------------------------------- # OS Process Sampler configuration @@ -1051,6 +1055,13 @@ csvdataset.file.encoding_list=UTF-8|UTF-16|ISO-8859-15|US-ASCII # ORO PatternCacheLRU size #oro.patterncache.size=1000 +# Cache function execution during test execution +# By default, JMeter caches function properties, however, it might cause unexpected results +# when the component is shared across threads and the expression depends on the thread variables. +# The caching behaviour would likely change in the upcoming versions +# Deprecation notice: the setting will likely disappear, so if you need it, consider raising an issue with the use-case. +#function.cache.per.iteration=false + #TestBeanGui # #propertyEditorSearchPath=null @@ -1090,8 +1101,8 @@ csvdataset.file.encoding_list=UTF-8|UTF-16|ISO-8859-15|US-ASCII # List of extra HTTP methods that should be available in select box #httpsampler.user_defined_methods=VERSION-CONTROL,REPORT,CHECKOUT,CHECKIN,UNCHECKOUT,MKWORKSPACE,UPDATE,LABEL,MERGE,BASELINE-CONTROL,MKACTIVITY -# The encoding to be used if none is provided (default ISO-8859-1) -#sampleresult.default.encoding=ISO-8859-1 +# The encoding to be used if none is provided (default UTF-8 since JMeter 5.6.1) +#sampleresult.default.encoding=UTF-8 # CookieManager behaviour - should cookies with null/empty values be deleted? # Default is true. Use false to revert to original behaviour @@ -1123,6 +1134,14 @@ cookies=cookies # If you want to use Rhino on JDK8, set this property to true #javascript.use_rhino=false +# Ability to switch out the old Oro Regex implementation with the JDK built-in implementation +# Any value different to 'oro' will disable the Oro implementation and enable the JDK based. +#jmeter.regex.engine=oro + +# We assist the JDK based Regex implementation by caching Pattern objects. The size of the +# cache can be set with this setting. It can be disabled by setting it to '0'. +#jmeter.regex.patterncache.size=1000 + # Number of milliseconds to wait for a thread to stop #jmeterengine.threadstop.wait=5000 @@ -1142,7 +1161,7 @@ cookies=cookies # How long to pause (in ms) in the daemon thread before reporting that the JVM has failed to exit. # If the value is <= 0, the JMeter does not start the daemon thread -#jmeter.exit.check.pause=2000 +#jmeter.exit.check.pause=0 # If running non-GUI, then JMeter listens on the following port for a shutdown message. # To disable, set the port to 1000 or less. @@ -1176,6 +1195,18 @@ cookies=cookies # Set to 0 to disable the size check and display the whole response #view.results.tree.max_size=10485760 +# UI gets unresponsive when response contains very long lines, +# So we break lines by adding artificial line breaks +# The break is introduced somewhere in between soft_wrap_line_size..max_line_size +# We try to break on word boundaries first +#view.results.tree.max_line_size=110000 +#view.results.tree.soft_wrap_line_size=100000 + +# Even with the above setting the UI can be unresponsive on large contents in the text view, +# so we allow to switch to a simpler view mode, that is faster, but does not break lines. +# Can be switched off by setting it to -1 +#view.results.tree.simple_view_limit=10000 + # Order of Renderers in View Results Tree # Note full class names should be used for non JMeter core renderers # For JMeter core renderers, class names start with '.' and are automatically @@ -1190,6 +1221,9 @@ view.results.tree.renderers_order=.RenderAsText,.RenderAsRegexp,.RenderAsBoundar # Set to 0 to disable the size check #document.max_size=0 +# Configures the maximum document length for rendering with kerning enabled +#text.kerning.max_document_size=10000 + #JMS options # Enable the following property to stop JMS Point-to-Point Sampler from using # the properties java.naming.security.[principal|credentials] when creating the queue connection diff --git a/bin/jmeter.sh b/bin/jmeter.sh index e5cf8a7e0c9..94843d2915c 100755 --- a/bin/jmeter.sh +++ b/bin/jmeter.sh @@ -90,14 +90,17 @@ fi JAVA9_OPTS= # Minimal version to run JMeter -MINIMAL_VERSION=8 +MINIMAL_VERSION=17 # Check if version is from OpenJDK or Oracle Hotspot JVM prior to 9 containing 1.${version}.x CURRENT_VERSION=`"${JAVA_HOME}/bin/java" -version 2>&1 | awk -F'"' '/version/ {gsub("^1[.]", "", $2); gsub("[^0-9].*$", "", $2); print $2}'` # Check if Java is present and the minimal version requirement -if [ "$CURRENT_VERSION" -gt "$MINIMAL_VERSION" ]; then +if [ "$CURRENT_VERSION" -ge "$MINIMAL_VERSION" ]; then JAVA9_OPTS="--add-opens java.desktop/sun.awt=ALL-UNNAMED --add-opens java.desktop/sun.swing=ALL-UNNAMED --add-opens java.desktop/javax.swing.text.html=ALL-UNNAMED --add-opens java.desktop/java.awt=ALL-UNNAMED --add-opens java.desktop/java.awt.font=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.lang.reflect=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.base/java.text=ALL-UNNAMED --add-opens=java.desktop/sun.awt.X11=ALL-UNNAMED --add-opens=java.desktop/sun.awt.shell=ALL-UNNAMED" +else + echo "JMeter requires Java $MINIMAL_VERSION or later. Current Java version is $CURRENT_VERSION" + exit 1 fi # Don't add additional arguments to the JVM start, except those needed for Java 9 diff --git a/bin/log4j2.xml b/bin/log4j2.xml index 47b012f2cf4..feb8954d56a 100644 --- a/bin/log4j2.xml +++ b/bin/log4j2.xml @@ -16,7 +16,7 @@ ~ limitations under the License. --> - + diff --git a/bin/mirror-server.cmd b/bin/mirror-server.cmd index 6f76adf5951..1f86cff1ef1 100644 --- a/bin/mirror-server.cmd +++ b/bin/mirror-server.cmd @@ -27,8 +27,8 @@ set JMETER_CMD_LINE_ARGS=%* cd /D %~dp0 set CP=..\lib\ext\ApacheJMeter_http.jar;..\lib\ext\ApacheJMeter_core.jar;..\lib\jorphan.jar;..\lib\oro-2.0.8.jar -set CP=%CP%;..\lib\slf4j-api-1.7.25.jar;..\lib\jcl-over-slf4j-1.7.25.jar;..\lib\log4j-slf4j-impl-2.11.1.jar -set CP=%CP%;..\lib\log4j-api-2.11.1.jar;..\lib\log4j-core-2.11.1.jar;..\lib\log4j-1.2-api-2.11.1.jar +set CP=%CP%;..\lib\slf4j-api-1.7.36.jar;..\lib\jcl-over-slf4j-1.7.36.jar;..\lib\log4j-slf4j-impl-2.22.1.jar +set CP=%CP%;..\lib\log4j-api-2.22.1.jar;..\lib\log4j-core-2.22.1.jar;..\lib\log4j-1.2-api-2.22.1.jar java -cp %CP% org.apache.jmeter.protocol.http.control.HttpMirrorServer %JMETER_CMD_LINE_ARGS% diff --git a/bin/mirror-server.sh b/bin/mirror-server.sh index 7e969626258..1da2f9d0349 100755 --- a/bin/mirror-server.sh +++ b/bin/mirror-server.sh @@ -22,7 +22,7 @@ cd "$(dirname "$0")" || exit 1 CP=../lib/ext/ApacheJMeter_http.jar:../lib/ext/ApacheJMeter_core.jar:../lib/jorphan.jar:../lib/oro-2.0.8.jar -CP=${CP}:../lib/slf4j-api-1.7.25.jar:../lib/jcl-over-slf4j-1.7.25.jar:../lib/log4j-slf4j-impl-2.11.0.jar -CP=${CP}:../lib/log4j-api-2.11.1.jar:../lib/log4j-core-2.11.1.jar:../lib/log4j-1.2-api-2.11.1.jar +CP=${CP}:../lib/slf4j-api-1.7.36.jar:../lib/jcl-over-slf4j-1.7.36.jar:../lib/log4j-slf4j-impl-2.22.1.jar +CP=${CP}:../lib/log4j-api-2.22.1.jar:../lib/log4j-core-2.22.1.jar:../lib/log4j-1.2-api-2.22.1.jar java -cp $CP org.apache.jmeter.protocol.http.control.HttpMirrorServer "$@" diff --git a/bin/report-template/content/pages/ResponseTimes.html.fmkr b/bin/report-template/content/pages/ResponseTimes.html.fmkr index 9b59d484b74..e3fc05542bb 100644 --- a/bin/report-template/content/pages/ResponseTimes.html.fmkr +++ b/bin/report-template/content/pages/ResponseTimes.html.fmkr @@ -217,7 +217,7 @@
  • Hide all samples
  • -
  • Save as PNG
  • +
  • Save as PNG