Skip to content

PyPI and npm Repositories

Python packages publish to Shared Nexus (nexus.shared.cwiq.io) using twine. npm packages install from Dev Nexus (nexus.dev.cwiq.io). All operations use port 443 (standard HTTPS).

PyPI Repositories

The Python package workflow uses the Shared Nexus instance. cwiq-common is the primary internal package.

Repository Structure

Repository Type Purpose
pypi-hosted Hosted Internal packages — cwiq-common publishes here
pypi-proxy Proxy Cache of pypi.org
pypi-group Group Combined endpoint — install target for all pipelines

PyPI URLs

Operation URL
Publish (twine) https://nexus.shared.cwiq.io/repository/pypi-hosted/
Install (pip) https://nexus.shared.cwiq.io/repository/pypi-group/simple/

The group repository combines hosted and proxy — a pip install resolves both internal packages and public packages from the cached pypi.org mirror through a single endpoint.

Publishing a Package (CI)

# Publish cwiq-common to Nexus PyPI
twine upload \
  --repository-url https://nexus.shared.cwiq.io/repository/pypi-hosted/ \
  --username "${NEXUS_USER}" \
  --password "${NEXUS_PASSWORD}" \
  dist/*

Installing from Nexus PyPI

# Install cwiq-common from Nexus group
pip install cwiq-common \
  --index-url https://nexus.shared.cwiq.io/repository/pypi-group/simple/ \
  --trusted-host nexus.shared.cwiq.io

# Install with extra-index for public packages
pip install fastapi \
  --extra-index-url https://nexus.shared.cwiq.io/repository/pypi-group/simple/

pip.conf (Developer Workstations)

Configure pip to always use Nexus as the primary index:

[global]
index-url = https://nexus.shared.cwiq.io/repository/pypi-group/simple/
trusted-host = nexus.shared.cwiq.io

Place this at ~/.pip/pip.conf (Linux/macOS) or %APPDATA%\pip\pip.ini (Windows).

pyproject.toml (Package Publishing)

[tool.poetry.source]
name = "nexus"
url = "https://nexus.shared.cwiq.io/repository/pypi-group/simple/"
priority = "primary"

CI/CD Variables (cwiq-common Pipeline)

# platform/cwiq-common/.gitlab-ci.yml
variables:
  NEXUS_HOST: nexus.shared.cwiq.io
  NEXUS_PYPI_PUSH_URL: "https://${NEXUS_HOST}/repository/pypi-hosted/"
  NEXUS_PYPI_PULL_URL: "https://${NEXUS_HOST}/repository/pypi-group/simple/"

cwiq-common Package Reference

Field Value
Package name cwiq-common
Current version 0.2.0
GitLab project orchestrator/cwiq-common (ID 29)
Import as cwiq_common
Publish repository pypi-hosted
Install repository pypi-group (group, includes proxy cache)

Install in any platform service:

pip install cwiq-common \
  --index-url https://nexus.shared.cwiq.io/repository/pypi-group/simple/

Publishing Workflow

The cwiq-common pipeline publishes on version tag push (v*):

  1. Build: python -m build creates dist/ with .whl and .tar.gz
  2. Auth: Vault JWT → secret/nexus/svc-orchestrator → NEXUS_USER / NEXUS_PASSWORD
  3. Publish: twine upload --repository-url ${NEXUS_PYPI_PUSH_URL}
  4. Version is immutable once pushed to pypi-hosted (ALLOW_ONCE not enforced for PyPI, but treat releases as immutable by convention)

npm Repositories

npm repositories live on the Dev Nexus instance (nexus.dev.cwiq.io). This is the only Nexus artifact type that uses Dev rather than Shared — the npm workflow predates the Shared npm setup and no internal npm packages currently exist in production use.

Repository Structure

Repository Type Purpose
npm-hosted Hosted Internal npm packages
npm-proxy Proxy Cache of npmjs.org
npm-group Group Combined endpoint — install target

npm URLs

Operation URL
Install (npm) https://nexus.dev.cwiq.io/repository/npm-group/
Publish https://nexus.dev.cwiq.io/repository/npm-hosted/

Configuring npm to Use Nexus

# Set Nexus as the npm registry
npm config set registry https://nexus.dev.cwiq.io/repository/npm-group/

# Or per-project (.npmrc in project root)
echo "registry=https://nexus.dev.cwiq.io/repository/npm-group/" > .npmrc

CI/CD Usage (UI Pipeline)

The UI pipeline installs npm packages through Nexus to avoid npmjs.org rate limits and ensure reproducible builds:

# platform/ui/.gitlab-ci.yml
before_script:
  - npm config set registry https://nexus.dev.cwiq.io/repository/npm-group/

install:
  script:
    - npm ci

Publishing an npm Package

# Authenticate to Nexus npm hosted
npm login \
  --registry https://nexus.dev.cwiq.io/repository/npm-hosted/ \
  --username "${NEXUS_USER}" \
  --password "${NEXUS_PASSWORD}" \
  --email dev@cwiq.io

# Publish
npm publish --registry https://nexus.dev.cwiq.io/repository/npm-hosted/

Authentication

Both PyPI and npm operations use Vault JWT auth — the same pattern as Docker and RPM:

# In .gitlab-ci.yml — fetch credentials from Vault before publish/install
get_nexus_creds:
  id_tokens:
    VAULT_ID_TOKEN:
      aud: https://gitlab.shared.cwiq.io
  script:
    - |
      VAULT_TOKEN=$(curl -s -X POST "${VAULT_ADDR}/v1/auth/jwt/login" \
        -d "{\"jwt\":\"${VAULT_ID_TOKEN}\",\"role\":\"nexus-ci\"}" \
        | jq -r .auth.client_token)
      NEXUS_USER=$(curl -s -H "X-Vault-Token: ${VAULT_TOKEN}" \
        "${VAULT_ADDR}/v1/secret/data/nexus/svc-orchestrator" | jq -r .data.data.username)
      NEXUS_PASSWORD=$(curl -s -H "X-Vault-Token: ${VAULT_TOKEN}" \
        "${VAULT_ADDR}/v1/secret/data/nexus/svc-orchestrator" | jq -r .data.data.password)

See Service Accounts for the full Vault JWT auth flow.