Nexus

이 문서는 source repo가 Nexus를 사용하는 기준을 설명합니다.

Package publish 시점과 dev/release channel 정책은 CI/CDRelease Policy를 따릅니다. 이 문서는 Nexus repository 주소, 인증, dev repository가 필요한 조건을 설명합니다.

1. 역할

Nexus는 사내 package/container artifact 흐름의 registry 역할을 합니다.

Artifact Repository type
npm package npm hosted/group
Python package PyPI hosted/group
Rust crate Cargo compatible registry
C/C++ package Conan hosted/group
Firmware binary raw hosted

Nexus repository는 보통 세 가지 역할로 나뉩니다. Proxy는 외부 registry를 cache해서 재현성과 속도를 높입니다. Hosted는 우리가 만든 package를 publish하는 곳입니다. Group은 proxy와 hosted를 하나의 download endpoint로 묶어 consumer가 주소를 덜 알게 합니다. CI에서 download URL과 publish URL을 분리하는 이유는 이 역할이 다르기 때문입니다.

이 source repo는 guide artifact를 만들기 때문에 publish target은 *-guide-hosted를 사용합니다. Package 이름은 실제 제품 code 예시처럼 자연스럽게 유지하고, guide artifact라는 구분은 Nexus hosted repository와 container image path가 담당합니다.

Role Meaning Example
Proxy 외부 registry cache npmjs, PyPI, crates.io, Conan Center, Go proxy
Hosted 사내 package publish target npm-guide-hosted, pypi-guide-hosted, conan-guide-hosted, raw-embedded-guide-hosted
Group download endpoint aggregation npm, pypi, conan group repository

2. Local 설정

Package dependency download도 Nexus 주소를 먼저 보도록 설정합니다. Local 개발자는 .env.example.env로 복사해 credential을 채운 뒤 local helper인 make nexus/configure를 실행합니다. make target은 .env가 있으면 자동으로 읽습니다.

cp .env.example .env
# edit .env
make nexus/configure
make package/install

scripts/configure-nexus.sh는 local developer helper입니다. CI는 이 script에 의존하지 않고 workflow와 composite action만 보고 동작해야 합니다.

직접 실행할 수도 있습니다.

NEXUS_NPM_REGISTRY=https://nexus.example/repository/npm/ \
NEXUS_NPM_PUBLISH_REGISTRY=https://nexus.example/repository/npm-guide-hosted/ \
NEXUS_USERNAME=github-actions \
NEXUS_PASSWORD=... \
bash scripts/configure-nexus.sh

언어별 registry 설정 위치는 다릅니다.

Ecosystem Committed address config Secret injection
Python/uv pyproject.toml[[tool.uv.index]] UV_INDEX_<NAME>_USERNAME/PASSWORD, UV_PUBLISH_*
TypeScript/npm project .npmrc 또는 CI가 생성한 .npmrc NEXUS_USERNAME/NEXUS_PASSWORD에서 생성한 basic auth
Rust/Cargo .cargo/config.toml 또는 CI가 생성한 Cargo config NEXUS_USERNAME/NEXUS_PASSWORD에서 생성한 publish token
Go committed go.mod module path + GOPROXY/GONOSUMDB env .netrc, CI secret, private proxy auth
C/Conan Conan remote config NEXUS_USERNAME/NEXUS_PASSWORD

3. Tirosh Nexus URL 기준

Tirosh home Nexus repository 주소는 tirosh-infra/sites/tirosh-home/nexus/vars.yml의 repository 이름을 기준으로 둡니다.

Purpose Variable URL
npm download NEXUS_NPM_REGISTRY https://nexus.internal.tirosh.ai/repository/npm/
npm publish NEXUS_NPM_PUBLISH_REGISTRY https://nexus.internal.tirosh.ai/repository/npm-guide-hosted/
PyPI download NEXUS_PYPI_INDEX_URL https://nexus.internal.tirosh.ai/repository/pypi/simple/
PyPI publish NEXUS_PYPI_PUBLISH_URL https://nexus.internal.tirosh.ai/repository/pypi-guide-hosted/
Cargo download NEXUS_CARGO_PROXY_REGISTRY sparse+https://nexus.internal.tirosh.ai/repository/cargo/
Cargo publish NEXUS_CARGO_REGISTRY_INDEX sparse+https://nexus.internal.tirosh.ai/repository/cargo-guide-hosted/
Go download NEXUS_GO_PROXY_URL https://nexus.internal.tirosh.ai/repository/go/
C package consume NEXUS_CONAN_REMOTE_URL https://nexus.internal.tirosh.ai/repository/conan/
C package publish NEXUS_CONAN_PUBLISH_REMOTE_URL https://nexus.internal.tirosh.ai/repository/conan-guide-hosted/
Firmware upload NEXUS_RAW_FIRMWARE_URL https://nexus.internal.tirosh.ai/repository/raw-embedded-guide-hosted

Download group은 기존 endpoint를 유지합니다. Nexus group repository 구성에는 *-guide-hosted를 추가해 같은 group URL로 guide package도 resolve되게 합니다. 단, guide package와 제품 package가 같은 이름과 version으로 공존해야 하는 시점이 오면 별도 guide group을 만들거나 package 이름/namespace를 다시 분리해야 합니다.

4. Dev Repository 기준

Nexus dev repository는 모든 package type에 기본으로 만들지 않습니다. Dev repository가 필요한 경우는 다른 service나 repo가 release 전 package를 package manager로 받아 써야 할 때입니다.

Container dev image는 GHCR tag만으로도 통합 검증이 가능한 경우가 많습니다. 이 repo는 main merge에서 GHCR dev image를 자동 push합니다. 반대로 package dev artifact는 dependency resolver를 통해 consumer build에 들어가므로, 필요하다면 release repository와 분리된 dev hosted repository나 dev channel을 둡니다.

Artifact Dev repo 필요성 기준
Container image 낮음 GHCR의 dev moving tag와 dev-<count>-g<sha> trace tag로 preview와 smoke를 검증합니다.
npm package 선택 consumer가 dev 또는 next dist-tag를 설치해야 하면 운영합니다.
Python wheel/sdist 높을 수 있음 release 전 wheel을 다른 repo가 설치해야 하면 pypi-dev-hosted 같은 dev index를 둡니다.
Rust crate 낮음 기본은 release publish입니다. Dev 검증은 cargo publish --dry-run과 source dependency로 처리합니다.
Go module 낮음 dev는 VCS commit 또는 pseudo-version 소비가 자연스럽습니다.
Conan/C package 선택 binary consumer가 release 전 package를 받아야 하면 conan-dev-hosted를 둡니다.
Firmware/raw artifact 선택 dev firmware image를 QA나 device lab에서 공유해야 하면 raw dev repository를 둡니다.

Dev repository를 만들 때도 group/download endpoint와 hosted/publish endpoint는 분리합니다. Consumer는 dev channel을 의식적으로 선택해야 하며, release dependency가 실수로 dev repository를 우선하지 않게 합니다.

*-guide-hosted*-dev-hosted는 다른 축입니다. Guide hosted는 이 repo의 artifact 소속을 구분하고, dev hosted는 release 전 snapshot lifecycle을 구분합니다. 지금 workflow는 guide hosted만 사용하며, dev hosted는 실제 consumer가 생길 때 opt-in group이나 명시적 index로 연결합니다.

5. CI 설정

CI에서는 repository secret과 variable을 사용합니다. credential은 commit하지 않고 workflow에서 .npmrc, Cargo config, uv auth, Conan remote config를 생성합니다.

Repository URL과 username은 GitHub Actions variables로, credential은 secrets로 주입합니다. URL은 민감정보가 아니고 review 가능한 configuration에 가깝습니다. Password/token은 secret이며 log masking과 protected environment를 통해 다뤄야 합니다.

Workflow는 Nexus publish URL fallback을 두지 않습니다. Repository variable이 빠졌다면 publish job은 실패해야 합니다. 그래야 guide artifact가 실수로 일반 hosted repository나 public registry로 publish되는 일을 막을 수 있습니다.

Variables:
NEXUS_NPM_REGISTRY
NEXUS_NPM_PUBLISH_REGISTRY
NEXUS_PYPI_INDEX_URL
NEXUS_PYPI_PUBLISH_URL
NEXUS_CARGO_PROXY_REGISTRY
NEXUS_CARGO_REGISTRY_INDEX
NEXUS_GO_PROXY_URL
NEXUS_CONAN_REMOTE_URL
NEXUS_CONAN_PUBLISH_REMOTE_URL
NEXUS_RAW_FIRMWARE_URL
NEXUS_USERNAME
GO_PRIVATE_MODULE_PATTERNS

Secrets:
NEXUS_PASSWORD

npm과 Cargo가 요구하는 auth 값은 CI에서 NEXUS_USERNAMENEXUS_PASSWORD로 생성합니다. 별도 NEXUS_NPM_TOKEN, NEXUS_CARGO_TOKEN secret은 두지 않습니다.

5-1. Publish 권한 기준

Guide hosted repository의 publisher role은 단순 ADD만으로 두지 않습니다. Package manager별 publish protocol이 metadata 생성, package blob upload, index 갱신, overwrite 방지용 사전 조회를 서로 다르게 수행하기 때문입니다.

Repository Publisher actions 이유
npm guide hosted BROWSE, READ, ADD, EDIT scoped package metadata와 tarball upload 과정에서 package document 갱신이 필요합니다.
PyPI guide hosted BROWSE, READ, ADD, EDIT wheel/sdist upload와 normalized project metadata 갱신을 허용해야 합니다.
Cargo guide hosted BROWSE, READ, ADD, EDIT sparse index와 crate artifact를 함께 갱신해야 합니다.
Conan guide hosted BROWSE, READ, ADD, EDIT recipe revision과 binary package revision을 업로드하면서 metadata가 갱신됩니다.
Raw embedded guide hosted BROWSE, READ, ADD, EDIT 같은 release path에 .elf, .hex, .bin, .map, manifest를 순차 업로드하고 사전 조회를 수행합니다.

Reader role은 BROWSE, READ만 가져야 합니다. Publisher credential은 GitHub Actions secret으로만 주입하고 local 문서나 repository file에 저장하지 않습니다.

6. Conan과 Raw Firmware

C library package는 Conan 2 package로 배포합니다. Header, library, package metadata를 함께 다루기 때문에 consumer app은 Conan dependency로 가져갈 수 있습니다. .elf/.hex/.bin/.map 같은 firmware image 산출물은 C library package가 아니라 device/release evidence에 가깝기 때문에 raw-embedded-guide-hosted repository에 올립니다.

Artifact Repository Why
patient-signal-c-core/<version> Conan guide hosted C library consumer가 dependency로 가져갈 수 있어야 합니다.
.elf raw-embedded-guide-hosted debug/release evidence로 추적합니다.
.hex raw-embedded-guide-hosted flash image로 사용됩니다.
.bin raw-embedded-guide-hosted binary image로 사용됩니다.
.map raw-embedded-guide-hosted memory layout, symbol size, review evidence로 사용됩니다.