Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 35 additions & 20 deletions .github/CI_SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@

`Java CI gate` requires the clean JDK 17 reactor build, JSP/Jakarta source parity,
CI policy tests, the Docker/Selenium browser test, exact reactor JAR inclusion in
the Jakarta WAR, and every ESAPI version from 2.5.1.0 through 2.7.0.0.
the Jakarta WAR.
`Packaged consumer gate` requires JDK 17 artifact preparation/API and Java 8
signature checks, package guard tests, the original packaged bytes on Java
8/11/17/21/25, and core/JSP/ESAPI unit tests with the Java 8 JVM and coverage.
8/11/17/21/25, and core/JSP unit tests with the Java 8 JVM and coverage.
JDK 21/25 build probes remain advisory. Require **both** gates: neither observes
the other workflow. The gates run with `always()` and accept only `success` for
every expected dependency; missing, failed, skipped and cancelled jobs fail.
Expand All @@ -34,15 +34,13 @@ See [local quarantine guidance](../RELEASING.md#maven-storage-and-repository-con
Baseline main runs [Java CI 36220505798](https://github.com/OWASP/owasp-java-encoder/actions/runs/36220505798)
and [consumers 36220505783](https://github.com/OWASP/owasp-java-encoder/actions/runs/36220505783)
had 14 Maven cache misses and one hit (Java 8 install job). Build took 3m14s;
ESAPI jobs 65–97s; preparation 85s; Java 8 tests 87s; runtimes 12–16s.
The separate clean test-compilation and install lifecycles are now one clean
verify lifecycle. Further core sharing between ESAPI versions is deferred: it
would complicate reactor resolution and package checks for little measured gain.
preparation took 85s; Java 8 tests 87s; runtimes 12–16s. The separate clean
test-compilation and install lifecycles are now one clean verify lifecycle.

## Scanning and dependency updates

Advanced CodeQL in `codeql.yaml` is the single analysis owner; leave default
setup unconfigured. Java uses a manual JDK 17 build of all four libraries and
setup unconfigured. Java uses a manual JDK 17 build of all three libraries and
the optional `testJakarta` application; Actions and Python tooling use extraction
without a build. It runs on PRs, main, a weekly schedule and manual dispatch.
Only analysis jobs request `security-events: write`; fork PRs use GitHub's
Expand All @@ -55,24 +53,41 @@ snapshot API. It builds its own checkout without caches or imported artifacts.
Separate correlators submit the normal reactor and the optional Jakarta profile.
The pinned Maven submission action includes all resolved project scopes,
including runtime, test and provided dependencies. Maven dependency plugin
3.11.0 `resolve-plugins` separately resolves build/report plugins and their
transitives; `scripts/build-dependency-snapshot.py` submits those edges as
development dependencies. Graph reports and submission JSON are retained for
inspection. Inspect representative ESAPI/AntiSamy HTTP transitives and Jakarta
Spring/Tomcat dependencies in the resulting graph; alert counts are not gates.

All four submissions use detector `encoder-maven-build-graph` with distinct,
stable correlators. Keep the action's detector inputs synchronized with the
3.11.0 `resolve-plugins` separately resolves the source-controlled allowlist of
plugins actually invoked by verification, consumer installation, metadata checks,
and release staging. The optional Jakarta app is resolved from its own smaller
package-gate allowlist, so inherited but inactive Boot plugin-management entries
are not submitted. The disabled Site plugin is likewise not represented as an
executed dependency. The five separately invoked consumer dependency fixtures inherit a
local toolchain parent which pins the downloader's plugin realm; that parent is
resolved separately so any drift from the submitted root closure remains visible.
`scripts/build-dependency-snapshot.py` submits those closures as development
dependencies, once for shared root tooling and only the differing plugin closures
for child or fixture POMs. Graph reports and submission JSON are retained for
inspection. Inspect representative Jakarta Spring/Tomcat dependencies in the
resulting graph; alert counts are not gates.

The immutable 1.4.1 Java Encoder artifacts used by japicmp are intentional
development-only comparison inputs. Keep them visible in the build graph: an alert
on a baseline artifact describes that historical input, not a dependency shipped
to 1.5 consumers, and must be assessed rather than hidden with a graph filter.

All submissions use detector `encoder-maven-build-graph` with distinct, stable
correlators. Keep the action's detector inputs synchronized with the
Python build snapshot: GitHub [merges correlators from the same detector](https://docs.github.com/en/code-security/concepts/supply-chain-security/dependency-graph-data#prioritization),
but selects between different detectors for a POM. Different detectors can hide
runtime dependencies behind build-only results despite successful submissions.
Check the final SBOM after both matrix jobs finish, including runtime versions
and development dependencies together, not just the snapshot API status.

Dependabot checks all library POMs, the parent and optional app weekly, with
separate Maven and SHA-pinned Actions groups and grouped Maven security updates.
Dependabot checks all current library POMs, the parent, optional app and compatibility
fixture toolchain parent weekly, with separate Maven and SHA-pinned Actions groups
and grouped Maven security updates.
Normal review and complete CI apply to automated PRs; no automatic merging is
configured. Review new action source and transitive downloads as well as pins.
Do not dismiss alerts merely to reduce the count. Correct versions or graph
semantics, submit the new graph, and let GitHub close packages that are no longer
present.
Baseline-sensitive API, JSP-engine and build-plugin dependencies are excluded only
from the broad Maven **version-update group**, so their proposals receive individual
review. They remain eligible for updates; the security-update group is unchanged.
Expand All @@ -85,9 +100,9 @@ an automatic baseline replacement. Inspect any advisory against its actual
local bundle-loading test scope, and record a specific disposition. Do not
suppress advisories across all Felix versions or application deployments.

ESAPI advisory triage lives in [the adapter guide](../esapi/README.md#dependency-security-triage).
Upstream fixes are preferred; tested mitigations remain possible. No transitive
finding is dismissed merely because another library introduces it. Optional
The retired `encoder-esapi` module is absent from Dependabot configuration and
the submitted 1.5 dependency graph. Its historical artifacts are not rewritten;
see the [retirement notice](../docs/encoder-esapi-retirement.md). Optional
Scorecard publication, best-practices registration and another scheduled scanner
are follow-ups, not prerequisites for these operating controls.

Expand Down
2 changes: 1 addition & 1 deletion .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ updates:
- /core
- /jsp
- /jakarta
- /esapi
- /jakarta-test
- /compatibility/dependencies
schedule:
interval: weekly
day: monday
Expand Down
43 changes: 6 additions & 37 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
fetch-depth: 0
- name: Check versions and isolate Maven storage
run: |
python3 scripts/check-ci-version.py --ref "$GITHUB_REF"
Expand All @@ -43,6 +44,8 @@ jobs:
run: python3 -m unittest discover -s scripts/tests
- name: Verify clean reactor including the required Docker/browser test
run: ./mvnw -B -ntp clean verify -PtestJakarta 2>&1 | tee build.log
- name: Check published modules' effective SCM metadata
run: python3 scripts/check-effective-pom-scm.py
- name: Confirm the Jakarta application contains this reactor's exact JAR
run: |
python3 - <<'PY'
Expand Down Expand Up @@ -70,51 +73,17 @@ jobs:
**/target/checkstyle-result.xml
jakarta-test/target/packaged-war.log

esapi-compatibility:
name: ESAPI ${{ matrix.esapi-version }}
runs-on: ubuntu-latest
timeout-minutes: 25
strategy:
fail-fast: false
matrix:
esapi-version:
- '2.5.1.0'
- '2.5.2.0'
- '2.5.3.0'
- '2.5.3.1'
- '2.5.4.0'
- '2.5.5.0'
- '2.6.0.0'
- '2.6.1.0'
- '2.6.2.0'
- '2.7.0.0'
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Check versions and isolate Maven storage
run: |
python3 scripts/check-ci-version.py --ref "$GITHUB_REF"
echo "MAVEN_OPTS=-Dmaven.repo.local=$RUNNER_TEMP/m2" >> "$GITHUB_ENV"
- name: Set up JDK 17
uses: actions/setup-java@de7274f081f381c8f8158605e0321c36c376e2e6 # v6.0.1
with:
java-version: '17'
distribution: 'temurin'
- name: Test ESAPI compatibility
run: ./mvnw -B -ntp -pl esapi -am verify -Desapi.version=${{ matrix.esapi-version }}

gate:
name: Java CI gate
if: ${{ always() }}
needs: [build, esapi-compatibility]
needs: [build]
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- name: Require every build, browser and ESAPI matrix result
- name: Require the build and browser result
env:
NEEDS: ${{ toJSON(needs) }}
run: python3 scripts/check-ci-gate.py build esapi-compatibility
run: python3 scripts/check-ci-gate.py build
13 changes: 4 additions & 9 deletions .github/workflows/consumer-compatibility.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ jobs:
**/target/surefire-reports/
**/target/failsafe-reports/
**/target/jsp-engine/
**/target/japicmp/
**/target/site/jacoco/

runtime:
Expand Down Expand Up @@ -99,7 +98,7 @@ jobs:
path: runtime.log

java8-unit-tests:
name: Core, JSP, and ESAPI unit tests on Java 8
name: Core and JSP unit tests on Java 8
needs: prepare
runs-on: ubuntu-latest
timeout-minutes: 20
Expand All @@ -118,12 +117,12 @@ jobs:
8
17
- name: Build with JDK 17
run: ./mvnw -B -ntp -DskipTests install -pl core,jsp,esapi -am 2>&1 | tee build.log
run: ./mvnw -B -ntp -DskipTests install -pl core,jsp -am 2>&1 | tee build.log
- name: Run unit tests and collect coverage with Java 8
run: ./mvnw -B -ntp -pl core,jsp,esapi jacoco:prepare-agent@prepare-agent surefire:test jacoco:report -Djvm="$JAVA_HOME_8_X64/bin/java" 2>&1 | tee java8-tests.log
run: ./mvnw -B -ntp -pl core,jsp jacoco:prepare-agent@prepare-agent surefire:test jacoco:report -Djvm="$JAVA_HOME_8_X64/bin/java" 2>&1 | tee java8-tests.log
- name: Confirm Java 8 execution and coverage in every tested module
run: |
for module in core jsp esapi; do
for module in core jsp; do
grep -q 'name="java.specification.version" value="1.8"' "$module"/target/surefire-reports/TEST-*.xml || {
echo "::error::Missing Java 8 Surefire report for $module"
exit 1
Expand All @@ -143,13 +142,10 @@ jobs:
java8-tests.log
core/target/surefire-reports/
jsp/target/surefire-reports/
esapi/target/surefire-reports/
core/target/site/jacoco/
jsp/target/site/jacoco/
esapi/target/site/jacoco/
core/target/jacoco.exec
jsp/target/jacoco.exec
esapi/target/jacoco.exec

forward-build:
name: Advisory build on JDK ${{ matrix.java }}
Expand Down Expand Up @@ -184,7 +180,6 @@ jobs:
**/target/surefire-reports/
**/target/failsafe-reports/
**/target/jsp-engine/
**/target/japicmp/
**/target/site/jacoco/

wrapper:
Expand Down
20 changes: 16 additions & 4 deletions .github/workflows/dependency-submission.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ jobs:
include:
- graph: libraries
profile: ''
plugins: maven-clean-plugin,maven-enforcer-plugin,maven-checkstyle-plugin,maven-compiler-plugin,maven-bundle-plugin,jacoco-maven-plugin,maven-surefire-plugin,maven-resources-plugin,maven-jar-plugin,build-helper-maven-plugin,maven-source-plugin,maven-javadoc-plugin,exec-maven-plugin,maven-failsafe-plugin,maven-antrun-plugin,maven-dependency-plugin,maven-help-plugin,animal-sniffer-maven-plugin,maven-install-plugin
- graph: jakarta-app
profile: -PtestJakarta
plugins: maven-clean-plugin,maven-enforcer-plugin,maven-checkstyle-plugin,maven-compiler-plugin,maven-bundle-plugin,jacoco-maven-plugin,maven-surefire-plugin,maven-resources-plugin,maven-jar-plugin,build-helper-maven-plugin,maven-source-plugin,maven-javadoc-plugin,exec-maven-plugin,maven-failsafe-plugin,maven-antrun-plugin,maven-dependency-plugin,maven-help-plugin,animal-sniffer-maven-plugin,maven-install-plugin
app_plugins: maven-clean-plugin,maven-enforcer-plugin,maven-checkstyle-plugin,maven-compiler-plugin,maven-surefire-plugin,maven-failsafe-plugin,maven-resources-plugin,maven-war-plugin,spring-boot-maven-plugin,maven-dependency-plugin
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -55,10 +58,17 @@ jobs:
detector-name: encoder-maven-build-graph
detector-version: '1.0.0'
detector-url: https://github.com/OWASP/owasp-java-encoder
- name: Resolve build plugins and their dependencies
- name: Resolve shared library build plugins and their dependencies
env:
PROFILE: ${{ matrix.profile }}
run: ./mvnw -B -ntp ${PROFILE:+"$PROFILE"} org.apache.maven.plugins:maven-dependency-plugin:3.11.0:resolve-plugins -DoutputFile=target/build-dependencies.txt
PLUGINS: ${{ matrix.plugins }}
run: ./mvnw -B -ntp org.apache.maven.plugins:maven-dependency-plugin:3.11.0:resolve-plugins -DincludeArtifactIds="$PLUGINS" -DoutputFile=target/build-dependencies.txt
- name: Resolve only the optional app plugins invoked by its package gate
if: matrix.graph == 'jakarta-app'
env:
APP_PLUGINS: ${{ matrix.app_plugins }}
run: ./mvnw -B -ntp -f jakarta-test/pom.xml org.apache.maven.plugins:maven-dependency-plugin:3.11.0:resolve-plugins -DincludeArtifactIds="$APP_PLUGINS" -DoutputFile=target/build-dependencies.txt
- name: Resolve the compatibility fixture downloader and its dependencies
run: ./mvnw -B -ntp -f compatibility/dependencies/pom.xml org.apache.maven.plugins:maven-dependency-plugin:3.11.0:resolve-plugins -DincludeArtifactIds=maven-dependency-plugin -DoutputFile=target/build-dependencies.txt
- name: Submit build graph
env:
GH_TOKEN: ${{ github.token }}
Expand All @@ -71,7 +81,9 @@ jobs:
env:
GH_TOKEN: ${{ github.token }}
run: |
./mvnw -B -ntp -Psign-artifacts dependency:resolve-plugins -DoutputFile=target/build-dependencies.txt
./mvnw -B -ntp -Psign-artifacts dependency:resolve-plugins \
-DincludeArtifactIds="${{ matrix.plugins }},maven-gpg-plugin,central-publishing-maven-plugin,maven-deploy-plugin" \
-DoutputFile=target/build-dependencies.txt
python3 scripts/build-dependency-snapshot.py --correlator encoder-build-release --output target/release-build-snapshot.json
gh api --method POST "repos/$GITHUB_REPOSITORY/dependency-graph/snapshots" --input target/release-build-snapshot.json
- name: Preserve resolved graphs
Expand Down
24 changes: 16 additions & 8 deletions BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Run from the root, with `-pl core -am`, or from a module using `../mvnw`.
The wrapper's `.mvn` root also anchors Checkstyle paths. Maven's JVM must be 17+
(Maven 3.9.16+); Java 8 is a **forked unit-test/consumer JVM**, never the build JVM.
Newer JDK build jobs remain advisory. Library class files retain releases 8/9.
The five library POMs share one Enforcer execution: tool minimums, duplicate
The four release POMs share one Enforcer execution: tool minimums, duplicate
coordinates, dependency convergence, upper bounds and explicit plugin versions.
The separate Boot application applies those rules under its own parent/BOM.

Expand All @@ -37,7 +37,7 @@ requires Java 21; 12.3.1 is the explicit Java 17 compatibility exception, not a
claim of upstream support for older engines. Review migration when the build JDK
changes. Its parser cannot parse module declarations, so `module-info.java` is
excluded from Checkstyle; compiler, packaged descriptor/source guards and actual
JPMS consumers cover it. Headers were added to those four descriptors and four
JPMS consumers cover it. Headers were added to the three library descriptors and four
app files using their 2024 Jeremy Long introduction commits. All existing BSD
notices and original attribution remain. TLD license comments remain intact;
JSP server-side comments do not emit output. The app declares the same BSD license.
Expand All @@ -53,16 +53,19 @@ Empty defaults support `-Djacoco.skip=true`. Appending execution data intentiona
unions successive unit JVMs in one build; use `clean` for an independent baseline.
CI's Java 8 run starts in its own job/cache and uploads its own reports/data.

The existing floors were selected from the following 2026-09-26 baseline
measurement recorded for PR #185:

| Module | Measured lines | Measured branches | Line floor | Branch floor |
| --- | --- | --- | --- | --- |
| core | 1228/1240 (99.032%) | 890/903 (98.560%) | 99.0% | 98.5% |
| jsp | 66/66 | no branches | 100% | 100% |
| jakarta | 66/66 | no branches | 100% | 100% |
| esapi | 27/28 (96.429%) | no branches | 96.4% | 100% |

Floors round the current baseline down to 0.1 percentage points. They are not a
claim that every encoding behavior is covered. CI retains reports alongside test
results. Changes that intentionally alter these baselines require reviewed evidence.
Floors round that recorded baseline down to 0.1 percentage points. They are not a
claim that every encoding behavior is covered. Current measured totals can change
when executable lines or branches change; do not lower the floors without reviewed
evidence. CI retains reports alongside test results.

## Retired Maven Site

Expand Down Expand Up @@ -95,7 +98,12 @@ Lifecycle pins are in root `pluginManagement`, with explicit versions on API,
source-helper and signature plugins. Maven 4 prerelease plugins were deliberately
not selected for this Maven 3 build. The optional app inherits maintained plugin
pins from Boot 4.1.1 and adds explicit Enforcer/Checkstyle/disabled Site pins.
Review effective POMs for normal, `testJakarta`, and `sign-artifacts` profiles;
`dependency:resolve-plugins` feeds their resolved closures into dependency review.
Review effective POMs for normal, `testJakarta`, and `sign-artifacts` profiles.
Dependency submission resolves a reviewed allowlist of the plugins those gates
actually invoke and feeds their closures into dependency review. The optional
Jakarta app has its own package-gate allowlist. Inactive plugin-management defaults
and the disabled Site lifecycle are not represented as executed build dependencies;
shared inherited tooling is submitted once at the root rather than copied onto
every child POM.
Release-only publisher dependencies are submitted separately with the same
GitHub detector and a distinct correlator, so they do not hide runtime graphs.
Loading
Loading