Phy Env Doctor

自动扫描代码中的环境变量,生成文档化的.env.example并检测安全风险。

已扫描
适合谁
后端开发工程师、团队技术负责人
不适合谁
无代码项目人员、仅需静态页面的用户
国内可用性
需网络配置。可能需要网络配置或第三方服务可访问。
安装难度
新手友好(★☆☆)。基于终端操作、依赖、API Key 和本地环境要求的初步判断。

安装与下载

openclaw skills install @phy041/phy-env-doctor

Skill 说明

命令、参数、文件名以原文为准

环境医生

扫描任意代码库中的环境变量使用情况,自动生成已文档化的 .env.example 文件,发现缺失的变量,并检测潜在的密钥泄露问题——在它们进入生产环境前。

无需配置文件,无需 API 密钥。完全基于源代码运行。


触发短语

  • "环境医生", "检查环境变量", "审计我的环境"
  • "生成 .env.example", "这个项目需要哪些环境变量"
  • "缺失的环境变量", "未定义的环境变量"
  • "审计密钥", "是否有密钥被暴露"
  • "/env-doctor"

第一步:扫描源代码中所有环境变量引用

使用语言特定的 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 文件对比

# 解析当前的 .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

根据上下文生成可读性描述:

  • 若用于数据库连接 → “PostgreSQL 连接字符串”
  • 若用于 API 客户端构造函数 → “[服务] 的 API 密钥”
  • 若用于 if (process.env.X === 'true') → “功能开关 — 设置为 'true' 以启用”
  • 若用作 URL → “[服务] API 的基础地址”
  • 若用于 JWT 签名 → “JWT 签名密钥 — 必须为 32 位以上随机字符”

第四步:安全扫描

检查可能导致密钥泄露的危险模式:

# 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

构建一份完整且带注释的 .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

Env Doctor 报告

项目:[name] | $(date) | 语言:Node.js, Python

摘要

状态数量
✅ 在 .env 中定义12
❌ 缺失(代码中使用,但不在 .env 中)3
📋 未记录(在 .env 中,但不在 .env.example 中)5
🗑️ 冗余(在 .env.example 中,但代码中未引用)1
⚠️ 安全问题2

❌ 缺失的变量 —— 可能导致运行时错误

变量使用位置类型(推断)
REDIS_URLsrc/cache.ts:14Redis 连接字符串
SENDGRID_API_KEYlib/email.js:8SendGrid 的 API 密钥
ENCRYPTION_KEYutils/crypto.py:22AES 加密密钥(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) —— 请移除该日志


📋 生成的 .env.example

[完整生成内容 —— 可直接复制]


🗑️ 冗余变量(可安全从 .env.example 中移除)

  • 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) —— 无需破坏品牌即可运行高性能营销。

  • GitHub:[github.com/PHY041](https://github.com/PHY041)
  • 所有技能:[clawhub.ai/PHY041](https://clawhub.ai/PHY041)
P
@phy041

已收录 3 个 Skill

相关推荐