This commit is contained in:
2026-01-02 18:44:10 +00:00
parent ce5a8fbffd
commit c727465646
19 changed files with 3400 additions and 0 deletions
+28
View File
@@ -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
+4
View File
@@ -68,7 +68,11 @@ web/dist/
# Test fixtures
tests/fixtures/temp/
# Markdown files (except README.md)
*.md
!README.md
/gohoarder
*.log
*.out
+1261
View File
File diff suppressed because it is too large Load Diff
+416
View File
@@ -0,0 +1,416 @@
# Kubernetes Deployment Guide
This directory contains Kubernetes manifests for deploying GoHoarder in a production environment.
## Architecture Overview
```
┌─────────────────────────────────────────────────────┐
│ Kubernetes Pod │
│ ┌────────────────────────────────────────────────┐ │
│ │ GoHoarder Container │ │
│ │ ┌──────────────────────────────────────────┐ │ │
│ │ │ Pattern-Based Credential Store │ │ │
│ │ │ ├─ github.com/myorg/* → token_A │ │ │
│ │ │ ├─ gitlab.com/team/* → token_B │ │ │
│ │ │ └─ * → fallback_token │ │ │
│ │ └──────────────────────────────────────────┘ │ │
│ └────────────────────────────────────────────────┘ │
│ │
│ Mounted Volumes: │
│ • config.yaml (ConfigMap) │
│ • git-credentials.json (Secret) │
│ • /var/lib/gohoarder/cache (PVC) │
│ • /var/lib/gohoarder (PVC for metadata DB) │
└─────────────────────────────────────────────────────┘
```
## Files
- `secret-git-credentials.yaml` - Git credentials for private repositories
- `configmap-config.yaml` - Application configuration
- `pvc.yaml` - Persistent volume claims for cache and metadata
- `deployment.yaml` - Main application deployment
- `service.yaml` - Service and optional ingress configuration
## Quick Start
### 1. Configure Git Credentials
Edit `secret-git-credentials.yaml` and replace the placeholder tokens with your actual tokens:
```yaml
{
"credentials": [
{
"pattern": "github.com/mycompany/*",
"host": "github.com",
"username": "oauth2",
"token": "ghp_YOUR_ACTUAL_TOKEN_HERE"
}
]
}
```
**Pattern Matching Examples:**
- `github.com/myorg/*` - Matches all repos under myorg
- `github.com/myorg/specific-repo` - Matches only specific-repo
- `gitlab.com/backend-team/*` - Matches all GitLab repos under backend-team
- `*` - Fallback pattern (matches everything)
**Credential Priority:**
1. Most specific pattern wins (longest match)
2. Fallback credential (`"fallback": true`)
3. System git config (if no matches)
### 2. Customize Configuration
Edit `configmap-config.yaml` to adjust:
- Cache size (`max_size_bytes`)
- Security scanning settings
- Upstream registries
- Logging level
### 3. Deploy to Kubernetes
```bash
# Create namespace (optional)
kubectl create namespace gohoarder
# Apply manifests
kubectl apply -f pvc.yaml
kubectl apply -f secret-git-credentials.yaml
kubectl apply -f configmap-config.yaml
kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
# Verify deployment
kubectl get pods -l app=gohoarder
kubectl logs -l app=gohoarder -f
```
### 4. Configure Go Client
```bash
# Set GOPROXY environment variable
export GOPROXY=http://gohoarder.default.svc.cluster.local:8080/go,direct
# Or in your Dockerfile
ENV GOPROXY=http://gohoarder.default.svc.cluster.local:8080/go,direct
# Test with a private module
go get github.com/mycompany/private-module@latest
```
## Advanced Configuration
### Using External Secrets Operator (ESO)
If you're using External Secrets Operator, uncomment the ExternalSecret section in `secret-git-credentials.yaml` and configure your SecretStore:
```yaml
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: gohoarder-git-credentials
spec:
refreshInterval: 1h
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: gohoarder-git-credentials
data:
- secretKey: credentials.json
remoteRef:
key: secret/gohoarder/git-credentials
```
### Storage Classes
For production deployments, specify appropriate storage classes:
```yaml
# In pvc.yaml
storageClassName: fast-ssd # For cache (needs fast I/O)
storageClassName: standard # For metadata (smaller, less critical)
```
### Horizontal Pod Autoscaling
```bash
kubectl autoscale deployment gohoarder \
--cpu-percent=70 \
--min=2 \
--max=10
```
### Monitoring
Check health and metrics:
```bash
# Health check
kubectl port-forward svc/gohoarder 8080:8080
curl http://localhost:8080/health
# Metrics (Prometheus format)
curl http://localhost:8080/metrics
```
## Multi-Organization Setup
### Example 1: Multiple GitHub Organizations
```json
{
"credentials": [
{
"pattern": "github.com/company-frontend/*",
"host": "github.com",
"username": "oauth2",
"token": "ghp_frontend_team_token"
},
{
"pattern": "github.com/company-backend/*",
"host": "github.com",
"username": "oauth2",
"token": "ghp_backend_team_token"
},
{
"pattern": "github.com/company-infra/*",
"host": "github.com",
"username": "oauth2",
"token": "ghp_infra_team_token"
},
{
"pattern": "*",
"host": "*",
"username": "oauth2",
"token": "ghp_readonly_default_token",
"fallback": true
}
]
}
```
### Example 2: GitHub + GitLab
```json
{
"credentials": [
{
"pattern": "github.com/myorg/*",
"host": "github.com",
"username": "oauth2",
"token": "ghp_github_token"
},
{
"pattern": "gitlab.com/myteam/*",
"host": "gitlab.com",
"username": "oauth2",
"token": "glpat_gitlab_token"
}
]
}
```
### Example 3: Enterprise GitHub
```json
{
"credentials": [
{
"pattern": "github.enterprise.com/engineering/*",
"host": "github.enterprise.com",
"username": "oauth2",
"token": "ghp_enterprise_token"
}
]
}
```
## Security Best Practices
1. **Token Scoping**: Use fine-grained personal access tokens with minimal permissions
- GitHub: Only `repo` scope needed for private repos
- GitLab: Only `read_repository` scope needed
2. **Secret Rotation**: Regularly rotate tokens
```bash
# Update secret
kubectl create secret generic gohoarder-git-credentials \
--from-file=credentials.json=./new-credentials.json \
--dry-run=client -o yaml | kubectl apply -f -
# Restart pods to pick up new credentials
kubectl rollout restart deployment gohoarder
```
3. **RBAC**: Limit who can read the secret
```bash
kubectl create role secret-reader \
--verb=get,list \
--resource=secrets \
--resource-name=gohoarder-git-credentials
```
4. **Audit Logging**: Enable Kubernetes audit logging for secret access
5. **Network Policies**: Restrict which pods can access GoHoarder
```yaml
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: allow-from-build-namespace
spec:
podSelector:
matchLabels:
app: gohoarder
ingress:
- from:
- namespaceSelector:
matchLabels:
name: build-namespace
```
## Troubleshooting
### Check if credentials are loaded
```bash
# Check logs for credential loading
kubectl logs -l app=gohoarder | grep "Loaded git credentials"
# Expected output:
# {"level":"info","file":"/etc/gohoarder/git-credentials.json","credentials":3,"message":"Loaded git credentials from file"}
# {"level":"debug","pattern":"github.com/myorg/*","host":"github.com","message":"Registered credential pattern"}
```
### Test credential pattern matching
```bash
# Enable debug logging
kubectl set env deployment/gohoarder LOG_LEVEL=debug
# Watch logs during a go get request
kubectl logs -l app=gohoarder -f
```
### Common Issues
**Issue**: `git clone failed: authentication required`
- **Cause**: No matching credential pattern
- **Solution**: Check pattern syntax in credentials.json, ensure it matches the module path
**Issue**: `Failed to load git credentials`
- **Cause**: Secret not mounted or JSON syntax error
- **Solution**: Verify secret exists and JSON is valid
```bash
kubectl get secret gohoarder-git-credentials
kubectl get secret gohoarder-git-credentials -o jsonpath='{.data.credentials\.json}' | base64 -d | jq .
```
**Issue**: Module fetch slow
- **Cause**: Git clone timeout or large repository
- **Solution**: Increase timeout in config.yaml or use upstream proxy for public modules
## Performance Tuning
### Cache Configuration
```yaml
cache:
max_size_bytes: 107374182400 # 100GB for large organizations
default_ttl: 168h # 7 days for stable modules
```
### Resource Limits
For high-traffic deployments:
```yaml
resources:
requests:
memory: "2Gi"
cpu: "1000m"
limits:
memory: "8Gi"
cpu: "4000m"
```
### Replicas
Run multiple replicas for high availability:
```yaml
spec:
replicas: 3
```
## Backup and Recovery
### Backup Metadata Database
```bash
# Backup SQLite database
kubectl exec -it deployment/gohoarder -- \
sqlite3 /var/lib/gohoarder/gohoarder.db ".backup /tmp/backup.db"
kubectl cp gohoarder-pod:/tmp/backup.db ./gohoarder-backup-$(date +%Y%m%d).db
```
### Restore from Backup
```bash
kubectl cp ./gohoarder-backup-20260102.db gohoarder-pod:/var/lib/gohoarder/gohoarder.db
kubectl rollout restart deployment gohoarder
```
## Integration Examples
### CI/CD Pipeline (GitHub Actions)
```yaml
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up Go
uses: actions/setup-go@v4
with:
go-version: '1.21'
- name: Configure GOPROXY
run: |
echo "GOPROXY=http://gohoarder.company.internal:8080/go,direct" >> $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
+31
View File
@@ -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/
+22
View File
@@ -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
+214
View File
@@ -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://<gohoarder-url>/npm/
```
### Go
```bash
export GOPROXY=http://<gohoarder-url>/go,direct
```
### PyPI
```bash
pip config set global.index-url http://<gohoarder-url>/pypi/simple
```
## Troubleshooting
### Check Pod Status
```bash
kubectl get pods -n gohoarder
kubectl logs -n gohoarder <pod-name>
```
### Verify Configuration
```bash
kubectl get configmap -n gohoarder <release-name>-gohoarder-config -o yaml
```
### Get Admin API Key
```bash
kubectl get secret -n gohoarder <release-name>-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.
+70
View File
@@ -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
+174
View File
@@ -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 }}
+168
View File
@@ -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 }}
@@ -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 }}
@@ -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 }}
@@ -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 }}
+83
View File
@@ -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 }}
+37
View File
@@ -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 }}
+66
View File
@@ -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 }}
+39
View File
@@ -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 }}
@@ -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 }}
+405
View File
@@ -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