diff --git a/assemblies/nexus-base-overlay/pom.xml b/assemblies/nexus-base-overlay/pom.xml
new file mode 100644
index 0000000000..6fc45e7bef
--- /dev/null
+++ b/assemblies/nexus-base-overlay/pom.xml
@@ -0,0 +1,269 @@
+
+
+
+
+ 4.0.0
+
+
+ org.sonatype.nexus.assemblies
+ nexus-assemblies
+ 3.60.0-SNAPSHOT
+
+
+ nexus-base-overlay
+ ${project.groupId}:${project.artifactId}
+ pom
+
+
+
+
+ org.sonatype.nexus
+ nexus-main
+ provided
+
+
+
+
+ org.apache.felix
+ org.apache.felix.framework
+ provided
+
+
+
+
+ org.apache.karaf.features
+ framework
+ kar
+
+
+
+ org.apache.karaf.features
+ standard
+ features
+ xml
+
+
+
+ org.sonatype.nexus.assemblies
+ nexus-startup-feature
+ features
+ xml
+
+
+
+
+ org.sonatype.nexus.assemblies
+ nexus-boot-feature
+ features
+ xml
+ runtime
+
+
+
+ org.sonatype.nexus.assemblies
+ nexus-base-feature
+ features
+ xml
+ runtime
+
+
+
+ org.sonatype.nexus
+ nexus-oss-edition
+ features
+ xml
+ runtime
+
+
+
+ org.sonatype.nexus.assemblies
+ nexus-core-feature
+ features
+ xml
+ runtime
+
+
+
+ org.sonatype.nexus
+ nexus-orient
+ features
+ xml
+ runtime
+
+
+
+ org.sonatype.nexus
+ nexus-datastore-mybatis
+ features
+ xml
+ runtime
+
+
+
+
+ org.sonatype.nexus
+ nexus-orient-console
+ provided
+
+
+
+ org.sonatype.nexus
+ nexus2-npm-metadata-export
+ provided
+
+
+
+
+
+
+
+ org.codehaus.gmavenplus
+ gmavenplus-plugin
+
+
+ pax-url-settings
+ initialize
+
+ execute
+
+
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-antrun-plugin
+
+
+ overlay-assembly
+ prepare-package
+
+ run
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ${org.ops4j.pax.logging:pax-logging-api:jar}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-assembly-plugin
+
+
+ archive-assembly
+ package
+
+ single
+
+
+ false
+
+ ${project.basedir}/src/main/assembly/bundle.xml
+
+
+
+
+
+
+
+
+
diff --git a/assemblies/nexus-base-overlay/src/main/assembly/bundle.xml b/assemblies/nexus-base-overlay/src/main/assembly/bundle.xml
new file mode 100644
index 0000000000..1e1c4b9c9d
--- /dev/null
+++ b/assemblies/nexus-base-overlay/src/main/assembly/bundle.xml
@@ -0,0 +1,73 @@
+
+
+
+
+ bundle
+
+
+ zip
+
+
+ false
+
+
+
+ ${project.build.directory}/assembly
+ ${project.build.finalName}
+ 0644
+ 0755
+
+ bin/*
+ data/**
+
+
+
+
+ ${project.build.directory}/assembly
+ ${project.build.finalName}
+ 0644
+ 0755
+ dos
+
+ bin/*.bat
+
+
+
+
+ ${project.build.directory}/assembly
+ ${project.build.finalName}
+ 0755
+ 0755
+ unix
+
+ bin/*
+
+
+ bin/*.bat
+
+
+
+
+ ${project.build.directory}/sonatype-work
+ sonatype-work
+ 0644
+ 0755
+
+
+
+
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/NOTICE.txt b/assemblies/nexus-base-overlay/src/main/resources/overlay/NOTICE.txt
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/NOTICE.txt
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/NOTICE.txt
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/OSS-LICENSE.txt b/assemblies/nexus-base-overlay/src/main/resources/overlay/OSS-LICENSE.txt
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/OSS-LICENSE.txt
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/OSS-LICENSE.txt
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/bin/nexus b/assemblies/nexus-base-overlay/src/main/resources/overlay/bin/nexus
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/bin/nexus
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/bin/nexus
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/bin/nexus.bat b/assemblies/nexus-base-overlay/src/main/resources/overlay/bin/nexus.bat
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/bin/nexus.bat
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/bin/nexus.bat
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/bin/setenv b/assemblies/nexus-base-overlay/src/main/resources/overlay/bin/setenv
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/bin/setenv
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/bin/setenv
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/bin/setenv.bat b/assemblies/nexus-base-overlay/src/main/resources/overlay/bin/setenv.bat
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/bin/setenv.bat
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/bin/setenv.bat
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/deploy/.placeholder b/assemblies/nexus-base-overlay/src/main/resources/overlay/deploy/.placeholder
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/deploy/.placeholder
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/deploy/.placeholder
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/fabric/ehcache.xml b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/fabric/ehcache.xml
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/fabric/ehcache.xml
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/fabric/ehcache.xml
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/fabric/elasticsearch.yml b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/fabric/elasticsearch.yml
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/fabric/elasticsearch.yml
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/fabric/elasticsearch.yml
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/fabric/mybatis.xml b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/fabric/mybatis.xml
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/fabric/mybatis.xml
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/fabric/mybatis.xml
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/fabric/orientdb-security.json b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/fabric/orientdb-security.json
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/fabric/orientdb-security.json
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/fabric/orientdb-security.json
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/jetty/jetty-http.xml b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/jetty/jetty-http.xml
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/jetty/jetty-http.xml
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/jetty/jetty-http.xml
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/jetty/jetty-https.xml b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/jetty/jetty-https.xml
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/jetty/jetty-https.xml
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/jetty/jetty-https.xml
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/jetty/jetty-requestlog.xml b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/jetty/jetty-requestlog.xml
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/jetty/jetty-requestlog.xml
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/jetty/jetty-requestlog.xml
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/jetty/jetty.xml b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/jetty/jetty.xml
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/jetty/jetty.xml
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/jetty/jetty.xml
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/jetty/nexus-web.xml b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/jetty/nexus-web.xml
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/jetty/nexus-web.xml
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/jetty/nexus-web.xml
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/config.properties b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/config.properties
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/config.properties
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/config.properties
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/custom.properties b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/custom.properties
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/custom.properties
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/custom.properties
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/java.util.logging.properties b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/java.util.logging.properties
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/java.util.logging.properties
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/java.util.logging.properties
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/jmx.acl.cfg b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/jmx.acl.cfg
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/jmx.acl.cfg
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/jmx.acl.cfg
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.apache.felix.fileinstall-deploy.cfg b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.apache.felix.fileinstall-deploy.cfg
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.apache.felix.fileinstall-deploy.cfg
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.apache.felix.fileinstall-deploy.cfg
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.apache.karaf.jaas.cfg b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.apache.karaf.jaas.cfg
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.apache.karaf.jaas.cfg
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.apache.karaf.jaas.cfg
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.apache.karaf.kar.cfg b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.apache.karaf.kar.cfg
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.apache.karaf.kar.cfg
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.apache.karaf.kar.cfg
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.apache.karaf.log.cfg b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.apache.karaf.log.cfg
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.apache.karaf.log.cfg
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.apache.karaf.log.cfg
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.apache.karaf.management.cfg b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.apache.karaf.management.cfg
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.apache.karaf.management.cfg
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.apache.karaf.management.cfg
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.apache.karaf.service.acl.command.cfg b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.apache.karaf.service.acl.command.cfg
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.apache.karaf.service.acl.command.cfg
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.apache.karaf.service.acl.command.cfg
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.apache.karaf.shell.cfg b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.apache.karaf.shell.cfg
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.apache.karaf.shell.cfg
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.apache.karaf.shell.cfg
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.ops4j.pax.logging.cfg b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.ops4j.pax.logging.cfg
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.ops4j.pax.logging.cfg
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.ops4j.pax.logging.cfg
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.ops4j.pax.url.mvn.cfg b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.ops4j.pax.url.mvn.cfg
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/org.ops4j.pax.url.mvn.cfg
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/org.ops4j.pax.url.mvn.cfg
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/shell.init.script b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/shell.init.script
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/shell.init.script
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/shell.init.script
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/system.properties b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/system.properties
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/karaf/system.properties
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/karaf/system.properties
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/logback/logback-access.xml b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/logback/logback-access.xml
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/logback/logback-access.xml
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/logback/logback-access.xml
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/logback/logback.xml b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/logback/logback.xml
similarity index 97%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/logback/logback.xml
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/logback/logback.xml
index faa1dc11c5..c9109b4870 100644
--- a/assemblies/nexus-base-template/src/main/resources/overlay/etc/logback/logback.xml
+++ b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/logback/logback.xml
@@ -17,6 +17,11 @@
+
+ ${karaf.data}/log/jvm.log
+ true
+
+
${karaf.data}/log/nexus.log
true
@@ -147,6 +152,7 @@
+
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/nexus-default.properties b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/nexus-default.properties
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/nexus-default.properties
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/nexus-default.properties
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/etc/ssl/.placeholder b/assemblies/nexus-base-overlay/src/main/resources/overlay/etc/ssl/.placeholder
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/etc/ssl/.placeholder
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/etc/ssl/.placeholder
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/public/COPYRIGHT.html b/assemblies/nexus-base-overlay/src/main/resources/overlay/public/COPYRIGHT.html
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/public/COPYRIGHT.html
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/public/COPYRIGHT.html
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/public/OSS-LICENSE.html b/assemblies/nexus-base-overlay/src/main/resources/overlay/public/OSS-LICENSE.html
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/public/OSS-LICENSE.html
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/public/OSS-LICENSE.html
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/public/apple-touch-icon.png b/assemblies/nexus-base-overlay/src/main/resources/overlay/public/apple-touch-icon.png
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/public/apple-touch-icon.png
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/public/apple-touch-icon.png
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/public/browserconfig.xml b/assemblies/nexus-base-overlay/src/main/resources/overlay/public/browserconfig.xml
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/public/browserconfig.xml
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/public/browserconfig.xml
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/public/favicon-16x16.png b/assemblies/nexus-base-overlay/src/main/resources/overlay/public/favicon-16x16.png
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/public/favicon-16x16.png
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/public/favicon-16x16.png
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/public/favicon-32x32.png b/assemblies/nexus-base-overlay/src/main/resources/overlay/public/favicon-32x32.png
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/public/favicon-32x32.png
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/public/favicon-32x32.png
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/public/favicon.ico b/assemblies/nexus-base-overlay/src/main/resources/overlay/public/favicon.ico
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/public/favicon.ico
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/public/favicon.ico
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/public/mstile-144x144.png b/assemblies/nexus-base-overlay/src/main/resources/overlay/public/mstile-144x144.png
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/public/mstile-144x144.png
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/public/mstile-144x144.png
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/public/mstile-150x150.png b/assemblies/nexus-base-overlay/src/main/resources/overlay/public/mstile-150x150.png
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/public/mstile-150x150.png
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/public/mstile-150x150.png
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/public/mstile-310x150.png b/assemblies/nexus-base-overlay/src/main/resources/overlay/public/mstile-310x150.png
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/public/mstile-310x150.png
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/public/mstile-310x150.png
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/public/mstile-310x310.png b/assemblies/nexus-base-overlay/src/main/resources/overlay/public/mstile-310x310.png
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/public/mstile-310x310.png
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/public/mstile-310x310.png
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/public/mstile-70x70.png b/assemblies/nexus-base-overlay/src/main/resources/overlay/public/mstile-70x70.png
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/public/mstile-70x70.png
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/public/mstile-70x70.png
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/public/robots.txt b/assemblies/nexus-base-overlay/src/main/resources/overlay/public/robots.txt
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/public/robots.txt
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/public/robots.txt
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/public/safari-pinned-tab.svg b/assemblies/nexus-base-overlay/src/main/resources/overlay/public/safari-pinned-tab.svg
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/public/safari-pinned-tab.svg
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/public/safari-pinned-tab.svg
diff --git a/assemblies/nexus-base-template/src/main/resources/overlay/system/settings.xml b/assemblies/nexus-base-overlay/src/main/resources/overlay/system/settings.xml
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/overlay/system/settings.xml
rename to assemblies/nexus-base-overlay/src/main/resources/overlay/system/settings.xml
diff --git a/assemblies/nexus-base-template/src/main/resources/sonatype-work/nexus3/clean_cache b/assemblies/nexus-base-overlay/src/main/resources/sonatype-work/nexus3/clean_cache
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/sonatype-work/nexus3/clean_cache
rename to assemblies/nexus-base-overlay/src/main/resources/sonatype-work/nexus3/clean_cache
diff --git a/assemblies/nexus-base-template/src/main/resources/sonatype-work/nexus3/log/.placeholder b/assemblies/nexus-base-overlay/src/main/resources/sonatype-work/nexus3/log/.placeholder
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/sonatype-work/nexus3/log/.placeholder
rename to assemblies/nexus-base-overlay/src/main/resources/sonatype-work/nexus3/log/.placeholder
diff --git a/assemblies/nexus-base-template/src/main/resources/sonatype-work/nexus3/tmp/.placeholder b/assemblies/nexus-base-overlay/src/main/resources/sonatype-work/nexus3/tmp/.placeholder
similarity index 100%
rename from assemblies/nexus-base-template/src/main/resources/sonatype-work/nexus3/tmp/.placeholder
rename to assemblies/nexus-base-overlay/src/main/resources/sonatype-work/nexus3/tmp/.placeholder
diff --git a/assemblies/nexus-base-template/pom.xml b/assemblies/nexus-base-template/pom.xml
index fefd16fa02..a17aec2a11 100644
--- a/assemblies/nexus-base-template/pom.xml
+++ b/assemblies/nexus-base-template/pom.xml
@@ -29,6 +29,20 @@
pom
+
+
+ org.sonatype.nexus.assemblies
+ nexus-base-overlay
+ zip
+ runtime
+
+
+ *
+ *
+
+
+
+
@@ -251,42 +265,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -353,14 +331,11 @@
-
-
-
-
-
-
-
-
+
+
+
diff --git a/assemblies/pom.xml b/assemblies/pom.xml
index d7b7aeeed8..b596934f17 100644
--- a/assemblies/pom.xml
+++ b/assemblies/pom.xml
@@ -33,6 +33,7 @@
nexus-boot-feature
nexus-base-feature
nexus-core-feature
+ nexus-base-overlay
nexus-base-template
diff --git a/components/nexus-cleanup-config/src/main/java/org/sonatype/nexus/cleanup/config/CleanupPolicyConstants.java b/components/nexus-cleanup-config/src/main/java/org/sonatype/nexus/cleanup/config/CleanupPolicyConstants.java
index 9c9eef68f8..70e9a6abdd 100644
--- a/components/nexus-cleanup-config/src/main/java/org/sonatype/nexus/cleanup/config/CleanupPolicyConstants.java
+++ b/components/nexus-cleanup-config/src/main/java/org/sonatype/nexus/cleanup/config/CleanupPolicyConstants.java
@@ -29,5 +29,9 @@ public interface CleanupPolicyConstants
String LAST_DOWNLOADED_KEY = "lastDownloaded";
+ String RETAIN_KEY = "retain";
+
+ String RETAIN_SORT_BY_KEY = "sortBy";
+
String REGEX_KEY = "regex";
}
diff --git a/components/nexus-cleanup-config/src/main/java/org/sonatype/nexus/cleanup/config/DefaultCleanupPolicyConfiguration.java b/components/nexus-cleanup-config/src/main/java/org/sonatype/nexus/cleanup/config/DefaultCleanupPolicyConfiguration.java
index 13b63197f6..747909edb2 100644
--- a/components/nexus-cleanup-config/src/main/java/org/sonatype/nexus/cleanup/config/DefaultCleanupPolicyConfiguration.java
+++ b/components/nexus-cleanup-config/src/main/java/org/sonatype/nexus/cleanup/config/DefaultCleanupPolicyConfiguration.java
@@ -23,6 +23,8 @@
import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.LAST_BLOB_UPDATED_KEY;
import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.LAST_DOWNLOADED_KEY;
import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.REGEX_KEY;
+import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.RETAIN_KEY;
+import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.RETAIN_SORT_BY_KEY;
/**
* Defines which default cleanup policy fields to display.
@@ -36,9 +38,14 @@ public class DefaultCleanupPolicyConfiguration
{
@Override
public Map getConfiguration() {
- return ImmutableMap.of(LAST_BLOB_UPDATED_KEY, true,
- LAST_DOWNLOADED_KEY, true,
- IS_PRERELEASE_KEY, false,
- REGEX_KEY, false);
+ return ImmutableMap.builder()
+ .put(LAST_BLOB_UPDATED_KEY, true)
+ .put(LAST_DOWNLOADED_KEY, true)
+ .put(IS_PRERELEASE_KEY, false)
+ .put(REGEX_KEY, false)
+ //disabling retain-n properties by default
+ .put(RETAIN_KEY, false)
+ .put(RETAIN_SORT_BY_KEY, false)
+ .build();
}
}
diff --git a/components/nexus-cleanup-config/src/main/java/org/sonatype/nexus/cleanup/storage/SortType.java b/components/nexus-cleanup-config/src/main/java/org/sonatype/nexus/cleanup/storage/SortType.java
new file mode 100644
index 0000000000..b40d3af0c9
--- /dev/null
+++ b/components/nexus-cleanup-config/src/main/java/org/sonatype/nexus/cleanup/storage/SortType.java
@@ -0,0 +1,19 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2008-present Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.cleanup.storage;
+
+public enum SortType
+{
+ VERSION,
+ DATE
+}
diff --git a/components/nexus-cleanup/src/main/java/org/sonatype/nexus/cleanup/internal/rest/CleanupPolicyResource.java b/components/nexus-cleanup/src/main/java/org/sonatype/nexus/cleanup/internal/rest/CleanupPolicyResource.java
index 67519bea8b..3852698125 100644
--- a/components/nexus-cleanup/src/main/java/org/sonatype/nexus/cleanup/internal/rest/CleanupPolicyResource.java
+++ b/components/nexus-cleanup/src/main/java/org/sonatype/nexus/cleanup/internal/rest/CleanupPolicyResource.java
@@ -23,6 +23,7 @@
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
+import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Provider;
@@ -52,6 +53,7 @@
import org.sonatype.nexus.cleanup.storage.CleanupPolicy;
import org.sonatype.nexus.cleanup.storage.CleanupPolicyCriteria;
import org.sonatype.nexus.cleanup.storage.CleanupPolicyPreviewXO;
+import org.sonatype.nexus.cleanup.storage.CleanupPolicyReleaseType;
import org.sonatype.nexus.cleanup.storage.CleanupPolicyStorage;
import org.sonatype.nexus.common.event.EventManager;
import org.sonatype.nexus.extdirect.model.PagedResponse;
@@ -83,6 +85,8 @@
import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.LAST_BLOB_UPDATED_KEY;
import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.LAST_DOWNLOADED_KEY;
import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.REGEX_KEY;
+import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.RETAIN_KEY;
+import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.RETAIN_SORT_BY_KEY;
import static org.sonatype.nexus.cleanup.internal.rest.CleanupPolicyResource.RESOURCE_URI;
import static org.sonatype.nexus.cleanup.storage.CleanupPolicy.ALL_FORMATS;
import static org.sonatype.nexus.cleanup.storage.CleanupPolicyReleaseType.PRERELEASES;
@@ -178,6 +182,9 @@ public CleanupPolicyXO add(@Valid final CleanupPolicyXO cleanupPolicyXO) {
if (!this.formatNames.contains(cleanupPolicyXO.getFormat())) {
throw new ValidationErrorsException("format", "specified format " + cleanupPolicyXO.getFormat() + " is not valid.");
}
+
+ validateRetainAttributes(cleanupPolicyXO);
+
return CleanupPolicyXO.fromCleanupPolicy(cleanupPolicyStorage.add(toCleanupPolicy(cleanupPolicyXO)), 0);
}
@@ -222,6 +229,8 @@ public CleanupPolicyXO edit(
throw new ValidationErrorsException("format", "You cannot change the format of a policy that is in use.");
}
+ validateRetainAttributes(cleanupPolicyXO);
+
cleanupPolicy.setNotes(cleanupPolicyXO.getNotes());
cleanupPolicy.setFormat(cleanupPolicyXO.getFormat());
cleanupPolicy.setCriteria(toCriteriaMap(cleanupPolicyXO));
@@ -300,43 +309,49 @@ public PageResult previewContent(PreviewRequestXO request)
}
}
- @POST
+ @GET
@Path("preview/components/csv")
@RequiresAuthentication
@RequiresPermissions("nexus:*")
@Produces(APPLICATION_OCTET_STREAM)
@Timed
- public Response previewContentCsv(final PreviewRequestXO request)
+ public Response previewContentCsv(
+ @QueryParam("name") @Nullable String name,
+ @QueryParam("repository") String repositoryName,
+ @QueryParam("criteriaLastBlobUpdated") @Nullable Integer criteriaLastBlobUpdated,
+ @QueryParam("criteriaLastDownloaded") @Nullable Integer criteriaLastDownloaded,
+ @QueryParam("criteriaReleaseType") @Nullable CleanupPolicyReleaseType criteriaReleaseType,
+ @QueryParam("criteriaAssetRegex") @Nullable String criteriaAssetRegex
+ )
{
+
if (!isDatastoreEnabled || !isPreviewEnabled) {
return Response.status(Status.NOT_FOUND).build();
}
Map cleanupDryRunXO = new HashMap<>();
cleanupDryRunXO.put(STARTED_AT_IN_MILLISECONDS, System.currentTimeMillis());
- Repository repository = repositoryManager.get(request.getRepository());
+ Repository repository = repositoryManager.get(repositoryName);
if (repository == null) {
- throw new NotFoundException("Repository " + request.getRepository() + " not found.");
+ throw new NotFoundException("Repository " + repositoryName + " not found.");
}
StreamingOutput streamingOutput = output -> {
CleanupPolicyPreviewXO xo = new CleanupPolicyPreviewXO();
- xo.setRepositoryName(request.getRepository());
+ xo.setRepositoryName(repositoryName);
xo.setCriteria(new CleanupPolicyCriteria());
- xo.getCriteria().setLastBlobUpdated(request.getCriteriaLastBlobUpdated());
- xo.getCriteria().setLastDownloaded(request.getCriteriaLastDownloaded());
- xo.getCriteria().setReleaseType(request.getCriteriaReleaseType());
- xo.getCriteria().setRegex(request.getCriteriaAssetRegex());
-
- QueryOptions options = new QueryOptions(request.getFilter(), "name", "asc", 0, null);
+ xo.getCriteria().setLastBlobUpdated(criteriaLastBlobUpdated);
+ xo.getCriteria().setLastDownloaded(criteriaLastDownloaded);
+ xo.getCriteria().setReleaseType(criteriaReleaseType);
+ xo.getCriteria().setRegex(criteriaAssetRegex);
Stream searchResultsStream =
- cleanupPreviewHelper.get().getSearchResultsStream(xo, repository, options);
+ cleanupPreviewHelper.get().getSearchResultsStream(xo, repository, null);
csvCleanupPreviewContentWriter.write(repository, searchResultsStream, output);
cleanupDryRunXO.put(FINISHED_AT_IN_MILLISECONDS, System.currentTimeMillis());
eventManager.post(new CleanupDryRunEvent(cleanupDryRunXO));
};
- String policyName = request.getName() == null ? "CleanupPreview" : request.getName();
+ String policyName = name == null ? "CleanupPreview" : name;
String filename = policyName + "-" +
repository.getName() + "-" +
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss")) +
@@ -346,6 +361,16 @@ public Response previewContentCsv(final PreviewRequestXO request)
.build();
}
+ private void validateRetainAttributes(final CleanupPolicyXO cleanupPolicyXO) {
+ if (cleanupPolicyXO.getRetain() != null && cleanupPolicyXO.getSortBy() == null) {
+ throw new ValidationErrorsException("sortBy", "sortBy should be defined if retain is set");
+ }
+
+ if (cleanupPolicyXO.getSortBy() != null && cleanupPolicyXO.getRetain() == null) {
+ throw new ValidationErrorsException("retain", "retain should be defined if sortBy is set");
+ }
+ }
+
private CleanupPolicy toCleanupPolicy(final CleanupPolicyXO cleanupPolicyXO) {
CleanupPolicy policy = cleanupPolicyStorage.newCleanupPolicy();
@@ -378,6 +403,14 @@ private Map toCriteriaMap(final CleanupPolicyXO cleanupPolicyXO)
handleCriteria(cleanupFormatConfiguration, criteriaMap, IS_PRERELEASE_KEY,
PRERELEASES.equals(cleanupPolicyXO.getCriteriaReleaseType()), "Release type", cleanupPolicyXO.getFormat());
}
+ if (cleanupPolicyXO.getRetain() != null) {
+ handleCriteria(cleanupFormatConfiguration, criteriaMap, RETAIN_KEY,
+ cleanupPolicyXO.getRetain(), "Retain components", cleanupPolicyXO.getFormat());
+ }
+ if (cleanupPolicyXO.getSortBy() != null) {
+ handleCriteria(cleanupFormatConfiguration, criteriaMap, RETAIN_SORT_BY_KEY,
+ cleanupPolicyXO.getSortBy(), "Retain sort by", cleanupPolicyXO.getFormat());
+ }
return criteriaMap;
}
diff --git a/components/nexus-cleanup/src/main/java/org/sonatype/nexus/cleanup/internal/rest/CleanupPolicyXO.java b/components/nexus-cleanup/src/main/java/org/sonatype/nexus/cleanup/internal/rest/CleanupPolicyXO.java
index 72430d81ad..ae0be1d29a 100644
--- a/components/nexus-cleanup/src/main/java/org/sonatype/nexus/cleanup/internal/rest/CleanupPolicyXO.java
+++ b/components/nexus-cleanup/src/main/java/org/sonatype/nexus/cleanup/internal/rest/CleanupPolicyXO.java
@@ -14,21 +14,25 @@
import java.util.Map;
import java.util.concurrent.TimeUnit;
-
+import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import org.sonatype.nexus.cleanup.storage.CleanupPolicy;
import org.sonatype.nexus.cleanup.storage.CleanupPolicyReleaseType;
+import org.sonatype.nexus.cleanup.storage.SortType;
import org.sonatype.nexus.cleanup.storage.config.CleanupPolicyAssetNamePattern;
import org.sonatype.nexus.cleanup.storage.config.UniqueCleanupPolicyName;
+import org.sonatype.nexus.validation.constraint.AnyOf;
import org.sonatype.nexus.validation.group.Create;
import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.IS_PRERELEASE_KEY;
import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.LAST_BLOB_UPDATED_KEY;
import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.LAST_DOWNLOADED_KEY;
import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.REGEX_KEY;
+import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.RETAIN_KEY;
+import static org.sonatype.nexus.cleanup.config.CleanupPolicyConstants.RETAIN_SORT_BY_KEY;
import static org.sonatype.nexus.cleanup.storage.CleanupPolicy.ALL_FORMATS;
import static org.sonatype.nexus.cleanup.storage.CleanupPolicy.ALL_CLEANUP_POLICY_FORMAT;
import static org.sonatype.nexus.cleanup.storage.CleanupPolicyReleaseType.PRERELEASES;
@@ -56,6 +60,12 @@ public class CleanupPolicyXO
private Long criteriaLastDownloaded; // days
+ @Min(value = 1, message = "retain must be > 0")
+ private Integer retain;
+
+ @AnyOf(enumClass = SortType.class, parameterName = "sortBy")
+ private String sortBy;
+
private CleanupPolicyReleaseType criteriaReleaseType;
@CleanupPolicyAssetNamePattern
@@ -87,6 +97,14 @@ public Long getCriteriaLastDownloaded() {
return criteriaLastDownloaded;
}
+ public Integer getRetain() {
+ return retain;
+ }
+
+ public String getSortBy() {
+ return sortBy;
+ }
+
public String getCriteriaAssetRegex() {
return criteriaAssetRegex;
}
@@ -119,6 +137,14 @@ public void setCriteriaLastDownloaded(final Long criteriaLastDownloaded) {
this.criteriaLastDownloaded = criteriaLastDownloaded;
}
+ public void setRetain(final Integer retain) {
+ this.retain = retain;
+ }
+
+ public void setSortBy(final String sortBy) {
+ this.sortBy = sortBy;
+ }
+
public void setCriteriaReleaseType(final CleanupPolicyReleaseType criteriaReleaseType) {
this.criteriaReleaseType = criteriaReleaseType;
}
@@ -135,11 +161,23 @@ public static CleanupPolicyXO fromCleanupPolicy(final CleanupPolicy cleanupPolic
xo.setCriteriaAssetRegex(cleanupPolicy.getCriteria().get(REGEX_KEY));
xo.setCriteriaLastBlobUpdated(toDays(getNullableLong(cleanupPolicy.getCriteria(), LAST_BLOB_UPDATED_KEY)));
xo.setCriteriaLastDownloaded(toDays(getNullableLong(cleanupPolicy.getCriteria(), LAST_DOWNLOADED_KEY)));
+ xo.setRetain(getNullableInt(cleanupPolicy.getCriteria() , RETAIN_KEY));
+ xo.setSortBy(cleanupPolicy.getCriteria().getOrDefault(RETAIN_SORT_BY_KEY , null));
xo.setCriteriaReleaseType(getNullableReleaseType(cleanupPolicy.getCriteria()));
xo.setInUseCount(inUseCount);
return xo;
}
+ private static Integer getNullableInt(final Map map, final String key) {
+ String value = map.get(key);
+
+ if (value == null) {
+ return null;
+ }
+
+ return Integer.valueOf(value);
+ }
+
private static Long getNullableLong(final Map map, final String key) {
String value = map.get(key);
diff --git a/components/nexus-cleanup/src/test/java/org/sonatype/nexus/cleanup/internal/rest/CleanupPolicyResourceTest.java b/components/nexus-cleanup/src/test/java/org/sonatype/nexus/cleanup/internal/rest/CleanupPolicyResourceTest.java
index 5d143520f0..2d73802d8b 100644
--- a/components/nexus-cleanup/src/test/java/org/sonatype/nexus/cleanup/internal/rest/CleanupPolicyResourceTest.java
+++ b/components/nexus-cleanup/src/test/java/org/sonatype/nexus/cleanup/internal/rest/CleanupPolicyResourceTest.java
@@ -66,15 +66,11 @@ public class CleanupPolicyResourceTest
private CleanupPolicyResource underTest;
- private PreviewRequestXO request;
-
private final String repositoryName = "test-repo";
@Before
public void setUp() throws Exception {
when(cleanupFormatConfigurationMap.get("default")).thenReturn(mock(CleanupPolicyConfiguration.class));
- request = new PreviewRequestXO();
- request.setRepository(repositoryName);
Repository repository = mock(Repository.class);
when(repositoryManager.get(repositoryName)).thenReturn(repository);
when(repository.getName()).thenReturn(repositoryName);
@@ -86,7 +82,7 @@ public void testPreviewContentCsv() {
new CleanupPolicyResource(cleanupPolicyStorage, formats, cleanupFormatConfigurationMap, cleanupPreviewHelper,
repositoryManager, eventManager, true, true, csvCleanupPreviewContentWriter);
- Response response = underTest.previewContentCsv(request);
+ Response response = underTest.previewContentCsv(null, repositoryName, null, null, null, null);
assertThat(response.getStatus(), is(200));
String contentDisposition = response.getHeaderString("Content-Disposition");
@@ -95,8 +91,7 @@ public void testPreviewContentCsv() {
assertThat(contentDisposition, startsWith(expectedPrefix));
assertThat(contentDisposition, endsWith(".csv"));
- request.setName("policy-name");
- response = underTest.previewContentCsv(request);
+ response = underTest.previewContentCsv("policy-name", repositoryName, null, null, null, null);
assertThat(response.getStatus(), is(200));
contentDisposition = response.getHeaderString("Content-Disposition");
@@ -112,7 +107,7 @@ public void testNotFoundResponseForOrient() {
new CleanupPolicyResource(cleanupPolicyStorage, formats, cleanupFormatConfigurationMap, cleanupPreviewHelper,
repositoryManager, eventManager, false, true, csvCleanupPreviewContentWriter);
- Response response = underTest.previewContentCsv(request);
+ Response response = underTest.previewContentCsv(null, repositoryName, null, null, null, null);
assertThat(response.getStatus(), is(404));
}
diff --git a/components/nexus-core/src/main/java/org/sonatype/nexus/internal/atlas/SystemInformationGeneratorImpl.groovy b/components/nexus-core/src/main/java/org/sonatype/nexus/internal/atlas/SystemInformationGeneratorImpl.groovy
index 697376b5ce..5517ba936b 100644
--- a/components/nexus-core/src/main/java/org/sonatype/nexus/internal/atlas/SystemInformationGeneratorImpl.groovy
+++ b/components/nexus-core/src/main/java/org/sonatype/nexus/internal/atlas/SystemInformationGeneratorImpl.groovy
@@ -34,6 +34,7 @@ import org.eclipse.sisu.Parameters
import org.osgi.framework.BundleContext
import static com.google.common.base.Preconditions.checkNotNull
+import static org.sonatype.nexus.common.text.Strings2.MASK
/**
* Default {@link SystemInformationGenerator}.
@@ -60,12 +61,12 @@ class SystemInformationGeneratorImpl
private final NodeAccess nodeAccess
- private final DeploymentAccess deploymentAccess;
+ private final DeploymentAccess deploymentAccess
static final Map UNAVAILABLE = ['unavailable': true].asImmutable()
- static final List SENSITIVE_FIELD_NAMES = ['password', 'secret', 'token'].asImmutable()
-
+ static final List SENSITIVE_FIELD_NAMES =
+ ['password', 'secret', 'token', 'sign', 'auth', 'cred', 'key', 'pass'].asImmutable()
@Inject
SystemInformationGeneratorImpl(final ApplicationDirectories applicationDirectories,
final ApplicationVersion applicationVersion,
@@ -214,6 +215,9 @@ class SystemInformationGeneratorImpl
if (key.toLowerCase(Locale.US).contains(sensitiveName)) {
value = Strings2.mask(value)
}
+ if (key == "sun.java.command" && value.contains(sensitiveName)) {
+ value = value.replaceAll(sensitiveName + "=\\S*", sensitiveName + "=" + MASK)
+ }
}
return [key, value]
}.sort()
diff --git a/components/nexus-core/src/main/java/org/sonatype/nexus/internal/atlas/customizers/JmxCustomizer.groovy b/components/nexus-core/src/main/java/org/sonatype/nexus/internal/atlas/customizers/JmxCustomizer.groovy
index bf71dc3b76..e527722c1a 100644
--- a/components/nexus-core/src/main/java/org/sonatype/nexus/internal/atlas/customizers/JmxCustomizer.groovy
+++ b/components/nexus-core/src/main/java/org/sonatype/nexus/internal/atlas/customizers/JmxCustomizer.groovy
@@ -27,6 +27,7 @@ import org.sonatype.nexus.supportzip.SupportBundleCustomizer
import groovy.json.JsonBuilder
+import static org.sonatype.nexus.common.text.Strings2.MASK
import static org.sonatype.nexus.supportzip.SupportBundle.ContentSource.Priority.OPTIONAL
import static org.sonatype.nexus.supportzip.SupportBundle.ContentSource.Type.JMX
@@ -45,6 +46,9 @@ class JmxCustomizer
@Named('platform')
MBeanServer server
+ private static final List SENSITIVE_FIELD_NAMES =
+ ['password', 'secret', 'token', 'sign', 'auth', 'cred', 'key', 'pass'].asImmutable()
+
@Override
void customize(final SupportBundle supportBundle) {
// add jmx.json
@@ -100,6 +104,14 @@ class JmxCustomizer
// TODO: Cope with password-like fields where we can detect .*password.* or something?
+ if (value instanceof String) {
+ SENSITIVE_FIELD_NAMES.each {sensitiveName ->
+ if (value.contains(sensitiveName)) {
+ value = value.replaceAll(sensitiveName + "=\\S*", sensitiveName + "=" + MASK)
+ }
+ }
+ }
+
def type = value.getClass()
log.trace "Rendering type: $type"
diff --git a/components/nexus-core/src/main/java/org/sonatype/nexus/internal/atlas/customizers/JvmLogCustomizer.java b/components/nexus-core/src/main/java/org/sonatype/nexus/internal/atlas/customizers/JvmLogCustomizer.java
new file mode 100644
index 0000000000..a1665d469d
--- /dev/null
+++ b/components/nexus-core/src/main/java/org/sonatype/nexus/internal/atlas/customizers/JvmLogCustomizer.java
@@ -0,0 +1,95 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2008-present Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.internal.atlas.customizers;
+
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+import javax.inject.Inject;
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.sonatype.goodies.common.ComponentSupport;
+import org.sonatype.nexus.common.log.LogManager;
+import org.sonatype.nexus.supportzip.GeneratedContentSourceSupport;
+import org.sonatype.nexus.supportzip.SupportBundle;
+import org.sonatype.nexus.supportzip.SupportBundleCustomizer;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.sonatype.nexus.common.text.Strings2.MASK;
+import static org.sonatype.nexus.supportzip.SupportBundle.ContentSource.Priority.LOW;
+import static org.sonatype.nexus.supportzip.SupportBundle.ContentSource.Type.LOG;
+
+/**
+ * Adds jvm log file to support bundle.
+ * Masks sensitive data passed as JVM arguments.
+ */
+@Named
+@Singleton
+public class JvmLogCustomizer
+ extends ComponentSupport
+ implements SupportBundleCustomizer
+{
+ private static final List SENSITIVE_FIELD_NAMES =
+ Arrays.asList("password", "secret", "token", "sign", "auth", "cred", "key", "pass");
+
+ private final LogManager logManager;
+
+ @Inject
+ public JvmLogCustomizer(final LogManager logManager) {
+ this.logManager = checkNotNull(logManager);
+ }
+
+ @Override
+ public void customize(final SupportBundle supportBundle) {
+ supportBundle.add(new GeneratedContentSourceSupport(LOG, "log/jvm.log", LOW)
+ {
+ @Override
+ protected void generate(final File file) {
+ File logFile = logManager.getLogFile("jvm.log");
+
+ if (logFile != null) {
+ try (BufferedReader reader = new BufferedReader(new FileReader(logFile));
+ BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
+
+ String line;
+ while ((line = reader.readLine()) != null) {
+ String redactedLine = maybeMaskSensitiveData(line);
+ writer.write(redactedLine);
+ writer.newLine();
+ }
+ } catch (IOException e) {
+ log.debug("Unable to include jvm.log file", e);
+ }
+ }
+ else {
+ log.debug("Not including missing jvm.log file");
+ }
+ }
+
+ private String maybeMaskSensitiveData(final String input) {
+ String result = input;
+ for (String name : SENSITIVE_FIELD_NAMES) {
+ result = result.replaceAll(name + "=\\S*", name + "=" + MASK);
+ }
+ return result;
+ }
+ });
+ }
+}
diff --git a/components/nexus-core/src/main/java/org/sonatype/nexus/internal/atlas/customizers/LogCustomizer.groovy b/components/nexus-core/src/main/java/org/sonatype/nexus/internal/atlas/customizers/LogCustomizer.groovy
index 8625b3cc2a..4143b05f38 100644
--- a/components/nexus-core/src/main/java/org/sonatype/nexus/internal/atlas/customizers/LogCustomizer.groovy
+++ b/components/nexus-core/src/main/java/org/sonatype/nexus/internal/atlas/customizers/LogCustomizer.groovy
@@ -85,7 +85,6 @@ class LogCustomizer
maybeIncludeFile new File(applicationDirectories.workDirectory, 'log/karaf.log'), 'log', LOW
maybeIncludeFile new File(applicationDirectories.workDirectory, 'log/request.log'), 'log', LOW
- maybeIncludeFile new File(applicationDirectories.workDirectory, 'log/jvm.log'), 'log', LOW
maybeIncludeFile new File(applicationDirectories.workDirectory, 'log/outbound-request.log'), 'log', LOW
logManager.getLogFor("clusterlogfile").ifPresent { maybeIncludeFile new File(applicationDirectories.workDirectory, 'log/' + it), 'log', LOW }
}
diff --git a/components/nexus-core/src/main/java/org/sonatype/nexus/internal/httpclient/DefaultsCustomizer.java b/components/nexus-core/src/main/java/org/sonatype/nexus/internal/httpclient/DefaultsCustomizer.java
index 756954253c..21120ca832 100644
--- a/components/nexus-core/src/main/java/org/sonatype/nexus/internal/httpclient/DefaultsCustomizer.java
+++ b/components/nexus-core/src/main/java/org/sonatype/nexus/internal/httpclient/DefaultsCustomizer.java
@@ -20,6 +20,7 @@
import org.sonatype.goodies.common.ComponentSupport;
import org.sonatype.goodies.common.Time;
import org.sonatype.nexus.httpclient.HttpClientPlan;
+import org.sonatype.nexus.utils.httpclient.UserAgentGenerator;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.impl.client.StandardHttpRequestRetryHandler;
diff --git a/components/nexus-core/src/main/java/org/sonatype/nexus/internal/httpclient/UserAgentGenerator.java b/components/nexus-core/src/main/java/org/sonatype/nexus/utils/httpclient/UserAgentGenerator.java
similarity index 76%
rename from components/nexus-core/src/main/java/org/sonatype/nexus/internal/httpclient/UserAgentGenerator.java
rename to components/nexus-core/src/main/java/org/sonatype/nexus/utils/httpclient/UserAgentGenerator.java
index ef6fdb4d04..92f8c86544 100644
--- a/components/nexus-core/src/main/java/org/sonatype/nexus/internal/httpclient/UserAgentGenerator.java
+++ b/components/nexus-core/src/main/java/org/sonatype/nexus/utils/httpclient/UserAgentGenerator.java
@@ -10,13 +10,14 @@
* of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
* Eclipse Foundation. All other trademarks are the property of their respective owners.
*/
-package org.sonatype.nexus.internal.httpclient;
+package org.sonatype.nexus.utils.httpclient;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import org.sonatype.goodies.common.ComponentSupport;
+import org.sonatype.nexus.capability.CapabilityReference;
import org.sonatype.nexus.common.app.ApplicationVersion;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -29,8 +30,14 @@
@Named
@Singleton
public class UserAgentGenerator
- extends ComponentSupport
+ extends ComponentSupport
{
+ private static final String PAU = "; pau)";
+
+ private static final String PAE = "; pae)";
+
+ private static final String PAD = "; pad)";
+
private final ApplicationVersion applicationVersion;
private String value;
@@ -59,4 +66,17 @@ public String generate() {
return value;
}
+
+ public String buildUserAgentForAnalytics(CapabilityReference capabilityReference) {
+ String ua = generate();
+ if (capabilityReference == null) {
+ return ua.replace(")", PAU);
+ }
+ else if (capabilityReference.context().isEnabled()) {
+ return ua.replace(")", PAE);
+ }
+ else {
+ return ua.replace(")", PAD);
+ }
+ }
}
diff --git a/components/nexus-core/src/test/java/org/sonatype/nexus/internal/atlas/SystemInformationGeneratorImplTest.groovy b/components/nexus-core/src/test/java/org/sonatype/nexus/internal/atlas/SystemInformationGeneratorImplTest.groovy
index 18ad3774e4..983fb68c72 100644
--- a/components/nexus-core/src/test/java/org/sonatype/nexus/internal/atlas/SystemInformationGeneratorImplTest.groovy
+++ b/components/nexus-core/src/test/java/org/sonatype/nexus/internal/atlas/SystemInformationGeneratorImplTest.groovy
@@ -26,6 +26,7 @@ import org.osgi.framework.BundleContext
import spock.lang.Specification
import static org.hamcrest.MatcherAssert.assertThat
+import static org.hamcrest.core.IsEqual.equalTo
import static org.hamcrest.text.IsEmptyString.isEmptyString
import static org.hamcrest.core.IsNot.not
@@ -143,4 +144,25 @@ class SystemInformationGeneratorImplTest
assertThat(systemEnvs.get('AZURE_TOKEN'), not('azureTokenValue'))
assertThat(systemEnvs.get('MY_PASSWORD_FOR_NXRM'), not('admin123'))
}
+
+ def "jvm variable sensitive data is hidden"() {
+ given:
+ def generator = new SystemInformationGeneratorImpl(
+ Mock(ApplicationDirectories.class),
+ Mock(ApplicationVersion.class),
+ Mock(ApplicationLicense.class),
+ Collections.singletonMap("sun.java.command", "test.variable=1 -Dnexus.password=nxrm -Dnexus.token=123456"),
+ Mock(BundleContext.class),
+ Mock(BundleService.class),
+ Mock(NodeAccess.class),
+ Mock(DeploymentAccess.class))
+
+ when:
+ def report = generator.report()
+
+ then:
+ def nexusProps = report.get("nexus-properties")
+ assertThat(nexusProps.get("sun.java.command"),
+ equalTo("test.variable=1 -Dnexus.password=**** -Dnexus.token=****"))
+ }
}
diff --git a/components/nexus-core/src/test/java/org/sonatype/nexus/internal/atlas/customizers/JvmLogCustomizerTest.java b/components/nexus-core/src/test/java/org/sonatype/nexus/internal/atlas/customizers/JvmLogCustomizerTest.java
new file mode 100644
index 0000000000..cef89b003e
--- /dev/null
+++ b/components/nexus-core/src/test/java/org/sonatype/nexus/internal/atlas/customizers/JvmLogCustomizerTest.java
@@ -0,0 +1,92 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2008-present Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.internal.atlas.customizers;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.time.ZonedDateTime;
+import java.util.List;
+
+import org.sonatype.goodies.testsupport.TestSupport;
+import org.sonatype.nexus.common.app.ApplicationDirectories;
+import org.sonatype.nexus.common.log.LogManager;
+import org.sonatype.nexus.supportzip.SupportBundle;
+import org.sonatype.nexus.supportzip.SupportBundle.ContentSource;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+import org.mockito.Mock;
+
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.when;
+import static org.sonatype.nexus.common.io.DirectoryHelper.mkdir;
+
+public class JvmLogCustomizerTest
+ extends TestSupport
+{
+ @Rule
+ public TemporaryFolder temporaryWorkDirectory = new TemporaryFolder();
+
+ @Mock
+ private LogManager mockLogManager;
+
+ @Mock
+ private ApplicationDirectories mockApplicationDirectories;
+
+ private JvmLogCustomizer underTest;
+
+
+ @Before
+ public void setup() throws IOException {
+ when(mockApplicationDirectories.getWorkDirectory()).thenReturn(temporaryWorkDirectory.getRoot());
+ mkdir(temporaryWorkDirectory.getRoot(), "log");
+ underTest = new JvmLogCustomizer(mockLogManager);
+ }
+
+ @Test
+ public void customizeJvmLog() throws Exception {
+ File file = createLogFile();
+ when(mockLogManager.getLogFile(anyString())).thenReturn(file);
+ try(FileWriter writer = new FileWriter(file)) {
+ writer.write("-Dnexus.password=nxrm -Dnexus.token=123");
+ }
+ SupportBundle supportBundle = new SupportBundle();
+ underTest.customize(supportBundle);
+
+ List list = supportBundle.getSources();
+ assertThat(list.size(), equalTo(1));
+
+ ContentSource contentSource = list.get(0);
+ contentSource.prepare();
+
+ try(BufferedReader reader = new BufferedReader(new InputStreamReader(contentSource.getContent()))) {
+ assertThat(reader.readLine(), equalTo("-Dnexus.password=**** -Dnexus.token=****"));
+ }
+ }
+
+
+ private File createLogFile() throws IOException {
+ File file = new File(temporaryWorkDirectory.getRoot(), "/log/jvm.log");
+ file.createNewFile();
+ file.setLastModified(ZonedDateTime.now().minusMinutes(0L).toInstant().toEpochMilli());
+ return file;
+ }
+
+}
diff --git a/components/nexus-repository-services/src/main/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupport.java b/components/nexus-repository-services/src/main/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupport.java
index 89d47769b9..fc60045c16 100644
--- a/components/nexus-repository-services/src/main/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupport.java
+++ b/components/nexus-repository-services/src/main/java/org/sonatype/nexus/repository/proxy/ProxyFacetSupport.java
@@ -17,6 +17,7 @@
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.time.Duration;
+import java.util.Arrays;
import java.util.Map;
import java.util.Optional;
import javax.annotation.Nonnull;
@@ -477,6 +478,7 @@ protected Content fetch(final String url, final Context context, @Nullable final
}
}
log.debug("Fetching: {}", request);
+ log.debug("Fetching Request Headers: {}", Arrays.toString(request.getAllHeaders()));
HttpResponse response = execute(context, client, request);
log.debug("Response: {}", response);
diff --git a/components/nexus-repository-view/src/main/java/org/sonatype/nexus/repository/http/HttpResponses.java b/components/nexus-repository-view/src/main/java/org/sonatype/nexus/repository/http/HttpResponses.java
index 408f2844ff..fce2ca4f3a 100644
--- a/components/nexus-repository-view/src/main/java/org/sonatype/nexus/repository/http/HttpResponses.java
+++ b/components/nexus-repository-view/src/main/java/org/sonatype/nexus/repository/http/HttpResponses.java
@@ -199,6 +199,12 @@ public static Response badGateway() {
return badGateway(null);
}
+ public static Response gatewayTimeout(@Nullable final String message) {
+ return new Response.Builder()
+ .status(Status.failure(GATEWAY_TIMEOUT, message))
+ .build();
+ }
+
public static Response notImplemented(@Nullable final String message) {
return new Response.Builder()
.status(Status.failure(NOT_IMPLEMENTED, message))
diff --git a/components/nexus-security/src/main/java/org/sonatype/nexus/security/token/BearerTokenRealm.java b/components/nexus-security/src/main/java/org/sonatype/nexus/security/token/BearerTokenRealm.java
index ccf1dc9825..8f4d4c017f 100644
--- a/components/nexus-security/src/main/java/org/sonatype/nexus/security/token/BearerTokenRealm.java
+++ b/components/nexus-security/src/main/java/org/sonatype/nexus/security/token/BearerTokenRealm.java
@@ -66,7 +66,7 @@ public BearerTokenRealm(final ApiKeyStore keyStore,
this.principalsHelper = checkNotNull(principalsHelper);
this.format = checkNotNull(format);
setName(format);
- setAuthenticationCachingEnabled(false);
+ setAuthenticationCachingEnabled(true);
}
@Inject
diff --git a/components/nexus-security/src/test/java/org/sonatype/nexus/security/token/BearerTokenRealmTest.java b/components/nexus-security/src/test/java/org/sonatype/nexus/security/token/BearerTokenRealmTest.java
index d3c0522723..ebe681c7d5 100644
--- a/components/nexus-security/src/test/java/org/sonatype/nexus/security/token/BearerTokenRealmTest.java
+++ b/components/nexus-security/src/test/java/org/sonatype/nexus/security/token/BearerTokenRealmTest.java
@@ -168,6 +168,6 @@ public void anonymousAccessNotSupportedByDefault() throws Exception {
@Test
public void cachingEnabled() {
- assertThat(underTest.isAuthenticationCachingEnabled(), is(false));
+ assertThat(underTest.isAuthenticationCachingEnabled(), is(true));
}
}
diff --git a/components/nexus-validation/src/main/java/org/sonatype/nexus/validation/constraint/AnyOf.java b/components/nexus-validation/src/main/java/org/sonatype/nexus/validation/constraint/AnyOf.java
new file mode 100644
index 0000000000..d2cb50e4b2
--- /dev/null
+++ b/components/nexus-validation/src/main/java/org/sonatype/nexus/validation/constraint/AnyOf.java
@@ -0,0 +1,41 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2008-present Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.validation.constraint;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import javax.validation.Constraint;
+import javax.validation.Payload;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+@Target({FIELD, METHOD, PARAMETER, ANNOTATION_TYPE})
+@Retention(RUNTIME)
+@Constraint(validatedBy = AnyOfValidator.class)
+public @interface AnyOf
+{
+
+ String message() default "%s must be one of the following : [%s]";
+
+ String parameterName() default "value";
+
+ Class>[] groups() default { };
+
+ Class extends Payload>[] payload() default { };
+
+ Class extends Enum>> enumClass();
+}
diff --git a/components/nexus-validation/src/main/java/org/sonatype/nexus/validation/constraint/AnyOfValidator.java b/components/nexus-validation/src/main/java/org/sonatype/nexus/validation/constraint/AnyOfValidator.java
new file mode 100644
index 0000000000..c0875e6df5
--- /dev/null
+++ b/components/nexus-validation/src/main/java/org/sonatype/nexus/validation/constraint/AnyOfValidator.java
@@ -0,0 +1,68 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2008-present Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+package org.sonatype.nexus.validation.constraint;
+
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+import javax.inject.Named;
+import javax.validation.ConstraintValidatorContext;
+
+import org.sonatype.nexus.validation.ConstraintValidatorSupport;
+
+@Named
+public class AnyOfValidator
+ extends ConstraintValidatorSupport
+{
+ Set values;
+
+ String paramName;
+
+ String message;
+
+ public AnyOfValidator() {
+ }
+
+ @Override
+ public void initialize(final AnyOf annotation) {
+ Class extends Enum>> enumClass = annotation.enumClass();
+
+ paramName = annotation.parameterName();
+ message = annotation.message();
+ values = Stream.of(enumClass.getEnumConstants())
+ .map(Enum::name)
+ .map(String::toLowerCase)
+ .collect(Collectors.toSet());
+ }
+
+ @Override
+ public boolean isValid(final String value, final ConstraintValidatorContext context) {
+ if (value == null) {
+ return true;
+ }
+
+ boolean isValid = values.contains(value.toLowerCase());
+
+ if (!isValid) {
+ context.disableDefaultConstraintViolation();
+ context.buildConstraintViolationWithTemplate(getEscapeHelper().stripJavaEl(buildMessage()))
+ .addConstraintViolation();
+ }
+
+ return isValid;
+ }
+
+ private String buildMessage() {
+ return String.format(message, paramName, String.join(",", values));
+ }
+}
diff --git a/nxrm.groovy b/nxrm.groovy
index 71a5e3c7e4..ef3d0633b9 100644
--- a/nxrm.groovy
+++ b/nxrm.groovy
@@ -862,8 +862,8 @@ def runDeploy() {
def deploy() {
extract("./assemblies/nexus-base-template/target/", "nexus-base-template-*.zip")
- extract("./private/assemblies/nexus-oss/target/", "nexus-*-bundle.zip")
- extract("./private/assemblies/nexus-pro/target/", "nexus-professional-*-bundle.zip")
+ extract("./private/assemblies/distributions/nexus-oss/target/", "nexus-*-bundle.zip")
+ extract("./private/assemblies/distributions/nexus-pro/target/", "nexus-professional-*-bundle.zip")
// Tell Karaf to load bundles from local .m2 folder
def files = new FileNameFinder().getFileNames("$TARGET_DIR", "nexus*/**/org.ops4j.pax.url.mvn.cfg")
diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesDryRun.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesDryRun.jsx
index 2504052b60..30bd487ebd 100644
--- a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesDryRun.jsx
+++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesDryRun.jsx
@@ -14,7 +14,6 @@ import React, {useEffect} from 'react';
import {useMachine} from '@xstate/react';
import {
- NxButton,
NxButtonBar,
NxFormRow,
NxFormSelect,
@@ -22,7 +21,7 @@ import {
NxLoadWrapper,
NxP
} from '@sonatype/react-shared-components';
-import {FormUtils} from '@sonatype/nexus-ui-plugin';
+import {ExtJS, FormUtils} from '@sonatype/nexus-ui-plugin';
import UIStrings from '../../../../constants/UIStrings';
import cleanupPoliciesDryRunMachine from './CleanupPoliciesDryRunMachine';
@@ -33,6 +32,13 @@ export default function CleanupPoliciesDryRun({policyData}) {
const [state, send] = useMachine(cleanupPoliciesDryRunMachine, {devTools: true});
const {loadError, repository, repositories} = state.context;
const isLoading = state.matches('loading');
+ const generateCSVUrl = ExtJS.urlOf('/service/rest/internal/cleanup-policies/preview/components/csv' +
+ '?repository=' + repository +
+ (policyData.name ? `&name=${policyData.name}` : '') +
+ (policyData.criteriaLastBlobUpdated ? `&criteriaLastBlobUpdated=${policyData.criteriaLastBlobUpdated}` : '') +
+ (policyData.criteriaLastDownloaded ? `&criteriaLastDownloaded=${policyData.criteriaLastDownloaded}` : '') +
+ (policyData.criteriaReleaseType ? `&criteriaReleaseType=${policyData.criteriaReleaseType}` : '') +
+ (policyData.criteriaAssetRegex ? `&criteriaAssetRegex=${policyData.criteriaAssetRegex}` : ''))
useEffect(() => {
send({type: 'LOAD_REPOSITORIES', format: policyData.format});
@@ -46,10 +52,6 @@ export default function CleanupPoliciesDryRun({policyData}) {
send({type: 'RETRY', format: policyData.format});
}
- function createCSVReport() {
- send({type: 'CREATE_CSV_REPORT', policyData});
- }
-
return
{() =>
@@ -68,7 +70,13 @@ export default function CleanupPoliciesDryRun({policyData}) {
)}
- {BUTTON}
+
+ {BUTTON}
+
>
diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesDryRunMachine.js b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesDryRunMachine.js
index 4c567e9bc8..006f03f879 100644
--- a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesDryRunMachine.js
+++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesDryRunMachine.js
@@ -18,8 +18,6 @@ import {assign, createMachine} from 'xstate';
import Axios from 'axios';
const INITIAL_DATA = {
- CSVContent: null,
- filename: '',
loadError: null,
repositories: [],
repository: ''
@@ -36,9 +34,6 @@ const cleanupPoliciesDryRunMachine = createMachine({
on: {
SET_REPOSITORY: {
actions: 'setRepository'
- },
- CREATE_CSV_REPORT: {
- target: 'creatingCSVReport'
}
}
},
@@ -64,15 +59,6 @@ const cleanupPoliciesDryRunMachine = createMachine({
actions: 'clearError'
}
}
- },
- creatingCSVReport: {
- invoke: {
- src: 'create',
- onDone: {
- target: 'loaded',
- actions: ['setResData', 'downloadCSV']
- }
- }
}
},
@@ -85,8 +71,6 @@ const cleanupPoliciesDryRunMachine = createMachine({
}, {
actions: {
resetData: assign({
- CSVContent: INITIAL_DATA.CSVContent,
- filename: INITIAL_DATA.filename,
loadError: INITIAL_DATA.loadError,
repositories: INITIAL_DATA.repositories,
repository: INITIAL_DATA.repository
@@ -106,36 +90,13 @@ const cleanupPoliciesDryRunMachine = createMachine({
clearError: assign({
loadError: () => null
- }),
-
- setResData: assign({
- filename: (_, event) => event.data?.headers['content-disposition'].split('filename=')[1],
- CSVContent: (_, event) => event.data?.data
- }),
-
- downloadCSV: ({CSVContent, filename}) => {
- const link = document.createElement('a');
- const blob = new Blob([CSVContent]);
- link.href = URL.createObjectURL(blob);
- link.download = filename;
- link.click();
- URL.revokeObjectURL(link.href);
- }
+ })
},
guards: {
canLoadRepositories: (_, {format}) => Boolean(format)
},
services: {
- fetchRepositories: (_, {format}) => Axios.get('/service/rest/internal/ui/repositories', {params: {format}}),
- create: ({repository}, {policyData}) => Axios.post(
- '/service/rest/internal/cleanup-policies/preview/components/csv', {
- repository,
- criteriaLastBlobUpdated: policyData.criteriaLastBlobUpdated,
- criteriaLastDownloaded: policyData.criteriaLastDownloaded,
- criteriaReleaseType: policyData.criteriaReleaseType,
- criteriaAssetRegex: policyData.criteriaAssetRegex,
- name: policyData.name
- })
+ fetchRepositories: (_, {format}) => Axios.get('/service/rest/internal/ui/repositories', {params: {format}})
}
});
diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesForm.test.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesForm.test.jsx
index b7aca2998c..9d2f3b2e55 100644
--- a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesForm.test.jsx
+++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/CleanupPolicies/CleanupPoliciesForm.test.jsx
@@ -42,6 +42,7 @@ jest.mock('@sonatype/nexus-ui-plugin', () => ({
...jest.requireActual('@sonatype/nexus-ui-plugin'),
ExtJS: {
requestConfirmation: jest.fn(),
+ urlOf: jest.fn(),
},
}));
@@ -92,7 +93,7 @@ const selectors = {
description: UIStrings.CLEANUP_POLICIES.DRY_RUN.REPOSITORY_DESCRIPTION,
}),
dryRunCreateCSVButton: () =>
- screen.getByRole('button', {name: LABELS.DRY_RUN.BUTTON}),
+ screen.getByRole('link', {name: LABELS.DRY_RUN.BUTTON}),
};
describe('CleanupPoliciesForm', function () {
@@ -610,17 +611,17 @@ describe('CleanupPoliciesForm', function () {
createButton = dryRunCreateCSVButton();
expect(selectDropdown).toHaveValue('');
- expect(createButton).toBeDisabled();
+ expect(createButton).toHaveAttribute('aria-disabled', 'true');
userEvent.selectOptions(selectDropdown, 'maven-central');
expect(selectDropdown).toHaveValue('maven-central');
- expect(createButton).not.toBeDisabled();
+ expect(createButton).toHaveAttribute('aria-disabled', 'false');
userEvent.selectOptions(selectDropdown, '');
expect(selectDropdown).toHaveValue('');
- expect(createButton).toBeDisabled();
+ expect(createButton).toHaveAttribute('aria-disabled', 'true');
});
});
});
diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/NodeCard.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/NodeCard.jsx
index dad8e4e898..25b2c6bcda 100644
--- a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/NodeCard.jsx
+++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/NodeCard.jsx
@@ -29,12 +29,13 @@ import {faCheckCircle, faTimesCircle} from '@fortawesome/free-solid-svg-icons';
import './SupportZipHa.scss';
import NodeCardMachine from './NodeCardMachine';
+import {URL} from './NodeCardHelper'
const {SUPPORT_ZIP: LABELS} = UIStrings;
const NODE_UNAVAILABLE = 'NODE_UNAVAILABLE';
-export default function NodeCard({initial, createZip, downloadZip}) {
+export default function NodeCard({initial, createZip}) {
const [current] = useMachine(NodeCardMachine, {
context: {
node: initial
@@ -98,7 +99,9 @@ export default function NodeCard({initial, createZip, downloadZip}) {
{zipNotCreated && {statusActionLabel}}
{zipCreated && (
- downloadZip(node)}>{statusActionLabel}
+
+ {statusActionLabel}
+
)}
{zipCreating && (
diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/NodeCard.test.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/NodeCard.test.jsx
index 0199dc9c8b..0568ab4e62 100644
--- a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/NodeCard.test.jsx
+++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/NodeCard.test.jsx
@@ -19,8 +19,6 @@ import NodeCardTestData from './NodeCard.testdata';
describe('NodeCard', function () {
const testNodes = NodeCardTestData;
- const NODE_ACTIVE_INDICATOR = 'Node Active';
-
const DOWNLOAD_ZIP_STATUS = 'Download Zip';
const CREATE_ZIP_STATUS = 'Create Support zip';
const CREATING_ZIP_STATUS = 'Creating Zip...';
diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/NodeCardHelper.js b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/NodeCardHelper.js
new file mode 100644
index 0000000000..fbd3e5bc15
--- /dev/null
+++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/NodeCardHelper.js
@@ -0,0 +1,21 @@
+/*
+ * Sonatype Nexus (TM) Open Source Version
+ * Copyright (c) 2008-present Sonatype, Inc.
+ * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
+ *
+ * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
+ * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
+ *
+ * Sonatype Nexus (TM) Open Source Version is distributed with Sencha Ext JS pursuant to a FLOSS Exception agreed upon
+ * between Sonatype, Inc. and Sencha Inc. Sencha Ext JS is licensed under GPL v3 and cannot be redistributed as part of a
+ * closed source work.
+ *
+ * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
+ * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
+ * Eclipse Foundation. All other trademarks are the property of their respective owners.
+ */
+const downloadZipFile = (blobRef) =>
+ `/service/rest/wonderland/download/${blobRef}`;
+
+export const URL = {downloadZipFile};
+
diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/SupportZipHa.jsx b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/SupportZipHa.jsx
index 531ca618eb..73ccc58f19 100644
--- a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/SupportZipHa.jsx
+++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/SupportZipHa.jsx
@@ -68,15 +68,6 @@ export default function SupportZipHa() {
});
}
- function downloadZip(node) {
- sendToNxrmNodes({
- type: 'DOWNLOAD_ZIP',
- data: {
- node: node
- }
- });
- }
-
function submitCreateNodeSupportZip() {
closeSupportZipFormModal();
@@ -106,8 +97,7 @@ export default function SupportZipHa() {
showCreateZipModalForm(node)}
- downloadZip={downloadZip}/>
+ createZip={() => showCreateZipModalForm(node)}/>
)}
diff --git a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/SupportZipHaMachine.js b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/SupportZipHaMachine.js
index ea4b088242..f0c3b06a17 100644
--- a/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/SupportZipHaMachine.js
+++ b/plugins/nexus-coreui-plugin/src/frontend/src/components/pages/admin/SupportZip/HA/SupportZipHaMachine.js
@@ -17,7 +17,7 @@
import Axios from 'axios';
import {assign} from 'xstate';
-import {APIConstants, ExtJS, FormUtils, UIStrings} from "@sonatype/nexus-ui-plugin";
+import {APIConstants, FormUtils} from "@sonatype/nexus-ui-plugin";
export default FormUtils.buildFormMachine({
id: 'SupportZipHaMachine',
@@ -50,17 +50,6 @@ export default FormUtils.buildFormMachine({
CREATE_SUPPORT_ZIP_FOR_NODE: {
target: 'creatingNodeSupportZip'
},
- DOWNLOAD_ZIP: {
- target: 'initSupportZipDownload',
- actions: 'setTargetNode'
- }
- }
- },
-
- downloadingZip: {
- entry: 'downloadZip',
- always: {
- target: 'loaded'
}
},
@@ -79,19 +68,6 @@ export default FormUtils.buildFormMachine({
target: 'loaded'
}
},
-
- initSupportZipDownload: {
- invoke: {
- src: 'verifyIsZipCanBeDownloaded',
- onDone: {
- target: 'downloadingZip'
- },
- onError: {
- target: 'loaded',
- actions: ['setCreateError']
- }
- }
- }
}
})
}).withConfig({
@@ -109,23 +85,6 @@ export default FormUtils.buildFormMachine({
showCreateZipModal: false,
selectedNode: null
}),
-
- downloadZip: (ctx) => {
- const { targetNode } = ctx;
-
- if (targetNode) {
- const url = ExtJS.urlOf(`service/rest/wonderland/download/${targetNode.blobRef}`);
- ExtJS.downloadUrl(url);
- }
- },
-
- setCreateError: () => {
- ExtJS.showErrorMessage(UIStrings.ERROR.NOT_FOUND_ERROR("Support zip"))
- },
-
- setTargetNode: assign({
- targetNode: (_, event) => event?.data?.node
- })
},
services: {
@@ -145,15 +104,5 @@ export default FormUtils.buildFormMachine({
}
return Promise.reject();
},
-
- verifyIsZipCanBeDownloaded: async (ctx) => {
- const { targetNode } = ctx;
-
- const { data } = await axios.get(APIConstants.REST.PUBLIC.NODE_ID)
- if (targetNode && data.nodeId === targetNode.nodeId) {
- return Promise.resolve();
- }
- return Promise.reject();
- }
}
});
diff --git a/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/orient/OrientAptUploadHandler.java b/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/orient/OrientAptUploadHandler.java
index c145088260..887f92ff7d 100644
--- a/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/orient/OrientAptUploadHandler.java
+++ b/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/orient/OrientAptUploadHandler.java
@@ -67,6 +67,7 @@ public UploadResponse handle(final Repository repository, final ComponentUpload
UnitOfWork.begin(storageFacet.txSupplier());
try {
Asset asset = hostedFacet.ingestAsset(upload.getAssetUploads().get(0).getPayload());
+ hostedFacet.invalidateMetadata();
return new UploadResponse(asset);
}
finally {
diff --git a/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/orient/internal/OrientAptComponentDirector.java b/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/orient/internal/OrientAptComponentDirector.java
index 9de4cd954f..9a3524bd8f 100644
--- a/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/orient/internal/OrientAptComponentDirector.java
+++ b/plugins/nexus-repository-apt/src/main/java/org/sonatype/nexus/repository/apt/orient/internal/OrientAptComponentDirector.java
@@ -74,15 +74,9 @@ public boolean allowMoveFrom(final Repository source) {
@Override
public void afterMove(final List