SonatypeNexus:Apt
A Nexus Repository 3 plugin that allows usage of apt repositories.
Build
## Clone the project:
$ git clone https://github.com/sonatype-nexus-community/nexus-repository-apt
## Build the plugin:
$ cd nexus-repository-apt
$ mvn
Docker
Build with docker and create an image based on nexus repository 3
Run a docker container from that image
Upload package
Manually upload a package to a new created repo:
$ curl -u user:pass -X POST -H "Content-Type: multipart/form-data" --data-binary "@package.deb" http://nexus_url:8081/repository/repo_name/
curl에서 --data-binary
를 사용할 경우 파일명 앞에 @
를 꼭 붙여야 한다.
How to use
APT Settings APT Browse 저장소 종류를 apt (hosted)로 선택한 후 아래와 같이 GPG Key를 생성한다.
사용자명(5글자 이상)과 E-mail을 입력하고, 편의를 위해 Passphrase는 공백으로 둔다.
그리고 GPG Key를 파일로 추출한다. [KEYSPEC]
부분에 위에서 입력한 사용자명을 입력한다.
APT의 배포(Distribution)명과 개인키를 입력한다. (배포명은 stable
로 가정한다)
WARNING |
개인키는 우측 스크린샷의 |
클라이언트에서 위의 저장소를 /etc/apt/sources.list
파일에 추가한다.
WARNING |
URL 뒤에 붙는 컴포넌트 들은 |
클라이언트에서 apt에 공개키를 추가한다.
apt저장소를 업데이트 한다.
Troubleshooting
What is "Signing Key"?
새로운 저장소를 생성할 경우 Signing Key
항목에 입력해야 할 내용에 대하여 아래와 같이 확인할 수 있다.
1. 플러그인 저장소의 ./src/main/java/net/staticsnow/nexus/repository/apt/internal/gpg/AptSigningFacet.java
파일에서 readSecretKey()
함수를 사용하는 부분에서 발생되는 Exception으로 추정된다. 따라서 해당 함수를 확인해 본다:
private PGPSecretKey readSecretKey() throws IOException, PGPException {
PGPSecretKeyRingCollection pgpSec = new PGPSecretKeyRingCollection(
PGPUtil.getDecoderStream(new ByteArrayInputStream(config.keypair.getBytes())),
new JcaKeyFingerprintCalculator());
Iterator<PGPSecretKeyRing> keyRings = pgpSec.getKeyRings();
while (keyRings.hasNext()) {
PGPSecretKeyRing keyRing = (PGPSecretKeyRing) keyRings.next();
Iterator<PGPSecretKey> keys = keyRing.getSecretKeys();
while (keys.hasNext()) {
PGPSecretKey key = (PGPSecretKey) keys.next();
if (key.isSigningKey()) {
return key;
}
}
}
throw new IllegalStateException("Can't find signing key in key ring.");
}
2. config.keypair.getBytes()
가 기반 정보가 되는 ByteArray를 사용하는 PGPUtil.getDecoderStream
함수를 확인해 본다. [https://www.borelly.net/cb/docs/javaBC-1.4.8/pg/org/bouncycastle/openpgp/PGPUtil.html#getDecoderStream(java.io.InputStream PGPUtil.getDecoderStream]
Return either an ArmoredInputStream or a BCPGInputStream based on whether the initial characters of the stream are binary PGP encodings or not.
3. 해당 라이브러리의 구현체를 확인해 본다. Github - bcgit/bc-java 경로는 pg/src/main/java/org/bouncycastle/openpgp/PGPUtil.java
이다.
/**
* Obtains a stream that can be used to read PGP data from the provided stream.
* <p>
* If the initial bytes of the underlying stream are binary PGP encodings, then the stream will
* be returned directly, otherwise an {@link ArmoredInputStream} is used to wrap the provided
* stream and remove ASCII-Armored encoding.
* </p>
*
* @param in the stream to be checked and possibly wrapped.
* @return a stream that will return PGP binary encoded data.
* @throws IOException if an error occurs reading the stream, or initialising the
* {@link ArmoredInputStream}.
*/
public static InputStream getDecoderStream(
InputStream in)
throws IOException
{
if (!in.markSupported())
{
in = new BufferedInputStreamExt(in);
}
in.mark(READ_AHEAD);
int ch = in.read();
if ((ch & 0x80) != 0)
{
in.reset();
return in;
}
else
{
if (!isPossiblyBase64(ch))
{
in.reset();
return new ArmoredInputStream(in);
}
byte[] buf = new byte[READ_AHEAD];
int count = 1;
int index = 1;
buf[0] = (byte)ch;
while (count != READ_AHEAD && (ch = in.read()) >= 0)
{
if (!isPossiblyBase64(ch))
{
in.reset();
return new ArmoredInputStream(in);
}
if (ch != '\n' && ch != '\r')
{
buf[index++] = (byte)ch;
}
count++;
}
in.reset();
//
// nothing but new lines, little else, assume regular armoring
//
if (count < 4)
{
return new ArmoredInputStream(in);
}
//
// test our non-blank data
//
byte[] firstBlock = new byte[8];
System.arraycopy(buf, 0, firstBlock, 0, firstBlock.length);
try
{
byte[] decoded = Base64.decode(firstBlock);
//
// it's a base64 PGP block.
//
if ((decoded[0] & 0x80) != 0)
{
return new ArmoredInputStream(in, false);
}
return new ArmoredInputStream(in);
}
catch (DecoderException e)
{
throw new IOException(e.getMessage());
}
}
}
4. 함수 내용 및 업로드시 Exception 메시지를 확인해 보면 Base64 문자열로 Secret Key를 입력하면 된다.