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.
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 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.
Both workflows run on pushes to main, pull requests, weekly schedules and manual dispatch, with bounded timeouts and per-workflow/ref concurrency cancellation. There are no path filters that could silently omit a required check. Changes to workflow topology must update the gate dependencies and required check names only after the replacement checks have succeeded.
Every checkout disables credential persistence. PRs use pull_request, never
pull_request_target or privileged workflow_run execution. Fork tokens are
read-only and receive no repository secrets; all external contributors require
run approval. A fork's artifacts are consumed only within that same unprivileged
run. Artifact download has no cross-run/repository/token input, preserving the
original packaged bytes. No privileged job restores PR artifacts or caches.
All Maven invocations use a fresh runner-temporary repository. Shared Maven
caching is deliberately disabled, including Java 8's necessary install, all
scanner builds, and intentional release commits. Setup Java's pinned v6.1.0
does expose cache controls, but this configuration does not rely on any of them.
See local quarantine guidance.
Baseline main runs Java CI 36220505798 and consumers 36220505783 had 14 Maven cache misses and one hit (Java 8 install job). Build took 3m14s; preparation took 85s; Java 8 tests 87s; runtimes 12–16s. The separate clean test-compilation and install lifecycles are now one clean verify lifecycle.
Advanced CodeQL in codeql.yaml is the single analysis owner; leave default
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
restricted PR SARIF upload path, not a general write token. Reports are retained
as artifacts and in Code scanning. No scanner secrets are required.
Dependency submission runs only for the trusted default branch, including manual
dispatch. Its only elevated permission is job-level contents: write for the
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 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.6.0 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 current development 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,
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 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 and the Maven
distribution used by the wrapper are
excluded from the broad Maven version-update group, so unsuppressed proposals
receive individual review. Reviewed incompatible minor and major proposal classes use
ignore.update-types; GitHub applies those rules only to version updates, so
security updates remain eligible and the security-update group is unchanged.
Dependabot classifies repeated Maven coordinates from their lowest occurrence;
where historical and current inputs share a coordinate, a current-line patch can
therefore fall inside a suppressed update class. Review those coordinates
manually during dependency/release maintenance and for every advisory. Revisiting
a suppressed version class requires a deliberate compatibility change and removal
or narrowing of its rule. See
dependency decisions for the exact scopes, current
contracts, PR dispositions and conditions for reconsideration.
The nonstandard XML files under compatibility/dependencies remain explicit
manual compatibility fixtures. In particular Felix 5.6.12 is an intentional
OSGi R6/Java 8 baseline, not a production dependency; the Maven ignore prevents
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.
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. Optional
Scorecard publication, best-practices registration and another scheduled scanner
are follow-ups, not prerequisites for these operating controls.
Before changes, snapshot repository/ruleset, Actions, Pages, collaborator/team and webhook settings. Store webhook configuration privately; do not publish endpoint tokens. Record changes and negative tests in issue #169.
Use read-only default Actions tokens, no bot PR approvals, supported secret
scanning/push protection, all-external-contributor run approval, and an allowlist
of the exact action repositories/paths in the action inventory.
Enable SHA enforcement after pins and the allowlist are ready. Re-read both
Actions endpoints afterward: updating the general permissions endpoint may reset
github_owned_allowed to true; reapply the exact allowlist and test rejection of
an unlisted GitHub-owned action as well as a mutable action tag. When adding a
reviewed action, update the allowlist before merging the workflow. Old open PRs
must refresh their workflows before rerunning under the SHA policy.
Main requires both complete CI gates and successful CodeQL language jobs in a separate ruleset with no bypass. The review rule keeps one independent approval, dismisses stale approvals, requires approval of the latest push, and requires resolution of review threads. The verified maintainers Jim Manico and Jeremy Long have only PR-based, audit-visible emergency review bypass; it cannot bypass required checks or directly push main. An emergency bypass is not independent approval. CODEOWNERS enforcement remains with #127's ownership validation; do not name unverified owners or treat review rules as CODEOWNERS validation.
All tags prohibit update/deletion with no bypass; new signed release tags still
follow RELEASING.md. GitHub required_signatures checks commit signatures,
not annotated tag signatures. The September validation
records disabling the legacy Codacy and Travis webhooks, with their private
configuration retained for recovery. Maven Site sources and publishing are
retired; the implicit Site lifecycle remains explicitly pinned and disabled.
For recovery, an administrator uses Settings or the REST API, records the actor, reason and affected PR in #169, makes the narrowest temporary change, then restores and verifies the controls. Do not introduce privileged PR workflows to repair policy failures. Check names can be repaired without removing review requirements; action patterns can be added without disabling SHA enforcement. There is no standing direct-push bypass. Never move a published tag or blanket disable tag protection. A disposable unpublished policy-test tag can be removed using an exclusion for that exact tag only, then immediately removing the exclusion. Review branch cleanup against current main and open PRs individually.