Publish your first Maven/npm/PyPI package¶
What you'll learn:
- How to configure your build tool's credentials for Repod
- How to publish a package with the native protocol your tool already speaks
(
mvn deploy,npm publish, ortwine upload— no Repod-specific plugin) - How to resolve it back with the same tool, proving it's a real, working private registry
Time: ~15 minutes
Prerequisites: Repod running locally (see Getting Started),
one of: a JDK + Maven, Node.js + npm, or Python + pip/twine. Pick the tab
that matches your ecosystem below — the three paths are independent, you only
need to follow one.
Step 1 — Get credentials¶
All three formats authenticate with your normal Repod account (or, for
CI/CD, an API token — Settings → API Tokens, role uploader or higher).
There's no separate registration step: the target repository/index/namespace
is created automatically the first time you publish into it.
Step 2 — Configure your build tool¶
Add a server credential to ~/.m2/settings.xml. The <id> must match
what you'll reference from pom.xml in the next step.
<settings>
<servers>
<server>
<id>repod-releases</id>
<username>admin</username>
<password>YourPassword1!</password>
</server>
</servers>
</settings>
Plain HTTP repositories
Maven blocks external http:// repositories by default since 3.8.1.
If your Repod instance isn't behind TLS yet, add a mirror override
to unblock this one repository id — see the "Plain HTTP repositories"
note in Client Setup.
Generate an API token (Settings → API Tokens, role uploader or
higher) — npm login's interactive flow isn't supported, so you paste a
pre-generated token directly into .npmrc instead, same as GitHub
Packages or Artifactory.
Step 3 — Create a minimal package¶
mkdir -p ~/hello-repod-maven/src/main/java/com/example
cd ~/hello-repod-maven
cat > src/main/java/com/example/Hello.java << 'EOF'
package com.example;
public class Hello {
public static void main(String[] args) {
System.out.println("Hello from Repod's Maven repository!");
}
}
EOF
cat > pom.xml << 'EOF'
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>hello-repod-maven</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<distributionManagement>
<repository>
<id>repod-releases</id>
<url>http://YOUR_HOST:8000/api/v1/maven/releases</url>
</repository>
</distributionManagement>
</project>
EOF
releases is the target Maven repository name — it doesn't need to
exist beforehand.
SNAPSHOT versions aren't supported in V1
Repod's Maven support rejects SNAPSHOT versions with a clear error.
Use a release version, as above.
Edit the generated package.json so it looks like this (adjust name
if it collides with something already published to this namespace):
mkdir -p ~/hello-repod-pypi/hello_repod_pypi && cd ~/hello-repod-pypi
cat > hello_repod_pypi/__init__.py << 'EOF'
def hello():
print("Hello from Repod's PyPI repository!")
EOF
cat > pyproject.toml << 'EOF'
[build-system]
requires = ["setuptools>=61.0"]
build-backend = "setuptools.build_meta"
[project]
name = "hello-repod-pypi"
version = "1.0.0"
description = "A demo package for Repod"
EOF
pip install --upgrade build twine
python -m build
python -m build produces dist/hello_repod_pypi-1.0.0-py3-none-any.whl
and a matching .tar.gz sdist.
Step 4 — Publish¶
You should see a normal Maven build finishing with:
Checksums (.sha1/.md5) and maven-metadata.xml are regenerated
server-side from what was actually stored — anything your client
uploaded for those is accepted but discarded, never trusted as-is.
Expected output:
npm notice
npm notice 📦 [email protected]
npm notice === Tarball Contents ===
...
+ [email protected]
Expected output:
Every format runs the same antivirus (ClamAV) + CVE (Grype) pipeline used for
.deb/.rpm/.apk packages before it's servable. A clean, dependency-free
demo package like this one passes in a couple of seconds.
What if a CVE is found?
A review-policy match lands the artifact in storage but keeps it
invisible to mvn/pip/npm until a maintainer or admin records a
decision — the exact same review queue used for OS packages. See
Walk through a CVE remediation.
Step 5 — Resolve it back¶
Prove it's a real, working registry by fetching your own package back with the same tool that published it.
cd /tmp && rm -rf resolve-test && mkdir resolve-test && cd resolve-test
mvn dependency:get -Dartifact=com.example:hello-repod-maven:1.0.0 \
-DremoteRepositories=repod-releases::default::http://YOUR_HOST:8000/api/v1/maven/releases
Expected output ends with:
cd /tmp && rm -rf resolve-test && mkdir resolve-test && cd resolve-test
npm view hello-repod-npm --registry http://YOUR_HOST:8000/api/v1/npm/private/
Expected output includes:
[email protected] | ISC
dist
.tarball: http://YOUR_HOST:8000/api/v1/npm/private/hello-repod-npm/-/hello-repod-npm-1.0.0.tgz
Troubleshooting¶
Maven: Return code is: 401
The <id> in pom.xml's <distributionManagement> doesn't match the
<id> of the <server> entry in settings.xml, or the password/token
is wrong.
Maven: deploy fails immediately with a SNAPSHOT-related error
Repod's Maven support only accepts release versions in V1. Change
<version> to something that doesn't end in -SNAPSHOT.
npm: npm ERR! code E401
Check .npmrc — the token line must be scoped to the exact registry URL
(including the trailing /), on a line starting with
//YOUR_HOST:8000/api/v1/npm/private/:_authToken=.
twine: 403 Forbidden
Either the credentials in .pypirc are wrong, or the private index has
been RBAC-restricted and your account's role isn't granted. Check
POST /api/v1/pypi/repositories/private/access.
It uploaded, but I can't resolve it back — 404
If the package tripped a review-policy CVE, it's stored but hidden
from every listing/download endpoint until a decision is recorded. Check
Security → Review Queue in the web UI.
What you just did¶
- Configured
settings.xml/.npmrc/.pypircwith Repod credentials - Published a package using your build tool's own native protocol — no Repod-specific CLI or plugin
- Watched the same antivirus + CVE pipeline used for OS packages run against it
- Resolved the package back with the same tool, from a clean directory
Next steps¶
- Client Setup (full reference) → — Gradle,
scoped npm namespaces,
--extra-index-urlfallback to public PyPI, access control for all three formats - Walk through a CVE remediation →
- Set up CI/CD publishing →