From c727465646fe1cfb5a522f52aa844599f3304594 Mon Sep 17 00:00:00 2001 From: Lukasz Raczylo Date: Fri, 2 Jan 2026 18:44:10 +0000 Subject: [PATCH] fixes --- .github/workflows/release.yaml | 28 + .gitignore | 4 + README.md | 1261 +++++++++++++++++ deployments/kubernetes/README.md | 416 ++++++ helm/gohoarder/.helmignore | 31 + helm/gohoarder/Chart.yaml | 22 + helm/gohoarder/README.md | 214 +++ helm/gohoarder/templates/NOTES.txt | 70 + helm/gohoarder/templates/_helpers.tpl | 174 +++ helm/gohoarder/templates/configmap.yaml | 168 +++ .../templates/deployment-frontend.yaml | 68 + .../templates/deployment-scanner.yaml | 111 ++ .../templates/deployment-server.yaml | 191 +++ helm/gohoarder/templates/ingress.yaml | 83 ++ helm/gohoarder/templates/pvc.yaml | 37 + helm/gohoarder/templates/secret.yaml | 66 + helm/gohoarder/templates/service.yaml | 39 + helm/gohoarder/templates/serviceaccount.yaml | 12 + helm/gohoarder/values.yaml | 405 ++++++ 19 files changed, 3400 insertions(+) create mode 100644 README.md create mode 100644 deployments/kubernetes/README.md create mode 100644 helm/gohoarder/.helmignore create mode 100644 helm/gohoarder/Chart.yaml create mode 100644 helm/gohoarder/README.md create mode 100644 helm/gohoarder/templates/NOTES.txt create mode 100644 helm/gohoarder/templates/_helpers.tpl create mode 100644 helm/gohoarder/templates/configmap.yaml create mode 100644 helm/gohoarder/templates/deployment-frontend.yaml create mode 100644 helm/gohoarder/templates/deployment-scanner.yaml create mode 100644 helm/gohoarder/templates/deployment-server.yaml create mode 100644 helm/gohoarder/templates/ingress.yaml create mode 100644 helm/gohoarder/templates/pvc.yaml create mode 100644 helm/gohoarder/templates/secret.yaml create mode 100644 helm/gohoarder/templates/service.yaml create mode 100644 helm/gohoarder/templates/serviceaccount.yaml create mode 100644 helm/gohoarder/values.yaml diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 0e7a2de..b611811 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -66,3 +66,31 @@ jobs: git add docs/bench git diff --staged --quiet || git commit -m "Update benchmark results" git push origin main + + publish-helm-chart: + name: Publish Helm Chart + needs: release + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Get release version + id: version + run: | + VERSION=$(git describe --tags --abbrev=0 2>/dev/null || echo "0.0.0") + VERSION=${VERSION#v} + echo "version=$VERSION" >> $GITHUB_OUTPUT + + - name: Trigger helm-charts release + env: + GH_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} + run: | + gh api repos/lukaszraczylo/helm-charts/dispatches \ + -f event_type=release-chart \ + -f client_payload[chart_name]=gohoarder \ + -f client_payload[version]=${{ steps.version.outputs.version }} \ + -f client_payload[source_repo]=lukaszraczylo/gohoarder \ + -f client_payload[chart_path]=helm/gohoarder diff --git a/.gitignore b/.gitignore index 2ec3556..23aaf2b 100644 --- a/.gitignore +++ b/.gitignore @@ -68,7 +68,11 @@ web/dist/ # Test fixtures tests/fixtures/temp/ + +# Markdown files (except README.md) *.md +!README.md + /gohoarder *.log *.out diff --git a/README.md b/README.md new file mode 100644 index 0000000..2272ff6 --- /dev/null +++ b/README.md @@ -0,0 +1,1261 @@ +# GoHoarder + +**A universal, security-first caching proxy for package managers with automated vulnerability scanning.** + +GoHoarder is a transparent pass-through cache proxy that supports npm, pip, and Go modules. It caches packages locally, scans them for vulnerabilities using multiple security scanners, and blocks packages that exceed your security thresholdsβ€”all without requiring changes to your existing workflows. + +[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) +[![Go Version](https://img.shields.io/badge/go-1.22+-blue.svg)](https://golang.org) + +--- + +## ✨ Features + +### πŸ”’ **Security-First** +- **Automated vulnerability scanning** with multiple scanners (Trivy, OSV, Grype, npm-audit, pip-audit, GitHub Advisory Database, govulncheck) +- **Configurable blocking thresholds** by severity (CRITICAL, HIGH, MODERATE, LOW) +- **CVE bypass system** for managing false positives or accepted risks +- **Real-time scanning** before package delivery - blocks vulnerable packages on **first download** +- **403 Forbidden responses** for blocked packages (not 502 errors) +- **No fallback mechanisms** - security is enforced across all package managers + +### πŸš€ **Performance** +- **Intelligent caching** reduces bandwidth and speeds up builds +- **Scan-once, serve-many** - packages scanned once, results cached +- **Background rescanning** keeps security assessments up-to-date +- **Multi-backend storage** (filesystem, S3, SMB/CIFS) +- **Connection pooling** and **rate limiting** for upstream registries +- **Circuit breaker** pattern for resilience + +### πŸ“Š **Observability** +- **Web dashboard** with Vue 3 frontend for package management +- **Detailed vulnerability reports** with CVE information and severity breakdown +- **Download analytics** and usage statistics +- **Health check endpoints** for monitoring +- **Prometheus metrics** integration +- **Structured JSON logging** with zerolog + +### 🌐 **Universal Support** +- **npm/pnpm/yarn** - Full npm registry protocol support +- **pip** - PyPI Simple API (PEP 503) implementation +- **Go modules** - GOPROXY protocol with sumdb support +- **Transparent proxying** - Works with existing tools without modification + +--- + +## πŸ“‹ Table of Contents + +- [Quick Start](#-quick-start) +- [Installation](#-installation) +- [Configuration](#-configuration) +- [Package Manager Setup](#-package-manager-setup) +- [Private Repository Support](#-private-repository-support) +- [Kubernetes Deployment](#️-kubernetes-deployment) +- [Security Scanning](#-security-scanning) +- [Web Dashboard](#-web-dashboard) +- [API Reference](#-api-reference) +- [Architecture](#-architecture) +- [Development](#-development) +- [Troubleshooting](#-troubleshooting) +- [Contributing](#-contributing) + +--- + +## πŸš€ Quick Start + +### 1. Install and Run + +```bash +# Clone the repository +git clone https://github.com/lukaszraczylo/gohoarder.git +cd gohoarder + +# Build +make build + +# Run (starts both backend and frontend) +make run +``` + +GoHoarder will start on **http://localhost:8080** + +### 2. Configure Your Package Manager + +**npm/pnpm:** +```bash +npm config set registry http://localhost:8080/npm +``` + +**pip:** +```bash +pip install --index-url http://localhost:8080/pypi/simple/ \ + --trusted-host localhost \ + package-name +``` + +**Go:** +```bash +# ⚠️ IMPORTANT: Do NOT use ",direct" fallback - it bypasses security! +export GOPROXY="http://localhost:8080/go" +``` + +### 3. Install Packages Normally + +```bash +# npm +npm install axios + +# pip +pip install requests + +# Go +go get github.com/gin-gonic/gin +``` + +**Vulnerable packages are automatically blocked:** +``` +npm install axios@0.21.1 +❌ ERROR: 403 Forbidden - Package has 3 HIGH vulnerabilities (threshold: 0) +``` + +--- + +## πŸ“¦ Installation + +### Prerequisites + +- **Go 1.22+** for building the backend +- **Node.js 18+** and **pnpm** for building the frontend +- **Security scanners** (optional, but recommended): + - [Trivy](https://github.com/aquasecurity/trivy) - Container and package scanning + - [Grype](https://github.com/anchore/grype) - Vulnerability scanner + - [govulncheck](https://pkg.go.dev/golang.org/x/vuln/cmd/govulncheck) - Go-specific scanner + +### Building from Source + +```bash +# Clone repository +git clone https://github.com/lukaszraczylo/gohoarder.git +cd gohoarder + +# Build backend only +make build + +# Build backend + frontend +make build-all + +# Run with frontend +make run + +# Run backend only +./bin/gohoarder serve +``` + +### Install Security Scanners + +**Trivy:** +```bash +# macOS +brew install aquasecurity/trivy/trivy + +# Linux +wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add - +echo "deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -sc) main" | sudo tee -a /etc/apt/sources.list.d/trivy.list +sudo apt-get update && sudo apt-get install trivy +``` + +**Grype:** +```bash +# macOS +brew tap anchore/grype +brew install grype + +# Linux +curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin +``` + +**govulncheck:** +```bash +go install golang.org/x/vuln/cmd/govulncheck@latest +``` + +--- + +## βš™οΈ Configuration + +### Configuration File + +Create `config.yaml` in the project root: + +```yaml +server: + port: 8080 + host: "0.0.0.0" + read_timeout: "5m" + write_timeout: "5m" + +storage: + backend: "filesystem" # Options: filesystem, s3, smb + path: "./data/storage" + +metadata: + backend: "sqlite" # Options: sqlite, postgresql + path: "./data/gohoarder.db" + +security: + enabled: true + update_db_on_startup: true + + # Block packages based on vulnerability counts + block_thresholds: + critical: 0 # Block if ANY critical vulnerabilities + high: 0 # Block if ANY high vulnerabilities + medium: 5 # Block if MORE than 5 medium vulnerabilities + low: -1 # -1 = don't block based on low severity + + # Or block based on highest severity present + block_on_severity: "high" # Options: critical, high, moderate, low, none + + scanners: + trivy: + enabled: true + osv: + enabled: true + grype: + enabled: true + govulncheck: + enabled: true + npm_audit: + enabled: true + pip_audit: + enabled: true + ghsa: + enabled: true + +cache: + default_ttl: 86400 # 24 hours in seconds + +logging: + level: "info" # debug, info, warn, error + format: "json" + +upstream: + npm: "https://registry.npmjs.org" + pypi: "https://pypi.org/simple" + go: "https://proxy.golang.org" +``` + +### Environment Variables + +All configuration values can be overridden with environment variables: + +```bash +# Server +export GOHOARDER_SERVER_PORT=8080 +export GOHOARDER_SERVER_HOST="0.0.0.0" + +# Storage +export GOHOARDER_STORAGE_BACKEND="filesystem" +export GOHOARDER_STORAGE_PATH="./data/storage" + +# Security +export GOHOARDER_SECURITY_ENABLED=true +export GOHOARDER_SECURITY_BLOCK_CRITICAL=0 +export GOHOARDER_SECURITY_BLOCK_HIGH=0 + +# Logging +export GOHOARDER_LOG_LEVEL="info" +``` + +--- + +## πŸ”§ Package Manager Setup + +### npm / pnpm / yarn + +#### ⚠️ Security Notice + +**All three package managers enforce security correctly - no fallback mechanisms.** + +#### Configuration + +**npm:** +```bash +npm config set registry http://localhost:8080/npm +``` + +**pnpm:** +```bash +pnpm config set registry http://localhost:8080/npm +``` + +**yarn (v4+):** +```yaml +# .yarnrc.yml +npmRegistryServer: "http://localhost:8080/npm" +unsafeHttpWhitelist: + - localhost +``` + +#### Usage + +```bash +# Install packages normally +npm install express +pnpm add react +yarn add lodash + +# Vulnerable packages will fail with 403 Forbidden +npm install axios@0.21.1 +# ❌ ERROR: 403 Forbidden - Package has 3 HIGH vulnerabilities (threshold: 0) +``` + +#### Clear Cache + +```bash +npm cache clean --force +pnpm store prune +yarn cache clean --all +``` + +--- + +### Python (pip) + +#### Configuration + +**Per-install:** +```bash +pip install --index-url http://localhost:8080/pypi/simple/ \ + --trusted-host localhost \ + package-name +``` + +**Global configuration:** +```ini +# ~/.pip/pip.conf (Linux/macOS) +# %APPDATA%\pip\pip.ini (Windows) + +[global] +index-url = http://localhost:8080/pypi/simple/ +trusted-host = localhost +``` + +#### Usage + +```bash +# Install packages normally +pip install requests + +# Vulnerable packages will fail +pip install flask==0.12.0 +# ❌ ERROR: HTTP error 403 while getting ... +# ❌ ERROR: 403 Client Error: Forbidden +``` + +#### Clear Cache + +```bash +pip cache purge +``` + +--- + +### Go Modules + +#### ⚠️ CRITICAL: No Fallback Configuration + +**The `,direct` fallback completely bypasses security scanning and must NEVER be used!** + +**❌ INSECURE (bypasses security):** +```bash +export GOPROXY="http://localhost:8080/go,direct" +# ^^^^^^^ NEVER USE THIS! +``` + +**βœ… SECURE (enforces scanning):** +```bash +export GOPROXY="http://localhost:8080/go" +``` + +**Persistent configuration:** +```bash +# Add to ~/.bashrc, ~/.zshrc, or ~/.profile +echo 'export GOPROXY="http://localhost:8080/go"' >> ~/.bashrc +source ~/.bashrc +``` + +#### Usage + +```bash +# Download packages normally +go get github.com/gin-gonic/gin@v1.7.0 +go mod download + +# Vulnerable packages will fail with 403 Forbidden +# (if vulnerability databases detect issues) +``` + +#### Clear Cache + +```bash +go clean -modcache +``` + +## πŸ” Private Repository Support + +GoHoarder supports private packages through **automatic credential forwarding** - no server-side configuration needed! Your existing authentication automatically works through the proxy. + +### How It Works + +1. **Client Authentication** β†’ Your package manager sends credentials to GoHoarder +2. **Credential Forwarding** β†’ GoHoarder forwards credentials to upstream registry +3. **Package Caching** β†’ Packages are cached with credential-aware keys +4. **Access Validation** β†’ For private packages, credentials are validated on every request (cached for 5 minutes) +5. **Multi-User Isolation** β†’ Different users with different credentials get separate cache entries + +### Security Model + +- **Per-Request Validation**: Private packages verify credentials with upstream before serving +- **Credential Isolation**: Each user's credentials create separate cache entries +- **Validation Caching**: Validation results cached for 5 minutes to reduce upstream load +- **Access Control**: 403 Forbidden if credentials are invalid or missing + +### Setup + +#### npm Private Packages + +**GitHub Packages:** + +```bash +# Configure .npmrc for GitHub Packages +echo "@yourorg:registry=https://npm.pkg.github.com" >> ~/.npmrc +echo "//npm.pkg.github.com/:_authToken=YOUR_GITHUB_TOKEN" >> ~/.npmrc + +# Use GoHoarder proxy +npm config set registry http://localhost:8080/npm +npm install @yourorg/private-package +``` + +**GitLab Packages:** + +```bash +# Configure .npmrc for GitLab +echo "@yourgroup:registry=https://gitlab.com/api/v4/packages/npm/" >> ~/.npmrc +echo "//gitlab.com/api/v4/packages/npm/:_authToken=YOUR_GITLAB_TOKEN" >> ~/.npmrc + +# Use GoHoarder proxy +npm config set registry http://localhost:8080/npm +``` + +**Private Artifactory / Nexus:** + +```bash +# Configure .npmrc with Basic auth +echo "//your-registry.com/:_auth=BASE64_CREDENTIALS" >> ~/.npmrc + +# Use GoHoarder proxy +npm config set registry http://localhost:8080/npm +``` + +#### PyPI Private Packages + +**Private PyPI Index:** + +```bash +# Configure pip with credentials in URL +pip config set global.index-url http://localhost:8080/pypi/simple + +# Install with credentials in request (pip handles auth) +pip install --index-url http://username:password@localhost:8080/pypi/simple private-package +``` + +**AWS CodeArtifact:** + +```bash +# Get CodeArtifact token +export CODEARTIFACT_AUTH_TOKEN=$(aws codeartifact get-authorization-token --domain your-domain --query authorizationToken --output text) + +# Use with pip +pip install --index-url http://aws:$CODEARTIFACT_AUTH_TOKEN@localhost:8080/pypi/simple private-package +``` + +**GitHub Packages (PyPI):** + +```bash +# Configure pip to use GitHub Packages through GoHoarder +pip install --index-url http://USERNAME:GITHUB_TOKEN@localhost:8080/pypi/simple your-private-package +``` + +#### Go Private Modules + +**GitHub Private Repositories:** + +```bash +# Configure .netrc with GitHub credentials +cat >> ~/.netrc <> ~/.netrc <> $GITHUB_ENV + + - name: Build + run: go build ./... +``` + +### Dockerfile + +```dockerfile +FROM golang:1.21-alpine + +# Configure proxy +ENV GOPROXY=http://gohoarder.default.svc.cluster.local:8080/go,direct +ENV GONOPROXY=none +ENV GONOSUMDB=github.com/yourcompany + +WORKDIR /app +COPY . . +RUN go build -o myapp ./cmd/myapp + +CMD ["/app/myapp"] +``` + +## Support + +For issues or questions: +- Check logs: `kubectl logs -l app=gohoarder` +- Enable debug logging: Set `logging.level: debug` in ConfigMap +- Review credential patterns in Secret diff --git a/helm/gohoarder/.helmignore b/helm/gohoarder/.helmignore new file mode 100644 index 0000000..819ee6e --- /dev/null +++ b/helm/gohoarder/.helmignore @@ -0,0 +1,31 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ +# CI/CD +.github/ +.gitlab-ci.yml +.travis.yml +# Documentation (keep README.md for chart documentation) +# README.md should be included in the chart package +docs/ +examples/ diff --git a/helm/gohoarder/Chart.yaml b/helm/gohoarder/Chart.yaml new file mode 100644 index 0000000..fe8ec29 --- /dev/null +++ b/helm/gohoarder/Chart.yaml @@ -0,0 +1,22 @@ +apiVersion: v2 +name: gohoarder +description: A universal package cache proxy supporting npm, PyPI, and Go modules with security scanning +type: application +version: 1.0.0 +appVersion: "1.0.0" +keywords: + - package-manager + - cache + - proxy + - npm + - pypi + - go-modules + - security + - vulnerability-scanning +home: https://github.com/lukaszraczylo/gohoarder +sources: + - https://github.com/lukaszraczylo/gohoarder +maintainers: + - name: Lukasz Raczylo + email: lukasz@raczylo.com +icon: https://raw.githubusercontent.com/lukaszraczylo/gohoarder/main/docs/logo.png diff --git a/helm/gohoarder/README.md b/helm/gohoarder/README.md new file mode 100644 index 0000000..6934266 --- /dev/null +++ b/helm/gohoarder/README.md @@ -0,0 +1,214 @@ +# GoHoarder Helm Chart + +A universal package cache proxy supporting npm, PyPI, and Go modules with integrated security scanning. + +## Features + +- **Multi-Registry Support**: Proxy for npm, PyPI, and Go modules +- **Security Scanning**: Integrated vulnerability scanning with multiple scanners +- **Flexible Storage**: Support for filesystem, S3, and SMB storage backends +- **Metadata Storage**: SQLite or PostgreSQL for metadata +- **Auto-Configuration**: Generates configuration from Helm values +- **Production Ready**: Includes health checks, resource limits, and security contexts + +## Prerequisites + +- Kubernetes 1.19+ +- Helm 3.0+ +- PV provisioner support in the underlying infrastructure (for persistent storage) + +## Installation + +### Add Helm Repository + +```bash +helm repo add gohoarder https://lukaszraczylo.github.io/gohoarder +helm repo update +``` + +### Install Chart + +```bash +# Install with default values +helm install gohoarder gohoarder/gohoarder + +# Install with custom values +helm install gohoarder gohoarder/gohoarder -f values.yaml + +# Install in a specific namespace +helm install gohoarder gohoarder/gohoarder -n gohoarder --create-namespace +``` + +## Quick Start Examples + +### Minimal Installation + +```bash +helm install gohoarder gohoarder/gohoarder \ + --set global.domain=example.com \ + --set ingress.enabled=true +``` + +### With Security Scanning + +```bash +helm install gohoarder gohoarder/gohoarder \ + --set security.enabled=true \ + --set security.scanners.trivy.enabled=true \ + --set security.scanners.osv.enabled=true +``` + +### With S3 Storage + +```bash +helm install gohoarder gohoarder/gohoarder \ + --set storage.backend=s3 \ + --set storage.s3.bucket=my-bucket \ + --set storage.s3.region=us-east-1 \ + --set storage.s3.accessKeyId=AKIAIOSFODNN7EXAMPLE \ + --set storage.s3.secretAccessKey=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY +``` + +## Configuration + +The following table lists the configurable parameters and their default values. + +### Global Parameters + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `global.domain` | Base domain for the deployment | `gohoarder.local` | +| `global.imagePullSecrets` | Image pull secrets | `[]` | + +### Replica Count + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `replicaCount.server` | Number of server replicas | `1` | +| `replicaCount.frontend` | Number of frontend replicas | `1` | +| `replicaCount.scanner` | Number of scanner replicas | `1` | + +### Image Configuration + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `image.server.repository` | Server image repository | `ghcr.io/lukaszraczylo/gohoarder-server` | +| `image.server.tag` | Server image tag | `latest` | +| `image.frontend.repository` | Frontend image repository | `ghcr.io/lukaszraczylo/gohoarder-frontend` | +| `image.frontend.tag` | Frontend image tag | `latest` | +| `image.scanner.repository` | Scanner image repository | `ghcr.io/lukaszraczylo/gohoarder-scanner` | +| `image.scanner.tag` | Scanner image tag | `latest` | + +### Storage Configuration + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `storage.backend` | Storage backend (filesystem, s3, smb) | `filesystem` | +| `storage.filesystem.storageClass` | Storage class for PVC | `""` | +| `storage.filesystem.size` | Storage size | `100Gi` | +| `storage.filesystem.useHostPath` | Use hostPath instead of PVC | `false` | +| `storage.filesystem.hostPath` | Host path for storage | `/var/lib/gohoarder` | +| `storage.s3.endpoint` | S3 endpoint | `s3.amazonaws.com` | +| `storage.s3.bucket` | S3 bucket name | `gohoarder-cache` | +| `storage.s3.region` | S3 region | `us-east-1` | + +### Metadata Configuration + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `metadata.backend` | Metadata backend (sqlite, postgresql) | `sqlite` | +| `metadata.sqlite.persistence.enabled` | Enable persistence for SQLite | `true` | +| `metadata.sqlite.persistence.size` | SQLite storage size | `10Gi` | +| `metadata.postgresql.host` | PostgreSQL host | `localhost` | +| `metadata.postgresql.database` | PostgreSQL database | `gohoarder` | + +### Security Configuration + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `security.enabled` | Enable security scanning | `false` | +| `security.blockOnSeverity` | Block packages on severity | `high` | +| `security.scanners.trivy.enabled` | Enable Trivy scanner | `false` | +| `security.scanners.osv.enabled` | Enable OSV scanner | `false` | +| `security.scanners.grype.enabled` | Enable Grype scanner | `false` | + +### Authentication + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `auth.enabled` | Enable authentication | `true` | +| `auth.adminApiKey` | Admin API key (auto-generated if empty) | `""` | +| `auth.existingSecret` | Use existing secret for admin key | `""` | + +### Ingress + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `ingress.enabled` | Enable ingress | `false` | +| `ingress.className` | Ingress class name | `nginx` | +| `ingress.frontend.enabled` | Enable frontend ingress | `true` | +| `ingress.frontend.host` | Frontend hostname | `gohoarder.local` | +| `ingress.frontend.tls.enabled` | Enable TLS for frontend | `false` | + +## Uninstallation + +```bash +helm uninstall gohoarder -n gohoarder +``` + +## Upgrading + +```bash +helm upgrade gohoarder gohoarder/gohoarder -f values.yaml +``` + +## Package Manager Configuration + +After installation, configure your package managers to use GoHoarder: + +### NPM + +```bash +npm config set registry http:///npm/ +``` + +### Go + +```bash +export GOPROXY=http:///go,direct +``` + +### PyPI + +```bash +pip config set global.index-url http:///pypi/simple +``` + +## Troubleshooting + +### Check Pod Status + +```bash +kubectl get pods -n gohoarder +kubectl logs -n gohoarder +``` + +### Verify Configuration + +```bash +kubectl get configmap -n gohoarder -gohoarder-config -o yaml +``` + +### Get Admin API Key + +```bash +kubectl get secret -n gohoarder -gohoarder-auth -o jsonpath='{.data.admin-api-key}' | base64 -d +``` + +## Contributing + +Contributions are welcome! Please visit [GitHub](https://github.com/lukaszraczylo/gohoarder) for more information. + +## License + +See the [LICENSE](https://github.com/lukaszraczylo/gohoarder/blob/main/LICENSE) file. diff --git a/helm/gohoarder/templates/NOTES.txt b/helm/gohoarder/templates/NOTES.txt new file mode 100644 index 0000000..15f6d50 --- /dev/null +++ b/helm/gohoarder/templates/NOTES.txt @@ -0,0 +1,70 @@ +** GoHoarder has been installed! ** + +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- if .Values.ingress.frontend.enabled }} + http{{ if .Values.ingress.frontend.tls.enabled }}s{{ end }}://{{ .Values.ingress.frontend.host | default (printf "%s.%s" "gohoarder" .Values.global.domain) }} +{{- end }} +{{- else if contains "NodePort" .Values.frontend.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "gohoarder.fullname" . }}-frontend) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.frontend.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "gohoarder.fullname" . }}-frontend' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "gohoarder.fullname" . }}-frontend --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.frontend.service.port }} +{{- else if contains "ClusterIP" .Values.frontend.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "gohoarder.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=frontend" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} + +2. Admin API Key: +{{- if .Values.auth.enabled }} +{{- if .Values.auth.existingSecret }} + The admin API key is stored in the existing secret: {{ .Values.auth.existingSecret }} + + To retrieve it: + kubectl get secret {{ .Values.auth.existingSecret }} -n {{ .Release.Namespace }} -o jsonpath='{.data.{{ .Values.auth.secretKey }}}' | base64 -d +{{- else if .Values.auth.adminApiKey }} + The admin API key you provided: {{ .Values.auth.adminApiKey }} +{{- else }} + A random admin API key has been generated. To retrieve it: + kubectl get secret {{ include "gohoarder.fullname" . }}-auth -n {{ .Release.Namespace }} -o jsonpath='{.data.{{ .Values.auth.secretKey }}}' | base64 -d +{{- end }} +{{- else }} + Authentication is disabled. +{{- end }} + +3. Configuration: + - Storage backend: {{ .Values.storage.backend }} + - Metadata backend: {{ .Values.metadata.backend }} + - Security scanning: {{ if .Values.security.enabled }}enabled{{ else }}disabled{{ end }} + {{- if .Values.security.enabled }} + - Active scanners: + {{- range $scanner, $config := .Values.security.scanners }} + {{- if $config.enabled }} + * {{ $scanner }} + {{- end }} + {{- end }} + {{- end }} + +4. Package Proxies: + Configure your package managers to use GoHoarder: + + NPM: + npm config set registry http://{{ include "gohoarder.fullname" . }}-server.{{ .Release.Namespace }}.svc.cluster.local/npm/ + + Go: + export GOPROXY=http://{{ include "gohoarder.fullname" . }}-server.{{ .Release.Namespace }}.svc.cluster.local/go,direct + + PyPI: + pip config set global.index-url http://{{ include "gohoarder.fullname" . }}-server.{{ .Release.Namespace }}.svc.cluster.local/pypi/simple + +5. Health Checks: + - Server health: http://{{ include "gohoarder.fullname" . }}-server.{{ .Release.Namespace }}.svc.cluster.local/health + - Server ready: http://{{ include "gohoarder.fullname" . }}-server.{{ .Release.Namespace }}.svc.cluster.local/health/ready + +For more information, visit: https://github.com/lukaszraczylo/gohoarder diff --git a/helm/gohoarder/templates/_helpers.tpl b/helm/gohoarder/templates/_helpers.tpl new file mode 100644 index 0000000..b3232b5 --- /dev/null +++ b/helm/gohoarder/templates/_helpers.tpl @@ -0,0 +1,174 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "gohoarder.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +*/}} +{{- define "gohoarder.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "gohoarder.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "gohoarder.labels" -}} +helm.sh/chart: {{ include "gohoarder.chart" . }} +{{ include "gohoarder.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "gohoarder.selectorLabels" -}} +app.kubernetes.io/name: {{ include "gohoarder.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Server labels +*/}} +{{- define "gohoarder.server.labels" -}} +{{ include "gohoarder.labels" . }} +app.kubernetes.io/component: server +{{- end }} + +{{/* +Server selector labels +*/}} +{{- define "gohoarder.server.selectorLabels" -}} +{{ include "gohoarder.selectorLabels" . }} +app.kubernetes.io/component: server +{{- end }} + +{{/* +Frontend labels +*/}} +{{- define "gohoarder.frontend.labels" -}} +{{ include "gohoarder.labels" . }} +app.kubernetes.io/component: frontend +{{- end }} + +{{/* +Frontend selector labels +*/}} +{{- define "gohoarder.frontend.selectorLabels" -}} +{{ include "gohoarder.selectorLabels" . }} +app.kubernetes.io/component: frontend +{{- end }} + +{{/* +Scanner labels +*/}} +{{- define "gohoarder.scanner.labels" -}} +{{ include "gohoarder.labels" . }} +app.kubernetes.io/component: scanner +{{- end }} + +{{/* +Scanner selector labels +*/}} +{{- define "gohoarder.scanner.selectorLabels" -}} +{{ include "gohoarder.selectorLabels" . }} +app.kubernetes.io/component: scanner +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "gohoarder.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "gohoarder.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Generate admin API key +*/}} +{{- define "gohoarder.adminApiKey" -}} +{{- if .Values.auth.adminApiKey }} +{{- .Values.auth.adminApiKey }} +{{- else }} +{{- randAlphaNum 32 }} +{{- end }} +{{- end }} + +{{/* +Storage volume configuration +*/}} +{{- define "gohoarder.storageVolume" -}} +{{- if eq .Values.storage.backend "filesystem" }} +{{- if .Values.storage.filesystem.useHostPath }} +- name: storage + hostPath: + path: {{ .Values.storage.filesystem.hostPath }} + type: DirectoryOrCreate +{{- else if .Values.storage.filesystem.existingClaim }} +- name: storage + persistentVolumeClaim: + claimName: {{ .Values.storage.filesystem.existingClaim }} +{{- else }} +- name: storage + persistentVolumeClaim: + claimName: {{ include "gohoarder.fullname" . }}-storage +{{- end }} +{{- else }} +- name: storage + emptyDir: {} +{{- end }} +{{- end }} + +{{/* +Metadata volume configuration +*/}} +{{- define "gohoarder.metadataVolume" -}} +{{- if and (eq .Values.metadata.backend "sqlite") .Values.metadata.sqlite.persistence.enabled }} +{{- if .Values.metadata.sqlite.persistence.existingClaim }} +- name: metadata + persistentVolumeClaim: + claimName: {{ .Values.metadata.sqlite.persistence.existingClaim }} +{{- else }} +- name: metadata + persistentVolumeClaim: + claimName: {{ include "gohoarder.fullname" . }}-metadata +{{- end }} +{{- else }} +- name: metadata + emptyDir: {} +{{- end }} +{{- end }} + +{{/* +Trivy cache volume configuration +*/}} +{{- define "gohoarder.trivyCacheVolume" -}} +{{- if .Values.security.scanners.trivy.enabled }} +- name: trivy-cache + emptyDir: {} +{{- end }} +{{- end }} diff --git a/helm/gohoarder/templates/configmap.yaml b/helm/gohoarder/templates/configmap.yaml new file mode 100644 index 0000000..cc742a4 --- /dev/null +++ b/helm/gohoarder/templates/configmap.yaml @@ -0,0 +1,168 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "gohoarder.fullname" . }}-config + labels: + {{- include "gohoarder.labels" . | nindent 4 }} +data: + config.yaml: | + server: + host: {{ .Values.server.host | quote }} + port: {{ .Values.server.port }} + read_timeout: {{ .Values.server.readTimeout | quote }} + write_timeout: {{ .Values.server.writeTimeout | quote }} + idle_timeout: {{ .Values.server.idleTimeout | quote }} + tls: + enabled: false + + storage: + backend: {{ .Values.storage.backend | quote }} + {{- if eq .Values.storage.backend "filesystem" }} + path: "/var/cache/gohoarder" + filesystem: + base_path: "/var/cache/gohoarder" + {{- else if eq .Values.storage.backend "s3" }} + s3: + endpoint: {{ .Values.storage.s3.endpoint | quote }} + region: {{ .Values.storage.s3.region | quote }} + bucket: {{ .Values.storage.s3.bucket | quote }} + {{- if .Values.storage.s3.existingSecret }} + access_key_id: "${S3_ACCESS_KEY_ID}" + secret_access_key: "${S3_SECRET_ACCESS_KEY}" + {{- else }} + access_key_id: {{ .Values.storage.s3.accessKeyId | quote }} + secret_access_key: {{ .Values.storage.s3.secretAccessKey | quote }} + {{- end }} + use_ssl: {{ .Values.storage.s3.useSSL }} + {{- else if eq .Values.storage.backend "smb" }} + smb: + host: {{ .Values.storage.smb.host | quote }} + share: {{ .Values.storage.smb.share | quote }} + {{- if .Values.storage.smb.existingSecret }} + username: "${SMB_USERNAME}" + password: "${SMB_PASSWORD}" + {{- else }} + username: {{ .Values.storage.smb.username | quote }} + password: {{ .Values.storage.smb.password | quote }} + {{- end }} + domain: {{ .Values.storage.smb.domain | quote }} + {{- end }} + + metadata: + backend: {{ .Values.metadata.backend | quote }} + {{- if eq .Values.metadata.backend "sqlite" }} + connection: "file:/var/lib/gohoarder/metadata/gohoarder.db?cache=shared&mode=rwc" + sqlite: + path: "/var/lib/gohoarder/metadata/gohoarder.db" + wal_mode: {{ .Values.metadata.sqlite.walMode }} + {{- else if eq .Values.metadata.backend "postgresql" }} + postgresql: + host: {{ .Values.metadata.postgresql.host | quote }} + port: {{ .Values.metadata.postgresql.port }} + database: {{ .Values.metadata.postgresql.database | quote }} + {{- if .Values.metadata.postgresql.existingSecret }} + user: "${POSTGRES_USER}" + password: "${POSTGRES_PASSWORD}" + {{- else }} + user: {{ .Values.metadata.postgresql.username | quote }} + password: {{ .Values.metadata.postgresql.password | quote }} + {{- end }} + ssl_mode: {{ .Values.metadata.postgresql.sslMode | quote }} + {{- end }} + + cache: + default_ttl: {{ .Values.cache.defaultTTL | quote }} + cleanup_interval: {{ .Values.cache.cleanupInterval | quote }} + max_size_bytes: {{ .Values.cache.maxSizeBytes }} + per_project_quota: {{ .Values.cache.perProjectQuota }} + ttl_overrides: + {{- range $key, $value := .Values.cache.ttlOverrides }} + {{ $key }}: {{ $value | quote }} + {{- end }} + + security: + enabled: {{ .Values.security.enabled }} + block_on_severity: {{ .Values.security.blockOnSeverity | quote }} + scan_on_download: {{ .Values.security.scanOnDownload }} + rescan_interval: {{ .Values.security.rescanInterval | quote }} + update_db_on_startup: {{ .Values.security.updateDbOnStartup }} + block_thresholds: + critical: {{ .Values.security.blockThresholds.critical }} + high: {{ .Values.security.blockThresholds.high }} + medium: {{ .Values.security.blockThresholds.medium }} + low: {{ .Values.security.blockThresholds.low }} + scanners: + trivy: + enabled: {{ .Values.security.scanners.trivy.enabled }} + timeout: {{ .Values.security.scanners.trivy.timeout | quote }} + cache_db: {{ .Values.security.scanners.trivy.cacheDb | quote }} + osv: + enabled: {{ .Values.security.scanners.osv.enabled }} + api_url: {{ .Values.security.scanners.osv.apiUrl | quote }} + timeout: {{ .Values.security.scanners.osv.timeout | quote }} + grype: + enabled: {{ .Values.security.scanners.grype.enabled }} + timeout: {{ .Values.security.scanners.grype.timeout | quote }} + govulncheck: + enabled: {{ .Values.security.scanners.govulncheck.enabled }} + timeout: {{ .Values.security.scanners.govulncheck.timeout | quote }} + npm_audit: + enabled: {{ .Values.security.scanners.npmAudit.enabled }} + timeout: {{ .Values.security.scanners.npmAudit.timeout | quote }} + pip_audit: + enabled: {{ .Values.security.scanners.pipAudit.enabled }} + timeout: {{ .Values.security.scanners.pipAudit.timeout | quote }} + ghsa: + enabled: {{ .Values.security.scanners.ghsa.enabled }} + timeout: {{ .Values.security.scanners.ghsa.timeout | quote }} + {{- if or .Values.security.scanners.ghsa.token .Values.security.scanners.ghsa.existingSecret }} + token: "${GHSA_TOKEN}" + {{- end }} + static: + enabled: {{ .Values.security.scanners.static.enabled }} + max_package_size: {{ .Values.security.scanners.static.maxPackageSize }} + check_checksums: {{ .Values.security.scanners.static.checkChecksums }} + block_suspicious: {{ .Values.security.scanners.static.blockSuspicious }} + + auth: + enabled: {{ .Values.auth.enabled }} + key_expiration: {{ .Values.auth.keyExpiration | quote }} + bcrypt_cost: {{ .Values.auth.bcryptCost }} + audit_log: {{ .Values.auth.auditLog }} + + network: + connect_timeout: {{ .Values.network.connectTimeout | quote }} + read_timeout: {{ .Values.network.readTimeout | quote }} + write_timeout: {{ .Values.network.writeTimeout | quote }} + max_idle_conns: {{ .Values.network.maxIdleConns }} + max_conns_per_host: {{ .Values.network.maxConnsPerHost }} + rate_limit: + per_api_key: {{ .Values.network.rateLimit.perApiKey }} + per_ip: {{ .Values.network.rateLimit.perIp }} + burst_size: {{ .Values.network.rateLimit.burstSize }} + circuit_breaker: + threshold: {{ .Values.network.circuitBreaker.threshold }} + timeout: {{ .Values.network.circuitBreaker.timeout | quote }} + reset_interval: {{ .Values.network.circuitBreaker.resetInterval | quote }} + retry: + max_attempts: {{ .Values.network.retry.maxAttempts }} + initial_backoff: {{ .Values.network.retry.initialBackoff | quote }} + max_backoff: {{ .Values.network.retry.maxBackoff | quote }} + + logging: + level: {{ .Values.logging.level | quote }} + format: {{ .Values.logging.format | quote }} + + handlers: + go: + enabled: {{ .Values.handlers.go.enabled }} + upstream_proxy: {{ .Values.handlers.go.upstreamProxy | quote }} + checksum_db: {{ .Values.handlers.go.checksumDb | quote }} + verify_checksums: {{ .Values.handlers.go.verifyChecksums }} + npm: + enabled: {{ .Values.handlers.npm.enabled }} + upstream_registry: {{ .Values.handlers.npm.upstreamRegistry | quote }} + pypi: + enabled: {{ .Values.handlers.pypi.enabled }} + upstream_url: {{ .Values.handlers.pypi.upstreamUrl | quote }} + simple_api_url: {{ .Values.handlers.pypi.simpleApiUrl | quote }} diff --git a/helm/gohoarder/templates/deployment-frontend.yaml b/helm/gohoarder/templates/deployment-frontend.yaml new file mode 100644 index 0000000..bd8f155 --- /dev/null +++ b/helm/gohoarder/templates/deployment-frontend.yaml @@ -0,0 +1,68 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "gohoarder.fullname" . }}-frontend + labels: + {{- include "gohoarder.frontend.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount.frontend }} + {{- end }} + selector: + matchLabels: + {{- include "gohoarder.frontend.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "gohoarder.frontend.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "gohoarder.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: frontend + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.frontend.repository }}:{{ .Values.image.frontend.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.frontend.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.frontend.port }} + protocol: TCP + env: + - name: VITE_BACKEND_URL + value: "http://{{ include "gohoarder.fullname" . }}-server:{{ .Values.server.service.port }}" + - name: VITE_PORT + value: "{{ .Values.frontend.port }}" + livenessProbe: + {{- toYaml .Values.frontend.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.frontend.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.frontend.resources | nindent 12 }} + volumeMounts: + - name: tmp + mountPath: /tmp + volumes: + - name: tmp + emptyDir: {} + {{- with .Values.frontend.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.frontend.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.frontend.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/helm/gohoarder/templates/deployment-scanner.yaml b/helm/gohoarder/templates/deployment-scanner.yaml new file mode 100644 index 0000000..f369f3e --- /dev/null +++ b/helm/gohoarder/templates/deployment-scanner.yaml @@ -0,0 +1,111 @@ +{{- if .Values.security.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "gohoarder.fullname" . }}-scanner + labels: + {{- include "gohoarder.scanner.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount.scanner }} + selector: + matchLabels: + {{- include "gohoarder.scanner.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "gohoarder.scanner.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "gohoarder.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + initContainers: + - name: init-permissions + image: busybox:latest + command: ['sh', '-c'] + args: + - | + mkdir -p /var/cache/gohoarder /var/lib/gohoarder/metadata /tmp/gohoarder + {{- if .Values.security.scanners.trivy.enabled }} + mkdir -p {{ .Values.security.scanners.trivy.cacheDb }} + chown -R 1000:1000 {{ .Values.security.scanners.trivy.cacheDb }} + {{- end }} + chown -R 1000:1000 /var/cache/gohoarder /var/lib/gohoarder /tmp/gohoarder + chmod 750 /var/cache/gohoarder /var/lib/gohoarder + volumeMounts: + {{- include "gohoarder.storageVolume" . | nindent 8 }} + {{- include "gohoarder.metadataVolume" . | nindent 8 }} + {{- include "gohoarder.trivyCacheVolume" . | nindent 8 }} + - name: tmp + mountPath: /tmp/gohoarder + securityContext: + runAsUser: 0 + containers: + - name: scanner + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.scanner.repository }}:{{ .Values.image.scanner.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.scanner.pullPolicy }} + env: + - name: CONFIG_FILE + value: /etc/gohoarder/config.yaml + {{- if and .Values.security.scanners.ghsa.enabled .Values.security.scanners.ghsa.existingSecret }} + - name: GHSA_TOKEN + valueFrom: + secretKeyRef: + name: {{ .Values.security.scanners.ghsa.existingSecret }} + key: token + {{- else if and .Values.security.scanners.ghsa.enabled .Values.security.scanners.ghsa.token }} + - name: GHSA_TOKEN + valueFrom: + secretKeyRef: + name: {{ include "gohoarder.fullname" . }}-ghsa + key: token + {{- end }} + resources: + {{- toYaml .Values.scanner.resources | nindent 12 }} + volumeMounts: + - name: config + mountPath: /etc/gohoarder + readOnly: true + - name: storage + mountPath: /var/cache/gohoarder + - name: metadata + mountPath: /var/lib/gohoarder/metadata + {{- if .Values.security.scanners.trivy.enabled }} + - name: trivy-cache + mountPath: {{ .Values.security.scanners.trivy.cacheDb }} + {{- end }} + - name: tmp + mountPath: /tmp + volumes: + - name: config + configMap: + name: {{ include "gohoarder.fullname" . }}-config + {{- include "gohoarder.storageVolume" . | nindent 6 }} + {{- include "gohoarder.metadataVolume" . | nindent 6 }} + {{- include "gohoarder.trivyCacheVolume" . | nindent 6 }} + - name: tmp + emptyDir: {} + {{- with .Values.scanner.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.scanner.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.scanner.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/helm/gohoarder/templates/deployment-server.yaml b/helm/gohoarder/templates/deployment-server.yaml new file mode 100644 index 0000000..1feb435 --- /dev/null +++ b/helm/gohoarder/templates/deployment-server.yaml @@ -0,0 +1,191 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "gohoarder.fullname" . }}-server + labels: + {{- include "gohoarder.server.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount.server }} + {{- end }} + selector: + matchLabels: + {{- include "gohoarder.server.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} + checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "gohoarder.server.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.global.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "gohoarder.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + initContainers: + - name: init-permissions + image: busybox:latest + command: ['sh', '-c'] + args: + - | + mkdir -p /var/cache/gohoarder /var/lib/gohoarder/metadata /tmp/gohoarder + chown -R 1000:1000 /var/cache/gohoarder /var/lib/gohoarder /tmp/gohoarder + chmod 750 /var/cache/gohoarder /var/lib/gohoarder + volumeMounts: + {{- include "gohoarder.storageVolume" . | nindent 8 }} + {{- include "gohoarder.metadataVolume" . | nindent 8 }} + - name: tmp + mountPath: /tmp/gohoarder + securityContext: + runAsUser: 0 + containers: + - name: server + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.server.repository }}:{{ .Values.image.server.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.server.pullPolicy }} + ports: + - name: http + containerPort: {{ .Values.server.port }} + protocol: TCP + env: + - name: CONFIG_FILE + value: /etc/gohoarder/config.yaml + {{- if and .Values.auth.enabled .Values.auth.existingSecret }} + - name: ADMIN_API_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.auth.existingSecret }} + key: {{ .Values.auth.secretKey }} + {{- else if .Values.auth.enabled }} + - name: ADMIN_API_KEY + valueFrom: + secretKeyRef: + name: {{ include "gohoarder.fullname" . }}-auth + key: {{ .Values.auth.secretKey }} + {{- end }} + {{- if and (eq .Values.storage.backend "s3") .Values.storage.s3.existingSecret }} + - name: S3_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: {{ .Values.storage.s3.existingSecret }} + key: access-key-id + - name: S3_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: {{ .Values.storage.s3.existingSecret }} + key: secret-access-key + {{- else if and (eq .Values.storage.backend "s3") .Values.storage.s3.accessKeyId }} + - name: S3_ACCESS_KEY_ID + valueFrom: + secretKeyRef: + name: {{ include "gohoarder.fullname" . }}-s3 + key: access-key-id + - name: S3_SECRET_ACCESS_KEY + valueFrom: + secretKeyRef: + name: {{ include "gohoarder.fullname" . }}-s3 + key: secret-access-key + {{- end }} + {{- if and (eq .Values.storage.backend "smb") .Values.storage.smb.existingSecret }} + - name: SMB_USERNAME + valueFrom: + secretKeyRef: + name: {{ .Values.storage.smb.existingSecret }} + key: username + - name: SMB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.storage.smb.existingSecret }} + key: password + {{- else if and (eq .Values.storage.backend "smb") .Values.storage.smb.username }} + - name: SMB_USERNAME + valueFrom: + secretKeyRef: + name: {{ include "gohoarder.fullname" . }}-smb + key: username + - name: SMB_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "gohoarder.fullname" . }}-smb + key: password + {{- end }} + {{- if and (eq .Values.metadata.backend "postgresql") .Values.metadata.postgresql.existingSecret }} + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: {{ .Values.metadata.postgresql.existingSecret }} + key: username + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.metadata.postgresql.existingSecret }} + key: password + {{- else if and (eq .Values.metadata.backend "postgresql") .Values.metadata.postgresql.username }} + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: {{ include "gohoarder.fullname" . }}-postgresql + key: username + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: {{ include "gohoarder.fullname" . }}-postgresql + key: password + {{- end }} + {{- if and .Values.security.scanners.ghsa.enabled .Values.security.scanners.ghsa.existingSecret }} + - name: GHSA_TOKEN + valueFrom: + secretKeyRef: + name: {{ .Values.security.scanners.ghsa.existingSecret }} + key: token + {{- else if and .Values.security.scanners.ghsa.enabled .Values.security.scanners.ghsa.token }} + - name: GHSA_TOKEN + valueFrom: + secretKeyRef: + name: {{ include "gohoarder.fullname" . }}-ghsa + key: token + {{- end }} + livenessProbe: + {{- toYaml .Values.server.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.server.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.server.resources | nindent 12 }} + volumeMounts: + - name: config + mountPath: /etc/gohoarder + readOnly: true + - name: storage + mountPath: /var/cache/gohoarder + - name: metadata + mountPath: /var/lib/gohoarder/metadata + - name: tmp + mountPath: /tmp + volumes: + - name: config + configMap: + name: {{ include "gohoarder.fullname" . }}-config + {{- include "gohoarder.storageVolume" . | nindent 6 }} + {{- include "gohoarder.metadataVolume" . | nindent 6 }} + - name: tmp + emptyDir: {} + {{- with .Values.server.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.server.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.server.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/helm/gohoarder/templates/ingress.yaml b/helm/gohoarder/templates/ingress.yaml new file mode 100644 index 0000000..8476b6b --- /dev/null +++ b/helm/gohoarder/templates/ingress.yaml @@ -0,0 +1,83 @@ +{{- if .Values.ingress.enabled -}} +{{- if .Values.ingress.frontend.enabled -}} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "gohoarder.fullname" . }}-frontend + labels: + {{- include "gohoarder.frontend.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.frontend.tls.enabled }} + tls: + - hosts: + - {{ .Values.ingress.frontend.host | default (printf "%s.%s" "gohoarder" .Values.global.domain) | quote }} + secretName: {{ .Values.ingress.frontend.tls.secretName }} + {{- end }} + rules: + - host: {{ .Values.ingress.frontend.host | default (printf "%s.%s" "gohoarder" .Values.global.domain) | quote }} + http: + paths: + - path: /api + pathType: Prefix + backend: + service: + name: {{ include "gohoarder.fullname" . }}-server + port: + number: {{ .Values.server.service.port }} + - path: /ws + pathType: Prefix + backend: + service: + name: {{ include "gohoarder.fullname" . }}-server + port: + number: {{ .Values.server.service.port }} + - path: / + pathType: Prefix + backend: + service: + name: {{ include "gohoarder.fullname" . }}-frontend + port: + number: {{ .Values.frontend.service.port }} +{{- end }} +--- +{{- if .Values.ingress.api.enabled }} +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "gohoarder.fullname" . }}-api + labels: + {{- include "gohoarder.server.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if .Values.ingress.className }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.api.tls.enabled }} + tls: + - hosts: + - {{ .Values.ingress.api.host | default (printf "api.%s.%s" "gohoarder" .Values.global.domain) | quote }} + secretName: {{ .Values.ingress.api.tls.secretName }} + {{- end }} + rules: + - host: {{ .Values.ingress.api.host | default (printf "api.%s.%s" "gohoarder" .Values.global.domain) | quote }} + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: {{ include "gohoarder.fullname" . }}-server + port: + number: {{ .Values.server.service.port }} +{{- end }} +{{- end }} diff --git a/helm/gohoarder/templates/pvc.yaml b/helm/gohoarder/templates/pvc.yaml new file mode 100644 index 0000000..f16c7c4 --- /dev/null +++ b/helm/gohoarder/templates/pvc.yaml @@ -0,0 +1,37 @@ +{{- if and (eq .Values.storage.backend "filesystem") (not .Values.storage.filesystem.useHostPath) (not .Values.storage.filesystem.existingClaim) }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "gohoarder.fullname" . }}-storage + labels: + {{- include "gohoarder.labels" . | nindent 4 }} + app.kubernetes.io/component: storage +spec: + accessModes: + - {{ .Values.storage.filesystem.accessMode }} + {{- if .Values.storage.filesystem.storageClass }} + storageClassName: {{ .Values.storage.filesystem.storageClass | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.storage.filesystem.size | quote }} +{{- end }} +--- +{{- if and (eq .Values.metadata.backend "sqlite") .Values.metadata.sqlite.persistence.enabled (not .Values.metadata.sqlite.persistence.existingClaim) }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: {{ include "gohoarder.fullname" . }}-metadata + labels: + {{- include "gohoarder.labels" . | nindent 4 }} + app.kubernetes.io/component: metadata +spec: + accessModes: + - {{ .Values.metadata.sqlite.persistence.accessMode }} + {{- if .Values.metadata.sqlite.persistence.storageClass }} + storageClassName: {{ .Values.metadata.sqlite.persistence.storageClass | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.metadata.sqlite.persistence.size | quote }} +{{- end }} diff --git a/helm/gohoarder/templates/secret.yaml b/helm/gohoarder/templates/secret.yaml new file mode 100644 index 0000000..cfa1876 --- /dev/null +++ b/helm/gohoarder/templates/secret.yaml @@ -0,0 +1,66 @@ +{{- if and .Values.auth.enabled (not .Values.auth.existingSecret) }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "gohoarder.fullname" . }}-auth + labels: + {{- include "gohoarder.labels" . | nindent 4 }} +type: Opaque +data: + {{- if .Values.auth.adminApiKey }} + {{ .Values.auth.secretKey }}: {{ .Values.auth.adminApiKey | b64enc | quote }} + {{- else }} + {{ .Values.auth.secretKey }}: {{ include "gohoarder.adminApiKey" . | b64enc | quote }} + {{- end }} +{{- end }} +--- +{{- if and (eq .Values.storage.backend "s3") (not .Values.storage.s3.existingSecret) .Values.storage.s3.accessKeyId }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "gohoarder.fullname" . }}-s3 + labels: + {{- include "gohoarder.labels" . | nindent 4 }} +type: Opaque +data: + access-key-id: {{ .Values.storage.s3.accessKeyId | b64enc | quote }} + secret-access-key: {{ .Values.storage.s3.secretAccessKey | b64enc | quote }} +{{- end }} +--- +{{- if and (eq .Values.storage.backend "smb") (not .Values.storage.smb.existingSecret) .Values.storage.smb.username }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "gohoarder.fullname" . }}-smb + labels: + {{- include "gohoarder.labels" . | nindent 4 }} +type: Opaque +data: + username: {{ .Values.storage.smb.username | b64enc | quote }} + password: {{ .Values.storage.smb.password | b64enc | quote }} +{{- end }} +--- +{{- if and (eq .Values.metadata.backend "postgresql") (not .Values.metadata.postgresql.existingSecret) .Values.metadata.postgresql.username }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "gohoarder.fullname" . }}-postgresql + labels: + {{- include "gohoarder.labels" . | nindent 4 }} +type: Opaque +data: + username: {{ .Values.metadata.postgresql.username | b64enc | quote }} + password: {{ .Values.metadata.postgresql.password | b64enc | quote }} +{{- end }} +--- +{{- if and .Values.security.scanners.ghsa.enabled (not .Values.security.scanners.ghsa.existingSecret) .Values.security.scanners.ghsa.token }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "gohoarder.fullname" . }}-ghsa + labels: + {{- include "gohoarder.labels" . | nindent 4 }} +type: Opaque +data: + token: {{ .Values.security.scanners.ghsa.token | b64enc | quote }} +{{- end }} diff --git a/helm/gohoarder/templates/service.yaml b/helm/gohoarder/templates/service.yaml new file mode 100644 index 0000000..7cb3848 --- /dev/null +++ b/helm/gohoarder/templates/service.yaml @@ -0,0 +1,39 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "gohoarder.fullname" . }}-server + labels: + {{- include "gohoarder.server.labels" . | nindent 4 }} + {{- with .Values.server.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.server.service.type }} + ports: + - port: {{ .Values.server.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "gohoarder.server.selectorLabels" . | nindent 4 }} +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "gohoarder.fullname" . }}-frontend + labels: + {{- include "gohoarder.frontend.labels" . | nindent 4 }} + {{- with .Values.frontend.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.frontend.service.type }} + ports: + - port: {{ .Values.frontend.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "gohoarder.frontend.selectorLabels" . | nindent 4 }} diff --git a/helm/gohoarder/templates/serviceaccount.yaml b/helm/gohoarder/templates/serviceaccount.yaml new file mode 100644 index 0000000..facf516 --- /dev/null +++ b/helm/gohoarder/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "gohoarder.serviceAccountName" . }} + labels: + {{- include "gohoarder.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/helm/gohoarder/values.yaml b/helm/gohoarder/values.yaml new file mode 100644 index 0000000..d7839ad --- /dev/null +++ b/helm/gohoarder/values.yaml @@ -0,0 +1,405 @@ +# Default values for gohoarder +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +# Global configuration +global: + # Base domain for the deployment + domain: "gohoarder.local" + # Image pull secrets + imagePullSecrets: [] + +# Deployment replicas +replicaCount: + server: 1 + frontend: 1 + scanner: 1 + +# Image configuration +image: + server: + repository: ghcr.io/lukaszraczylo/gohoarder-server + pullPolicy: IfNotPresent + tag: "latest" + + frontend: + repository: ghcr.io/lukaszraczylo/gohoarder-frontend + pullPolicy: IfNotPresent + tag: "latest" + + scanner: + repository: ghcr.io/lukaszraczylo/gohoarder-scanner + pullPolicy: IfNotPresent + tag: "latest" + +# Service Account +serviceAccount: + create: true + annotations: {} + name: "" + +# Pod annotations +podAnnotations: {} + +# Pod security context +podSecurityContext: + fsGroup: 1000 + runAsNonRoot: true + runAsUser: 1000 + +# Container security context +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + +# Server configuration +server: + host: "0.0.0.0" + port: 8080 + readTimeout: "5m" + writeTimeout: "5m" + idleTimeout: "2m" + + # Service configuration + service: + type: ClusterIP + port: 80 + targetPort: 8080 + annotations: {} + + # Resource limits + resources: + limits: + cpu: 2000m + memory: 2Gi + requests: + cpu: 500m + memory: 512Mi + + # Liveness and readiness probes + livenessProbe: + httpGet: + path: /health + port: http + initialDelaySeconds: 30 + periodSeconds: 10 + timeoutSeconds: 5 + failureThreshold: 3 + + readinessProbe: + httpGet: + path: /health/ready + port: http + initialDelaySeconds: 10 + periodSeconds: 5 + timeoutSeconds: 3 + failureThreshold: 3 + + # Node selector + nodeSelector: {} + + # Tolerations + tolerations: [] + + # Affinity + affinity: {} + +# Frontend configuration +frontend: + port: 3000 + + # Service configuration + service: + type: ClusterIP + port: 80 + targetPort: 3000 + annotations: {} + + # Resource limits + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 100m + memory: 128Mi + + # Liveness and readiness probes + livenessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 30 + periodSeconds: 10 + + readinessProbe: + httpGet: + path: / + port: http + initialDelaySeconds: 10 + periodSeconds: 5 + + nodeSelector: {} + tolerations: [] + affinity: {} + +# Scanner configuration +scanner: + # Resource limits + resources: + limits: + cpu: 2000m + memory: 4Gi + requests: + cpu: 500m + memory: 1Gi + + nodeSelector: {} + tolerations: [] + affinity: {} + +# Storage configuration +storage: + # Storage backend: filesystem, s3, smb + backend: "filesystem" + + # Filesystem storage + filesystem: + # Storage class for PVC + storageClass: "" + # Storage size + size: "100Gi" + # Access mode + accessMode: "ReadWriteOnce" + # Use hostPath instead of PVC (for single-node testing) + useHostPath: false + hostPath: "/var/lib/gohoarder" + # Existing PVC name (if you want to use existing PVC) + existingClaim: "" + + # S3 storage + s3: + endpoint: "s3.amazonaws.com" + region: "us-east-1" + bucket: "gohoarder-cache" + accessKeyId: "" + secretAccessKey: "" + # Use existing secret for S3 credentials + existingSecret: "" + useSSL: true + + # SMB storage + smb: + host: "" + share: "" + username: "" + password: "" + domain: "" + # Use existing secret for SMB credentials + existingSecret: "" + +# Metadata storage configuration +metadata: + # Backend: sqlite, postgresql + backend: "sqlite" + + # SQLite configuration + sqlite: + # Use PVC for SQLite database + persistence: + enabled: true + storageClass: "" + size: "10Gi" + accessMode: "ReadWriteOnce" + existingClaim: "" + walMode: true + + # PostgreSQL configuration + postgresql: + # Use bundled PostgreSQL (sets up postgresql subchart) + enabled: false + host: "localhost" + port: 5432 + database: "gohoarder" + username: "gohoarder" + password: "" + sslMode: "disable" + # Use existing secret for PostgreSQL credentials + existingSecret: "" + +# Cache configuration +cache: + defaultTTL: "168h" # 7 days + cleanupInterval: "1h" + maxSizeBytes: 536870912000 # 500GB + perProjectQuota: 53687091200 # 50GB + ttlOverrides: + npm: "168h" + pip: "168h" + go: "168h" + +# Security scanning configuration +security: + enabled: false + blockOnSeverity: "high" # none, low, medium, high, critical + scanOnDownload: true + rescanInterval: "24h" + updateDbOnStartup: false + + blockThresholds: + critical: 0 + high: -1 + medium: -1 + low: -1 + + scanners: + trivy: + enabled: false + timeout: "5m" + cacheDb: "/var/lib/trivy" + + osv: + enabled: false + apiUrl: "https://api.osv.dev" + timeout: "30s" + + grype: + enabled: false + timeout: "5m" + + govulncheck: + enabled: false + timeout: "5m" + + npmAudit: + enabled: false + timeout: "2m" + + pipAudit: + enabled: false + timeout: "2m" + + ghsa: + enabled: false + timeout: "30s" + # GitHub token for higher rate limits + token: "" + existingSecret: "" + + static: + enabled: true + maxPackageSize: 2147483648 # 2GB + checkChecksums: true + blockSuspicious: false + +# Authentication configuration +auth: + enabled: true + keyExpiration: "0" # Never expire + bcryptCost: 10 + auditLog: true + + # Admin API key - will be auto-generated if not provided + adminApiKey: "" + # Use existing secret for admin API key + existingSecret: "" + # Secret key name for admin API key + secretKey: "admin-api-key" + +# Network configuration +network: + connectTimeout: "10s" + readTimeout: "5m" + writeTimeout: "5m" + maxIdleConns: 100 + maxConnsPerHost: 10 + + rateLimit: + perApiKey: 1000 + perIp: 100 + burstSize: 50 + + circuitBreaker: + threshold: 5 + timeout: "30s" + resetInterval: "60s" + + retry: + maxAttempts: 3 + initialBackoff: "1s" + maxBackoff: "30s" + +# Logging configuration +logging: + level: "info" # debug, info, warn, error + format: "json" # json, pretty + +# Package handlers configuration +handlers: + go: + enabled: true + upstreamProxy: "https://proxy.golang.org" + checksumDb: "https://sum.golang.org" + verifyChecksums: true + + npm: + enabled: true + upstreamRegistry: "https://registry.npmjs.org" + + pypi: + enabled: true + upstreamUrl: "https://pypi.org" + simpleApiUrl: "https://pypi.org/simple" + +# Ingress configuration +ingress: + enabled: false + className: "nginx" + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + nginx.ingress.kubernetes.io/proxy-body-size: "2048m" + nginx.ingress.kubernetes.io/proxy-read-timeout: "300" + nginx.ingress.kubernetes.io/proxy-send-timeout: "300" + + # Ingress for frontend + frontend: + enabled: true + host: "gohoarder.local" + tls: + enabled: false + secretName: "gohoarder-frontend-tls" + + # Ingress for API (if you want separate ingress) + api: + enabled: false + host: "api.gohoarder.local" + tls: + enabled: false + secretName: "gohoarder-api-tls" + +# Autoscaling configuration +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 10 + targetCPUUtilizationPercentage: 80 + targetMemoryUtilizationPercentage: 80 + +# Pod Disruption Budget +podDisruptionBudget: + enabled: false + minAvailable: 1 + +# Network Policy +networkPolicy: + enabled: false + # Allow external access to server + ingress: + - from: + - namespaceSelector: {} + ports: + - protocol: TCP + port: 8080