Skip to content

Harden GitHub Actions workflows: token permissions, SHA pinning, latest actions - #170

Merged
vharseko merged 2 commits into
OpenIdentityPlatform:masterfrom
vharseko:ci-actions-permissions-pinning
Oct 22, 2026
Merged

vharseko merged 2 commits into
OpenIdentityPlatform:masterfrom
vharseko:ci-actions-permissions-pinning

Conversation

@vharseko

@vharseko vharseko commented Sep 18, 2026 •

Copy link
Copy Markdown
Member

Closes the 16 open medium code scanning alerts in .github/workflows (actions/missing-workflow-permissions #70–#73, #85 and actions/unpinned-tag #74–#84).

Explicit GITHUB_TOKEN permissions

Workflow / job Needs permissions
build.yml (workflow-level) checkout, artifacts, push to localhost:5000 contents: read
release.yml / release-maven mvn release:prepare pushes commits + tag, action-gh-release, wiki push contents: write
release.yml / release-docker checkout, docker/login-action to GHCR with GITHUB_TOKEN contents: read, packages: write
deploy.yml / deploy-maven checkout, wiki push (OSSRH and doc site use their own secrets/PAT) contents: write

Third-party actions pinned to commit SHAs

docker/metadata-action v6.2.0, docker/setup-qemu-action v4.4.0, docker/setup-buildx-action v4.4.1, docker/login-action v4.6.0, docker/build-push-action v7.4.0, softprops/action-gh-release v3.0.3 — each as @<sha> # vX.Y.Z. actions/* and github/codeql-action stay on major tags (first-party, not flagged by CodeQL).

Actions updated to the latest releases

  • actions/checkout v6 → v7
  • actions/setup-java v5 → v6
  • actions/cache v5 → v6
  • softprops/action-gh-release v2 → 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 (our deploy.yml job only runs for push events of the base repo); cache v6 is an ESM migration with no input changes. setup-java v6 renames server-username / server-password to server-username-env-var / server-password-env-var and keeps the old names only as deprecated aliases that log a warning on every run, so release.yml and deploy.yml switch to the new inputs (the generated settings.xml is unchanged: ${env.MAVEN_USERNAME} / ${env.MAVEN_PASSWORD}).

.github/dependabot.yml

New: github-actions ecosystem, weekly, all action updates grouped into a single PR with labels ci + dependencies. Dependabot updates the pinned SHA and the # vX.Y.Z comment together, so the pins do not go stale.

License headers

  • .github/dependabot.yml — new file, CDDL header with Copyright 2026 3A Systems, LLC.
  • .github/workflows/build.yml, deploy.yml, release.yml — CDDL header added with Portions Copyright 2026 3A Systems, LLC.

Note for the reviewer

The permissions blocks for release.yml and deploy.yml can only be fully validated by a real release / deploy run. The wiki and doc-site steps are continue-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.

@vharseko vharseko added dependencies Pull requests that update a dependency file security Security fixes and CVE / vulnerability updates ci Build, CI/CD, and GitHub Actions changes labels Sep 18, 2026
vharseko added a commit to vharseko/OpenIG that referenced this pull request Sep 18, 2026
vharseko added a commit to vharseko/OpenIDM that referenced this pull request Sep 18, 2026
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.
vharseko added a commit to vharseko/OpenAM that referenced this pull request Sep 18, 2026
Add "ci"/"dependencies" labels and the grouping comment to
.github/dependabot.yml, matching OpenIdentityPlatform/OpenIG#170.
vharseko added a commit to vharseko/OpenAM that referenced this pull request Sep 29, 2026
Add "ci"/"dependencies" labels and the grouping comment to
.github/dependabot.yml, matching OpenIdentityPlatform/OpenIG#170.
vharseko added a commit to vharseko/OpenAM that referenced this pull request Sep 29, 2026
Add "ci"/"dependencies" labels and the grouping comment to
.github/dependabot.yml, matching OpenIdentityPlatform/OpenIG#170.
vharseko added a commit to vharseko/OpenIDM that referenced this pull request Oct 3, 2026
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.
vharseko added a commit to vharseko/OpenIDM that referenced this pull request Oct 5, 2026
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.
vharseko added a commit to OpenIdentityPlatform/OpenIDM that referenced this pull request Oct 6, 2026
* 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 maximthomas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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: write goes only to release-docker, the one job that pushes to GHCR. release-maven and deploy-maven get contents: write only.
  • All 14 PR checks are green on the head. That includes the build-maven matrix on actions/setup-java@v6 (ubuntu/macos/windows), and build-docker, whose job log shows the push to localhost: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_PASSWORD

note (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
@vharseko
vharseko force-pushed the ci-actions-permissions-pinning branch from b1f0088 to bbc3ecf Compare October 22, 2026 11:03
@vharseko

Copy link
Copy Markdown
Member Author

Both points taken.

  • release.yml and deploy.yml now use server-username-env-var / server-password-env-var. These inputs exist since setup-java v6.0.0, and @v6 cannot resolve below that.
  • The description is corrected (setup-java v6 does rename inputs) and now lists the CDDL headers.

The branch is rebased onto current master (#185, #186). Neither brings a new third-party action, so there are no new unpinned tags.

@vharseko
vharseko requested a review from maximthomas October 22, 2026 11:03
vharseko added a commit to vharseko/OpenIG that referenced this pull request Oct 22, 2026

@maximthomas maximthomas left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 a settings.xml byte-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-maven and build-docker are cleared by the workflow-level block at build.yml:23-24; release-maven, release-docker and deploy-maven by 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. Under checkout@v7, the doc-site push still carries the PAT (deploy.yml:114-136); credential persistence is unchanged from v6.1.0.

@vharseko
vharseko merged commit 270d7c2 into OpenIdentityPlatform:master Oct 22, 2026
14 checks passed
@vharseko
vharseko deleted the ci-actions-permissions-pinning branch October 22, 2026 16:47
vharseko added a commit that referenced this pull request Oct 22, 2026
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.
vharseko added a commit that referenced this pull request Oct 22, 2026
… 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci Build, CI/CD, and GitHub Actions changes dependencies Pull requests that update a dependency file security Security fixes and CVE / vulnerability updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants