@coffeerunhobby/mcp-ha-connect 1.5.4 → 1.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,6 +9,10 @@ name: CI
9
9
  on:
10
10
  push:
11
11
  branches: [main, dev]
12
+ # Version tags trigger the full gate + auto-create the GitHub Release (see
13
+ # the `release` job) — v1.5.4 sat tag-only for two weeks because the manual
14
+ # `gh release create` step kept getting skipped.
15
+ tags: ['v*']
12
16
  pull_request:
13
17
  branches: [main, dev]
14
18
  # Lets you re-run it by hand from the Actions tab.
@@ -28,8 +32,9 @@ jobs:
28
32
  # we want to see both results.
29
33
  fail-fast: false
30
34
  matrix:
31
- # The two LTS lines we support (package.json engines: ">=20").
32
- node-version: ['20.x', '22.x']
35
+ # The LTS lines we support (package.json engines: ">=20"). 24.x is the
36
+ # Docker image's actual runtime (since v1.5.6); 26 is the next LTS (2026-10).
37
+ node-version: ['20.x', '22.x', '24.x', '26.x']
33
38
 
34
39
  name: node ${{ matrix.node-version }}
35
40
 
@@ -67,3 +72,66 @@ jobs:
67
72
  # floor in vitest.config.ts — a coverage DROP fails the build.
68
73
  - name: Test + coverage gate
69
74
  run: npm run test:coverage
75
+
76
+ docker-smoke:
77
+ # Boot-test the ACTUAL image: build it, point it at a mock Home Assistant,
78
+ # and require /health to answer. Motivation: v1.5.5 shipped without ever
79
+ # having been run — its first boot was in production on the NAS (where the
80
+ # node:26 base then failed its first fetch). A release must never again be
81
+ # the image's first boot.
82
+ runs-on: ubuntu-latest
83
+ steps:
84
+ - name: Checkout
85
+ uses: actions/checkout@v4
86
+
87
+ - name: Build image
88
+ run: docker build -t mcp-smoke:ci .
89
+
90
+ - name: Boot against a mock HA and assert /health
91
+ run: |
92
+ set -eu
93
+ docker network create smoke
94
+ # Mock HA: 200 {"message":"API running."} — the same body the real
95
+ # /api/ startup check (checkApi) expects.
96
+ docker run -d --name mockha --network smoke node:24-alpine \
97
+ node -e 'require("http").createServer((q,s)=>{s.writeHead(200,{"Content-Type":"application/json"});s.end(JSON.stringify({message:"API running."}))}).listen(8123,()=>console.log("mock HA up"))'
98
+ docker run -d --name mcp --network smoke \
99
+ -e MCP_SERVER_USE_HTTP=true \
100
+ -e MCP_HTTP_PORT=3000 -e MCP_HTTP_BIND_ADDR=0.0.0.0 \
101
+ -e MCP_HTTP_ENABLE_HEALTHCHECK=true -e MCP_HTTP_HEALTHCHECK_PATH=/health \
102
+ -e MCP_AUTH_METHOD=bearer -e MCP_AUTH_SECRET=ci-smoke-dummy-secret-0123456789 \
103
+ -e HA_PLUGIN_ENABLED=true -e HA_URL=http://mockha:8123 -e HA_TOKEN=ci-dummy \
104
+ -e AI_PLUGIN_ENABLED=false -e OMADA_PLUGIN_ENABLED=false \
105
+ mcp-smoke:ci
106
+ for i in $(seq 1 15); do
107
+ if docker run --rm --network smoke curlimages/curl:latest -sf http://mcp:3000/health >/dev/null 2>&1; then
108
+ echo "smoke OK: image boots, startup HA check passes, /health answers"
109
+ exit 0
110
+ fi
111
+ sleep 2
112
+ done
113
+ echo "SMOKE FAILED — container logs:"
114
+ docker logs mcp
115
+ exit 1
116
+
117
+ release:
118
+ # Auto-create the GitHub Release when a `v*` tag passes BOTH gates above —
119
+ # the test matrix AND the image boot-test. Notes are auto-generated from the
120
+ # commits since the previous release; polish them in the web UI afterwards
121
+ # if the release deserves prose.
122
+ # Idempotent: if the Release already exists (created by hand), this no-ops.
123
+ if: startsWith(github.ref, 'refs/tags/v')
124
+ needs: [build-test-lint, docker-smoke]
125
+ runs-on: ubuntu-latest
126
+ permissions:
127
+ contents: write
128
+ steps:
129
+ - name: Checkout
130
+ uses: actions/checkout@v4
131
+
132
+ - name: Create GitHub Release
133
+ env:
134
+ GH_TOKEN: ${{ github.token }}
135
+ run: |
136
+ gh release view "$GITHUB_REF_NAME" >/dev/null 2>&1 || \
137
+ gh release create "$GITHUB_REF_NAME" --latest --generate-notes --title "$GITHUB_REF_NAME"
package/Dockerfile CHANGED
@@ -1,6 +1,6 @@
1
1
  # syntax=docker/dockerfile:1.7
2
2
 
3
- FROM node:25-alpine AS deps
3
+ FROM node:24-alpine AS deps
4
4
  WORKDIR /app
5
5
  COPY package*.json ./
6
6
  # npm ci installs exactly from the committed package-lock.json (reproducible) and
@@ -8,13 +8,13 @@ COPY package*.json ./
8
8
  # above pulls in package-lock.json, so the lockfile is present in this stage.
9
9
  RUN npm ci
10
10
 
11
- FROM node:25-alpine AS build
11
+ FROM node:24-alpine AS build
12
12
  WORKDIR /app
13
13
  COPY --from=deps /app/node_modules ./node_modules
14
14
  COPY . .
15
15
  RUN npm run build
16
16
 
17
- FROM node:25-alpine AS runtime
17
+ FROM node:24-alpine AS runtime
18
18
 
19
19
  # OCI metadata labels
20
20
  LABEL org.opencontainers.image.title="MCP-HA-Connect"
@@ -27,14 +27,24 @@ LABEL org.opencontainers.image.licenses="MIT"
27
27
 
28
28
  WORKDIR /app
29
29
  ENV NODE_ENV=production
30
- RUN apk add --no-cache curl
30
+ # apk upgrade: pick up Alpine security patches even when the node base tag lags
31
+ # (the 2026-07 Trivy scan's 24 libssl/libcrypto CVEs were exactly this rot).
32
+ RUN apk upgrade --no-cache && apk add --no-cache curl
31
33
  COPY package*.json ./
32
- # Reproducible prod-only install from the lockfile (drops devDependencies).
33
- RUN npm ci --omit=dev
34
+ # Reproducible prod-only install from the lockfile (drops devDependencies), then
35
+ # strip the package managers from the runtime image: nothing invokes npm/yarn after
36
+ # this line, and the npm CLI's vendored deps were the only Trivy findings left on
37
+ # v1.5.5 (undici 6.26.0 inside /usr/local/lib/node_modules/npm).
38
+ RUN npm ci --omit=dev && \
39
+ rm -rf /usr/local/lib/node_modules /usr/local/bin/npm /usr/local/bin/npx \
40
+ /usr/local/bin/corepack /opt/yarn* /usr/local/bin/yarn /usr/local/bin/yarnpkg \
41
+ /root/.npm
34
42
  COPY --from=build /app/dist ./dist
35
43
 
36
44
  # M10: drop root. The official node image ships a non-root `node` user (uid 1000).
37
45
  # Built artifacts under /app are world-readable, so no chown is required; the
38
46
  # server listens on 3000 (>1024) which needs no privileged capability.
39
47
  USER node
40
- CMD ["node", "--experimental-quic", "dist/index.js"]
48
+ # --experimental-quic was dropped 2026-07-10: nothing in src/ uses QUIC, and the
49
+ # flag tied the image to a specific Node major (25, now EOL) for no benefit.
50
+ CMD ["node", "dist/index.js"]
package/dist/version.d.ts CHANGED
@@ -2,4 +2,4 @@
2
2
  * Package version - hardcoded at build time for reliability
3
3
  * Keep in sync with package.json version
4
4
  */
5
- export declare const VERSION = "1.5.3";
5
+ export declare const VERSION = "1.5.6";
package/dist/version.js CHANGED
@@ -2,5 +2,5 @@
2
2
  * Package version - hardcoded at build time for reliability
3
3
  * Keep in sync with package.json version
4
4
  */
5
- export const VERSION = '1.5.3';
5
+ export const VERSION = '1.5.6';
6
6
  //# sourceMappingURL=version.js.map
package/openapi.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "openapi": "3.1.0",
3
3
  "info": {
4
4
  "title": "Home Assistant MCP Wrapper",
5
- "version": "1.5.4",
5
+ "version": "1.5.6",
6
6
  "description": "REST endpoints that wrap MCP tools for Home Assistant integration. Raw JSON-RPC passthrough available at POST / for n8n compatibility."
7
7
  },
8
8
  "servers": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coffeerunhobby/mcp-ha-connect",
3
- "version": "1.5.4",
3
+ "version": "1.5.6",
4
4
  "description": "Smart home MCP server for Home Assistant plus Local AI integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/src/version.ts CHANGED
@@ -2,4 +2,4 @@
2
2
  * Package version - hardcoded at build time for reliability
3
3
  * Keep in sync with package.json version
4
4
  */
5
- export const VERSION = '1.5.4';
5
+ export const VERSION = '1.5.6';