Repository navigation
Harden GitHub Actions workflows: token permissions, SHA pinning, latest actions - #170
Conversation
Same file as in OpenIdentityPlatform#170; whichever PR lands first brings it in.
Keeps the commit-hash-pinned third-party actions in .github/workflows up to date: Dependabot bumps the SHA and the trailing version comment together, grouped into one weekly PR. Ported from OpenIdentityPlatform/OpenIG#170.
Add "ci"/"dependencies" labels and the grouping comment to .github/dependabot.yml, matching OpenIdentityPlatform/OpenIG#170.
Add "ci"/"dependencies" labels and the grouping comment to .github/dependabot.yml, matching OpenIdentityPlatform/OpenIG#170.
Add "ci"/"dependencies" labels and the grouping comment to .github/dependabot.yml, matching OpenIdentityPlatform/OpenIG#170.
Keeps the commit-hash-pinned third-party actions in .github/workflows up to date: Dependabot bumps the SHA and the trailing version comment together, grouped into one weekly PR. Ported from OpenIdentityPlatform/OpenIG#170.
Keeps the commit-hash-pinned third-party actions in .github/workflows up to date: Dependabot bumps the SHA and the trailing version comment together, grouped into one weekly PR. Ported from OpenIdentityPlatform/OpenIG#170.
* Harden GitHub workflows and SMTP STARTTLS trust - Set an explicit read-only GITHUB_TOKEN permissions block on the build, deploy and release workflows, elevating only the jobs that need it (wiki/docs push and release tag: contents:write; ghcr push: packages:write) - Pin the third-party docker/* and softprops/action-gh-release actions to commit SHAs - EmailClient: stop trusting every SMTP server certificate over STARTTLS; validation is now the default, with opt-in starttls.trustedHosts / starttls.trustAll settings (documented) Resolves CodeQL alerts #711-#716, #718-#738, #920, #921 (actions) and #22 (java/insecure-smtp-ssl). * Add .github/dependabot.yml for the SHA-pinned actions Keeps the commit-hash-pinned third-party actions in .github/workflows up to date: Dependabot bumps the SHA and the trailing version comment together, grouped into one weekly PR. Ported from OpenIdentityPlatform/OpenIG#170. * Address review on STARTTLS trust: host check, trustedHosts, Admin UI - Validate the SMTP certificate's host name by default (mail.smtp.ssl.checkserveridentity=true); JavaMail 1.4.7 leaves it off - Exclude jakarta.mail from the email bundle's classpath: compiling against its com.sun.mail.util made the bundle import MailSSLSocketFactory from jakarta.mail, which javax.mail's SocketFetcher does not recognise, so starttls.trustedHosts trusted every host - Warn when starttls.trustedHosts does not contain the SMTP host - Admin UI: keep starttls.trustedHosts/trustAll when saving the Email form - Tests: host check, trustAll precedence, socket factory origin - Docs: host match, exact trustedHosts entry, trustAll precedence * Embed javax.mail in the email bundle and enable current TLS for STARTTLS The com.sun.mail.util [1.4,2) import from the previous commit left openidm-external-email unresolved, so OpenIDM never reached "ready" in CI: javax.mail 1.4.7 imports its own com.sun.mail.* packages with no upper bound, Felix wires them to jakarta.mail 2.0.2 and drops the 1.4.7 exports. The same wiring already broke mail on master, where MimeMessage fails with NoSuchMethodError on com.sun.mail.util.PropUtil. - Embed javax.mail 1.4.7 in the bundle so Session, SMTPTransport, SocketFetcher and MailSSLSocketFactory come from one jar, and point the context class loader at the bundle while JavaMail loads its providers. - Set mail.smtp.ssl.protocols to the JVM defaults when STARTTLS is on. Without it JavaMail 1.4.7 enables only TLSv1, which current JDKs disable, so no STARTTLS handshake could succeed. * Address review round 2 on STARTTLS trust: IP SAN note and tests - chap-mail.adoc: on Java 17+ the host is matched only against DNS SANs (or the CN), so a relay addressed by IP is rejected even with an IP SAN - EmailClientTest: replace withoutStartTlsNoSocketFactoryIsConfigured with trustSettingsApplyOnlyWithStartTls, which fails if the trust settings are applied outside STARTTLS - EmailConfigViewTest: pin that saving Settings > Email keeps starttls.trustedHosts and starttls.trustAll
maximthomas
left a comment
There was a problem hiding this comment.
praise: Every pin is real, and token scopes are set per job.
- All six third-party pins resolve to the tags in their comments (
git ls-remote):docker/build-push-action@c3c9e263… # v7.4.0,docker/login-action@dbcb8138… # v4.6.0,docker/metadata-action@dc802804… # v6.2.0,docker/setup-buildx-action@f87e5991… # v4.4.1,docker/setup-qemu-action@99012661… # v4.4.0,softprops/action-gh-release@efb35369… # v3.0.3. packages: writegoes only torelease-docker, the one job that pushes to GHCR.release-mavenanddeploy-mavengetcontents: writeonly.- All 14 PR checks are green on the head. That includes the
build-mavenmatrix onactions/setup-java@v6(ubuntu/macos/windows), andbuild-docker, whose job log shows the push tolocalhost:5000.
suggestion (non-blocking): Switch to setup-java v6's server-username-env-var / server-password-env-var inputs. The old server-username / server-password names are deprecated aliases.
.github/workflows/release.yml:52-53, .github/workflows/deploy.yml:48-49
actions/setup-java v6 (already in v6.0.0) declares server-username and server-password in its action.yml as "Deprecated alias for server-username-env-var" / "…server-password-env-var". They still resolve, so settings.xml gets the same ${env.MAVEN_USERNAME} / ${env.MAVEN_PASSWORD} as with v5. Every release and deploy run will log a deprecation warning, though. A future release that drops the alias would break OSSRH auth on paths that no PR check runs. The description's "setup-java v6 … no input changes" also needs correcting.
server-id: ossrh
server-username-env-var: MAVEN_USERNAME
server-password-env-var: MAVEN_PASSWORDnote (non-blocking): Changes the description does not mention:
.github/dependabot.yml— new CDDL header,Copyright 2026 3A Systems, LLC..github/workflows/build.yml— CDDL header added,Portions Copyright 2026 3A Systems, LLC..github/workflows/deploy.yml— CDDL header added,Portions Copyright 2026 3A Systems, LLC..github/workflows/release.yml— CDDL header added,Portions Copyright 2026 3A Systems, LLC.
…st actions - Add explicit GITHUB_TOKEN permissions to every job (read-only for build, contents:write for release/deploy, packages:write for the GHCR push) (actions/missing-workflow-permissions) - Pin third-party actions (docker/*, softprops/action-gh-release) to full commit SHAs with a version comment (actions/unpinned-tag) - Update actions/checkout to v7, actions/setup-java and actions/cache to v6, softprops/action-gh-release to v3.0.3 - Add .github/dependabot.yml (github-actions, weekly, grouped) so the pinned SHAs keep getting updated
b1f0088 to
bbc3ecf
Compare
|
Both points taken.
The branch is rebased onto current master (#185, #186). Neither brings a new third-party action, so there are no new unpinned tags. |
Same file as in OpenIdentityPlatform#170; whichever PR lands first brings it in.
maximthomas
left a comment
There was a problem hiding this comment.
praise: The release/deploy paths that no PR check runs hold up when exercised outside CI.
server-username-env-var/server-password-env-var(.github/workflows/release.yml:52-53,.github/workflows/deploy.yml:48-49): setup-java v6.1.0's dist, run locally with these inputs, writes asettings.xmlbyte-identical to v5's (<id>ossrh</id>,${env.MAVEN_USERNAME},${env.MAVEN_PASSWORD}), and it logs no deprecation warning.- CodeQL's own
MissingActionsPermissions.ql(jobHasPermissions) clears all five jobs.build-mavenandbuild-dockerare cleared by the workflow-level block atbuild.yml:23-24;release-maven,release-dockeranddeploy-mavenby their job-level blocks. - On linux x64, setup-java v6 resolves temurin
'11'to 11.0.32+101 and'8'to 8u504-b01, and the checksums it verifies match Adoptium's published.sha256.txt. Undercheckout@v7, the doc-site push still carries the PAT (deploy.yml:114-136); credential persistence is unchanged from v6.1.0.
Adds Docker image vulnerability scanning with [Trivy](https://github.com/aquasecurity/trivy), the same setup as OpenIdentityPlatform/OpenDJ#854 in its final, reviewed form, plus what the later sibling PRs settled (OpenIdentityPlatform/OpenICF#135, OpenIdentityPlatform/OpenIDM#216): a separately cached Trivy install and a scan that cannot fail the build. **`build.yml`** — `build-docker` now scans the freshly built image (resolved from the local Docker daemon, so the runner's `linux/amd64` manifest only) right after the docker test. The image is built from this commit's `OpenIG-*.war` (the `ubuntu-latest-11` artifact; the Dockerfile downloads the release war only when none was copied in), so the scan covers this commit's dependencies plus the `tomcat` base image. The SARIF report is uploaded via `codeql-action/upload-sarif` and the full list lives in the Security tab. Only fixable CRITICAL/HIGH CVEs are reported (`ignore-unfixed: true` plus `limit-severities-for-sarif: true` — without the latter the severity filter is silently dropped for SARIF output), and only the vulnerability scanner runs (`scanners: vuln`). - **The scan never fails the build.** Findings exit 0 (no `exit-code`), and the Install and Scan steps are `continue-on-error`, so a Trivy or trivy-db registry outage cannot turn `build-docker` red — a red Build would also skip the snapshot deploy in `deploy.yml`. The scan step has `timeout-minutes: 15`: trivy's own `--timeout` does not bound the Java DB download. The upload runs on `!cancelled()` and only when a report exists. - **Caching.** The action's built-in DB cache is disabled (`cache: false`): it saves the ~1 GB trivy DBs per branch scope and day, which would fill the repo's 10 GB actions-cache quota within days and LRU-evict the `m2-repository` caches (350–480 MiB each) the `build-maven` matrix depends on. The cache stood at 10.12 GiB when this PR was opened. `cache: false` would also skip setup-trivy's binary cache and leave an anonymous github.com release lookup in every run (it lost a scan in OpenICF#135), so Trivy `v0.70.0` (trivy-action v0.36.0's default) is installed by its own `aquasecurity/setup-trivy` step with `cache: true`, and trivy-action runs with `skip-setup-trivy: true`. - **The PR check.** GitHub creates one `Trivy` check-run per SARIF tool, next to `CodeQL`; `trivy-build-default` is only the SARIF category. That check is diff-scoped: image-path alerts never fall inside a PR diff, so it reports "No new alerts in code changed by this pull request" whatever the scan found. The findings for a PR are in the Security tab under `pr:<N> tool:Trivy`. - The job gets `contents: read` + `security-events: write`; SARIF upload also works for fork PRs on public repositories. `actions/checkout@v7` (with `persist-credentials: false`) is added as the first step of the job, as in OpenDJ, so `upload-sarif` has a git checkout to work from (before `download-artifact`, since checkout cleans the workspace). **`docker-scan.yml`** (new) — weekly cron (`30 5 * * 1`, no overlap with CodeQL's `27 3 * * 1`) + `workflow_dispatch` scan of the published `openidentityplatform/openig:latest` image: new CVEs surface in the already-released image (mostly via the `tomcat` base image) without any change in this repository. Unlike the build-time scan, unfixed CVEs are reported too — surfacing them in a released image is the point. Report category `trivy-image-latest`, distinct from `trivy-build-default`. The scheduled run is skipped in forks; manual runs are always allowed. OpenIG publishes a single image variant, so the matrix has one tag. - Only the `linux/amd64` manifest is scanned (no `--platform` is passed); the other published platforms (arm64, ppc64le, s390x) are not. - No `continue-on-error` here: a failed weekly scan is the signal. The job has `timeout-minutes: 30`, for the same reason as the build-time step. - Once it has run, `trivy-image-latest` exists only on master, so every PR's `Trivy` check concludes **neutral** with "1 configuration not found" (as on OpenAM PRs today). This is documented in the workflow header. - Its triggers need the file on the default branch, so it cannot run on this PR. I will start it by hand (`gh workflow run docker-scan.yml`) right after merge and report the run here. `aquasecurity/trivy-action` (`ed142fd…`, v0.36.0 — the current latest) and `aquasecurity/setup-trivy` (`81e5143…`, v0.3.1) are pinned by commit SHA; `actions/*` and `github/codeql-action` stay on major tags, the policy of #170. **`.github/dependabot.yml`** (new, second commit) enables the `github-actions` ecosystem so the pinned SHAs keep getting updated: weekly, one grouped PR for all actions, labels `ci` + `dependencies`. It is byte-identical to the file added in #170, so whichever PR lands first brings it in without a conflict. Not used: `TRIVY_INSECURE` (global TLS off, and not needed — the image is read from the daemon, the registry is never contacted). Overlap with #170: both touch `build.yml`, in different hunks (#170: workflow-level `permissions` and the `uses:` pins; here: the `build-docker` job header, its first step and its tail). The added license header is the identical block, so it should merge cleanly either way. This PR's own `build-docker` run exercises the new build-time steps.
… that its results no longer follow the default JDK of the runner image (#189) Fixes #188 ### Problem The java-kotlin job of the CodeQL workflow runs with `build-mode: none` and sets up no JDK. CodeQL infers no JDK from the project (`No specific JDK inferred from the project being analysed; using the java on the PATH`), so it models the JDK API on the default `java` of the runner image. On 2026-10-19 `ubuntu-latest` moved from ubuntu-24.04 to ubuntu-26.04, and that `java` changed from 17 to 25. Code scanning then opened alerts for APIs deprecated only after Java 11, the version the release is built with. The details are in #188. ### Fix - Before `Initialize CodeQL`, the java-kotlin job sets up the JDK that the release is built with, with the `actions/setup-java` parameters of `release.yml`: temurin, 8 on `sustaining/5.4.x` and 11 otherwise. The branch is taken from `github.base_ref` for a pull request and from `github.ref_name` for a push. - The commented-out JDK step of the manual build section is removed. If that build is turned on, the new step serves it. The other languages do not use the step. The same change for OpenDJ is OpenIdentityPlatform/OpenDJ#1232. The alignment that #188 proposes first — `actions/setup-java@v6` in `build.yml`, `deploy.yml` and `release.yml`, a `.github/dependabot.yml` with weekly grouped GitHub Actions updates, and the CDDL header of the workflow files — reached master with #170, so this PR no longer carries it. ### Test The change only takes effect in a CodeQL run, so the CodeQL run of this PR is the test. The java-kotlin job log must show `Java version: 11...` from `Eclipse Adoptium`, where master shows `Java version: 25.0.4.1`. A pull request analysis only reports results on the changed lines, so it cannot show the alerts going away. They are closed by the first analysis of master after the merge.
Closes the 16 open
mediumcode scanning alerts in.github/workflows(actions/missing-workflow-permissions#70–#73, #85 andactions/unpinned-tag#74–#84).Explicit
GITHUB_TOKENpermissionspermissionsbuild.yml(workflow-level)localhost:5000contents: readrelease.yml/release-mavenmvn release:preparepushes commits + tag,action-gh-release, wiki pushcontents: writerelease.yml/release-dockerdocker/login-actionto GHCR withGITHUB_TOKENcontents: read,packages: writedeploy.yml/deploy-mavencontents: writeThird-party actions pinned to commit SHAs
docker/metadata-actionv6.2.0,docker/setup-qemu-actionv4.4.0,docker/setup-buildx-actionv4.4.1,docker/login-actionv4.6.0,docker/build-push-actionv7.4.0,softprops/action-gh-releasev3.0.3 — each as@<sha> # vX.Y.Z.actions/*andgithub/codeql-actionstay on major tags (first-party, not flagged by CodeQL).Actions updated to the latest releases
actions/checkoutv6 → v7actions/setup-javav5 → v6actions/cachev5 → v6softprops/action-gh-releasev2 → v3.0.3 (Node 24 runtime)Release notes checked for breaking changes: checkout v7 only blocks fork-PR checkouts under
pull_request_target/workflow_run(ourdeploy.ymljob only runs forpushevents of the base repo); cache v6 is an ESM migration with no input changes. setup-java v6 renamesserver-username/server-passwordtoserver-username-env-var/server-password-env-varand keeps the old names only as deprecated aliases that log a warning on every run, sorelease.ymlanddeploy.ymlswitch to the new inputs (the generatedsettings.xmlis unchanged:${env.MAVEN_USERNAME}/${env.MAVEN_PASSWORD})..github/dependabot.ymlNew:
github-actionsecosystem, weekly, all action updates grouped into a single PR with labelsci+dependencies. Dependabot updates the pinned SHA and the# vX.Y.Zcomment together, so the pins do not go stale.License headers
.github/dependabot.yml— new file, CDDL header withCopyright 2026 3A Systems, LLC..github/workflows/build.yml,deploy.yml,release.yml— CDDL header added withPortions Copyright 2026 3A Systems, LLC.Note for the reviewer
The
permissionsblocks forrelease.ymlanddeploy.ymlcan only be fully validated by a real release / deploy run. The wiki and doc-site steps arecontinue-on-error: true, so a missing permission there would not fail the workflow but would silently skip the publish — worth a glance at the logs of the first run after merge.