Также, если packaging артефакта равен jar, и артефакт содержит классы, то помимо основного
артефакта следует загрузить -sources.jar и -javadoc.jar. Если это невозможно, например, если не
позволяет лицензия или если ваш проект написан на Scala, то нужно создать фейковые -sources.jar и
-javadoc.jar с README-файлом в них и воспользоваться ими.
Кроме того, в pom.xml не должно быть секций или , потому что
такая конфигурация может сломать сборку у пользователей вашего артефакта, если указанные репозитории
лягут.
Необходимо также подписать артефакты при помощи GnuPG, и соответствующий публичный ключ должен быть
загружен на сервер ключей hkp://pool.sks-keyservers.net/. Про настройку GnuPG чуть ниже.
Вот пример базового pom.xml с необходимой структурой:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.bitbucket.googolplex.devourer</groupId>
<artifactId>devourer</artifactId>
<version>0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Devourer</name>
<description>Feeds on XML and produces objects</description>
<url>http://bitbucket.org/googolplex/devourer</url>
<licenses>
<license>
<name>The Apache Software License, Version 2.0</name>
<url>http://www.apache.org/licenses/LICENSE-2.0.txt</url>
<distribution>repo</distribution>
</license>
</licenses>
<scm>
<url>https://bitbucket.org/googolplex/devourer</url>
<connection>scm:hg:https://bitbucket.org/googolplex/devourer</connection>
</scm>
<developers>
<developer>
<id>owner</id>
<name>Vladimir Matveev</name>
<email>dpx.infinity@gmail.com</email>
<timezone>UTC+4</timezone>
</developer>
</developers>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>14.0-rc3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
В принципе, такого pom.xml достаточно, чтобы загружать артефакты в репозиторий. Артефакты тогда
надо будет подписывать вручную и вручную же загружать их в staging-репозиторий. Однако, мавен был
придуман для того, чтобы автоматизировать рутинные операции, и деплой артефактов в репозиторий
содержится в их числе.
Чтобы мавен сам загружал артефакты в репозиторий и подписывал их, нужно добавить и сконфигурировать
несколько плагинов. Однако, перед этим настроим GnuPG.
Настройка GnuPG для подписи артефактов
GnuPG (GNU Privacy Guard) — это альтернативная реализация известного пакета программ для
криптографии PGP, полностью совместимая со стандартом OpenPGP. С помощью GnuPG можно создавать ключи
для асимметричного и симметричного шифрования данных, а также проводить само шифрование многими
алгоритмами. Также с помощью GnuPG можно подписывать данные. Именно этот функционал нам интересен.
Установка GnuPG зависит от системы. В линуксе всё очень просто. Обычно GnuPG поставляется в
стандартном репозитории и, вполне вероятно, уже установлен у вас. Если нет, то нужно попросить
менеджер пакетов его установить. В Archlinux, например, это делается так:
$ sudo pacman -S gnupg
После установки в PATH появится программа gpg. Этого достаточно для мавена.
Под Windows установка немного сложнее. GnuPG предоставляет бинарники, собранные для Windows, но там
есть только относительно старые версии. На мой взгляд, лучшим вариантом будет воспользоваться
gpg4win. Это сборка GnuPG под Windows с несколькими дополнительными программами, например,
графическим менеджером ключей. Для мавена это, в общем-то, не нужно, но может быть полезно вам. Сайт
gpg4win:
http://www.gpg4win.org/. Там можно найти установщик. При установке он должен автоматически
добавить в системный PATH путь к каталогу, где лежит gpg.exe — то, что нам и нужно.
После установки GnuPG открываем терминал и пишем в нём:
$ gpg --gen-key
GnuPG запросит у вас следующие параметры:
- Алгоритм ключа — по умолчанию у вас, скорее всего, будет
RSA and RSA
, это наилучший вариант.
- Размер ключа — по умолчанию должно быть 2048 бит, этого вполне достаточно.
- Срок действия ключа — по умолчанию ключ действует неограниченно долго; вы можете установить
срок действия как дополнительную меру безопасности. После окончания срока действия ключ можно
будет продлить, если вы не забыли пароль к ключу.
- Имя и E-Mail — ваши имя и электронная почта. Желательно всё же указать здесь реальные
значения.
- Комментарий — необязательное поле (не знаю, зачем оно нужно), оставьте его пустым.
- Пароль — здесь нужно ввести пароль для защиты приватного ключа. В зависимости от системы
пароль вам предложат ввести по-разному: может появиться графическое окно (gpg4win или GnuPG,
запущенный из под графической оболочки линукса), или возникнет предложение ввести пароль в
терминале. Этот пароль будет запрашиваться всегда, когда вам понадобится использовать приватный
ключ, например, для подписи или обновления времени действия ключа.
После ввода всех этих параметров GnuPG попросит подёргать мышкой или попечатать что-нибудь на
клавиатуре, чтобы получить энтропию для генерации ключа. Будьте с этим осторожны, если вы работаете
на сервере через SSH: GnuPG может зависнуть очень надолго в ожидании энтропии от устройств, а через
SSH мышь или клавиатуру не подёргаешь.
Затем GnuPG сообщит об успешной генерации ключей и выведет их отпечаток. Ещё раз проверить наличие
ключа можно, введя команду gpg --list-keys:
$ gpg --list-keys
C:/Users/vpupkin/AppData/Roaming/gnupg/pubring.gpg
----------------------------------------------------
pub 2048R/1A89FE67 2013-02-26
uid Vasiliy Pupkin <vp@example.com>
sub 2048R/D9725D51 2013-02-26
Теперь вы можете подписывать файлы (да и вообще любые данные) с помощью GnuPG. Остался ещё один
момент: нужно загрузить ваш публичный ключ на сервер ключей hkp://pool.sks-keyservers.net. Для
этого нужно ввести следующую команду:
$ gpg --keyserver hkp://pool.sks-keyservers.net --send-keys 1A89FE67
Аргументом к параметру --send-keys указан короткий отпечаток ключа, который можно взять из вывода
команды gpg --list-keys. Через некоторое время GnuPG завершит работу, что будет означать, что ключ
опубликован.
Теперь, если вы не хотите подписывать артефакты и загружать их в репозиторий вручную, нужно
настроить мавен, чтобы он делал это за вас.
Настройка мавена для автоматической подписи и загрузки артефактов в snapshot- и staging-репозитории
Большая часть конфигурации мавена делается из pom.xml настройкой соответствующих плагинов. Однако,
часть конфигурации следует добавить в settings.xml, системном файле настроек мавена. Обычно этот
файл лежит в $HOME/.m2/settings.xml (%HOME%\.m2\settings.xml в Windows) и предназначен для
специфичных для пользователя настроек, вроде паролей или репозиториев.
Сначала нужно сделать так, чтобы ваш pom.xml наследовался от артефакта, предоставленного Sonatype
специально для упрощения выгрузки артефактов к ним на сервера. Для этого нужно добавить следующий
кусок в ваш pom.xml:
<parent>
<groupId>org.sonatype.oss</groupId>
<artifactId>oss-parent</artifactId>
<version>7</version>
</parent>
Насколько я понимаю (сам я ещё не пробовал), если вы собираетесь загружать сложный многомодульный
проект, который уже использует наследование POM, то нужно сделать oss-parent предком всех тех
артефактов, которые предков не имеют, то есть, корней всех иерархий в проекте. Обычно такой корень
один, но всё же.
Вот список необходимых плагинов:
maven-source-plugin
maven-javadoc-plugin
maven-gpg-plugin
Также нужен ещё maven-release-plugin, но он добавляется автоматически с нужной конфигурацией через
наследование от oss-parent.
Самое простое — настройка maven-source-plugin и maven-javadoc-plugin. Достаточно добавить
следующие секции в pom.xml:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<id>attach-javadocs</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Здесь мы указали, что на фазе жизненного цикла package нужно создать jar-файлы с исходниками и с
документацией. Остальные плагины, maven-release-plugin и maven-gpg-plugin, автоматически
подхватят эти сгенерированные артефакты, никакой дополнительной конфигурации не потребуется.
Далее, настроим плагин для релиза артефактов, maven-release-plugin. Как я уже сказал, этот плагин
автоматически конфигурируется в артефакте oss-parent, от которого должны наследоваться наши
артефакты. Также в этом артефакте конфигурируются адреса репозиториев. maven-release-plugin будет
использовать именно их для загрузки артефактов. Но, очевидно, просто так загрузить артефакты в
репозиторий нельзя, нужно себя идентифицировать, то есть указать имя и пароль.
Имя и пароль указываются в settings.xml. Окончательный вариант этого файла должен выглядеть
примерно так:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<servers>
<server>
<id>sonatype-nexus-snapshots</id>
<username>vpupkin</username>
<password>password</password>
</server>
<server>
<id>sonatype-nexus-staging</id>
<username>vpupkin</username>
<password>password</password>
</server>
<server>
<id>bitbucket.org</id>
<username>vpupkin</username>
<password>password</password>
</server>
</servers>
</settings>
Идентификаторы репозиториев sonatype-nexus-snapshots и sonatype-nexus-staging определены в
oss-parent, и мавен автоматически возьмёт имя и пароль из соответствующих секций settings.xml
для загрузки артефактов в эти репозитории. Имя и пароль здесь должны быть указаны те, что были
использованы при регистрации на Sonatype JIRA.
Также я ещё указал здесь сервер с идентификатором bitbucket.org. Это нужно для плагина
maven-scm-plugin, который используется плагином maven-release-plugin для создания в системе
контроля версий тегов, соответствующих релизу. Для того, чтобы это работало, нужно указать
дополнительный адрес в блоке в pom.xml:
<scm>
<url>https://bitbucket.org/googolplex/devourer</url>
<connection>scm:hg:https://bitbucket.org/googolplex/devourer</connection>
<developerConnection>scm:hg:https://bitbucket.org/googolplex/devourer</developerConnection>
</scm>
Новый адрес указан в элементе developerConnection. Здесь он совпадает с адресом в connection,
но, вообще говоря, они могут быть разными: connection означает адрес на read-only доступ к коду, а
developerConnection — на read-write. Как раз для него мы и добавляли логин и пароль к
bitbucket.org в settings.xml. maven-scm-plugin сам распознает, что этот логин и пароль
относятся к серверу, который указан в .
Для работы maven-scm-plugin бинарник вашей системы контроля версий должен находиться в
PATH. Например, в моём примере это должен быть hg или hg.exe. Поэтому перед использованием
maven-release-plugin вам потребуется настроить вашу VCS и операционную систему соответствующим
образом. На этом останавливаться не будет: под линуксом всё очень просто, а под Windows установщики
обычно достаточно умные, чтобы добавить пути в PATH.
Теперь нужно настроить maven-gpg-plugin. Вообще говоря, подписывать нужно только релизные версии
артефактов, то есть те, которые попадут в Maven Central. Поэтому имеет смысл настроить вызов этого
плагина только тогда, когда запускается команда для создания релизного артефакта. Мавен, точнее,
maven-release-plugin, предоставляет такую возможность.
Воспользуемся такой фичей мавена, как профили. Профили позволяют динамически включать и отключать
различные части конфигурации мавена по необходимости, в том числе и плагины. Профили можно объявлять
как в pom.xml, так и в settings.xml. Объявим профиль для вызова maven-gpg-plugin прямо в
pom.xml:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
...
<profiles>
<profile>
<id>sign-artifacts</id>
<activation>
<property>
<name>performRelease</name>
<value>true</value>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.4</version>
<configuration>
<passphrase>${gpg.passphrase}</passphrase>
</configuration>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Здесь объявляется новый профиль, sign-artifacts, и указывается, что его следует активировать
тогда, когда системное свойство performRelease будет равно true. Это свойство устанавливает
maven-release-plugin, когда запущена его команда на создание релиза. В профиле конфигурируется
maven-gpg-plugin: его следует запускать по достижении фазы жизненного цикла verify. Также
плагину передаётся наш пароль для GPG-ключа.
Пароль этот передаётся через свойство gpg.passphrase. Понятно, что сохранять пароль на приватный
ключ в самом pom.xml несколько неразумно. Вместо этого сконфигурируем его в settings.xml. Для
этого создадим ещё один профиль, но уже внутри settings.xml. Выглядеть это будет так:
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
...
<profiles>
<profile>
<id>gpg-passphrase</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<gpg.passphrase>passphrase</gpg.passphrase>
</properties>
</profile>
</profiles>
</settings>
Здесь мы указываем, что в профиле нужно определить свойство gpg.passphrase со значением, равным
паролю к ключу. Это значение будет подставлено в соответствующее место в конфигурации
maven-gpg-plugin'а. В условиях активации стоит
, потому что пароль к ключу
понадобится не только во время самого процесса релиза, но и в процессе подготовки к нему, а для
этого никаких отличительных свойств никакими плагинами не устанавливается.
Выгружаем артефакты в репозиторий
В общем, это всё, что нужно сделать, чтобы мавен умел загружать артефакты в репозиторий. Если теперь
вы выполните такую команду в корне проекта:
$ mvn deploy
то через некоторое время в snapshot-репозиторий будет загружена текущая версия ваших артефактов.
К snapshots-репозиторию можно получить доступ извне, например, чтобы пользоваться snapshot-версиями
артефакта. Возможно это сделать, например, по этому адресу:
https://oss.sonatype.org/content/groups/staging. Однако, репозиторий по этой ссылке важен по другой
причине. В него попадают не только снэпшоты и релизы, но и т.н.
staged-версии
артефактов. Фактически, это релизные версии, которые ещё не синхронизированы Maven
Central. Stage-пространство нужно для последней проверки, что с вашими артефактами всё в порядке. То
есть, перед релизом артефакта в Central стоит проверить, что, например, проект, использующий ваш
артефакт, компилируется нормально, если он будет зависеть от новой релизной версии. Если возникнут
какие-то проблемы, staged-артефакт можно удалить и создать заново. Как только все проблемы
разрешены, staged-артефакт можно "продвинуть" в Maven Central. С этого момента его изменить уже
будет нельзя.
Рассмотрим поподробнее, как выглядит загрузка артефакта в staging-репозиторий, и что нужно делать
для "продвижения" артефакта в Central.
Поскольку проект уже настроен для релиза артефактов, достаточно выполнить две команды:
$ mvn release:prepare
...
$ mvn release:perform
...
Первая команда подготавливает релиз. Если конкретнее, то она делает следующее:
- проверяет, что в дереве исходников нет незакоммиченных изменений;
- проверяет, что у всех артефактов нет зависимостей на snapshot-версии других артефактов;
- меняет версию у всех артефактов с
x-SNAPSHOT
на ту, что вы укажете;
- изменяет информацию о системе контроля версий в
pom.xml
, чтобы она соответствовала новому пути
в репозитории для нового релиза (актуально для тех VCS, в которых нет отдельного понятия тегов,
таких, как SVN);
- запускает автоматические тесты с изменёнными
pom.xml
, чтобы проверить, что ничего не сломалось;
- коммитит изменённые
pom.xml
;
- создаёт тег в репозитории для новой версии, запрашивая у вас имя тега;
- обновляет версию в
pom.xml
на y-SNAPSHOT
(это тоже плагин у вас спросит);
- коммитит изменённые
pom.xml
.
Таким образом, после выполнения mvn release:prepare в репозитории образуется два коммита (первый с
обновлением текущей snapshot-версии на релизную, а второй — с релизной на новую snapshot'ную) и
один тег (который будет указывать на тот коммит, в котором присутствует релизная версия).
Другими словами, mvn release:prepare создаёт "точку релиза" в репозитории, фиксируя то состояние
проекта, которое попадёт в Central.
Теперь нужно загрузить артефакт в репозиторий. Для этого служит вторая команда, mvn release:perform. Эта команда выкачивает тег релизной версии из репозитория и собирает его командой
вроде mvn site-deploy. Команда mvn site-deploy в условиях такой конфигурации проекта, которую мы
сделали, загрузит артефакт в staging-репозиторий.
Очевидно, mvn release:perform должна откуда-то брать название тега, который нужно загрузить. Она
может брать тег либо из файла release.properties, который создаётся командой mvn release:prepare, либо из командной строки. После успешной выгрузки артефакта и сопутствующих файлов
в репозиторий, release:perform удалит лишние файлы, созданные release:prepare.
Внимание: при использовании таких VCS, у которых понятие тега не связано с файловой системой
(например, это Mercurial и Git), через командную строку указать название тега, к сожалению,
нельзя. Я вообще не нашёл способа указать тег для mvn release:perform, если перед этим не был
выполнен mvn release:prepare. Если кто-то подскажет, как это сделать, буду очень благодарен.
Таким образом, после выполнения этих команд ваши артефакты будут загружены в staging-репозиторий. Их
можно увидеть через веб-интерфейс системы управления репозиториями Sonatype Nexus на
https://oss.sonatype.org/. В правом верхнем углу по ссылке
Log In нужно войти в систему с тем
логином и паролем, который вы выбрали при регистрации на JIRA. После этого слева в списке появится
группа
Build Promotion, а в ней три ссылки. Нужная нам называется
Staging Repositories. По
нажатию на неё в центральном окне откроется список staging-репозиториев, то есть, временных хранилищ
для артефактов в состоянии staging. В официальной документации приводятся скриншоты окна, в котором
виден всего лишь один репозиторий, тот, в который мы только что выгрузили артефакт. Однако, по
какой-то причине у меня это выглядит так:

Как мне ответили в тикете на JIRA, наличие этих артефактов не страшно, они не мешаются, и у обычных
пользователей всё равно нет прав на их изменение.
Мой репозиторий наверху. Видно, что он в статусе Closed, но у вас он будет сначала в статусе
Open. Вообще staging-репозиторий может быть в двух состояниях —
Open и
Closed. В статусе
Open репозиторий находится сразу после выгрузки артефактов. В состояние
Closed репозиторий нужно
перевести вручную, с помощью кнопки
Close на панели инструментов сверху. При этом Nexus проверит,
что все артефакты в репозитории находится в состоянии, подходящем для Maven Central: присутствуют
корректные цифровые подписи, pom.xml имеет правильный формат и т.д. Если будут какие-то проблемы,
то Nexus сообщит об ошибках, и после исправления проблема артефакты надо будет выгрузить снова. Как
только репозиторий оказывается в статусе
Closed, он более недоступен для изменения; именно в таком
виде он попадёт в Maven Central. После закрытия репозитория артефакты становятся доступным в
staging-репозитории:
https://oss.sonatype.org/content/groups/staging. Можно воспользоваться им,
чтобы проверить работу артефакта перед тем, как "продвигать" его в Maven Central.
Если вы удовлетворены проверками и считаете, что уже пора бы вашему артефакту попасть в Central, то
нужно выбрать ваш staging-репозиторий и нажать кнопку Release на панели инструментов. Через
некоторое время staging-репозиторий пропадёт из списка. Теперь артефакт попадёт в основной
репозиторий Sonatype OSSRH:
https://oss.sonatype.org/content/groups/public. Но раз мы хотим, чтобы
наш артефакт был доступен в Maven Central, то нужно сделать ещё один шаг.
Поскольку вы загружаете свой репозиторий в Maven Central в первый раз, вам нужно будет оставить
комментарий на вашем тикете в Sonatype JIRA о том, что вы "продвинули" свой артефакт, и что нужно
включить синхронизацию с Maven Central:

Сотрудник Sonatype вам ответит через некоторое время (здесь мне опять повезло: мне ответили почти
сразу после того, как я оставил комментарий; похоже, что самое подходящее время для общения на JIRA
— около 12 ночи по Москве), что синхронизация включена. В течение нескольких часов ваш артефакт
будет доступен в Maven Central. Поздравляю! :)
Процедуру с комментарием надо провести только один раз. После этого синхронизация будет включена уже
навсегда, и все артефакты, которые вы загружаете в staging-репозиторий после "продвижения" будут
синхронизированы с Maven Central автоматически.
Замечания по поводу хранения паролей в settings.xml
Возможно, некоторые читатели возмутились, что я использовал в статье хранение паролей в открытом
виде в settings.xml. В этом я с ними соглашусь: хранение паролей плейнтекстом — действительно
неудачная идея. К счастью, создатели мавена об этом также осведомлены. В мавене есть возможность
хранить пароли и в зашифрованном виде.
Использование зашифрованных паролей описано в руководстве по мавену:
http://maven.apache.org/guides/mini/guide-encryption.html. Если вкратце, то зашифрованные пароли
используются следующим образом.
- Создаётся мастер-пароль:
$ mvn --encrypt-master-password your-password
Пароль нужно указывать в командной строке. О безопасности этого ниже.
Значение, выведенное этой командой, будет выглядеть примерно так:
{FshtxgrHbMoH+X+v4cwYL9t9QgtwTgoLmfiV6LkPkvg=}
Это значение необходимо сохранить в файле $HOME/.m2/settings-security.xml
, вот таким образом:
<settingsSecurity>
<master>{jSMOWnoPFgsHVpMvz5VrIt5kRbzGpI8u+9EF1iFQyJQ=}</master>
</settingsSecurity>
- Теперь можно шифровать серверные пароли. Делается это с помощью команды:
$ mvn --encrypt-password your-password
Пароль также надо указать в командной строке. Результат будет наподобие такого:
{tly+tTyx46MHPhht/SryJw8+x4n4oWfzgAPZ/B+KFoc=}
Этот пароль можно использовать внутри секции в settings.xml:
<settings>
...
<servers>
...
<server>
<id>my.server</id>
<username>foo</username>
<password>{tly+tTyx46MHPhht/SryJw8+x4n4oWfzgAPZ/B+KFoc=}</password>
</server>
...
</servers>
...
</settings>
Это будет работать для всех плагинов, использующих : maven-deploy-plugin,
maven-scm-plugin и т.д. Однако, здесь не обошлось без ложки дёгтя: см. далее.
Также иногда может быть так, что мавен откажется шифровать пароль с какой-то ошибкой насчёт блока
шифра. Это не страшно, достаточно перегенерировать мастер-пароль.
Таким образом, для использования паролей в settings.xml
будет обязательно нужен
мастер-пароль. Наличия файла settings-security.xml
с зашифрованным мастер-паролем внутри
достаточно, чтобы можно было пользоваться зашифрованными паролями в settings.xml
. Чтобы сохранить
мастер-пароль в безопасности, файл settings-security.xml
с мастер-паролем можно поместить на
съёмный носитель, например, на флешку, а в файле $HOME/.m2/settings-security.xml
указать, что
нужно использовать файл, находящийся в другом месте:
<settingsSecurity>
<relocation>/media/secure-flash/settings-security.xml</relocation>
</settingsSecurity>
Таким образом, пароли в файле settings.xml
могут быть надёжно защищены.
К сожалению, здесь не обошлось без проблем. Во-первых, по какой-то причине maven-scm-plugin
у меня
не захотел работать с зашифрованными паролями при использовании Mercurial. Из логов мавена было
видно, что он отправляет пароль as-is, не расшифровывая его, и, естественно, получает ошибку. Я не
знаю с чем это связано, и гугление ничего существенного не дало. Я решил эту проблему использованием
SSH-транспорта для Mercurial. Конкретнее, секция у меня в pom.xml стала выглядеть так:
<scm>
<url>https://bitbucket.org/googolplex/devourer</url>
<connection>scm:hg:https://bitbucket.org/googolplex/devourer</connection>
<developerConnection>scm:hg:ssh://hg@bitbucket.org/googolplex/devourer</developerConnection>
</scm>
Обратите внимание на . SSH-клиент у меня на машине настроен на использование
ключей для аутентикации, так что такой метод работает вполне удовлетворительно. Вполне возможно, что
с другими VCS проблем не будет.
Ещё одна проблема — это ограниченность применимости зашифрованных паролей. Их можно использовать
только в , в любом другом месте дешифрация проводиться не будет. Вспомним наш
дополнительный профиль в settings.xml, который содержит пароль на приватный ключ:
<profiles>
<profile>
<id>gpg-passphrase</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<gpg.passphrase>passphrase</gpg.passphrase>
</properties>
</profile>
</profiles>
Здесь бесполезно заменять пароль зашифрованной версией, так как maven-gpg-plugin не использует
мавеновское шифрование и, судя по открытому два с половиной года назад тикету, вообще не может его
использовать (ну по крайней мере это сопряжено с существенными трудностями).
Возможная альтернатива — отключение пароля на ключ (это возможно сделать с помощью GnuPG) и
перемещение "связки ключей" GnuPG на внешний зашифрованный носитель. Для этого нужно немного
исправить settings.xml и pom.xml.
Профиль в settings.xml:
<profiles>
<profile>
<id>gpg-passphrase</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<gpg.passphrase/>
<gpg.home>/media/secure-flash/gnupg</gpg.home>
</properties>
</profile>
</profiles>
Настройки maven-gpg-plugin в pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.4</version>
<configuration>
<passphrase>${gpg.passphrase}</passphrase>
<homedir>${gpg.home}</homedir>
</configuration>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
Здесь мы использовали новое свойство, gpg.home, которое указывает на каталог с ключами GnuPG на
внешнем устройстве, а также убрали пароль на ключ.
Ещё один вариант — просто вводить пароль каждый раз, когда мавен его попросит при сборке. Для
этого нужно убрать опцию в свойствах maven-gpg-plugin в pom.xml. В такой
конфигурации, какая приведена в этой статье, вводить пароль придётся два раза: во время mvn release:prepare и во время mvn release:perform.
Если вы пользуетесь Unix-системами, то, наверное, знаете, что SSH-ключи в каталоге пользователя
защищаются с помощью прав на файлы: у ключей обычно стоят права доступа вроде 600, то есть только
для пользователя-владельца файла. В принципе с файлами конфигурации мавена можно поступить так же
— выставить правильные привилегии на файл settings.xml. Это даст бонус к защите ваших паролей.
Ну и последняя возможность — передавать пароль в командной строке: mvn release:prepare -Dgpg.passphrase=passphrase, но это уже будет совсем большая дыра, так, конечно, лучше не делать.
Насчёт ввода паролей открытым текстом при вызове mvn --encrypt{,-master}-password: с этим ничего
не поделаешь, их придётся вводить как аргумент к команде. После этого стоит почистить файл с
историей вашего шелла, например, ~/.zsh_history. Также после редактирования файлов желательно
посмотреть, что ваш редактор не сохранил пароли в кэше, например, ~/.viminfo или в ~-файлах у
емакса.
Вполне возможно, что со всеми этими недостатками в хранении паролей при использовании мавена
справляются другие системы сборки. Я не исследовал этот вопрос и буду рад, если кто-нибудь расскажет
про это.
Заключение
Такие репозитории, как Maven Central — это огромное преимущество Java как платформы, и чем больше
в них будет готовых к использованию артефактов, тем лучше будет для всей экосистемы Java. К счастью,
весь процесс публикации библиотеки оказался не таким сложным, как выглядит. Надеюсь, моя статья
помогла внести ещё большую ясность в него. Спасибо за прочтение.
Буду рад указаниям на все ошибки, опечатки и фактические неточности.
Статья подготовлена в Emacs Org Mode, сконвертирована в формат Хабра с помощью Org -> Docbook -> Habr Exporter.
Использованные ресурсы
- Официальный гайд Sonatype по использованию OSSRH:
https://docs.sonatype.org/display/Repository/Sonatype+OSS+Maven+Repository+Usage+Guide
- Гайд Sonatype по использованию GnuPG совместно с мавеном:
https://docs.sonatype.org/display/Repository/How+To+Generate+PGP+Signatures+With+Maven
- Документация по мавену и его плагинам: http://maven.apache.org/guides/index.html,
http://maven.apache.org/plugins/index.html
- Конечно же, гугл.
Original : https://habr.com/ru/post/171493/