根本原因是ssh未通过~/.ssh/config路由分流,导致composer调用git时默认使用首个密钥连接所有域名;必须为每个私有源配置独立host条目、在composer.json中使用对应别名url,并确保ci中正确启动ssh-agent及加载密钥。

ssh-agent 里混了多个密钥,git clone 能通但 composer install 失败
根本原因不是 Composer 不支持多密钥,而是它调用 git 时没指定 Host 别名,导致 SSH 默认用第一个加载的密钥去连所有域名 —— 比如你同时加了 GitHub 和 GitLab 的密钥,ssh-add -l 显示两个都存在,但 git clone git@github.com:user/repo.git 成功,composer install 却卡在 git@gitlab.example.com:group/project.git 上报 Permission denied (publickey)。
必须靠 ~/.ssh/config 做路由分流,否则 SSH 客户端根本不知道该挑哪个私钥。常见错误是只配了 IdentityFile 却漏掉 Host 和 HostName 对应关系。
- 确认
~/.ssh/config中每个私有源都有独立Host条目,例如:Host github-private HostName github.com User git IdentityFile ~/.ssh/id_rsa_github_private <p>Host gitlab-company HostName gitlab.example.com User git IdentityFile ~/.ssh/id_rsa_gitlab_company</p>
-
composer.json里的仓库 URL 必须用你定义的Host别名,不能直接写真实域名:"url": "git@github-private:user/private-repo.git",而不是git@github.com:user/private-repo.git - 删掉所有已加载密钥:
ssh-add -D,再逐个加载:ssh-add ~/.ssh/id_rsa_github_private、ssh-add ~/.ssh/id_rsa_gitlab_company,避免 agent 缓存旧状态
GitLab 子组嵌套路径被 Composer 解析错,报 “repository ‘’ not found”
GitLab 的 SSH URL 格式对斜杠敏感,git@gitlab.example.com:topgroup/subgroup/project.git 是合法的,但如果你在 ~/.ssh/config 里把 HostName 写成 gitlab.example.com/topgroup 或误加路径到 Host 行,SSH 就会把整个字符串当主机名解析,结果连不上,git 报错后 Composer 直接抛出空 repository 名。
这个错误不报具体域名,只说 repository '' not found,容易误判为权限问题,其实是 SSH 连接阶段就失败了,根本没走到认证环节。
- 务必从 GitLab Web 页面点「Clone with SSH」复制完整 URL,不要手动拼接;尤其注意冒号
:后面是全路径,不是/开头 -
~/.ssh/config中只处理域名映射,路径部分留给 Git 自己解析:HostName必须是纯域名(如gitlab.example.com),不能带任何路径或端口 - 测试配置是否生效:运行
ssh -T git@gitlab-company(用你定义的Host别名),看到You've successfully authenticated才算通
composer.json 里私有源排在镜像后面,导致 404 而不是 Permission denied
如果 composer.json 的 repositories 数组里,国内镜像(如阿里云)写在前面,私有 VCS 源写在后面,Composer 会先去镜像查包 —— 镜像没有你的私有包,直接返回 404,错误日志里甚至不会出现 SSH 相关关键词,让人误以为是网络或权限问题。
工作流任务拆解与模型编排技能。使用场景:(1) 收到复杂工作任务需要拆解为可执行步骤,(2) 需要为不同步骤选择最合适的模型,(3) 需要跟踪工作流进度和模型使用情况,(4) 长时间任务卡住需要问题诊断和解决方案。
这个顺序问题在 CI/CD 环境特别隐蔽,因为本地开发可能用了全局镜像配置,而构建机只读项目级 composer.json,行为不一致。
- 私有源必须声明为
vcs类型,且url字段以git@开头,例如:{"type": "vcs", "url": "git@gitlab-company:group/project.git"} - 把私有源对象放在
repositories数组最前面,镜像源放最后;不要依赖composer config -g repo.packagist全局设置,项目级配置优先级更高 - 检查是否被企业 Nexus/Artifactory 代理覆盖:运行
composer config --list,确认repositories输出里私有源确实排第一
CI/CD 环境下 ssh-agent 没启动,或者密钥没注入
本地 ssh-add 成功不代表 CI 环境也行。GitHub Actions、GitLab CI 默认不启用 ssh-agent,也不自动加载 ~/.ssh/ 下的密钥 —— 即使你用 secrets.SSH_PRIVATE_KEY 注入了内容,没显式启动 agent 并 add 密钥,composer install 依然走 HTTPS fallback 或直接失败。
这个坑常出现在 YAML 脚本里只写了 echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa,却忘了 chmod 600 ~/.ssh/id_rsa 和 eval $(ssh-agent -s)。
- GitHub Actions 示例(必须包含三步):
- name: Setup SSH agent uses: webfactory/ssh-agent@v0.8.0 with: ssh-private-key: ${{ secrets.SSH_PRIVATE_KEY }} - GitLab CI 需手动启动:
before_script: - mkdir -p ~/.ssh - echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa - chmod 600 ~/.ssh/id_rsa - eval $(ssh-agent -s) - ssh-add ~/.ssh/id_rsa
- 无论哪种 CI,都要确保
~/.ssh/config也在构建机上存在,且Host别名与composer.json中 URL 一致
关键点在于:SSH 认证失败的表象背后,90% 不是密钥本身有问题,而是路径没对齐——composer.json 的 URL、~/.ssh/config 的 Host、CI 脚本里 ssh-add 的文件路径、GitLab 页面显示的克隆地址,这四者必须严格一一对应,差一个字符都会静默失败。










