fix: optional MCP_API_KEY in tunnel mode + address Copilot review issues

- start.sh: detect POKE_TUNNEL env var; skip MCP_API_KEY requirement and
  auth when running via poke tunnel (server.py reads the same var)
- start.sh: pass POKE_TOKEN into Python via env var + use json.dumps to
  safely escape quotes/backslashes in YAML (fixes shell-interpolation
  injection risk, Copilot issue #5 / start.sh:72)
- start.sh: anchor MCP_API_KEY guard to non-commented line-start
  assignments and also detect empty value (Copilot issues #1, #8 /
  start.sh:104)
- start.sh: anchor re.sub pattern with re.MULTILINE so only the actual
  assignment line is rewritten, not mid-line occurrences (Copilot
  issue #2)
- start.sh: check re.sub replacement count, warn when poke_api_key key
  is missing from config.yml (Copilot issue #6)
- start.sh: guard npm/npx usage with command -v check; fall back to npx
  poke instead of hard-failing (Copilot issue #3)
- start.sh: use python3 consistently for server.py (Copilot issue #9 /
  start.sh:134)
- start.sh: prefer npx poke tunnel; check command -v poke and fall back
  gracefully (Copilot issue #10 / start.sh:135)
- server.py: honour POKE_TUNNEL=1 — skip bearer-token auth so the poke
  tunnel handles identity; MCP_API_KEY becomes optional in that mode
- README.md: add Node.js/npm prerequisite note (Copilot issue #4)
- README.md: clarify server starts on first run; update AI agent prompt
  (Copilot issue #11 / README.md:48)
This commit is contained in:
0xK
2026-03-24 11:40:26 +01:00
parent 7e94e91753
commit 581dd0b89a
3 changed files with 87 additions and 25 deletions
+57 -17
View File
@@ -52,7 +52,7 @@ if grep -q 'your-api-key-here' config.yml 2>/dev/null; then
if [ -f "$POKE_CREDENTIALS_FILE" ]; then
POKE_TOKEN=$(python3 -c "
import json
import json, sys
try:
data = json.load(open('$POKE_CREDENTIALS_FILE'))
print(data.get('token', ''))
@@ -63,11 +63,17 @@ except Exception:
if [ -n "$POKE_TOKEN" ]; then
echo " ✓ Poke API key detected from 'poke login'"
python3 - <<PYEOF
import re
# Pass token via env var to avoid shell-interpolation injection in Python source.
# json.dumps handles quoting/escaping so the result is valid YAML.
POKE_TOKEN="$POKE_TOKEN" python3 - <<'PYEOF'
import os, re, json
token = os.environ['POKE_TOKEN']
with open('config.yml', 'r') as f:
content = f.read()
new_content = re.sub(r'(poke_api_key:\s*)[^\n]+', r'\g<1>"${POKE_TOKEN}"', content)
pattern = r'(?m)^([ \t]*poke_api_key:[ \t*])[^\n]+'
new_content, n = re.subn(pattern, lambda m: m.group(1) + json.dumps(token), content)
if n == 0:
print(' ⚠ Warning: poke_api_key key not found in config.yml — update it manually.')
with open('config.yml', 'w') as f:
f.write(new_content)
PYEOF
@@ -81,11 +87,15 @@ PYEOF
read -r POKE_TOKEN_INPUT
POKE_TOKEN_INPUT=$(echo "$POKE_TOKEN_INPUT" | tr -d '[:space:]')
if [ -n "$POKE_TOKEN_INPUT" ]; then
python3 - <<PYEOF
import re
POKE_TOKEN="$POKE_TOKEN_INPUT" python3 - <<'PYEOF'
import os, re, json
token = os.environ['POKE_TOKEN']
with open('config.yml', 'r') as f:
content = f.read()
new_content = re.sub(r'(poke_api_key:\s*)[^\n]+', r'\g<1>"${POKE_TOKEN_INPUT}"', content)
pattern = r'(?m)^([ \t]*poke_api_key:[ \t*])[^\n]+'
new_content, n = re.subn(pattern, lambda m: m.group(1) + json.dumps(token), content)
if n == 0:
print(' ⚠ Warning: poke_api_key key not found in config.yml — update it manually.')
with open('config.yml', 'w') as f:
f.write(new_content)
PYEOF
@@ -96,20 +106,27 @@ PYEOF
fi
# 4. MCP_API_KEY — generate once and persist to .env
if [ ! -f .env ] || grep -q 'your-secret-key-here' .env 2>/dev/null || ! grep -q 'MCP_API_KEY=' .env 2>/dev/null; then
# Regenerate when: .env is missing, contains the placeholder, or has an
# empty assignment (MCP_API_KEY=) which would still fail at the :? check.
# Anchored to non-commented, line-start assignments only.
if [ ! -f .env ] \
|| grep -Eq '^[[:space:]]*MCP_API_KEY=your-secret-key-here' .env 2>/dev/null \
|| ! grep -Eq '^[[:space:]]*MCP_API_KEY=.+' .env 2>/dev/null; then
RANDOM_KEY=$(python3 -c "
import secrets, string
alphabet = string.ascii_letters + string.digits
print(''.join(secrets.choice(alphabet) for _ in range(48)))
")
if [ -f .env ]; then
python3 - <<PYEOF
import re
# Anchor to line-start with MULTILINE so only the actual assignment is updated.
RANDOM_KEY="$RANDOM_KEY" python3 - <<'PYEOF'
import os, re
new_key = os.environ['RANDOM_KEY']
with open('.env', 'r') as f:
content = f.read()
new_content = re.sub(r'MCP_API_KEY=.*', 'MCP_API_KEY=${RANDOM_KEY}', content)
if 'MCP_API_KEY=' not in new_content:
new_content += 'MCP_API_KEY=${RANDOM_KEY}\n'
new_content, n = re.subn(r'(?m)^[[:space:]]*MCP_API_KEY=.*', f'MCP_API_KEY={new_key}', content)
if n == 0:
new_content += f'MCP_API_KEY={new_key}\n'
with open('.env', 'w') as f:
f.write(new_content)
PYEOF
@@ -127,17 +144,40 @@ if [ -f .env ]; then
set +a
fi
: "${MCP_API_KEY:?MCP_API_KEY is not set — add it to .env or export it}"
# ── Tunnel-mode detection ─────────────────────────────────────────────────────
# When POKE_TUNNEL=1 the poke tunnel handles auth — MCP_API_KEY is optional.
# In all other modes (direct HTTP, Docker, etc.) it is required.
POKE_TUNNEL="${POKE_TUNNEL:-1}" # default to tunnel mode since start.sh always tunnels
if [ "${POKE_TUNNEL}" != "1" ]; then
: "${MCP_API_KEY:?MCP_API_KEY is not set — add it to .env or export it}"
else
# In tunnel mode warn when the key is absent but don't abort.
if [ -z "${MCP_API_KEY:-}" ]; then
echo " MCP_API_KEY not set — server runs unauthenticated (safe: poke tunnel handles auth)."
fi
export POKE_TUNNEL
fi
# ── Start server + tunnel ─────────────────────────────────────────────────────
echo "Starting poke-mail server..."
python src/server.py &
python3 src/server.py &
SERVER_PID=$!
trap "kill $SERVER_PID 2>/dev/null" EXIT
# Wait for server to be ready
sleep 2
# Tunnel to Poke
# Tunnel to Poke — prefer the globally-installed poke binary; fall back to npx.
echo "Starting tunnel to Poke..."
poke tunnel http://localhost:3000/mcp --name "poke-mail"
if command -v poke &>/dev/null; then
poke tunnel http://localhost:3000/mcp --name "poke-mail"
else
echo " 'poke' binary not found in PATH — using npx poke (requires Node.js)."
if ! command -v npx &>/dev/null; then
echo " ✗ Neither 'poke' nor 'npx' found. Install Node.js (nodejs.org) and run:"
echo " npm install -g poke OR npx poke tunnel ..."
exit 1
fi
npx --yes poke tunnel http://localhost:3000/mcp --name "poke-mail"
fi