Compare commits

..
2 Commits
Author SHA1 Message Date
lukaszraczylo 1da6c3d0a3 fixup! fixes 2026-01-02 19:10:04 +00:00
lukaszraczylo c727465646 fixes 2026-01-02 18:44:10 +00:00
21 changed files with 3442 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
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Lukasz Raczylo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+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: [email protected]
icon: https://raw.githubusercontent.com/lukaszraczylo/gohoarder/main/docs/logo.png
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Lukasz Raczylo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+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