Skip to content

Commit ce039f6

Browse files
MAVRICK-1CopilotmatifaliDevelopmentCats
authored
Add Sonatype Nexus repository integration module (#262)
# Add Sonatype Nexus Repository Integration Module ## Summary Implements a Coder module for Sonatype Nexus Repository Manager integration that automatically configures Maven, npm, PyPI, and Docker registries for development workspaces. ## Demo Video & Screenshots https://github.com/user-attachments/assets/2c51f229-d34d-483b-a0e9-f4e0d79332c2 ![Nexus Repository Integration](https://github.com/user-attachments/assets/1a778a8f-0e48-40f2-ae0f-5b8d5d5ce849) ## Features - ✅ **Maven Support**: Automatic `settings.xml` configuration - ✅ **npm Support**: Automatic `.npmrc` configuration with scoped packages - ✅ **PyPI Support**: Automatic `pip.conf` configuration - ✅ **Docker Support**: Registry authentication setup - ✅ **Flexible Configuration**: Support for multiple repositories per package manager - ✅ **Secure Credentials**: API token and password support - ✅ **Username Options**: Configurable username field (username or email) ## Nexus Repository Manager Requirements ### Version Requirements **Yes, this module requires Nexus Repository Manager Pro version** for full functionality, though basic features work with the Community Edition (OSS). ### Supported Authentication Methods This module supports **4 authentication methods**: 1. **User Token Authentication** (Recommended - Pro only) - Enhanced security with two-part tokens - Ideal for CI/CD and automated environments - Requires `nx-usertoken-current` privilege 2. **API Token Authentication** (Pro only) - Single-use access tokens via REST API - Programmatic token generation and management 3. **Basic Authentication** (OSS & Pro) - Standard HTTP Basic Auth with username/password - Works with both OSS and Pro versions 4. **Base64 Encoded Credentials** (OSS & Pro) - Base64 encoded `username:password` format - Compatible with npm and other package managers ### Testing Instructions #### Prerequisites - Nexus Repository Manager instance (OSS or Pro) - Admin access to configure repositories - Test repositories for each package manager you want to test #### Setup Test Environment 1. **Create Test Repositories** in your Nexus instance: - Maven: `maven-public`, `maven-releases` - npm: `npm-public`, `@company:npm-private` - PyPI: `pypi-public`, `pypi-private` - Docker: `docker-public`, `docker-private` 2. **Configure Authentication**: - For Pro: Generate user tokens via UI (User menu → User Token) - For OSS: Use username/password or base64 encoded credentials - Set up appropriate permissions for test repositories 3. **Test the Module**: ```hcl module "nexus" { source = "registry.coder.com/mavrickrishi/nexus/coder" version = "1.0.0" agent_id = coder_agent.main.id nexus_url = "https://your-nexus-instance.com" nexus_password = var.nexus_api_token # or password package_managers = { maven = ["maven-public", "maven-releases"] npm = ["npm-public", "@Company:npm-private"] pypi = ["pypi-public", "pypi-private"] docker = ["docker-public", "docker-private"] } } ``` 4. **Verify Configuration**: - Check generated config files in workspace - Test package installation from configured repositories - Verify authentication works for each package manager #### EC2 Deployment Testing Tested by deploying on EC2 instance with: - Ubuntu 22.04 LTS - Nexus Repository Manager Pro - All package managers (Maven, npm, PyPI, Docker) - Both token and basic authentication methods ## Usage Example ```hcl module "nexus" { source = "registry.coder.com/mavrickrishi/nexus/coder" version = "1.0.0" agent_id = coder_agent.main.id nexus_url = "https://nexus.company.com" nexus_password = var.nexus_api_token package_managers = { maven = ["maven-public", "maven-releases"] npm = ["npm-public", "@Company:npm-private"] pypi = ["pypi-public", "pypi-private"] docker = ["docker-public", "docker-private"] } } ``` ## Testing - ✅ 11 comprehensive tests covering all functionality - ✅ Variable validation tests - ✅ Package manager configuration tests - ✅ Error handling tests - ✅ All tests passing - ✅ EC2 deployment tested ## Files Added - `registry/mavrickrishi/modules/nexus/main.tf` - Main module configuration - `registry/mavrickrishi/modules/nexus/README.md` - Complete documentation - `registry/mavrickrishi/modules/nexus/main.test.ts` - Test suite ## Checklist - [x] Module follows existing patterns and conventions - [x] Comprehensive test coverage (11 tests) - [x] Complete documentation with examples - [x] Input validation and error handling - [x] Secure credential handling - [x] All tests passing - [x] Demo video included - [x] Screenshots added - [x] Testing instructions provided - [x] Authentication methods documented - [x] EC2 deployment tested Closes #202 /claim #202 --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Atif Ali <[email protected]> Co-authored-by: DevCats <[email protected]> Co-authored-by: DevCats <[email protected]>
1 parent 8acda84 commit ce039f6

File tree

6 files changed

+544
-0
lines changed

6 files changed

+544
-0
lines changed

.icons/nexus-repository.svg

Lines changed: 5 additions & 0 deletions
Loading

registry/mavrickrishi/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ participating in LFX CNCF programs, and helping the developer community grow.
1919
## Modules
2020

2121
- **aws-ami-snapshot**: Create and manage AMI snapshots for Coder workspaces with restore capabilities
22+
- [nexus-repository](./modules/nexus-repository/) - Configure package managers to use Sonatype Nexus Repository
2223
- [auto-start-dev-server](modules/auto-start-dev-server/README.md) - Automatically detect and start development servers for various project types
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
---
2+
display_name: Nexus Repository
3+
description: Configure package managers to use Sonatype Nexus Repository for Maven, npm, PyPI, and Docker registries.
4+
icon: ../../../../.icons/nexus-repository.svg
5+
verified: true
6+
tags: [integration, nexus-repository, maven, npm, pypi, docker]
7+
---
8+
9+
# Sonatype Nexus Repository
10+
11+
Configure package managers (Maven, npm, Go, PyPI, Docker) to use [Sonatype Nexus Repository](https://help.sonatype.com/en/sonatype-nexus-repository.html) with API token authentication. This module provides secure credential handling, multiple repository support per package manager, and flexible username configuration.
12+
13+
```tf
14+
module "nexus_repository" {
15+
source = "registry.coder.com/mavrickrishi/nexus-repository/coder"
16+
version = "1.0.0"
17+
agent_id = coder_agent.example.id
18+
nexus_url = "https://nexus.example.com"
19+
nexus_password = var.nexus_api_token
20+
package_managers = {
21+
maven = ["maven-public", "maven-releases"]
22+
npm = ["npm-public", "@scoped:npm-private"]
23+
go = ["go-public", "go-private"]
24+
pypi = ["pypi-public", "pypi-private"]
25+
docker = ["docker-public", "docker-private"]
26+
}
27+
}
28+
```
29+
30+
## Requirements
31+
32+
- Nexus Repository Manager 3.x
33+
- Valid API token or user credentials
34+
- Package managers installed on the workspace (Maven, npm, Go, pip, Docker as needed)
35+
36+
> [!NOTE]
37+
> This module configures package managers but does not install them. You need to handle the installation of Maven, npm, Go, Python pip, and Docker yourself.
38+
39+
## Examples
40+
41+
### Configure Maven to use Nexus repositories
42+
43+
```tf
44+
module "nexus_repository" {
45+
source = "registry.coder.com/mavrickrishi/nexus-repository/coder"
46+
version = "1.0.0"
47+
agent_id = coder_agent.example.id
48+
nexus_url = "https://nexus.example.com"
49+
nexus_password = var.nexus_api_token
50+
package_managers = {
51+
maven = ["maven-public", "maven-releases", "maven-snapshots"]
52+
}
53+
}
54+
```
55+
56+
### Configure npm with scoped packages
57+
58+
```tf
59+
module "nexus_repository" {
60+
source = "registry.coder.com/mavrickrishi/nexus-repository/coder"
61+
version = "1.0.0"
62+
agent_id = coder_agent.example.id
63+
nexus_url = "https://nexus.example.com"
64+
nexus_password = var.nexus_api_token
65+
package_managers = {
66+
npm = ["npm-public", "@mycompany:npm-private"]
67+
}
68+
}
69+
```
70+
71+
### Configure Go module proxy
72+
73+
```tf
74+
module "nexus_repository" {
75+
source = "registry.coder.com/mavrickrishi/nexus-repository/coder"
76+
version = "1.0.0"
77+
agent_id = coder_agent.example.id
78+
nexus_url = "https://nexus.example.com"
79+
nexus_password = var.nexus_api_token
80+
package_managers = {
81+
go = ["go-public", "go-private"]
82+
}
83+
}
84+
```
85+
86+
### Configure Python PyPI repositories
87+
88+
```tf
89+
module "nexus_repository" {
90+
source = "registry.coder.com/mavrickrishi/nexus-repository/coder"
91+
version = "1.0.0"
92+
agent_id = coder_agent.example.id
93+
nexus_url = "https://nexus.example.com"
94+
nexus_password = var.nexus_api_token
95+
package_managers = {
96+
pypi = ["pypi-public", "pypi-private"]
97+
}
98+
}
99+
```
100+
101+
### Configure Docker registries
102+
103+
```tf
104+
module "nexus_repository" {
105+
source = "registry.coder.com/mavrickrishi/nexus-repository/coder"
106+
version = "1.0.0"
107+
agent_id = coder_agent.example.id
108+
nexus_url = "https://nexus.example.com"
109+
nexus_password = var.nexus_api_token
110+
package_managers = {
111+
docker = ["docker-public", "docker-private"]
112+
}
113+
}
114+
```
115+
116+
### Use custom username
117+
118+
```tf
119+
module "nexus_repository" {
120+
source = "registry.coder.com/mavrickrishi/nexus-repository/coder"
121+
version = "1.0.0"
122+
agent_id = coder_agent.example.id
123+
nexus_url = "https://nexus.example.com"
124+
nexus_username = "custom-user"
125+
nexus_password = var.nexus_api_token
126+
package_managers = {
127+
maven = ["maven-public"]
128+
}
129+
}
130+
```
131+
132+
### Complete configuration for all package managers
133+
134+
```tf
135+
module "nexus_repository" {
136+
source = "registry.coder.com/mavrickrishi/nexus-repository/coder"
137+
version = "1.0.0"
138+
agent_id = coder_agent.example.id
139+
nexus_url = "https://nexus.example.com"
140+
nexus_password = var.nexus_api_token
141+
package_managers = {
142+
maven = ["maven-public", "maven-releases"]
143+
npm = ["npm-public", "@company:npm-private"]
144+
go = ["go-public", "go-private"]
145+
pypi = ["pypi-public", "pypi-private"]
146+
docker = ["docker-public", "docker-private"]
147+
}
148+
}
149+
```
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import { describe, expect, it } from "bun:test";
2+
import {
3+
executeScriptInContainer,
4+
runTerraformApply,
5+
runTerraformInit,
6+
testRequiredVariables,
7+
} from "~test";
8+
9+
describe("nexus-repository", async () => {
10+
await runTerraformInit(import.meta.dir);
11+
12+
testRequiredVariables(import.meta.dir, {
13+
agent_id: "test-agent",
14+
nexus_url: "https://nexus.example.com",
15+
nexus_password: "test-password",
16+
});
17+
18+
it("configures Maven settings", async () => {
19+
const state = await runTerraformApply(import.meta.dir, {
20+
agent_id: "test-agent",
21+
nexus_url: "https://nexus.example.com",
22+
nexus_password: "test-token",
23+
package_managers: JSON.stringify({
24+
maven: ["maven-public"],
25+
}),
26+
});
27+
28+
const output = await executeScriptInContainer(state, "ubuntu:20.04");
29+
expect(output.stdout.join("\n")).toContain("☕ Configuring Maven...");
30+
expect(output.stdout.join("\n")).toContain("🥳 Configuration complete!");
31+
});
32+
33+
it("configures npm registry", async () => {
34+
const state = await runTerraformApply(import.meta.dir, {
35+
agent_id: "test-agent",
36+
nexus_url: "https://nexus.example.com",
37+
nexus_password: "test-token",
38+
package_managers: JSON.stringify({
39+
npm: ["npm-public"],
40+
}),
41+
});
42+
43+
const output = await executeScriptInContainer(state, "ubuntu:20.04");
44+
expect(output.stdout.join("\n")).toContain("📦 Configuring npm...");
45+
expect(output.stdout.join("\n")).toContain("🥳 Configuration complete!");
46+
});
47+
48+
it("configures PyPI repository", async () => {
49+
const state = await runTerraformApply(import.meta.dir, {
50+
agent_id: "test-agent",
51+
nexus_url: "https://nexus.example.com",
52+
nexus_password: "test-token",
53+
package_managers: JSON.stringify({
54+
pypi: ["pypi-public"],
55+
}),
56+
});
57+
58+
const output = await executeScriptInContainer(state, "ubuntu:20.04");
59+
expect(output.stdout.join("\n")).toContain("🐍 Configuring pip...");
60+
expect(output.stdout.join("\n")).toContain("🥳 Configuration complete!");
61+
});
62+
63+
it("configures multiple package managers", async () => {
64+
const state = await runTerraformApply(import.meta.dir, {
65+
agent_id: "test-agent",
66+
nexus_url: "https://nexus.example.com",
67+
nexus_password: "test-token",
68+
package_managers: JSON.stringify({
69+
maven: ["maven-public"],
70+
npm: ["npm-public"],
71+
pypi: ["pypi-public"],
72+
}),
73+
});
74+
75+
const output = await executeScriptInContainer(state, "ubuntu:20.04");
76+
expect(output.stdout.join("\n")).toContain("☕ Configuring Maven...");
77+
expect(output.stdout.join("\n")).toContain("📦 Configuring npm...");
78+
expect(output.stdout.join("\n")).toContain("🐍 Configuring pip...");
79+
expect(output.stdout.join("\n")).toContain(
80+
"✅ Nexus repository configuration completed!",
81+
);
82+
});
83+
84+
it("handles empty package managers", async () => {
85+
const state = await runTerraformApply(import.meta.dir, {
86+
agent_id: "test-agent",
87+
nexus_url: "https://nexus.example.com",
88+
nexus_password: "test-token",
89+
package_managers: JSON.stringify({}),
90+
});
91+
92+
const output = await executeScriptInContainer(state, "ubuntu:20.04");
93+
expect(output.stdout.join("\n")).toContain(
94+
"🤔 no maven repository is set, skipping maven configuration.",
95+
);
96+
expect(output.stdout.join("\n")).toContain(
97+
"🤔 no npm repository is set, skipping npm configuration.",
98+
);
99+
expect(output.stdout.join("\n")).toContain(
100+
"🤔 no pypi repository is set, skipping pypi configuration.",
101+
);
102+
expect(output.stdout.join("\n")).toContain(
103+
"🤔 no docker repository is set, skipping docker configuration.",
104+
);
105+
});
106+
107+
it("configures Go module proxy", async () => {
108+
const state = await runTerraformApply(import.meta.dir, {
109+
agent_id: "test-agent",
110+
nexus_url: "https://nexus.example.com",
111+
nexus_password: "test-token",
112+
package_managers: JSON.stringify({
113+
go: ["go-public", "go-private"],
114+
}),
115+
});
116+
117+
const output = await executeScriptInContainer(state, "ubuntu:20.04");
118+
expect(output.stdout.join("\n")).toContain("🐹 Configuring Go...");
119+
expect(output.stdout.join("\n")).toContain(
120+
"Go proxy configured via GOPROXY environment variable",
121+
);
122+
expect(output.stdout.join("\n")).toContain("🥳 Configuration complete!");
123+
});
124+
125+
it("validates nexus_url format", async () => {
126+
await expect(
127+
runTerraformApply(import.meta.dir, {
128+
agent_id: "test-agent",
129+
nexus_url: "invalid-url",
130+
nexus_password: "test-token",
131+
package_managers: JSON.stringify({}),
132+
}),
133+
).rejects.toThrow();
134+
});
135+
136+
it("validates username_field values", async () => {
137+
await expect(
138+
runTerraformApply(import.meta.dir, {
139+
agent_id: "test-agent",
140+
nexus_url: "https://nexus.example.com",
141+
nexus_password: "test-token",
142+
username_field: "invalid",
143+
package_managers: JSON.stringify({}),
144+
}),
145+
).rejects.toThrow();
146+
});
147+
});

0 commit comments

Comments
 (0)