Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,11 @@ Makefile
# Docker & Kubernetes
# ===================
Dockerfile
Dockerfile.dev
.dockerignore
docker-compose.yaml
helm/
deploy/
skaffold.yaml
prometheus.yml

# ===================
Expand Down
91 changes: 91 additions & 0 deletions .github/workflows/helm-ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
name: Helm Chart CI

on:
push:
branches: [main]
paths:
- "deploy/helm/**"
- "deploy/local/**"
- ".github/workflows/helm-ci.yml"
pull_request:
branches: [main]
paths:
- "deploy/helm/**"
- "deploy/local/**"
- ".github/workflows/helm-ci.yml"

concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

permissions:
contents: read

jobs:
lint-test:
name: Lint and template
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow file =="
if [ -f .github/workflows/helm-ci.yml ]; then
  nl -ba .github/workflows/helm-ci.yml | sed -n '1,110p'
else
  echo "missing .github/workflows/helm-ci.yml"
fi

echo
echo "== action uses lines =="
rg -n 'uses:\s*[^#\s]+' .github/workflows/helm-ci.yml || true

Repository: ENTERPILOT/GoModel

Length of output: 216


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== workflow file =="
if [ -f .github/workflows/helm-ci.yml ]; then
  awk '{printf "%7d  %s\n", NR, $0}' .github/workflows/helm-ci.yml | sed -n '1,110p'
else
  echo "missing .github/workflows/helm-ci.yml"
fi

echo
echo "== action uses lines =="
grep -nE 'uses:\s*[^#\s]+' .github/workflows/helm-ci.yml || true

Repository: ENTERPILOT/GoModel

Length of output: 3983


Pin every GitHub Action to a full commit SHA.

Mutable action tags such as actions/checkout@v7, azure/setup-helm@v4, and helm/chart-testing-action@v2 can be retargeted to execute different code. Pin lines 29, 34, 55, 64, and 67 to reviewed full commit SHAs, and keep the version tag in a comment for maintenance.

🧰 Tools
🪛 zizmor (1.28.0)

[warning] 29-31: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 29-29: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/helm-ci.yml at line 29, Pin the actions at lines 29, 34,
55, 64, and 67 to their reviewed full commit SHAs instead of mutable version
tags, while preserving each original version tag in an adjacent comment for
maintenance.

Source: Linters/SAST tools

with:
fetch-depth: 0

- name: Set up Helm
uses: azure/setup-helm@v4
with:
version: v3.16.3

- name: Helm lint (strict)
run: helm lint --strict deploy/helm/gomodel

# Render every example value set to catch templating regressions that lint misses.
- name: Helm template (all value sets)
run: |
set -euo pipefail
helm template ci deploy/helm/gomodel > /dev/null
for f in deploy/helm/gomodel/ci/*-values.yaml; do
echo "Rendering with $f"
helm template ci deploy/helm/gomodel -f "$f" > /dev/null
done

- name: Helm template (local dev values)
run: helm template ci deploy/helm/gomodel -f deploy/local/values.yaml > /dev/null

- name: Set up chart-testing
uses: helm/chart-testing-action@v2

- name: Run chart-testing (lint)
run: ct lint --charts deploy/helm/gomodel --validate-maintainers=false --target-branch ${{ github.event.repository.default_branch }}

kubeconform:
name: Validate against Kubernetes schemas
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

- name: Set up Helm
uses: azure/setup-helm@v4
with:
version: v3.16.3

- name: Install kubeconform
run: |
curl -sSL -o /tmp/kubeconform.tar.gz \
https://github.com/yannh/kubeconform/releases/download/v0.6.7/kubeconform-linux-amd64.tar.gz
tar -xzf /tmp/kubeconform.tar.gz -C /tmp
sudo mv /tmp/kubeconform /usr/local/bin/
Comment on lines +73 to +76

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

gh api repos/yannh/kubeconform/releases/tags/v0.6.7 \
  --jq '.assets[].name'

Repository: ENTERPILOT/GoModel

Length of output: 470


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

URL="https://github.com/yannh/kubeconform/releases/download/v0.6.7/kubeconform-linux-amd64.tar.gz"

printf 'asset URL reachable: '
curl -Ifs "$URL" > /tmp/kubeconform-check-url-reach.txt
curl -Ifs "$URL" | sed -n '1p'

printf '\nchecksum file URL reachable: '
GH="https://github.com/yannh/kubeconform/releases/download/v0.6.7/CHECKSUMS"
curl -Ifs "$GH" > /tmp/kubeconform-check-checksum-url.txt
curl -Ifs "$GH" | sed -n '1p'

printf '\nchecksum file first lines:\n'
curl -sf "$GH" | sed -n '1,20p'

printf '\nlocal workflow lines:\n'
sed -n '60,85p' .github/workflows/helm-ci.yml

Repository: ENTERPILOT/GoModel

Length of output: 1269


Verify the kubeconform checksum before installing.

This script downloads the release asset directly to /tmp, extracts it, and moves it onto PATH without comparing it against the upstream CHECKSUMS checksum file. Add a checksum verification step for kubeconform-linux-amd64.tar.gz before extraction.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/helm-ci.yml around lines 73 - 76, Update the kubeconform
installation steps around the curl download and tar extraction to download the
release CHECKSUMS file, verify kubeconform-linux-amd64.tar.gz against its
expected checksum, and only extract and install after verification succeeds.
Keep the existing version and asset names consistent.


# ServiceMonitor is a CRD, so skip resources kubeconform can't resolve.
- name: Render and validate manifests
run: |
set -euo pipefail
for f in deploy/helm/gomodel/ci/*-values.yaml deploy/local/values.yaml; do
echo "Validating manifests rendered with $f"
helm template ci deploy/helm/gomodel -f "$f" \
| kubeconform -strict -ignore-missing-schemas -summary
done
Comment on lines +82 to +86

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Validate the default chart render with kubeconform.

The workflow renders default values at line 45, but only named value files enter the kubeconform pipeline here. Add a no-values helm template validation before the loop. Otherwise, an invalid default-only manifest can pass CI.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/helm-ci.yml around lines 82 - 86, Add a no-values helm
template validation before the existing values-file loop in the workflow, piping
the default render through kubeconform with the same strict, missing-schema, and
summary options. Keep the current named-values validation loop unchanged.


- name: Validate local dev dependency manifests
run: |
kubeconform -strict -ignore-missing-schemas -summary \
deploy/local/deps.yaml deploy/local/mockllm.yaml
64 changes: 64 additions & 0 deletions .github/workflows/helm-release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Helm Chart Release

# Publishes the GoModel Helm chart to the Docker Hub OCI registry.
# Trigger with a chart tag (decoupled from application releases), e.g. helm-v0.1.0,
# or run manually. The pushed chart version is read from Chart.yaml.
on:
push:
tags:
- "helm-v*"
workflow_dispatch:

permissions:
contents: read

concurrency:
group: helm-release-${{ github.ref_name }}
cancel-in-progress: false

jobs:
release:
name: Package and push chart
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7
Comment on lines +24 to +25

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Harden the checkout/setup-helm pinning and secret usage.

Two independent hardening gaps:

  • actions/checkout@v7 (line 25) and azure/setup-helm@v4 (line 28) are pinned to mutable tags, not commit SHAs. A compromised or re-pointed tag would run arbitrary code in this release pipeline.
  • secrets.DOCKER_USERNAME/secrets.DOCKERHUB_TOKEN (lines 49-51) are interpolated directly into run: script text instead of passed through env:, unlike the DOCKER_USERNAME handling in the earlier "Resolve chart metadata" step (lines 38-39). Passing ${{ }} expressions through env: is the recommended pattern to avoid the value being spliced directly into the shell script.
🔒 Proposed fix for the login step
       - name: Login to Docker Hub (OCI)
+        env:
+          DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
+          DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
         run: |
-          echo "${{ secrets.DOCKERHUB_TOKEN }}" \
+          echo "${DOCKERHUB_TOKEN}" \
             | helm registry login registry-1.docker.io \
-                --username "${{ secrets.DOCKER_USERNAME }}" --password-stdin
+                --username "${DOCKER_USERNAME}" --password-stdin

Also applies to: 28-28, 47-51

🧰 Tools
🪛 zizmor (1.28.0)

[warning] 24-25: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)


[error] 25-25: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/helm-release.yml around lines 24 - 25, Harden the release
workflow by pinning both actions/checkout and azure/setup-helm to immutable
commit SHAs instead of mutable version tags, and update the Docker login step to
receive DOCKER_USERNAME and DOCKERHUB_TOKEN through its env block rather than
interpolating secrets directly in the run script; preserve the existing
metadata-step environment handling.

Source: Linters/SAST tools


- name: Set up Helm
uses: azure/setup-helm@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Release setup action is not immutable

azure/setup-helm@v4 is a mutable tag and runs before this job reads Docker Hub credentials, authenticates to the registry, and publishes the OCI chart. Pin the action to the reviewed full commit SHA, retaining a version comment if useful, so a moved or compromised tag cannot execute unreviewed code in the release job.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Artifacts

Focused workflow pinning assertion source

  • Python assertion source executed against the workflow and a SHA-pinned comparison fixture; it checks the action ref format and exact credential/push ordering, with the takeaway that the check is reproducible.

Current workflow check showing mutable Helm action tag

  • Captured execution of the focused assertion on the current repository workflow; it reports `v4` at line 28 as a non-SHA tag before Docker credential use and OCI publishing, confirming the issue.

SHA-pinned comparison check

  • Captured execution of the same assertion against a same-scope SHA-pinned workflow copy; it classifies the 40-character ref as immutable while preserving the workflow ordering, showing the required remediation shape.

View artifacts

T-Rex Ran code and verified through T-Rex

with:
version: v3.16.3
Comment on lines +27 to +30

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

What is the latest Helm v3 patch release?

💡 Result:

The latest Helm v3 patch release is v3.21.3, which was released on July 9, 2026 [1][2]. Helm v3 is currently in support mode, receiving only bug and security fixes [3]. The next scheduled patch release for Helm v3 is v3.21.4, planned for August 12, 2026 [1][2].

Citations:


Bump the pinned Helm version.

version: v3.16.3 is several patch releases behind current Helm v3.x patch releases. Bump to the latest supported v3.x patch version to pick up fixes.

🧰 Tools
🪛 zizmor (1.28.0)

[error] 28-28: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)

(unpinned-uses)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/helm-release.yml around lines 27 - 30, Update the version
value in the “Set up Helm” workflow step to the latest supported Helm v3.x patch
release, replacing the outdated v3.16.3 pin while preserving the existing
azure/setup-helm@v4 action configuration.


- name: Lint chart
run: helm lint --strict deploy/helm/gomodel

- name: Resolve chart metadata
id: meta
shell: bash
env:
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
run: |
version="$(helm show chart deploy/helm/gomodel | awk '/^version:/ {print $2}')"
{
echo "version=${version}"
echo "registry=registry-1.docker.io/${DOCKER_USERNAME}"
} >> "$GITHUB_OUTPUT"

- name: Login to Docker Hub (OCI)
run: |
echo "${{ secrets.DOCKERHUB_TOKEN }}" \
| helm registry login registry-1.docker.io \
--username "${{ secrets.DOCKER_USERNAME }}" --password-stdin

- name: Package chart
run: helm package deploy/helm/gomodel --destination "${RUNNER_TEMP}"

- name: Push chart to OCI registry
run: |
helm push \
"${RUNNER_TEMP}/gomodel-${{ steps.meta.outputs.version }}.tgz" \
"oci://${{ steps.meta.outputs.registry }}"

- name: Logout
if: always()
run: helm registry logout registry-1.docker.io || true
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ repos:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
exclude: ^helm/templates/
exclude: ^deploy/helm/gomodel/templates/
- id: check-json
- id: check-added-large-files

Expand Down
34 changes: 34 additions & 0 deletions Dockerfile.dev
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Development Dockerfile for the local Kubernetes (kind + Skaffold) workflow.
# Optimized for fast, repeated native-arch rebuilds — it skips cross-compilation
# and symbol stripping used by the production Dockerfile. Do NOT use for releases.
FROM golang:1.26.4-alpine3.23 AS builder

WORKDIR /app

RUN apk add --no-cache ca-certificates

# Cache dependencies separately from source for fast incremental builds.
COPY go.mod go.sum ./
RUN go mod download

COPY . .
# Build cache mounts keep incremental rebuilds quick under Skaffold.
RUN --mount=type=cache,target=/root/.cache/go-build \
--mount=type=cache,target=/go/pkg/mod \
CGO_ENABLED=0 go build -o /gomodel ./cmd/gomodel

RUN mkdir -p /app/.cache /app/data && touch /app/.cache/.keep /app/data/.keep

# Same distroless runtime as production for parity.
FROM gcr.io/distroless/static-debian12:nonroot

COPY --from=builder /gomodel /gomodel
COPY --from=builder /app/config/*.yaml /app/config/
COPY --from=builder --chown=65532:65532 /app/.cache /app/.cache
COPY --from=builder --chown=65532:65532 /app/data /app/data

WORKDIR /app

EXPOSE 8080

ENTRYPOINT ["/gomodel"]
37 changes: 36 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: all build run demo clean tidy test test-race test-dashboard test-e2e test-integration test-contract test-all lint lint-fix fix fix-check record-api swagger docs-openapi install-tools perf-check perf-bench infra image seed-demo-data
.PHONY: all build run demo clean tidy test test-race test-dashboard test-e2e test-integration test-contract test-all lint lint-fix fix fix-check record-api swagger docs-openapi install-tools perf-check perf-bench infra image seed-demo-data kind-up kind-down dev-k8s deploy-k8s undeploy-k8s

all: build

Expand Down Expand Up @@ -55,6 +55,41 @@ image:
seed-demo-data:
bash tools/seed-demo-data.sh

# ---------------------------------------------------------------------------
# Local Kubernetes development (kind + Skaffold)
# See docs/dev/local-kubernetes.md
# ---------------------------------------------------------------------------
KIND_CLUSTER ?= gomodel-dev

# Create the local kind cluster and deploy in-cluster dependencies (idempotent).
kind-up:
@kind get clusters | grep -qx "$(KIND_CLUSTER)" \
|| kind create cluster --config deploy/local/kind-cluster.yaml
@kubectl cluster-info --context kind-$(KIND_CLUSTER)
Comment on lines +65 to +68

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Makefile KIND references:"
if [ -f Makefile ]; then
  nl -ba Makefile | sed -n '1,110p'
else
  fd -a 'Makefile' . | sed -n '1,20p'
fi

echo
echo "Search KIND_CLUSTER and cluster-info/create commands:"
rg -n "KIND_CLUSTER|kind create cluster|cluster-info|kind-gomodel-dev|kind-\\$\\{KIND_CLUSTER\\}|kind-\\$\\(KIND_CLUSTER\\)" .

Repository: ENTERPILOT/GoModel

Length of output: 222


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Makefile candidates:"
find . -name Makefile -o -name makefile -o -name GNUmakefile | sort

echo
echo "Relevant Makefile content:"
if [ -f Makefile ]; then
  awk '{printf "%6d\t%s\n", NR, $0}' Makefile | sed -n '1,120p'
fi

echo
echo "Search KIND_CLUSTER and kind commands:"
rg -n "KIND_CLUSTER|kind create cluster|cluster-info|kind-gomodel-dev|kind-\\$\\(KIND_CLUSTER\\)" -S . || true

echo
echo "Kind documentation/name semantics from local installed docs:"
if command -v kind >/dev/null 2>&1; then
  kind version 2>&1 || true
  kind create cluster --help 2>&1 | grep -A80 "^Usage:" || true
else
  echo "kind binary not installed"
fi

Repository: ENTERPILOT/GoModel

Length of output: 7004


🌐 Web query:

kind create cluster --name default cluster name kubectl config set-context kind-name

💡 Result:

When creating a cluster using kind, the tool automatically manages the Kubernetes configuration file (typically located at ~/.kube/config) and creates a context for you [1][2]. To create a cluster with a specific name, use the --name flag: kind create cluster --name By default, when you create a cluster, kind assigns it a context name prefixed with "kind-". For example, if you create a cluster with --name my-cluster, the resulting context name in your kubeconfig will be kind-my-cluster [3]. If you need to manually set or switch your kubectl context to this cluster, use the following command: kubectl config set-context kind- To verify or switch to the context, you can also use: kubectl config use-context kind- Kind automatically sets the current context to the new cluster upon creation, so you generally do not need to run these commands immediately after creating the cluster [3]. If your context is not found, ensure that you are running kubectl as the same user that created the kind cluster, as the kubeconfig file is written based on the user's home directory [4].

Citations:


Pass KIND_CLUSTER to kind create cluster.

The create command omits --name "$(KIND_CLUSTER)". If no gomodel-dev cluster exists, kind create cluster creates the default kind cluster and context. The following commands then use kind-gomodel-dev, so make kind-up fails on new setups.

Proposed fix
 	`@kind` get clusters | grep -qx "$(KIND_CLUSTER)" \
-		|| kind create cluster --config deploy/local/kind-cluster.yaml
+		|| kind create cluster --name "$(KIND_CLUSTER)" --config deploy/local/kind-cluster.yaml
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
kind-up:
@kind get clusters | grep -qx "$(KIND_CLUSTER)" \
|| kind create cluster --config deploy/local/kind-cluster.yaml
@kubectl cluster-info --context kind-$(KIND_CLUSTER)
kind-up:
`@kind` get clusters | grep -qx "$(KIND_CLUSTER)" \
|| kind create cluster --name "$(KIND_CLUSTER)" --config deploy/local/kind-cluster.yaml
`@kubectl` cluster-info --context kind-$(KIND_CLUSTER)
🧰 Tools
🪛 checkmake (0.3.2)

[warning] 65-65: Target body for "kind-up" exceeds allowed length of 5 lines (9).

(maxbodylength)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 65 - 68, Update the kind create command in the kind-up
target to pass KIND_CLUSTER via the kind cluster name option, ensuring newly
created clusters and contexts match the existing kind-$(KIND_CLUSTER)
references.

kubectl --context kind-$(KIND_CLUSTER) apply -f deploy/local/deps.yaml
kubectl --context kind-$(KIND_CLUSTER) apply -f deploy/local/mockllm.yaml
kubectl --context kind-$(KIND_CLUSTER) rollout status deploy/redis --timeout=120s
kubectl --context kind-$(KIND_CLUSTER) rollout status deploy/postgres --timeout=120s
kubectl --context kind-$(KIND_CLUSTER) rollout status deploy/mongodb --timeout=180s
kubectl --context kind-$(KIND_CLUSTER) rollout status deploy/mockllm --timeout=120s

# Delete the local kind cluster.
kind-down:
kind delete cluster --name $(KIND_CLUSTER)

# Inner dev loop: build image, load into kind, deploy via Helm, watch for changes.
# The gateway is reachable at http://localhost:8080 via the kind NodePort mapping.
dev-k8s:
skaffold dev --kube-context kind-$(KIND_CLUSTER)

# One-shot build + deploy (no watch).
deploy-k8s:
skaffold run --kube-context kind-$(KIND_CLUSTER)

# Tear down the deployed release and dependencies.
undeploy-k8s:
skaffold delete --kube-context kind-$(KIND_CLUSTER)
Comment on lines +89 to +91

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Correct the teardown scope description.

skaffold delete removes the Helm release only. It does not remove the dependency manifests applied by kind-up. State that dependencies remain until make kind-down, or delete them explicitly in this target.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Makefile` around lines 89 - 91, Update the comment above the undeploy-k8s
target to clarify that skaffold delete removes only the Helm release, while
dependency manifests remain until make kind-down; do not change the command
unless explicitly adding dependency deletion to this target.


# Run unit tests only
test:
go test ./cmd/... ./internal/... ./config/... -v
Expand Down
12 changes: 12 additions & 0 deletions deploy/helm/gomodel/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Patterns to ignore when building packages.
.DS_Store
.git/
.gitignore
*.tmpl
*.tgz
.helmignore
ci/
README.md.gotmpl
# CI/development artifacts
.github/
tests/
23 changes: 23 additions & 0 deletions deploy/helm/gomodel/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
apiVersion: v2
name: gomodel
description: A high-performance, lightweight AI gateway that routes requests to multiple AI model providers through an OpenAI-compatible API.
type: application
# Chart version is independent of the application version and follows SemVer.
version: 0.1.0
# appVersion tracks the GoModel application release this chart was tested against.
appVersion: "latest"
Comment on lines +7 to +8

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Pin appVersion to a released version instead of latest.

gomodel.image in deploy/helm/gomodel/templates/_helpers.tpl (line 57) defaults image.tag to .Chart.AppVersion. With appVersion: "latest" and the default pullPolicy: IfNotPresent in values.yaml (line 12), a default install resolves to enterpilot/gomodel:latest and nodes reuse a stale cached image. The rendered app.kubernetes.io/version label also becomes "latest", so version-based selectors and dashboards lose meaning.

Set appVersion to the concrete GoModel release the chart was tested against, and bump it with each chart release.

🔧 Proposed change
 # appVersion tracks the GoModel application release this chart was tested against.
-appVersion: "latest"
+appVersion: "0.1.0"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# appVersion tracks the GoModel application release this chart was tested against.
appVersion: "latest"
# appVersion tracks the GoModel application release this chart was tested against.
appVersion: "0.1.0"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@deploy/helm/gomodel/Chart.yaml` around lines 7 - 8, Replace the "latest"
value in Chart.yaml’s appVersion with the concrete released GoModel version this
chart was tested against, and update that pinned version for every subsequent
chart release so default image tags and version labels remain meaningful.

home: https://github.com/ENTERPILOT/GoModel
sources:
- https://github.com/ENTERPILOT/GoModel
keywords:
- ai
- gateway
- llm
- openai
- proxy
maintainers:
- name: GoModel Maintainers
url: https://github.com/ENTERPILOT/GoModel
icon: https://raw.githubusercontent.com/ENTERPILOT/GoModel/main/docs/logo.png
annotations:
category: AIMachineLearning
Loading
Loading