Skip to content

Commit b02a628

Browse files
rguichardclaude0x666c6fCopilot
authored
chore(helm/charts): import erpc from morpho-infra-helm (#90)
* chore(helm/charts): import erpc from morpho-infra-helm * fix(helm): address Aikido review findings on validation scripts Apply the fixes from the per-finding review branches directly: validate-helm-charts.sh: - process_chart now returns instead of exit, so the sequential loop validates every chart and reaches the summary (the parallel path is unaffected). - Use a single `mktemp -d` dir (lint/template files) instead of an unused base temp file; clean up with one `rm -rf`. - Pass the chart path to `helm dependency update` / `helm template` instead of cd-ing into the dir; drop the now-unused INITIAL_DIR. - Split the `helm template | kubeconform` pipeline for readability (keeping the `if !` guard, which is pipefail-safe). test-local.sh: - Redact LABELS_SERVICE_API_KEY when echoing the auth response. - Correct the eth_getLogs decimal block numbers (0x1254048f = 307,496,079, 0x12558b2f = 307,596,079, range = 100,000). The Aikido suggestion to move should_skip_validation before `helm lint` was intentionally not applied: lint is meant to run for all charts; only kubeconform is skipped for database charts. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * chore(helm): address @0x666c6f review on CODEOWNERS and image versions - CODEOWNERS: add @0x666c6f as a mandatory codeowner alongside the teams, on every pattern (incl. /helm/) so he is a required reviewer repo-wide, not only for files matching the default `*` rule. - values.yaml: bump erpc and erpc-validator image tags 0.0.77 -> 0.1.3 to match the latest prd values in morpho-org/morpho-infra-helm. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(harness): make repo map sort deterministic * ci(helm): stop persisting checkout credentials * chore(helm): resync prd erpc values from morpho-infra-helm HEAD The import predates the latest bumps in morpho-infra-helm (images 0.1.3, main replicaCount 12); cutting ArgoCD over on the stale copy would roll production back. * chore(helm): anchor erpc image tags for automated bumps Anchor the nine ECR image tags (erpcImageTag for the erpc runtime, erpcValidatorImageTag for the validator job image) so the update-image-tag workflow can bump them all in one place. The upstream ghcr.io digest pins are intentionally left out of the anchors. * ci(helm): add update-image-tag workflow and values.yaml guard Replicate the morpho-api in-repo image bump flow, adapted to erpc: - update-image-tag.yaml: workflow_dispatch with a semver version_tag (validated), prd/morpho-main only (erpc has no dev environment or branch), bumps the erpcImageTag and erpcValidatorImageTag anchors, creates a GitHub-signed commit via createCommitOnBranch with the morpho-infra-deployer app token, opens a PR and — when vars.ERPC_PRD_AUTOMERGE is true — waits for required checks with the workflow token then merges with admin bypass. Auto-merge defaults to off: production PRs require manual approval. - only-values-yaml-guard.yml: same guard as morpho-api targeting morpho-main, scoping the bot's review bypass to values.yaml-only changes. * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Romain Guichard <romain@particule.io> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Romain Guichard <romain@particule.io> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: Romain Guichard <romain@particule.io> * remove wrong gitignore lines --------- Signed-off-by: Romain Guichard <romain@particule.io> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Florian <florian.pautot@gmail.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
1 parent 545e755 commit b02a628

50 files changed

Lines changed: 5477 additions & 15 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 @0x666c6f
3+
4+
# Helm charts migrated from morpho-infra-helm (2026-06-17)
5+
/helm/ @morpho-org/platform-engineers @morpho-org/api-engineers @0x666c6f
6+
/validate-helm-charts.sh @morpho-org/platform-engineers @0x666c6f
7+
/setup-hooks.sh @morpho-org/platform-engineers @0x666c6f
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
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+
with:
27+
persist-credentials: false
28+
29+
- name: Find all charts
30+
id: find
31+
run: |
32+
# Find all Chart.yaml files and get their directories
33+
charts=$(find helm/charts helm/environments -name Chart.yaml -type f -exec dirname {} \; | sort | jq -R -s -c 'split("\n") | map(select(length > 0))')
34+
count=$(echo "$charts" | jq 'length')
35+
echo "Found $count charts to validate"
36+
echo "charts=$charts" >> $GITHUB_OUTPUT
37+
echo "count=$count" >> $GITHUB_OUTPUT
38+
39+
# =============================================================================
40+
# Job 2: Validate each chart in parallel
41+
# =============================================================================
42+
validate:
43+
name: Validate
44+
needs: discover-charts
45+
runs-on: ubuntu-latest
46+
strategy:
47+
fail-fast: false # Continue validating other charts if one fails
48+
matrix:
49+
chart: ${{ fromJson(needs.discover-charts.outputs.charts) }}
50+
steps:
51+
- name: Checkout
52+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
53+
with:
54+
persist-credentials: false
55+
56+
- name: Set up Helm
57+
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4
58+
with:
59+
version: v3.16.4
60+
61+
- name: Install kubeconform
62+
run: |
63+
KUBECONFORM_VERSION=v0.6.1
64+
KUBECONFORM_SHA256=7f84c1e4109fb72f151da41bdffea05e1e37591f179de51adc048c83533ad215
65+
curl -fsSLo /tmp/kubeconform.tar.gz "https://github.com/yannh/kubeconform/releases/download/${KUBECONFORM_VERSION}/kubeconform-linux-amd64.tar.gz"
66+
echo "${KUBECONFORM_SHA256} /tmp/kubeconform.tar.gz" | sha256sum -c -
67+
tar xzf /tmp/kubeconform.tar.gz
68+
sudo mv kubeconform /usr/local/bin/
69+
70+
- name: Add Helm repositories
71+
run: |
72+
helm repo add bitnami https://charts.bitnami.com/bitnami 2>/dev/null || true
73+
helm repo add cnpg https://cloudnative-pg.github.io/charts 2>/dev/null || true
74+
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts 2>/dev/null || true
75+
helm repo add haproxytech https://haproxytech.github.io/helm-charts 2>/dev/null || true
76+
helm repo add dandydeveloper https://dandydeveloper.github.io/charts 2>/dev/null || true
77+
helm repo update
78+
79+
- name: Get chart info
80+
id: chart-info
81+
run: |
82+
chart_path="${{ matrix.chart }}"
83+
chart_name=$(basename "$chart_path")
84+
echo "name=$chart_name" >> $GITHUB_OUTPUT
85+
echo "path=$chart_path" >> $GITHUB_OUTPUT
86+
87+
# Check if chart should skip kubeconform validation
88+
skip_validation="false"
89+
case "$chart_name" in
90+
*-db|*database*|*postgres*)
91+
skip_validation="true"
92+
;;
93+
esac
94+
echo "skip-kubeconform=$skip_validation" >> $GITHUB_OUTPUT
95+
96+
- name: Helm lint
97+
run: |
98+
echo "::group::Helm lint ${{ steps.chart-info.outputs.name }}"
99+
helm lint "${{ matrix.chart }}"
100+
echo "::endgroup::"
101+
102+
- name: Update dependencies
103+
run: |
104+
cd "${{ matrix.chart }}"
105+
if grep -q "dependencies:" Chart.yaml 2>/dev/null; then
106+
echo "::group::Updating dependencies for ${{ steps.chart-info.outputs.name }}"
107+
helm dependency update
108+
echo "::endgroup::"
109+
fi
110+
111+
- name: Kubeconform validation
112+
if: steps.chart-info.outputs.skip-kubeconform != 'true'
113+
run: |
114+
CUSTOM_RESOURCES="PodMonitor,ServiceMonitor,AlertManager,Prometheus,PrometheusRule,Cluster,ScheduledBackup,ImageCatalog,IngressRoute,Certificate,CronJob,EventSource,EventBus,Sensor"
115+
116+
echo "::group::Kubeconform validation for ${{ steps.chart-info.outputs.name }}"
117+
cd "${{ matrix.chart }}"
118+
helm template . | kubeconform --ignore-missing-schemas --summary --skip "$CUSTOM_RESOURCES"
119+
echo "::endgroup::"
120+
121+
- name: Skip notice
122+
if: steps.chart-info.outputs.skip-kubeconform == 'true'
123+
run: |
124+
echo "::notice::Skipping kubeconform validation for ${{ steps.chart-info.outputs.name }} (database chart)"
125+
126+
# =============================================================================
127+
# Job 3: Summary (ensures all validations completed)
128+
# =============================================================================
129+
validation-summary:
130+
name: Validation Summary
131+
needs: [discover-charts, validate]
132+
runs-on: ubuntu-latest
133+
if: always()
134+
steps:
135+
- name: Check validation results
136+
run: |
137+
if [ "${{ needs.discover-charts.result }}" == "failure" ]; then
138+
echo "::error::Chart discovery failed"
139+
exit 1
140+
elif [ "${{ needs.discover-charts.result }}" == "cancelled" ]; then
141+
echo "::warning::Chart discovery was cancelled"
142+
exit 1
143+
elif [ "${{ needs.validate.result }}" == "failure" ]; then
144+
echo "::error::Some chart validations failed"
145+
exit 1
146+
elif [ "${{ needs.validate.result }}" == "cancelled" ]; then
147+
echo "::warning::Validation was cancelled"
148+
exit 1
149+
elif [ "${{ needs.validate.result }}" == "skipped" ]; then
150+
echo "::warning::Validation was skipped unexpectedly"
151+
exit 1
152+
else
153+
echo "::notice::All ${{ needs.discover-charts.outputs.chart-count }} charts validated successfully"
154+
fi
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Required status check that scopes the morpho-infra-deployer bot's review
2+
# bypass to values.yaml-only changes: it is skipped unless the deployer bot
3+
# authored the PR or triggered the run, and fails only when such a PR touches
4+
# anything other than values.yaml.
5+
name: only-values-yaml-guard
6+
7+
on:
8+
pull_request:
9+
branches: [morpho-main]
10+
merge_group:
11+
12+
permissions:
13+
contents: read
14+
pull-requests: read
15+
16+
jobs:
17+
guard:
18+
name: values-yaml-guard
19+
runs-on: ubuntu-latest
20+
# Skipped for non-bot PRs: a skipped job SATISFIES required status checks,
21+
# so human PRs merge normally without spinning up a runner. Covers the bot
22+
# both as PR author and as pusher on someone else's PR, matching on the
23+
# immutable user id (not the login) so an app rename cannot silently turn
24+
# the guard off while the bot keeps its review-bypass.
25+
if: github.event.pull_request.user.id == 187494245 || github.actor_id == 187494245 # morpho-infra-deployer[bot]
26+
steps:
27+
- name: Enforce values.yaml-only changes for the deployer bot
28+
env:
29+
GH_TOKEN: ${{ github.token }}
30+
PR_NUMBER: ${{ github.event.pull_request.number }}
31+
MERGE_GROUP_HEAD_REF: ${{ github.event.merge_group.head_ref }}
32+
REPO: ${{ github.repository }}
33+
run: |
34+
# merge_group events carry no pull_request.number; extract it from
35+
# the head ref (refs/heads/gh-readonly-queue/<base>/pr-<N>-<sha>).
36+
if [[ -z "$PR_NUMBER" && -n "$MERGE_GROUP_HEAD_REF" ]]; then
37+
PR_NUMBER=$(echo "$MERGE_GROUP_HEAD_REF" | grep -oE '/pr-[0-9]+' | grep -oE '[0-9]+')
38+
fi
39+
40+
# Include previous_filename so a rename cannot smuggle a non-values
41+
# path out of sight (the files API only reports the new path).
42+
if ! mapfile -t CHANGED < <(gh api --paginate "repos/${REPO}/pulls/${PR_NUMBER}/files" --jq '.[] | .filename, (.previous_filename // empty)'); then
43+
echo "❌ Failed to fetch changed files from the GitHub API."
44+
exit 1
45+
fi
46+
echo "Files changed by the deployer bot:"
47+
printf ' %s\n' "${CHANGED[@]}"
48+
49+
OFFENDING=()
50+
for file in "${CHANGED[@]}"; do
51+
if [[ "$file" != "values.yaml" && "$file" != *"/values.yaml" ]]; then
52+
OFFENDING+=("$file")
53+
fi
54+
done
55+
56+
if (( ${#OFFENDING[@]} > 0 )); then
57+
echo "❌ Deployer bot PR modifies files other than values.yaml:"
58+
printf ' %s\n' "${OFFENDING[@]}"
59+
echo "The bot may only bypass review for values.yaml-only changes."
60+
exit 1
61+
fi
62+
63+
echo "✅ Deployer bot PR only modifies values.yaml files."
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Slack PR Notification
2+
3+
on:
4+
pull_request:
5+
types: [closed]
6+
branches: [morpho-main]
7+
8+
jobs:
9+
notify-slack:
10+
if: github.event.pull_request.merged == true && github.event.pull_request.user.login != 'github-actions[bot]' && github.event.pull_request.user.login != 'morpho-infra-deployer[bot]'
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Send Slack notification
15+
uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1
16+
with:
17+
webhook: ${{ secrets.SLACK_WEBHOOK_URL }}
18+
webhook-type: incoming-webhook
19+
payload: |
20+
{
21+
"text": ":rocket: PR merged to Production",
22+
"attachments": [
23+
{
24+
"color": "#ff6b6b",
25+
"fallback": "PR #${{ github.event.pull_request.number }} merged: ${{ github.event.pull_request.title }}",
26+
"title": ":white_check_mark: PR #${{ github.event.pull_request.number }}: ${{ github.event.pull_request.title }}",
27+
"title_link": "${{ github.event.pull_request.html_url }}",
28+
"fields": [
29+
{
30+
"title": ":busts_in_silhouette: Author",
31+
"value": "${{ github.event.pull_request.user.login }}",
32+
"short": true
33+
},
34+
{
35+
"title": ":earth_americas: Environment",
36+
"value": ":red_circle: Production (morpho-main)",
37+
"short": true
38+
},
39+
{
40+
"title": ":arrow_right: Branch",
41+
"value": "`${{ github.event.pull_request.head.ref }}` → `${{ github.event.pull_request.base.ref }}`",
42+
"short": false
43+
}
44+
],
45+
"footer": ":octopus: ${{ github.repository }}",
46+
"footer_icon": "https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png"
47+
}
48+
]
49+
}

0 commit comments

Comments
 (0)