Movatterモバイル変換


[0]ホーム

URL:


 
» GitHub Actions Workflows Edit on GitHub

GitHub Actions Workflows

PMD uses GitHub Actions as the CI/CD infrastructure to build and release new versions.This page gives an overview of how these workflows work and how to use them.
Table of Contents

Note:This page is work in progress and does not yet describe all workflows.

Build, Build Pull Request, Build Snapshot, Build Release

“Build” itself is areuseable workflow,that is called by “Build Pull Request” and “Build Snapshot” and “Build Release”.

All these workflows execute exactly the same steps. But only the triggering event is different.It is designed to run on the main repository in PMD’s GitHub organization as well as for forks, as it doesnot require any secrets.

“Build Pull Request” is triggered, whenever a pull request is created or synchronized.

“Build Snapshot” is triggered, whenever new commits are pushed to a branch (including the default branch andincluding forks). This is also a scheduled workflow that runs every month to make sure, the projectcan still be built.

“Build Release” is triggered, whenever a tag is pushed. Note that the whole project is built at once, thatmeans if pmd-designer/pmd-core update is required, this can’t be built. See alsoCircular dependencies between pmd-designer, pmd-core, pmd-cli #4446.As this happens very seldom, this situation is ignored for now.

In order to avoid unnecessary builds, we use concurrency control to make sure, we cancel any in-progress jobs forthe current branch or pull request when a new commit has been pushed. This means, only the latest commit is built,which is enough, since only this will be released or merged in the end. Only the latest build matters.

The workflow is self-contained, e.g. it doesn’t depend on the shell scripts from PMD’s build-tools.It also uses only read permissions and doesn’t need access to any secrets. It is safe to run also onforks.

During the build we create a couple of artifacts, that can be downloaded:

  • compile-artifact: contains all the built classes (everything in thetarget/ directories). It is built under Linux,so unfortunately it can only be used to speed up other Linux based builds, but not Windows or MacOS.
  • staging-repository: contains all the artifacts of groupIdnet.sourceforge.pmd. Could be used as a localrepository to test against this built PMD version without the need to deploy the SNAPSHOTs anywhere. It isactually used by the dogfood job.
  • dist-artifact: contains the binary distribution files, ready to be downloaded. This can be used to testPMD with the changes from the pull request without the need to build it locally. It is actually used by theregression tester job to avoid building PMD another time. It also includes the SBOM files (in json and xml format).
  • docs-artifact: contains the generated PMD documentation including rule descriptions.
  • javadocs-artifact: contains the javadoc jars of all PMD modules generated during build.
  • pmd-regression-tester: contains the generation regression report, if there were any changes to rules.

In order to have fast feedback of the build results, we run a couple of jobs in parallel and not sequentially.The jobs are:

  • “compile”: First a fast compile job to sort out any basic problems at the beginning. If this job fails, nothingelse is executed. It also populates the build cache (maven dependencies) that is reused for the following jobs.The created artifacts are: “compile-artifact”, “staging-repository”, “dist-artifact”.
  • After this first job, a bunch of other jobs are run in parallel:
    • “verify”: runs a complete./mvnw verify with all code checks like checkstyle, japicmp, javadoc, etc.but excluding unit tests (these are run in a separate job).This job is only run on linux. It reuses the already compiled artifacts from the first “compile” job.Since it runs javadoc, it creates the javadocs-artifact.
    • “verify-unittests”: just runs the unit tests on Linux, Windows and MacOS. Only linux reuses the“compile-artifact” from the first job. For Windows/MacOS we can’t reuse this due to platform specific lineendings and timestamp issues.
    • “dogfood”: runs maven-pmd-plugin on PMD with the latest changes from this very pull request. It uses the“staging-repository” artifact.
    • “documentation”: generates the rule documentations and builds PMD’s documentation page using jekyll.It also executes the verification for wrong rule tags and dead links. Additional it contains the releasenotes in markdown format, to be used for release publishing. It creates the artifact “docs-artifact”.
    • “regressiontester”: runs thepmdtester to produce the regression report.It reuses the artifact “dist-artifact” so that we don’t need to build PMD again. It uses a different buildcache as the other jobs, as this cache now contains the test projects (like Spring Framework) and theirdependencies. It produces the artifact “pmd-regression-tester” with the regression report.

Publish Results from Pull Requests

This workflow runs after “Build Pull Request”, when it is completed. It runs in the context of our ownrepository and has write permissions and complete access to the configured secrets.For security reasons, this workflow won’t check out the pull request code and won’t build anything.

It just uses the artifacts from the pull request build, uploads it as static website and addsa commit status and check status to the PR and finally adds a PR comment.

Both the “docs-artifact” and the “pmd-regression-tester” artifact are uploaded to an AWS S3 bucketcalledpmd-pull-requests. This bucket is served via AWS Cloudfront (for having TLS) underthe URLhttps://pull-requests.pmd-code.org. Note, there is no directory listing. The resultsof each pull request are uploaded under the folders “pr-{PR_NUMBER}/{PR_SHA}/docs” and “pr-{PR_NUMBER}/{PR_SHA}/regression”,respectively. The data in the S3 bucket is available for 60 days, after that the files are removedautomatically (hopefully). Since the head SHA of the PR is included in the URL, an updated PR will uploadnew versions of the artifacts. Otherwise, Cloudfront’s cache might prevent us from seeing theupdated artifacts.

In order to upload the files to AWS S3, we use theAWS CLItool, that is available on the GitHub provided runners for GitHub Actions. It needs the followingsecrets:

  • AWS_S3_PMD_PULL_REQUESTS_ACCESS_KEY_ID
  • AWS_S3_PMD_PULL_REQUESTS_SECRET_ACCESS_KEY

These are configured at the organization level of pmd:https://github.com/organizations/pmd/settings/secrets/actions.

In order to set the commit status and add a check status, we useGitHub’s CLI toolwhich is also available on the GitHub provided runners for GitHub Actions. It will use the GitHub tokenthat the workflow is assigned to automatically and that is available as the secret “GITHUB_TOKEN”.The permissions are controlled in the workflow yaml file itself.SeeAutomatic token authentication.

In the end, we use the actionsticky-pull-request-commentto create or update a comment on the pull request which shows the regression tester summary.

This workflow is in that sense optional, as the docs-artifact and pmd-regression-tester artifacts canbe manually downloaded from the “Pull Request Build” workflow run. It merely adds convenience bygiving easy access to a preview of the documentation and to the regression tester results.

In the end, this workflow adds additional links to a pull request page. For the comment, GitHub seemsto automatically add “rel=nofollow” to the links in the text. This is also applied for the check statuspages. However, the links in the commit status are plain links. This might lead to unnecessarycrawling by search engines. To avoid this, the following robots.txt is usedathttps://pull-requests.pmd-code.org/robots.txt to disallow any (search engine) bot:

User-agent: *Disallow: /

The reasons, why we don’t want to have the pages there indexed: They are short-lived and onlytemporary. These temporary created documentation pages should not end up in any search result.This also helps to avoid unnecessary traffic and load for both the hosting side and thecrawling side.

Publish Snapshot

This runs after “Build Snapshot” of a push on themain branch is finished.It runs in the context of our own repository and has access to all secrets. In orderto have a nicer progress display in GitHub actions, we leverage “environments”, which alsocontain secrets.

There is a first job “check-version” that just determines the version of PMD we are building. This is to ensure,we are actually building a SNAPSHOT version. Then a couple of other jobs are being executed in parallel:

  • deploy-to-maven-central: Rebuilds PMD from branch main and deploys the snapshot artifacts tohttps://central.sonatype.com/service/rest/repository/browse/maven-snapshots/net/sourceforge/pmd/.Rebuilding is necessary in order to produce all necessary artifacts (sources, javadoc) and also gpg-sign theartifacts. This is not available from the build artifacts of the “Build” workflow.
    • Environment: maven-central
    • Secrets: MAVEN_CENTRAL_PORTAL_USERNAME, MAVEN_CENTRAL_PORTAL_PASSWORD
  • deploy-to-sourceforge-files: Downloads the “dist-artifact” and “docs-artifact” from the “Build” workflow,gpg-signs the files and uploads them tohttps://sourceforge.net/projects/pmd/files/pmd/.
    • Environment: sourceforge
    • Secrets: PMD_WEB_SOURCEFORGE_NET_DEPLOY_KEY
    • Vars: PMD_WEB_SOURCEFORGE_NET_KNOWN_HOSTS, PMD_GIT_CODE_SF_NET_KNOWN_HOSTS
  • deploy-to-sourceforge-io: Uploads the documentation page to be hosted athttps://pmd.sourceforge.io/snapshot.
    • Environment: sourceforge
    • Secrets: PMD_WEB_SOURCEFORGE_NET_DEPLOY_KEY
    • Vars: PMD_WEB_SOURCEFORGE_NET_KNOWN_HOSTS
  • deploy-to-pmd-code-doc: Uploads the documentation page to be hosted athttps://docs.pmd-code.org/snapshot/.
    • Environment: pmd-code
    • Secrets: PMD_CODE_ORG_DEPLOY_KEY
    • Vars: PMD_CODE_ORG_KNOWN_HOSTS
  • deploy-to-pmd-code-javadoc: Uploads the javadoc of PMD’s modules to be hosted athttps://docs.pmd-code.org/apidocs/.
    • Environment: pmd-code
    • Secrets: PMD_CODE_ORG_DEPLOY_KEY
    • Vars: PMD_CODE_ORG_KNOWN_HOSTS
  • deploy-to-github-pages: Updates the branch “gh-pages” wit the new documentation pageand pushes a new commit onto that branch. This will trigger a new github pages deployment,so that the new documentation page is available athttps://pmd.github.io/pmd/.
    • Environment: github-pages
    • Secrets: no additional secrets
  • create-regression-tester-baseline: Creates a new baseline to be used by the pull request buildsfor regression testing. The baseline is uploaded tohttps://pmd-code.org/pmd-regression-tester/main-baseline.zip.
    • Environment: pmd-code
    • Secrets: PMD_CODE_ORG_DEPLOY_KEY
    • Vars: PMD_CODE_ORG_KNOWN_HOSTS
  • run-sonar: Executessonar-scanner-plugin anduploads the results to sonarcloud athttps://sonarcloud.io/dashboard?id=net.sourceforge.pmd%3Apmd.
    • Environment: sonarcloud
    • Secrets: SONAR_TOKEN
  • run-coveralls: Executescoveralls-maven-plugin anduploads the results to coveralls athttps://coveralls.io/github/pmd/pmd.
    • Environment: coveralls
    • Secrets: COVERALLS_REPO_TOKEN

Publish Release

This runs after “Build Release” finishes from building from a tag.It runs in the context of our own repository and has access to all secrets. In order to havea nicer progress display in GitHub actions, we leverage “environments”, which alsocontain secrets.

There is a first job “check-version” that just determines the version of PMD we are building. This is to ensure,we are actually building a RELEASE version. Then a first job is executed:

  • deploy-to-maven-central: Rebuilds PMD from the tag and deploys the artifact to maven central athttps://repo.maven.apache.org/maven2/net/sourceforge/pmd/.Rebuilding is necessary in order to produce all necessary artifacts (sources, javadoc) and also gpg-sign theartifacts. This is not available from the build artifacts of the “Build” workflow.
    The maven plugincentral-publishing-maven-plugin is usedto upload and publish the artifacts to maven central.
    • Environment: maven-central
    • Secrets: MAVEN_CENTRAL_PORTAL_USERNAME, MAVEN_CENTRAL_PORTAL_PASSWORD

When this was successful, then a couple of other jobs are being executed in parallel:

  • deploy-to-sourceforge-files: Uploads the binary distribution files to sourceforge athttps://sourceforge.net/projects/pmd/files/pmd/ and select the new file as the latestversion.
    • Environment: sourceforge
    • Secrets: PMD_WEB_SOURCEFORGE_NET_DEPLOY_KEY, PMD_SF_APIKEY
    • Vars: PMD_WEB_SOURCEFORGE_NET_KNOWN_HOSTS
  • deploy-to-sourceforge-io: Uploads the documentation tohttps://pmd.sourceforge.io/pmd-${PMD_VERSION}/.
    • Environment: sourceforge
    • Secrets: PMD_WEB_SOURCEFORGE_NET_DEPLOY_KEY
    • Vars: PMD_WEB_SOURCEFORGE_NET_KNOWN_HOSTS
  • deploy-to-pmd-code-doc: Uploads the documentation tohttps://docs.pmd-code.org/latest.
    • Environment: pmd-code
    • Secrets: PMD_CODE_ORG_DEPLOY_KEY
    • Vars: PMD_CODE_ORG_KNOWN_HOSTS
  • deploy-to-pmd-code-javadoc: Uploads the javadoc tohttps://docs.pmd-code.org/apidocs/
    • Environment: pmd-code
    • Secrets: PMD_CODE_ORG_DEPLOY_KEY
    • Vars: PMD_CODE_ORG_KNOWN_HOSTS
  • github-release: Creates a new github release athttps://github.com/pmd/pmd/releases includingthe attached artifacts.
    • Environment: github
  • create-sourceforge-blog-post: Creates a news entry athttps://sourceforge.net/p/pmd/news/.
    • Environment: sourceforge
    • Secrets: PMD_SF_BEARER_TOKEN
  • create-regression-tester-baseline: Creates a new baseline and uploads it tohttps://pmd-code.org/pmd-regression-tester/.
    • Environment: pmd-code
    • Secrets: PMD_CODE_ORG_DEPLOY_KEY
    • Vars: PMD_CODE_ORG_KNOWN_HOSTS
  • upload-regression-tester-baseline-sourceforge: Uploads the baseline additionally to sourceforgeathttps://sourceforge.net/projects/pmd/files/pmd-regression-tester/. Needs the previous job.
    • Environment: sourceforge
    • Secrets: PMD_WEB_SOURCEFORGE_NET_DEPLOY_KEY
    • Vars: PMD_WEB_SOURCEFORGE_NET_KNOWN_HOSTS
  • create-docker: Triggers a new build athttps://github.com/pmd/docker/actions to create andupload a new docker image to Docker Hub and GitHub Packages.
    • Environment: github
    • Uses PMD Actions Helper app to call a workflow in the other repository
    • Secrets: PMD_ACTIONS_HELPER_ID, PMD_ACTIONS_HELPER_PRIVATE_KEY

Secrets and Variables

The “Build” workflow doesn’t need any secrets or additional permissions, it just builds and creates artifacts.This is necessary, so that this workflow can also run on forks, so that contributors can develop in theirown fork and have their build validated already. All branches (not only main) are built. The same workflow isalso used for pull request builds.

On the main PMD repository (https://github.com/pmd/pmd) additional workflows are triggered after “Build”.These additional workflows run with privileged mode, so that they have access to all secrets and canelevate permissions as needed.

Secrets and variables are organized in a hierarchy, beginning at the organization level (those secrets areavailable in all repositories), repository level and environment level (environments can be created at therepository level).

At time of this writing (2025-05-10), the following secrets and variables are configured:

Organization

Seehttps://github.com/organizations/pmd/settings/secrets/actions

  • PMD_ACTIONS_HELPER_ID andPMD_ACTIONS_HELPER_PRIVATE_KEY: These are the app id and private key for ourcustom GitHub AppPMD Actions Helper.This is a private app defined at our organization and can only be installed within our organization. With these twosecrets and the actioncreate-github-app-token we cancreate a temporary github token, that has more permissions to access other repositories.This is used to trigger the workflow in pmd/docker from pmd/pmd to create and upload a new docker image andalso in “publish-snapshot” to push to repository pmd/pmd-eclipse-plugin-p2-site during the buildof pmd/pmd-eclipse-plugin.
    A new private key can be generated through GitHub organization settings.

  • PMD_CI_GPG_PASSPHRASE andPMD_CI_GPG_PRIVATE_KEY: That’s the secret GPG key used to sign our releases,seeSigned Releases. The key is exported in armored format(beginning with “—–BEGIN PGP PRIVATE KEY BLOCK—–”). The key is imported during the build either withthe option “gpg-private-key” ofsetup-java action or manuallyvia a small shell script (“gpg –import …”).
    The release signing key is created in such a way, that we use the primary key only for certifying our ownsubkeys (capability C) and we have a separate subkey that is used only for signing releases(capability S). In case the signing subkey gets compromised, we can add a new subkey, but keep theprimary key. The idea is, that only the private key of the subkey is exported and put into thesecret variablePMD_CI_GPG_PRIVATE_KEY. This can be achieved throughgpg --armor --export-secret-subkeys 2EFA55D0785C31F956F2F87EA0B5CA1A4E086838 | wl-copy.
    More information about creating and renewing this key, see belowRelease Signing Keys.

Repository pmd/pmd

Seehttps://github.com/pmd/pmd/settings/secrets/actions

  • AWS_S3_PMD_PULL_REQUESTS_ACCESS_KEY_ID andAWS_S3_PMD_PULL_REQUESTS_SECRET_ACCESS_KEY: Used by“Publish Results From Pull Request” to upload the regression report and documentation to the AWS S3bucket “pmd-pull-requests”: http://pmd-pull-requests.s3-website.eu-central-1.amazonaws.com/.This access key corresponds to the user “arn:aws:iam::624352026855:user/pmd-pull-requests”, which isgranted write access to this bucket via the following permission policy:

    {"Version":"2012-10-17","Statement":[{"Sid":"VisualEditor0","Effect":"Allow","Action":["s3:Get*","s3:List*","s3:PutObject","s3:DeleteObject"],"Resource":["arn:aws:s3:::pmd-pull-requests/*","arn:aws:s3:::pmd-pull-requests"]}]}

    New access key/users need to be created via AWS.

Repository pmd/docker

Seehttps://github.com/pmd/docker/settings/secrets/actions

Repository pmd/pmd-regression-tester - Environment “rubygems”

Seehttps://github.com/pmd/pmd-regression-tester/settings/secrets/actions

Repository pmd/pmd - Environment “maven-central”

Repository pmd/pmd - Environment “coveralls”

Repository pmd/pmd - Environment “sonarcloud”

Repository pmd/pmd - Environment “sourceforge”

  • PMD_WEB_SOURCEFORGE_NET_DEPLOY_KEY: The private ssh key used to access web.sourceforge.net toupload files and web pages. It is also used to push to sourceforge’s git repository at “git.code.sf.net”.
    It is created withssh-keygen -t ed25519 -C "ssh key for pmd. used for github actions push to web.sourceforge.net" -f web.sourceforge.net_deploy_key.
    You need to configure the public key part here:https://sourceforge.net/auth/shell_services. The user is yoursourceforge user id.
    The key should begin with “—–BEGIN OPENSSH PRIVATE KEY—–”.

  • PMD_SF_BEARER_TOKEN: This is needed to access sourceforge API (https://sourceforge.net/p/forge/documentation/Allura%20API/)to create new blog entries. The token is created athttps://sourceforge.net/auth/oauth/.

  • PMD_SF_APIKEY: This is needed to select the latest release on sourceforge files, seehttps://sourceforge.net/p/forge/documentation/Using%20the%20Release%20API/. The key is created athttps://sourceforge.net/auth/preferences/ under “Releases API Key”.

This environment also has a variable, which is the known_hosts content asPMD_WEB_SOURCEFORGE_NET_KNOWN_HOSTS:

## web.sourceforge.net (https://sourceforge.net/p/forge/documentation/SSH%20Key%20Fingerprints/)## run locally:# ssh-keyscan web.sourceforge.net | tee -a sf_known_hosts## verify fingerprints:# ssh-keygen -F web.sourceforge.net -l -f sf_known_hosts# # Host web.sourceforge.net found: line 1 # web.sourceforge.net RSA SHA256:xB2rnn0NUjZ/E0IXQp4gyPqc7U7gjcw7G26RhkDyk90 # # Host web.sourceforge.net found: line 2 # web.sourceforge.net ECDSA SHA256:QAAxYkf0iI/tc9oGa0xSsVOAzJBZstcO8HqGKfjpxcY # # Host web.sourceforge.net found: line 3 # web.sourceforge.net ED25519 SHA256:209BDmH3jsRyO9UeGPPgLWPSegKmYCBIya0nR/AWWCY ## then add output of `ssh-keygen -F web.sourceforge.net -f sf_known_hosts`#web.sourceforge.net ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA2uifHZbNexw6cXbyg1JnzDitL5VhYs0E65Hk/tLAPmcmm5GuiGeUoI/B0eUSNFsbqzwgwrttjnzKMKiGLN5CWVmlN1IXGGAfLYsQwK6wAu7kYFzkqP4jcwc5Jr9UPRpJdYIK733tSEmzab4qc5Oq8izKQKIaxXNe7FgmL15HjSpatFt9w/ot/CHS78FUAr3j3RwekHCm/jhPeqhlMAgC+jUgNJbFt3DlhDaRMa0NYamVzmX8D47rtmBbEDU3ld6AezWBPUR5Lh7ODOwlfVI58NAf/aYNlmvl2TZiauBCTa7OPYSyXJnIPbQXg6YQlDknNCr0K769EjeIlAfY87Z4tw==web.sourceforge.net ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCwsY6sZT4MTTkHfpRzYjxG7mnXrGL74RCT2cO/NFvRrZVNB5XNwKNn7G5fHbYLdJ6UzpURDRae1eMg92JG0+yo=web.sourceforge.net ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOQD35Ujalhh+JJkPvMckDlhu4dS7WH6NsOJ15iGCJLC

Another variablePMD_GIT_CODE_SF_NET_KNOWN_HOSTS contains the known_hosts for “git.code.sf.net”:

## git.code.sf.net (https://sourceforge.net/p/forge/documentation/SSH%20Key%20Fingerprints/)## ssh-keyscan git.code.sf.net | tee -a sf-git_known_hosts# ssh-keygen -F git.code.sf.net -l -f sf-git_known_hosts# # Host git.code.sf.net found: line 1 # git.code.sf.net RSA SHA256:3WhEqJaBPKb69eT5dfgYcPJTgqc9rq1Y9saZlXqkbWg# # Host git.code.sf.net found: line 2 # git.code.sf.net ECDSA SHA256:FeVkoYYBjuQzb5QVAgm3BkmeN5TTgL2qfmqz9tCPRL4# # Host git.code.sf.net found: line 3 # git.code.sf.net ED25519 SHA256:vDwNztsrZFViJXWpUTSKGo8cF6n79iKAURNiK68n/yE# ssh-keygen -F git.code.sf.net -f sf-git_known_hostsgit.code.sf.net ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAoMesJ60dow5VqNsIqIQMBNmSYz6txSC5YSUXzPNWV4VIWTWdqbQoQuIu+oYGhBMoeaSWWCiVIDTwFDzQXrq8CwmyxWp+2TTuscKiOw830N2ycIVmm3ha0x6VpRGm37yo+z+bkQS3m/sE7bkfTU72GbeKufFHSv1VLnVy9nmJKFOraeKSHP/kjmatj9aC7Q2n8QzFWWjzMxVGg79TUs7sjm5KrtytbxfbLbKtrkn8OXsRy1ib9hKgOwg+8cRjwKbSXVrNw/HM+MJJWp9fHv2yzWmL8B6fKoskslA0EjNxa6d76gvIxwti89/8Y6xlhR0u65u1AiHTX9Q4BVsXcBZUDw==git.code.sf.net ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPAa5MFfMaXyT3Trf/Av/laAvIhUzZJUnvPZAd9AC6bKWAhVl+A3s2+M6SlhF/Tn/W0akN03GyNviBtqJKtx0RU=git.code.sf.net ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGObtXLh/mZom0pXjE5Mu211O+JvtzolqdNKVA+XJ466

Repository pmd/pmd - Environment “pmd-code”

  • PMD_CODE_ORG_DEPLOY_KEY: The private ssh key used to access docs.pmd-code.org.It is created withssh-keygen -t ed25519 -C "ssh key for pmd. used for github actions push to pmd-code.org" -f pmd-code.org_deploy_key.
    The public key is configured in~/.ssh/authorized_keys on pmd@pmd-code.org. That means, the user is “pmd”.
    The key should begin with “—–BEGIN OPENSSH PRIVATE KEY—–”.

This environment also has a variable, which is the known_hosts content asPMD_CODE_ORG_KNOWN_HOSTS:

## pmd-code.org## ssh-keyscan pmd-code.org | tee -a pmd_known_hosts# ssh-keygen -F pmd-code.org -l -f pmd_known_hosts# # Host pmd-code.org found: line 1 # pmd-code.org RSA SHA256:/uKehVNumCNvJL8C5CziwV9KkUUxHfggq0C4GTrUhwg# # Host pmd-code.org found: line 2 # pmd-code.org ECDSA SHA256:6aD1r1XuIoc/zgBT3bt1S9L5ToyJzdQ9rrcMchnqiRA# # Host pmd-code.org found: line 3 # pmd-code.org ED25519 SHA256:nvkIAzZhYTxXqSU3DWvos83A0EocZ5dsxNkx1LoMZhg# ssh-keygen -F pmd-code.org -f pmd_known_hostspmd-code.org ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDVsIeF6xU0oPb/bMbxG1nU1NDyBpR/cBEPZcm/PuJwdI9B0ydPHA6FysqAnt32fNFznC2SWisnWyY3iNsP3pa8RQJVwmnnv9OboGFlW2/61o3iRyydcpPbgl+ADdt8iU9fmMI7dC04UqgHGBoqOwVNna9VylTjp5709cK2qHnwU450F6YcOEiOKeZfJvV4PmpJCz/JcsUVqft6StviR31jKnqbnkZdP8qNoTbds6WmGKyXkhHdLSZE7X1CFQH28tk8XFqditX93ezeCiThFL7EleDexV/3+2+cs5878sDMUMzHS5KShTjkxzhHaodhtIEdNesinq/hOPbxAGkQ0FbDpmd-code.org ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBMfSJtZcJCeENSZMvdngr+Hwe7oUVQWWKwC4HnfiOoAh/NSIlzJyQvpoPZxnEFid6Y3ntDK+rnx04Japo63zD8Q=pmd-code.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFa88nqfMavMH/tGeS5DNrSeM5AVHmZQGHh98vC1717o

Release Signing Keys

Creating a new key

In general, a key created once should be reused. However, if the key is (potentially) compromised, a newkey needs to be generated. A gpg key consists of a primary key and one or more subkeys. The primary keydefines the identity (fingerprint, key ID) and subkeys can be used for actual signing. The primary key isthen only used to create new subkeys or renew subkeys. For a more safe operation, the primary key shouldbe kept offline and only the subkeys should be used for signing. A Release Signing Key also doesn’t needa subkey for encryption. In case a signing key gets compromised, the subkey can be revoked and a new keycan be generated. But the primary key still is safe.

Creating such a key is not straightforward, hence this how to (there are a couple of guidesin the internet about best practices):

$ gpg --expert --full-generate-key...Please select what kind of key you want:> 8 (RSA (set your own capabilities)> S (Toggle Sign)> E (Toggle Encrypt)> QCurrent allowed actions: CertifyWhat keysize do you want?> 4096Please specify how long the key should be valid.> 2yReal name:> PMD Release Signing KeyEmail address:> releases@pmd-code.org...pub   rsa4096 2025-01-04 [C] [expires: 2027-01-04]      2EFA55D0785C31F956F2F87EA0B5CA1A4E086838uid                      PMD Release Signing Key <releases@pmd-code.org>

Then we create a subkey for signing:

$ gpg --edit-key 2EFA55D0785C31F956F2F87EA0B5CA1A4E086838gpg> addkey> 4 (RSA (sign only))keysize:> 4096Expiration> 2y...> save

Now let’s publish the public key:

$ gpg --armor --export 2EFA55D0785C31F956F2F87EA0B5CA1A4E086838 | curl -T - https://keys.openpgp.orgKey successfully uploaded. Proceed with verification here:https://keys.openpgp.org/upload/....

Export the key to upload it tohttps://keyserver.ubuntu.com/#submitKey:gpg --armor --export 2EFA55D0785C31F956F2F87EA0B5CA1A4E086838 | wl-copyAlso upload it tohttp://pgp.mit.edu/.

Verify the uploaded (public) key (and expiration date):

gpg --armor --export 2EFA55D0785C31F956F2F87EA0B5CA1A4E086838 > release-signing-key-2EFA55D0785C31F956F2F87EA0B5CA1A4E086838-public.ascgpg --show-keys release-signing-key-2EFA55D0785C31F956F2F87EA0B5CA1A4E086838-public.asccurl 'https://keys.openpgp.org/vks/v1/by-fingerprint/2EFA55D0785C31F956F2F87EA0B5CA1A4E086838' | gpg --show-keyscurl 'https://keyserver.ubuntu.com/pks/lookup?search=0x2EFA55D0785C31F956F2F87EA0B5CA1A4E086838&fingerprint=on&exact=on&options=mr&op=get' | gpg --show-keyscurl 'http://pgp.mit.edu/pks/lookup?op=get&search=0x2EFA55D0785C31F956F2F87EA0B5CA1A4E086838' | gpg --show-keys

Current Key

  • Used since January 2025
  • Fingerprint2EFA 55D0 785C 31F9 56F2 F87E A0B5 CA1A 4E08 6838
  • Used for signing artifacts in Maven Central
$ gpg --list-keys --fingerprint --with-subkey-fingerprint 2EFA55D0785C31F956F2F87EA0B5CA1A4E086838pub   rsa4096 2025-01-04 [C] [verfällt: 2027-01-04]      2EFA 55D0 785C 31F9 56F2  F87E A0B5 CA1A 4E08 6838uid        [ ultimativ ] PMD Release Signing Key <releases@pmd-code.org>sub   rsa4096 2025-01-04 [S] [verfällt: 2027-01-04]      1E04 6C19 ED28 73D8 C08A  F7B8 A063 2691 B78E 3422

The public key is available here:

Old keys

  • FingerprintEBB2 41A5 45CB 17C8 7FAC B2EB D0BF 1D73 7C9A 1C22
    • Used until December 2024
    • Replaced as the passphrase has been compromised and therefore the key is potentiallycompromised. Note - as until now (January 2025) we don’t have any indication that the keyactually has been misused.
    • Revoked 2025-01-04.
    • see filerelease-signing-key-D0BF1D737C9A1C22-public.asc.
  • Fingerprint94A5 2756 9CAF 7A47 AFCA BDE4 86D3 7ECA 8C2E 4C5B
    • Old key used to sign PMD Designer
    • Revoked 2025-01-04.

Private key

In order for GitHub Actions to automatically sign the artifacts for snapshot builds and release builds,we need to make the private key along with the passphrase available. This is done usingmultiplesecrets.The secrets are configured on the organization level of PMD, so that the Release Signing key is availablefor all repositories.

To not expose the master key, we only export the subkeys we use for signing and store this in the secretPMD_CI_GPG_PRIVATE_KEY.

For setting up, export the secret key and copy-paste it into a new secret:

gpg --armor --export-secret-subkeys 2EFA55D0785C31F956F2F87EA0B5CA1A4E086838 | wl-copy

(instead of wl-copy, use xclip or pbcopy, depending on your os).

This private key will be imported by setup-java or a small shell script.

Note 1: We use option--export-secret-subkeys to only export the subkey and not the master key.That way, we don’t need to transfer the master key.

Note 2: In order to use the key later on, the passphrase is needed. This is also setup as a secret:PMD_CI_GPG_PASSPHRASE. This secret is then exported as “MAVEN_GPG_PASSPHRASE” where needed(MAVEN_GPG_PASSPHRASE: $) in github actions workflows.See alsohttps://maven.apache.org/plugins/maven-gpg-plugin/usage.html#sign-artifacts-with-gnupg.

Note 3: The private key is now only secured by the passphrase. It is stored as a GitHub Actionssecret and available in an environment variable. It is not committed as a file anywhere. Note:When importing the key, it is stored on disk in “~/.gnupg” - hence the GitHub Actions should make sureto delete this directory on the runner after the workflow is finished in order to not leakthe key to following users of the runner.

Updating the key

From time to time the key needs to be renewed, passphrase needs to be changed or a whole (sub)key needs tobe replaced.

For renewing or changing the passphrase, import the private master key and public key into your local gpg keystore(if you don’t have it already in your keyring) and renew it.Make sure to renew all subkeys. Then export the public key again.

For replacing, generate a new (sub) key, just export it.

You can verify the expiration date withgpg --fingerprint --list-key 2EFA55D0785C31F956F2F87EA0B5CA1A4E086838:

pub   rsa4096 2025-01-04 [C] [expires: 2027-01-04]      2EFA 55D0 785C 31F9 56F2  F87E A0B5 CA1A 4E08 6838uid           [ultimate] PMD Release Signing Key <releases@pmd-code.org>sub   rsa4096 2025-01-04 [S] [expires: 2027-01-04]

Upload the exportedpublic key to

Verify the uploaded key expiration date:

gpg --show-keys release-signing-key-2EFA55D0785C31F956F2F87EA0B5CA1A4E086838-public.asccurl 'https://keys.openpgp.org/vks/v1/by-fingerprint/2EFA55D0785C31F956F2F87EA0B5CA1A4E086838' | gpg --show-keyscurl 'https://keyserver.ubuntu.com/pks/lookup?search=0x2EFA55D0785C31F956F2F87EA0B5CA1A4E086838&fingerprint=on&exact=on&options=mr&op=get' | gpg --show-keyscurl 'http://pgp.mit.edu/pks/lookup?op=get&search=0x2EFA55D0785C31F956F2F87EA0B5CA1A4E086838' | gpg --show-keys

Don’t forget to update the secretPMD_CI_GPG_PRIVATE_KEY with the renewed private signing subkey.


This documentation is written in markdown.
If there is something missing or can be improved, edit this page on github and create a PR: Edit on GitHub

©2025 PMD Open Source Project. All rights reserved.
Page last updated: June 2025 (7.15.0)
Site last generated: Jun 27, 2025

PMD                logo


[8]ページ先頭

©2009-2025 Movatter.jp