How to publish artifacts to Maven Central from a CI build server? - maven

I want to publish an artifact to Maven Central from our build server, just like is common practice with internal projects in my company, which are deployed to a local Nexus.
The only difference is that artifacts on Maven Central need to be PGP-signed, before they are accepted.
How do other projects handle this? Do I need to upload my private PGP key and passphrase to the CI server? This doesn't feel right, since a private key usually should never leave my own machine. Should I build releases for Maven Central from my local machine? How does this work in teams where multiple people can publish an artifact?
While there's an official guide on how to upload artifacts and a guide on working with PGP signatures, my questions are not covered there.

Related

What is the best practice for archiving Jenkins pipeline artifacts

I see that you can add a goal to a maven Pom to archive artifacts to a repo manager such as nexus
https://www.baeldung.com/maven-deploy-nexus
distributionManagement>
   <snapshotRepository>
      <id>nexus-snapshots</id>
      <url>http://localhost:8081/nexus/content/repositories/snapshots</url>
   </snapshotRepository>
</distributionManagement>
But Jenkins also allows you to do this from the pipeline itself
https://wiki.jenkins.io/plugins/servlet/mobile?contentId=96076078#content/view/96076078
freeStyleJob('NexusArtifactUploaderJob') {
steps {
nexusArtifactUploader {
nexusVersion('nexus2')
protocol('http')
nexusUrl('localhost:8080/nexus')
groupId('sp.sd')
version('2.4')
repository('NexusArtifactUploader')
credentialsId('44620c50-1589-4617-a677-7563985e46e1')
artifact {
artifactId('nexus-artifact-uploader')
type('jar')
classifier('debug')
file('nexus-artifact-uploader.jar')
}
artifact {
artifactId('nexus-artifact-uploader')
type('hpi')
classifier('debug')
file('nexus-artifact-uploader.hpi')
}
}
}
}
What is the difference between the two approaches, is one more commonly used?
The main difference is that if you use maven, you can manually add artifacts to Nexus from your local computer, using mvn deploy. So it really comes down to how you want to create the artifacts that end up being used in production. In my experience, the preferred way of doing this is through using Jenkins. The advantage of using Jenkins is that you link your new version builds to other activities, as well as the possibility to trigger a release when certain conditions have been met, rather than starting the build manually. Also, you end up with all versions being built on the same platform, and you avoid differences between computers if every developer builds such versions from their own computer.
But you might still need the maven configuration. Jenkins might use this information to find the URL to upload the artifact to (your example says nothing about how Jenkins finds Nexus), and sometimes it is useful to upload a SNAPSHOT-version, or some other temporary version not meant for production. In your example you only define Nexus for upload SNAPSHOT-versions, I guess this is done on purpose to enforce a rule that uploading final version from local computers is disallowed.
By the way, having a repository defined in your pom.xml does not automatically mean that anything will be uploaded. It is only if you do mvn deploy with a repository defined in your pom that something will be uploaded.

How to preserve the timestamps generated for SNAPSHOT artifacts?

Currently a Maven build (inside Jenkins) is configured to deploy every artifact it builds (releases and snapshots) to a Nexus repository. Now I have to push some of those artifacts to application servers and thought of letting the target servers fetch them from Nexus - this is easy for releases but how can I reference the SNAPSHOT artifacts? Maven's deploy plugin adds a timestamp to make each artifact unique (which is good) but I couldn't find a way to get that generated timestamp for later use!
Quick Aside: I plan to use the promoted builds plugin to start a script on the target server(s) which then in turn ask Nexus for the new artifact to deploy.
Does anybody know how I can make Maven say the timestamp it generates? Or do I really have to parse the whole output for Uploaded: https://NEXUS_URL/content/repositories/snapshots/GROUP/ARTIFACT/VERSION/ARTIFACT-VERSION-TIMESTAMP-SUFFIX.TYPE?
As far as I know you do need to parse the output of the deploy goal.

How to host a maven repo without Nexus

I have small open-source projects hosted on Github which I want to make available for others via Maven. I have a small webspace where I can host static files. How can I create a repo? Also, I would want to remove old snapshots from there if possible.
Standard maven repository implementations are almost all Tomcat web apps. Each one of them should have a static repository, just as your local repository. The webapp serves to the purpose of searching and management of the artifacts stored in that static repository.
If you want to host the repository with static web access only, you'll have to perform the management manually and provide a static manually generated html page that contains GAV coordinates of all artifacts in the repo. No other user but you could ever upload to the repository unless you give your password or enable anonymous FTP acces.
If maven doesn't try to upload anything to the repo until the deploy phase then this approach is still partly usable, since running a mvn clean deploy should fail.
You can check if is it doable like this (I suppose that you have that projects in your local repo):
upload your local repoistory folder to a URL
for the purpose of testing mirror your central repo to that URL
try to build your project with dependencies from your repo
Open your settings.xml file and under <mirrors> node add:
<mirror>
<url>http://your/url/repo</url>
<mirrorOf>*</mirrorOf>
</mirror>
and see if mvn clean install suceeds. Please feedback.
In this SO answer I have outlined the way I set up my OSS projects which are all hosted in Github. There are actually a number of free services out there you could you when you would like to run an OSS project.
I would recommend publishing to Maven Central, if your plugin is well-tested and expected to bring other people benefits as well. You can use CloudBee's BuildHive as a free Jenkins CI.
A static repo works great, per my experience.
I scp'd up my local repository into a static apache server. Legit repo. Not as easy to maintain as a real repo of course, but quite a bit cheaper if you've already got a plain vanilla web host.
Other than setting the permissions properly (same as required for you to browse the folders), it was a pretty painless procedure.
The only two things I did to make it more reasonable were
1 - Wrote a script to "rm -rf ...." on most of the contents of my local repo so that the only thing I am deploying is those few artifacts that are not available in the general repos.
2 - Tarred it up first before scping to my web host.
Hope this helps.
The guy below did something similar, only using FTP which saves him a lot of hand work if he updates his binaries very often.
http://stuartsierra.com/2009/09/08/run-your-own-maven-repository
I think I know how to do it now. I'm using mvn deploy now to create a local repository on the file system and then I upload it to the webserver. If I'm not wrong, there doesn't even need to be a file listing.
The command I'm using is:
mvn deploy -DaltDeploymentRepository=local::default::file:./repo
This creates/updates the local repository automatically, so the repo can be synced with a server.

How to opensource a Maven plugin?

I have a Maven plugin that I want to share with outside world. Is there an official Maven repository I can deploy this plugin too ? What are the steps involved ?
Any links to documentation much appreciated
I've been reading http://www.sonatype.com/people/2008/11/adding-a-jar-to-a-maven-repository-with-sonatype-nexus/ but this just seems to describe deploying to internal Nexus repository, wheras I want to deploy to an external repo so any user can use it.
I would recommend:
Setting up an account in Github in order to have a place to host your source code.
Setting up an account in Cloudbee's BuildHive. This is a free Jenkins CI for Open Source projects. This will test your project on every push to Github.
Request rights to publish your project to Maven Central.
The bit with the request will take around up to a day normally and then you'll be able to publish your code directly to Maven Central.

Maven verify signatures of downloaded pom/jar files

I was trying to find if there is SSL enabled central repository but there probably isn't. I noticed that there are signatures for every jar and pom file in maven central repository. So at least I'd like to check signatures of all maven downloaded files (pom/jar).
The example from http://repo1.maven.org/maven2/org/apache/ant/ant/1.8.2/:
ant-1.8.2.jar
ant-1.8.2.jar.asc
ant-1.8.2.jar.asc.md5
ant-1.8.2.jar.asc.sha1
ant-1.8.2.jar.md5
ant-1.8.2.jar.sha1
ant-1.8.2.pom
ant-1.8.2.pom.asc
ant-1.8.2.pom.asc.md5
ant-1.8.2.pom.asc.sha1
ant-1.8.2.pom.md5
ant-1.8.2.pom.sha1
I realize that I'll have to import public keys for every repository and I'm fine with that. I guess that public keys for maven central are here https://svn.apache.org/repos/asf/maven/project/KEYS.
There are PLENTY of tutorials on web on how to sign with maven. However I didn't find any information on how to force maven (2 or 3) to verify signatures of downloaded jar/pom files. Is it possible?
(Nexus Professional is not an option)
Thank you for help.
Now, that people seem to realize this is a real security problem (as described in this blog-post (the blog seems down, here is an archived version of the blog)), there is a plugin for verifying PGP signatures. You can verify the signatures for all dependencies of your project with the following command:
mvn org.simplify4u.plugins:pgpverify-maven-plugin:check
Of course, to be 100% sure the plugin is not malicious by itself, you would have to download and verify the source for the plugin from maven central, build it with maven, and execute it. (And this should also be done with all the dependencies and plugins that are needed for the build, recursively.)
Or you use Maven 3.2.3 or above (with a clean repository), which uses TLS for downloading all artefacts. Thus man-in-the-middle attacks are impossible and you get at least the artefacts as they are on maven central.
See also:
related Question and Answer
Sonatype's Blog to this topic
Could you write a bash shell script using GnuPG to verify each sig?
Something like:
for x in *.jar; do gpg --verify "${x}".asc; done
Obviously you would need the public keys for all the sigs before you started.
SSL access to Central is now available for a token payment. From https://blog.sonatype.com/people/2012/10/now-available-ssl-connectivity-to-central/ :
We’re making SSL connectivity to Central available to anyone that downloads open source components regardless of the repository manager.
...
In order to ensure the highest level of performance for those who count on SSL, we are securing the service with a token. You can get a token for your organization simply by providing a $10 donation that will be donated to open source causes.
Assuming you only want to download artifacts w/ valid checksums, one option would be to run the OSS version of Nexus and configure it to have a proxy of central. Then configure your settings.xml to only load from your repo (mirror tag in settings.xml). You can then configure nexus to only allow artifacts that have a valid checksum.

Resources