Skip to content

Commit 3db6a38

Browse files
committed
chore(helm/charts): import erpc from morpho-infra-helm
1 parent c8ec6bd commit 3db6a38

44 files changed

Lines changed: 5520 additions & 0 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/CODEOWNERS

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Default ownership
2+
* @morpho-org/platform-engineers
3+
4+
# Helm charts migrated from morpho-infra-helm (2026-06-17)
5+
/helm/ @morpho-org/platform-engineers @morpho-org/api-engineers
6+
/validate-helm-charts.sh @morpho-org/platform-engineers
7+
/setup-hooks.sh @morpho-org/platform-engineers
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
name: Helm Chart Validation
2+
3+
on:
4+
push:
5+
branches: [morpho-main]
6+
paths:
7+
- 'helm/**'
8+
pull_request:
9+
branches: [morpho-main]
10+
paths:
11+
- 'helm/**'
12+
13+
jobs:
14+
# =============================================================================
15+
# Job 1: Discover all charts to validate
16+
# =============================================================================
17+
discover-charts:
18+
name: Discover Charts
19+
runs-on: ubuntu-latest
20+
outputs:
21+
charts: ${{ steps.find.outputs.charts }}
22+
chart-count: ${{ steps.find.outputs.count }}
23+
steps:
24+
- name: Checkout
25+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
26+
27+
- name: Find all charts
28+
id: find
29+
run: |
30+
# Find all Chart.yaml files and get their directories
31+
charts=$(find helm/charts helm/environments -name Chart.yaml -type f -exec dirname {} \; | sort | jq -R -s -c 'split("\n") | map(select(length > 0))')
32+
count=$(echo "$charts" | jq 'length')
33+
echo "Found $count charts to validate"
34+
echo "charts=$charts" >> $GITHUB_OUTPUT
35+
echo "count=$count" >> $GITHUB_OUTPUT
36+
37+
# =============================================================================
38+
# Job 2: Validate each chart in parallel
39+
# =============================================================================
40+
validate:
41+
name: Validate
42+
needs: discover-charts
43+
runs-on: ubuntu-latest
44+
strategy:
45+
fail-fast: false # Continue validating other charts if one fails
46+
matrix:
47+
chart: ${{ fromJson(needs.discover-charts.outputs.charts) }}
48+
steps:
49+
- name: Checkout
50+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
51+
52+
- name: Set up Helm
53+
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4
54+
with:
55+
version: v3.16.4
56+
57+
- name: Install kubeconform
58+
run: |
59+
KUBECONFORM_VERSION=v0.6.1
60+
KUBECONFORM_SHA256=7f84c1e4109fb72f151da41bdffea05e1e37591f179de51adc048c83533ad215
61+
curl -fsSLo /tmp/kubeconform.tar.gz "https://github.com/yannh/kubeconform/releases/download/${KUBECONFORM_VERSION}/kubeconform-linux-amd64.tar.gz"
62+
echo "${KUBECONFORM_SHA256} /tmp/kubeconform.tar.gz" | sha256sum -c -
63+
tar xzf /tmp/kubeconform.tar.gz
64+
sudo mv kubeconform /usr/local/bin/
65+
66+
- name: Add Helm repositories
67+
run: |
68+
helm repo add bitnami https://charts.bitnami.com/bitnami 2>/dev/null || true
69+
helm repo add cnpg https://cloudnative-pg.github.io/charts 2>/dev/null || true
70+
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts 2>/dev/null || true
71+
helm repo add haproxytech https://haproxytech.github.io/helm-charts 2>/dev/null || true
72+
helm repo add dandydeveloper https://dandydeveloper.github.io/charts 2>/dev/null || true
73+
helm repo update
74+
75+
- name: Get chart info
76+
id: chart-info
77+
run: |
78+
chart_path="${{ matrix.chart }}"
79+
chart_name=$(basename "$chart_path")
80+
echo "name=$chart_name" >> $GITHUB_OUTPUT
81+
echo "path=$chart_path" >> $GITHUB_OUTPUT
82+
83+
# Check if chart should skip kubeconform validation
84+
skip_validation="false"
85+
case "$chart_name" in
86+
*-db|*database*|*postgres*)
87+
skip_validation="true"
88+
;;
89+
esac
90+
echo "skip-kubeconform=$skip_validation" >> $GITHUB_OUTPUT
91+
92+
- name: Helm lint
93+
run: |
94+
echo "::group::Helm lint ${{ steps.chart-info.outputs.name }}"
95+
helm lint "${{ matrix.chart }}"
96+
echo "::endgroup::"
97+
98+
- name: Update dependencies
99+
run: |
100+
cd "${{ matrix.chart }}"
101+
if grep -q "dependencies:" Chart.yaml 2>/dev/null; then
102+
echo "::group::Updating dependencies for ${{ steps.chart-info.outputs.name }}"
103+
helm dependency update
104+
echo "::endgroup::"
105+
fi
106+
107+
- name: Kubeconform validation
108+
if: steps.chart-info.outputs.skip-kubeconform != 'true'
109+
run: |
110+
CUSTOM_RESOURCES="PodMonitor,ServiceMonitor,AlertManager,Prometheus,PrometheusRule,Cluster,ScheduledBackup,ImageCatalog,IngressRoute,Certificate,CronJob,EventSource,EventBus,Sensor"
111+
112+
echo "::group::Kubeconform validation for ${{ steps.chart-info.outputs.name }}"
113+
cd "${{ matrix.chart }}"
114+
helm template . | kubeconform --ignore-missing-schemas --summary --skip "$CUSTOM_RESOURCES"
115+
echo "::endgroup::"
116+
117+
- name: Skip notice
118+
if: steps.chart-info.outputs.skip-kubeconform == 'true'
119+
run: |
120+
echo "::notice::Skipping kubeconform validation for ${{ steps.chart-info.outputs.name }} (database chart)"
121+
122+
# =============================================================================
123+
# Job 3: Summary (ensures all validations completed)
124+
# =============================================================================
125+
validation-summary:
126+
name: Validation Summary
127+
needs: [discover-charts, validate]
128+
runs-on: ubuntu-latest
129+
if: always()
130+
steps:
131+
- name: Check validation results
132+
run: |
133+
if [ "${{ needs.discover-charts.result }}" == "failure" ]; then
134+
echo "::error::Chart discovery failed"
135+
exit 1
136+
elif [ "${{ needs.discover-charts.result }}" == "cancelled" ]; then
137+
echo "::warning::Chart discovery was cancelled"
138+
exit 1
139+
elif [ "${{ needs.validate.result }}" == "failure" ]; then
140+
echo "::error::Some chart validations failed"
141+
exit 1
142+
elif [ "${{ needs.validate.result }}" == "cancelled" ]; then
143+
echo "::warning::Validation was cancelled"
144+
exit 1
145+
elif [ "${{ needs.validate.result }}" == "skipped" ]; then
146+
echo "::warning::Validation was skipped unexpectedly"
147+
exit 1
148+
else
149+
echo "::notice::All ${{ needs.discover-charts.outputs.chart-count }} charts validated successfully"
150+
fi

.github/workflows/pr-commands.yml

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
name: PR Commands
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
pull_request_review_comment:
7+
types: [created]
8+
pull_request_review:
9+
types: [submitted]
10+
issues:
11+
types: [opened, assigned]
12+
13+
jobs:
14+
# =============================================================================
15+
# Job: Claude Interactive (/claude)
16+
# =============================================================================
17+
claude-interactive:
18+
name: Claude Interactive
19+
if: |
20+
github.actor == '0x666c6f' && (
21+
(github.event_name == 'issue_comment' && (github.event.comment.body == '/claude' || startsWith(github.event.comment.body, '/claude ') || startsWith(github.event.comment.body, '/claude\n'))) ||
22+
(github.event_name == 'pull_request_review_comment' && (github.event.comment.body == '/claude' || startsWith(github.event.comment.body, '/claude ') || startsWith(github.event.comment.body, '/claude\n'))) ||
23+
(github.event_name == 'pull_request_review' && github.event.review.body && (github.event.review.body == '/claude' || startsWith(github.event.review.body, '/claude ') || startsWith(github.event.review.body, '/claude\n'))) ||
24+
(github.event_name == 'issues' && (
25+
github.event.issue.title == '/claude' ||
26+
startsWith(github.event.issue.title, '/claude ') ||
27+
startsWith(github.event.issue.title, '/claude\n') ||
28+
(github.event.issue.body && (
29+
github.event.issue.body == '/claude' ||
30+
startsWith(github.event.issue.body, '/claude ') ||
31+
startsWith(github.event.issue.body, '/claude\n')
32+
))
33+
))
34+
)
35+
runs-on: ubuntu-latest
36+
concurrency:
37+
group: claude-interactive-${{ github.event.issue.number || github.event.pull_request.number || github.run_id }}
38+
cancel-in-progress: false
39+
permissions:
40+
contents: write
41+
pull-requests: write
42+
issues: write
43+
id-token: write
44+
actions: read
45+
46+
steps:
47+
- name: Checkout repository
48+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
49+
with:
50+
fetch-depth: 0
51+
52+
- name: Run Claude Code
53+
id: claude
54+
uses: anthropics/claude-code-action@905d4eb99ab3d43143d74fb0dcae537f29ac330a # v1
55+
with:
56+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
57+
trigger_phrase: "/claude"
58+
59+
additional_permissions: |
60+
actions: read
61+
62+
claude_args: |
63+
--model claude-opus-4-5-20251101
64+
--max-turns 200
65+
--system-prompt "You are an expert DevOps engineer working on a Helm charts repository for Kubernetes infrastructure.
66+
67+
## Your Expertise
68+
- Helm chart best practices (templates, helpers, values, dependencies)
69+
- Kubernetes resources (Deployments, Services, ConfigMaps, Secrets, RBAC)
70+
- Security best practices (securityContext, NetworkPolicy, RBAC)
71+
- Observability (Prometheus, metrics, logging)
72+
73+
## When Making Code Changes
74+
- Follow existing patterns in the repository
75+
- Use proper Helm templating syntax
76+
- Ensure backward compatibility
77+
- Add comments for complex logic"
78+
--allowed-tools "Bash(gh:*),Bash(helm:*),Bash(kubectl:*),Bash(git:*),Read,Glob,Grep,Write,Edit"
79+
80+
# =============================================================================
81+
# Job: Claude Code Review (/claude-review)
82+
# =============================================================================
83+
claude-review:
84+
name: Claude Code Review
85+
if: |
86+
github.actor == '0x666c6f' && (
87+
(github.event_name == 'issue_comment' && github.event.issue.pull_request && contains(github.event.comment.body, '/claude-review')) ||
88+
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/claude-review')) ||
89+
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '/claude-review'))
90+
)
91+
runs-on: ubuntu-latest
92+
concurrency:
93+
group: claude-review-${{ github.event.issue.number || github.event.pull_request.number || github.run_id }}
94+
cancel-in-progress: true
95+
permissions:
96+
contents: read
97+
pull-requests: write
98+
issues: write
99+
id-token: write
100+
actions: read
101+
102+
env:
103+
PR_NUMBER: ${{ github.event.issue.number || github.event.pull_request.number }}
104+
HEAD_REPO: ${{ github.repository }}
105+
HEAD_SHA: ${{ github.sha }}
106+
107+
steps:
108+
- name: Fetch PR metadata
109+
env:
110+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
111+
run: |
112+
pr_number="${PR_NUMBER}"
113+
pr_json="$(gh api repos/${{ github.repository }}/pulls/${pr_number})"
114+
head_repo="$(echo "$pr_json" | jq -r .head.repo.full_name)"
115+
head_sha="$(echo "$pr_json" | jq -r .head.sha)"
116+
117+
if [ "$head_repo" != "${{ github.repository }}" ]; then
118+
echo "PR from fork; skipping."
119+
echo "SKIP_WORKFLOW=true" >> "$GITHUB_ENV"
120+
exit 0
121+
fi
122+
123+
echo "HEAD_REPO=$head_repo" >> "$GITHUB_ENV"
124+
echo "HEAD_SHA=$head_sha" >> "$GITHUB_ENV"
125+
126+
- name: Checkout PR head
127+
if: env.SKIP_WORKFLOW != 'true'
128+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5
129+
with:
130+
repository: ${{ env.HEAD_REPO }}
131+
ref: ${{ env.HEAD_SHA }}
132+
fetch-depth: 0
133+
134+
- name: Setup Helm
135+
if: env.SKIP_WORKFLOW != 'true'
136+
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4
137+
with:
138+
version: v3.16.4
139+
140+
- name: Install kubeconform
141+
if: env.SKIP_WORKFLOW != 'true'
142+
run: |
143+
KUBECONFORM_VERSION=v0.6.1
144+
KUBECONFORM_SHA256=7f84c1e4109fb72f151da41bdffea05e1e37591f179de51adc048c83533ad215
145+
curl -fsSLo /tmp/kubeconform.tar.gz "https://github.com/yannh/kubeconform/releases/download/${KUBECONFORM_VERSION}/kubeconform-linux-amd64.tar.gz"
146+
echo "${KUBECONFORM_SHA256} /tmp/kubeconform.tar.gz" | sha256sum -c -
147+
tar xzf /tmp/kubeconform.tar.gz
148+
sudo mv kubeconform /usr/local/bin/
149+
150+
- name: Cache Helm dependencies
151+
if: env.SKIP_WORKFLOW != 'true'
152+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4
153+
with:
154+
path: |
155+
~/.cache/helm
156+
**/charts/*.tgz
157+
key: helm-deps-${{ hashFiles('**/Chart.lock') }}
158+
restore-keys: |
159+
helm-deps-
160+
161+
- name: Run Claude Code Review
162+
if: env.SKIP_WORKFLOW != 'true'
163+
id: claude-review
164+
uses: anthropics/claude-code-action@905d4eb99ab3d43143d74fb0dcae537f29ac330a # v1
165+
with:
166+
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
167+
prompt: |
168+
## Review Task
169+
Perform a code review on PR #${{ github.event.issue.number || github.event.pull_request.number }}.
170+
171+
Use `gh pr diff ${{ github.event.issue.number || github.event.pull_request.number }}` to see the changes, then use `gh pr view ${{ github.event.issue.number || github.event.pull_request.number }}` to get PR details.
172+
173+
## Helm Charts Repository - Specialized Review Guidelines
174+
175+
This is a **Helm charts repository** for Kubernetes infrastructure. Apply these domain-specific checks:
176+
177+
### Helm Chart Quality
178+
- **Chart.yaml**: Verify version bumps follow semver, dependencies are correct, apiVersion is v2
179+
- **values.yaml**: Check for sensible defaults, proper structure, documented options
180+
- **templates/**: Validate helper usage, proper indentation, correct YAML generation
181+
- **Chart.lock**: Ensure dependencies are locked and up-to-date
182+
183+
### Kubernetes Best Practices
184+
- **Resources**: Verify requests/limits are set appropriately
185+
- **Probes**: Check liveness/readiness probes are configured
186+
- **Security**: Ensure securityContext, runAsNonRoot, readOnlyRootFilesystem
187+
- **Labels**: Validate app.kubernetes.io/* standard labels
188+
- **PDB**: Check PodDisruptionBudget for HA deployments
189+
190+
### Security Focus
191+
- **Secrets**: NO hardcoded credentials (use ExternalSecrets/Vault)
192+
- **Images**: No :latest tags, prefer digest pinning
193+
- **RBAC**: Minimal required permissions
194+
- **NetworkPolicy**: Proper network segmentation where needed
195+
- **ServiceAccount**: Dedicated accounts with minimal privileges
196+
197+
### Review Output Format
198+
Categorize findings by severity prefix in your comments:
199+
- `[CRITICAL]`: Must fix before merge (security vulnerabilities, breaking changes)
200+
- `[HIGH]`: Should fix (best practice violations, potential issues)
201+
- `[MEDIUM]`: Consider fixing (improvements, minor issues)
202+
- `[LOW]`: Nice to have (style, documentation)
203+
204+
### How to Post Your Review
205+
- Use `mcp__github_inline_comment__create_inline_comment` to highlight specific code issues on specific lines
206+
- Use `gh pr comment` for top-level summary feedback
207+
- Only post GitHub comments - don't submit review text as messages
208+
209+
### Validation Commands Available
210+
- `helm lint helm/charts/<name>` - Lint a chart
211+
- `helm template helm/charts/<name>` - Render templates
212+
- `helm template helm/charts/<name> | kubeconform --ignore-missing-schemas` - Validate rendered YAML
213+
214+
claude_args: |
215+
--model claude-opus-4-5-20251101
216+
--max-turns 200
217+
--allowed-tools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),Bash(helm lint:*),Bash(helm template:*),Bash(helm dependency:*),Bash(kubeconform:*),Read,Glob,Grep"

0 commit comments

Comments
 (0)