Local MCP Server
在Termux中运行本地MCP服务器,支持Ollama模型的文件读取与命令执行。
自动扫描代码中的环境变量,生成文档化的.env.example并检测安全风险。
openclaw skills install @phy041/phy-env-doctor命令、参数、文件名以原文为准
扫描任意代码库中的环境变量使用情况,自动生成已文档化的 .env.example 文件,发现缺失的变量,并检测潜在的密钥泄露问题——在它们进入生产环境前。
无需配置文件,无需 API 密钥。完全基于源代码运行。
使用语言特定的 grep 模式提取每个被引用的环境变量:
# Node.js / TypeScript — process.env.VAR_NAME
grep -rn "process\.env\.\([A-Z_][A-Z0-9_]*\)" \
--include="*.js" --include="*.ts" --include="*.mjs" --include="*.cjs" \
--exclude-dir=node_modules --exclude-dir=.git \
-h . | grep -oE "process\.env\.[A-Z_][A-Z0-9_]*" | sort -u
# Python — os.environ["VAR"] / os.getenv("VAR") / os.environ.get("VAR")
grep -rn \
--include="*.py" --exclude-dir=.git --exclude-dir=venv --exclude-dir=__pycache__ \
-hE 'os\.environ\[.([A-Z_][A-Z0-9_]*).|(os\.getenv|os\.environ\.get)\(.([A-Z_][A-Z0-9_]*).' \
. | grep -oE '[A-Z_][A-Z0-9_]{2,}' | sort -u
# Go — os.Getenv("VAR")
grep -rn --include="*.go" --exclude-dir=.git \
-hE 'os\.Getenv\("([A-Z_][A-Z0-9_]*)"\)' \
. | grep -oE '"[A-Z_][A-Z0-9_]*"' | tr -d '"' | sort -u
# Ruby — ENV["VAR"] / ENV.fetch("VAR")
grep -rn --include="*.rb" --exclude-dir=.git \
-hE 'ENV\[.([A-Z_][A-Z0-9_]*).|(ENV\.fetch)\(.([A-Z_][A-Z0-9_]*).' \
. | grep -oE '[A-Z_][A-Z0-9_]{2,}' | sort -u
# Shell 脚本
grep -rn --include="*.sh" --include="*.bash" --exclude-dir=.git \
-hE '\$\{?([A-Z_][A-Z0-9_]*)\}?' \
. | grep -oE '[A-Z_][A-Z0-9_]{2,}' | grep -v "^IFS$\|^PATH$\|^HOME$\|^USER$\|^PWD$\|^SHELL$" | sort -u将所有结果合并为一个主列表,包含每个变量在代码中出现的文件:行位置。
# 解析当前的 .env(如果存在)
if [ -f .env ]; then
grep -v '^#' .env | grep '=' | cut -d= -f1 | sort -u > /tmp/env_defined.txt
echo "找到 $(wc -l < /tmp/env_defined.txt) 个已定义的变量"
else
echo "未找到 .env 文件"
fi
# 检查是否存在 .env.example
if [ -f .env.example ]; then
grep -v '^#' .env.example | grep '=' | cut -d= -f1 | sort -u > /tmp/env_example.txt
echo "在 .env.example 中找到 $(wc -l < /tmp/env_example.txt) 个变量"
fi交叉比对以识别:
.env 中定义 → 可能导致运行时错误.env 但不在 .env.example 中 → 新成员无法知晓.env.example 但代码中无引用 → 已过时,可删除针对每个发现的环境变量,读取其周围的代码以推断其用途:
# 获取每个变量使用处前后各 1 行的上下文
grep -rn "PROCESS_ENV_VAR_NAME\|os.getenv.*VAR_NAME" . --include="*.py" --include="*.js" -A 1 -B 1根据上下文生成可读性描述:
if (process.env.X === 'true') → “功能开关 — 设置为 'true' 以启用”检查可能导致密钥泄露的危险模式:
# 1. .env 是否已被提交到 git?
git ls-files .env 2>/dev/null && echo "⚠️ .env 已被 Git 跟踪"
# 2. .env 是否在 .gitignore 中?
grep -q "^\.env$\|^\.env\b" .gitignore 2>/dev/null && echo "✅ .env 在 .gitignore 中" || echo "⚠️ .env 不在 .gitignore 中"
# 3. 是否有环境变量被打印或日志输出?
grep -rn --include="*.js" --include="*.ts" --include="*.py" \
-E "(console\.log|print|logger\.(info|debug|warn))\(.*process\.env|os\.environ" \
. | grep -v node_modules | head -10
# 4. 是否存在硬编码的密钥(常见模式)?
grep -rn --include="*.js" --include="*.ts" --include="*.py" --include="*.go" \
-E "(api_key|apikey|secret|password|token)\s*=\s*['\"][a-zA-Z0-9+/]{20,}['\"]" \
. | grep -v "\.env\|test\|spec\|mock\|example" | grep -v node_modules | head -10
# 5. 是否存在除根目录外的 .env 文件?
find . -name ".env*" -not -path "*/node_modules/*" -not -name ".env.example" -not -name ".env.sample"构建一份完整且带注释的 .env.example 文件:
cat > .env.example.generated << 'EOF'
# 由 phy-env-doctor 生成 — $(date)
# 此文件记录了本项目所需的所有环境变量。
# 请复制到 .env 并填写真实值。切勿将 .env 提交至版本控制。
# ─── 数据库 ───────────────────────────────────────────────
DATABASE_URL= # PostgreSQL 连接字符串。格式:postgresql://user:pass@host:5432/dbname
# ─── 认证 ─────────────────────────────────────────────────
JWT_SECRET= # JWT 签名密钥。必须为 32 位以上随机字符。生成方式:openssl rand -base64 32
JWT_EXPIRY=7d # Token 过期时间。示例:7d、24h、3600
# ─── 外部 API ────────────────────────────────────────────
STRIPE_SECRET_KEY= # Stripe 秘密密钥。从 dashboard.stripe.com/apikeys 获取
STRIPE_WEBHOOK_SECRET= # Stripe Webhook 签名密钥。可通过 Stripe CLI 或仪表板获取
# ─── 应用配置 ────────────────────────────────────────────
NODE_ENV=development # 环境:development | staging | production
PORT=3000 # HTTP 服务器端口
LOG_LEVEL=info # 日志级别:debug | info | warn | error
EOF项目:[name] | $(date) | 语言:Node.js, Python
| 状态 | 数量 |
|---|---|
| ✅ 在 .env 中定义 | 12 |
| ❌ 缺失(代码中使用,但不在 .env 中) | 3 |
| 📋 未记录(在 .env 中,但不在 .env.example 中) | 5 |
| 🗑️ 冗余(在 .env.example 中,但代码中未引用) | 1 |
| ⚠️ 安全问题 | 2 |
| 变量 | 使用位置 | 类型(推断) |
|---|---|---|
REDIS_URL | src/cache.ts:14 | Redis 连接字符串 |
SENDGRID_API_KEY | lib/email.js:8 | SendGrid 的 API 密钥 |
ENCRYPTION_KEY | utils/crypto.py:22 | AES 加密密钥(32 字符) |
快速修复:
echo "REDIS_URL=" >> .env
echo "SENDGRID_API_KEY=" >> .env
echo "ENCRYPTION_KEY=" >> .env[严重] .env 文件被 Git 跟踪
→ 执行:echo ".env" >> .gitignore && git rm --cached .env
[高危] 密钥可能在 src/auth.js:42 被日志输出:
→ console.log('Auth config:', process.env.JWT_SECRET) —— 请移除该日志
[完整生成内容 —— 可直接复制]
OLD_API_URL —— 当前代码库中未被引用如用户只需快速检查:env doctor --quick
快速环境检查:
❌ 3 个变量缺失 ⚠️ 2 个安全问题 📋 5 个未记录
缺失变量:REDIS_URL, SENDGRID_API_KEY, ENCRYPTION_KEY
运行 /env-doctor 获取完整报告 + 生成的 .env.example现有工具如 bytesagain3/env-config 提供的是 模板管理器 —— 你需要告诉它要创建哪些变量。而本技能恰恰相反:它 读取你的代码,发现你实际使用的变量,然后基于真实使用情况生成文档,而非依赖你记忆中的记录。
这解决了环境变量最核心的问题:未被发现的缺失变量,仅在生产环境中才引发崩溃。
[Canlah AI](https://canlah.ai) —— 无需破坏品牌即可运行高性能营销。
已收录 3 个 Skill