Skip to content

fix: 收敛 SSH 与发布流程的边界问题 - #12

Merged
zhinkgit merged 1 commit into
zhinkgit:mainfrom
shipiyouniao:fix/post-merge-hardening
Sep 3, 2026
Merged

zhinkgit merged 1 commit into
zhinkgit:mainfrom
shipiyouniao:fix/post-merge-hardening

Conversation

@shipiyouniao

Copy link
Copy Markdown
Contributor

背景

这是收敛后的单提交版本,替代已关闭的 #11。修改集中处理 SSH 环境映射边界、发布打包正确性以及 CI/Release 安全性。

修改内容

  • 修正 SSH 配置解析边界:Host *、通配 Host、Match、无缩进选项和空行不再污染具体主机记录。
  • 补齐确定性解析:OpenSSH 精确别名优先,其次是元数据精确别名;共享分组仍返回歧义。
  • 完整校验 add 与 probe 参数,覆盖端口、控制字符、Host 模式、注释截断和超时。
  • 收紧发布打包:
    • 拒绝通过符号链接读取仓库外文件;
    • 在遍历前剪枝当前输出目录;
    • 始终排除 dist/、测试和缓存目录;
    • 删除目标版本的陈旧 skill 包,同时保留其他版本和无关文件;
    • 在函数边界校验版本,避免通配符扩大清理范围;
    • 正确处理仓库内、仓库外及仓库父目录输出布局。
  • 修正 SKILL frontmatter 和测试目录发现的误匹配,并补齐折叠式 description 校验。
  • 固定 GitHub Actions 到已核对的提交 SHA,关闭 checkout 凭据持久化,收紧 Release 写权限并增加并发控制。

验证

  • Windows Python 3.13:仓库检查通过;43 项测试完成,其中 41 项通过,2 项符号链接用例因本机权限跳过。
  • Linux Python 3.10 / 3.13:仓库检查通过,43/43 项测试通过,符号链接安全用例实际执行。
  • 默认 dist、skill 内部、仓库同级和仓库父目录四种输出布局验证通过。
  • Ruff 目标检查、Actionlint、Zizmor 通过。
  • 完整包及 12 个独立 skill 包构建成功,13 个 SHA-256 校验全部通过。

Copilot AI lite review requested due to automatic review settings September 3, 2026 04:54

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The updated skip-directory logic relies on absolute path.parts (can incorrectly skip all files/tests depending on checkout path), and the new control-character validation misses DEL (0x7f) in security-sensitive inputs.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

This PR tightens the boundary behavior between the SSH tooling and the release packaging/CI pipeline, focusing on safer parsing/validation, deterministic packaging, and hardened GitHub Actions configuration.

Changes:

  • Improve OpenSSH config parsing + alias/port/add argument validation; extend probe argument validation and document Match exec risk.
  • Harden release packaging (exclude dist/, prune output directory, reject repo-escaping symlinks, validate version before cleanup) and add regression tests.
  • Pin GitHub Actions to specific SHAs, disable credential persistence, tighten permissions, and add concurrency controls.
File summaries
File Description
tools/run_tests.py Skip discovery inside common build/cache directories during test discovery.
tools/repo_checks.py Improve file matching (avoid false positives) and support folded frontmatter parsing.
tools/package_release.py Harden packaging against symlinks/output-dir contamination and make cleanup/version handling safer.
tests/test_repo_tools.py Add tests for folded frontmatter, SKILL discovery, version validation, and packaging hardening.
ssh/scripts/ssh_probe.py Add probe argument validation for timeouts and known-hosts file safety.
ssh/tests/test_ssh_probe.py Add tests for probe timeout validation and known-hosts control-character rejection.
ssh/scripts/ssh_config.py Fix host parsing boundaries, improve deterministic resolution, validate inputs, and safer ssh -G invocation.
ssh/tests/test_ssh_config.py Add extensive regression tests for parsing boundaries, add validation, and resolution ranking.
ssh/SKILL.md Document probe safety boundary regarding Match exec.
ssh/README.md Document probe safety boundary regarding Match exec.
README.md Update ssh skill feature list/commands.
README.en.md Update ssh skill feature list/commands (English).
.github/workflows/release.yml Pin action SHAs, disable credential persistence, narrow permissions, add concurrency.
.github/workflows/ci.yml Pin action SHAs, disable credential persistence, add concurrency, clarify job naming.
Review details
  • Files reviewed: 14/14 changed files
  • Comments generated: 4
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread ssh/scripts/ssh_config.py
Comment on lines 185 to +187
def validate_single_line_field(name: str, value: object) -> None:
if isinstance(value, str) and ("\n" in value or "\r" in value):
raise ValueError(f"{name} must be a single line")
if isinstance(value, str) and any(ord(character) < 32 for character in value):
raise ValueError(f"{name} must not contain control characters")
Comment thread ssh/scripts/ssh_probe.py
Comment on lines +30 to +39
def validate_arguments(args: argparse.Namespace) -> None:
validate_alias(args.alias)
if args.timeout <= 0:
raise ValueError("timeout must be greater than zero")
if args.connect_timeout <= 0:
raise ValueError("connect-timeout must be greater than zero")
if args.known_hosts_file and any(
ord(character) < 32 for character in args.known_hosts_file
):
raise ValueError("known-hosts-file must not contain control characters")
Comment thread tools/repo_checks.py
Comment on lines +20 to 26
def matching_files(root: Path, pattern: str) -> list[Path]:
return sorted(
path
for path in root.rglob(f"*{suffix}")
if not any(part in SKIP_DIRECTORIES for part in path.parts)
for path in root.rglob(pattern)
if path.is_file()
and not any(part in SKIP_DIRECTORIES for part in path.parts)
)
Comment thread tools/run_tests.py
and any(path.glob("test_*.py"))
and ".git" not in path.parts
and "__pycache__" not in path.parts
and not any(part in SKIP_DIRECTORIES for part in path.parts)
@zhinkgit
zhinkgit merged commit d1add2c into zhinkgit:main Sep 3, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants