Skip to content

Commit bf4f179

Browse files
authored
Merge pull request #247 from keboola/mcp-v18-update
Copied PR: Make sure app is running with correct user release notes Bump version to 1.18.2 in pyproject.toml. Harden Docker image: run as non-root user with configurable UID/GID; fix COPY --chown to use UID/GID; set USER in Dockerfile. CI: add push-only job to build the Docker image and run a simple e2e smoke test via tests/docker/ci.sh against the HTTP-compat endpoint. No functional changes to server runtime or API. plans for customer communication If customers use the Docker image: note the switch to non-root user. Advise verifying file/volume permissions and ownership when bind mounting or writing to host volumes. Otherwise, no customer-facing changes required. impact analysis Worst case: container fails to read/write mounted volumes due to permissions, causing startup/runtime errors. CI-only job uses secrets for smoke test; failures block push CI but do not affect runtime package. No API/transport behavior changes; ports unchanged. change type Improvement/Security hardening + CI enhancement justification Improve container security by dropping root. Add automated Docker build + smoke test to catch regressions before release. deployment plan Merge PR; tag main. Existing workflow will run build, integration tests, and Docker smoke test. Publish pipeline remains unchanged. rollback plan Revert PR; retag/release prior version. post release support plan
2 parents 952342d + 5507b90 commit bf4f179

File tree

4 files changed

+107
-2
lines changed

4 files changed

+107
-2
lines changed

.github/workflows/ci.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,42 @@ jobs:
147147
path: ./integtest-results.xml
148148
reporter: 'java-junit'
149149

150+
build_docker_image_and_do_basic_test:
151+
name: Build Docker image and do basic test
152+
needs:
153+
- build
154+
- integration_tests
155+
runs-on: ubuntu-latest
156+
# run this job only for push events (not pull requests)
157+
if: github.event_name == 'push'
158+
steps:
159+
- uses: actions/checkout@v4
160+
161+
- name: Set up Docker Buildx
162+
uses: docker/setup-buildx-action@v3
163+
164+
- name: Docker login
165+
uses: docker/login-action@v3
166+
with:
167+
username: ${{ secrets.DOCKERHUB_PUSH_USER }}
168+
password: ${{ secrets.DOCKERHUB_PUSH_TOKEN }}
169+
170+
- name: Build Docker image
171+
uses: docker/build-push-action@v6
172+
with:
173+
context: .
174+
file: ./Dockerfile
175+
platforms: linux/amd64
176+
tags: "keboola/mcp-server:ci"
177+
push: false
178+
load: true
179+
cache-from: type=gha
180+
cache-to: type=gha,mode=max
181+
182+
- name: Run simple e2e test
183+
run: |
184+
STORAGE_API_TOKEN=${{ secrets.INTEGTEST_STORAGE_TOKEN }} STORAGE_API_URL=${{ vars.INTEGTEST_STORAGE_API_URL }} ./tests/docker/ci.sh
185+
150186
deploy_to_pypi:
151187
needs:
152188
- build

Dockerfile

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,23 @@ RUN --mount=type=cache,target=/root/.cache/uv uv pip install ddtrace~=3.0
2222

2323
FROM python:3.12-slim-bookworm
2424

25+
ARG APP_USER_NAME=app
26+
ARG APP_USER_UID=1000
27+
ARG APP_USER_GID=1000
28+
29+
RUN groupadd --gid ${APP_USER_GID} ${APP_USER_NAME} \
30+
&& useradd --uid ${APP_USER_UID} --gid ${APP_USER_GID} ${APP_USER_NAME}
31+
2532
WORKDIR /app
2633
ENV LOG_CONFIG=/app/logging-json.conf
2734

28-
COPY --from=uv --chown=app:app /app/.venv /app/.venv
35+
COPY --from=uv --chown=${APP_USER_UID}:${APP_USER_GID} /app/.venv /app/.venv
2936
COPY logging-json.conf /app/logging-json.conf
3037

3138
# Place executables in the environment at the front of the path
3239
ENV PATH="/app/.venv/bin:$PATH"
3340

41+
USER $APP_USER_NAME
42+
3443
# when running the container, add KBC_STORAGE_API_URL environment variable and a bind mount to the host's db file
3544
ENTRYPOINT ["python", "-m", "keboola_mcp_server", "--log-level", "DEBUG"]

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "keboola-mcp-server"
7-
version = "1.18.1"
7+
version = "1.18.2"
88
description = "MCP server for interacting with Keboola Connection"
99
readme = "README.md"
1010
requires-python = ">=3.10"

tests/docker/ci.sh

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/usr/bin/env bash
2+
set -Eeuo pipefail
3+
4+
CONTAINER_NAME="keboola-mcp-server-test-docker"
5+
IMAGE_NAME="keboola/mcp-server:ci"
6+
7+
cleanup() {
8+
docker stop "$CONTAINER_NAME" >/dev/null 2>&1 || true
9+
docker rm "$CONTAINER_NAME" >/dev/null 2>&1 || true
10+
}
11+
trap cleanup EXIT
12+
13+
main() {
14+
# Start container
15+
echo "Starting container..."
16+
docker run -d \
17+
--name "$CONTAINER_NAME" \
18+
-p "8080:8000" \
19+
"$IMAGE_NAME" \
20+
--transport http-compat \
21+
--api-url "$STORAGE_API_URL" \
22+
--storage-token "$STORAGE_API_TOKEN" \
23+
--host "0.0.0.0" \
24+
--port 8000 >/dev/null
25+
26+
# Give server time to start
27+
sleep 5
28+
29+
# Wait and test MCP initialize
30+
echo "Testing MCP initialize..."
31+
for i in $(seq 1 30); do
32+
response=$(curl -s -w "\n%{http_code}" -X POST \
33+
-H "Content-Type: application/json" \
34+
-H "Accept: application/json, text/event-stream" \
35+
-d '{"jsonrpc": "2.0", "id": 1, "method": "initialize", "params": {"protocolVersion": "2024-11-05", "capabilities": {}, "clientInfo": {"name": "ci-docker-test", "version": "1.0.0"}}}' \
36+
"http://localhost:8080/mcp" 2>/dev/null)
37+
38+
http_code=$(echo "$response" | tail -n1)
39+
body=$(echo "$response" | sed '$d')
40+
41+
if [ "$http_code" = "200" ] && [ -n "$body" ]; then
42+
echo "✓ MCP server initialized successfully"
43+
echo "Response body:"
44+
if command -v jq >/dev/null 2>&1; then
45+
echo "$body" | grep "^data: " | sed 's/^data: //' | jq '.'
46+
else
47+
echo "$body"
48+
fi
49+
echo "✓ Test passed"
50+
exit 0
51+
fi
52+
sleep 1
53+
done
54+
55+
echo "✗ Server failed to respond"
56+
docker logs "$CONTAINER_NAME" 2>&1 | tail -10
57+
exit 1
58+
}
59+
60+
main "$@"

0 commit comments

Comments
 (0)