Lesstep
Azure Repos・git push・2026年11月2日に確認

Azure DevOps:「VS403654: The push was rejected because it contains one or more secrets.」

Azure Repos のプッシュ保護が、push したコミットのどれかに資格情報らしいものを見つけ、push をまるごと断りました。サーバーのブランチは変わっていません。メッセージにはコミット・ファイル・行が出ています。今のファイルからだけでなく、そのコミットから秘密を取り除いて、もう一度 push します。

メッセージの全体

git push の出力です。LibGit2Sharp の公開の issue に貼られたもので、組織とブランチの名前は置き換えました。

remote: Analyzing objects... (3/3) (27 ms)
remote: Validating commits... (1/1) done (0 ms)
remote: Checking for credentials and other secrets...  done (59 ms)
error: remote unpack failed: error VS403654: The push was rejected because it contains one or more secrets.
To https://dev.azure.com/<organization>/<project>/_git/<repo>
 ! [remote rejected]         <branch> -> <branch> (VS403654: The push was rejected because it contains one or more secrets.

Resolve the following secrets before pushing again. For help, see …

続く一覧は、Aspire のリポジトリの公開の報告(2026年8月)ではこうでした。

VS403654:BypassableBlock The push was rejected because it contains one or more secrets.

commit: 59219d7439b183a5171e95811c9e6174636b0a26
/src/Aspire.Dashboard/Model/ConnectionStringParser.cs(187,29-37) : SEC101/033 : MongoDbCredentials
/tests/Aspire.Dashboard.Tests/ConnectionStringParserTests.cs(127,33-41) : SEC101/033 : MongoDbCredentials

1行ごとに、ファイル、行と桁、規則の ID、秘密の種類が並びます。VS403654: の後ろの語は、ブロックを回避できるかどうかを表します。公開の報告には NonbypassableBlock もあります。libgit2 を使う LibGit2Sharp では unpacking the sent packfile failed on the remote としか出ません。一覧を見るには、同じ push を git のコマンドラインでやり直します。

なぜ断られたか

Microsoft のシークレット スキャンを設定するによると、プッシュ保護は入ってくる push を全部調べ、確度の高い秘密があれば止めます。GitHub Advanced Security for Azure DevOps か、単体の GitHub Secret Protection for Azure DevOps の機能なので、リポジトリ・プロジェクト・組織のどこかで誰かが有効にしています。Web の画面での編集も調べられます。

同じページは、ファイルからだけでなくコミットの履歴から秘密を消すよう書いています。消すコミットを後に足しても通りません。Aspire の報告のとおり、秘密を含むコミットが、push する履歴の中に残っているからです。

見つかったものを見る

git show 59219d7:src/Aspire.Dashboard/Model/ConnectionStringParser.cs

メッセージの行へ行けば、桁の範囲がフラグの付いた文字です。パスの先頭の / は外します。付けたまま試すと、Git は fatal: path '/appsettings.json' does not exist と返しました。

履歴から取り除く

どのコミットもサーバーには届いていないので、作り直してかまいません。

秘密が入ったのが最後のコミットなら、ファイルから消して、そのコミットを直します。

git commit --amend -a
git push

もっと前のコミットなら、Microsoft のページのとおり、そのコミットを編集します。

git rebase -i 59219d7~1

エディターで、そのコミットの行の pick を edit に変えて保存します。ファイルから秘密を消し、続けて次を打ちます。

git commit --amend -a
git rebase --continue

後のコミットで秘密をすでに消していた場合、そのコミットはやることが無くなります。試すと、Git はそこで The previous cherry-pick is now empty, possibly due to conflict resolution. と止まり、git rebase --skip でそのコミットを落として最後まで進みました。

コミットを分けておく必要が無ければ、もっと短く済みます。先にファイルから秘密を消してから、作業を始めたブランチを起点に、コミットを1つにまとめ直します。

git reset --soft origin/main
git commit -m "変更の説明"

push の前に、秘密を持つコミットが残っていないか確かめます。試すと、どちらのやり方でも次のコマンドは何も出しませんでした。

git log -S "<秘密の一部>" --oneline origin/main..HEAD

本物の資格情報だったなら、作り直しもします。新しいものはコードに置かず、Microsoft のページが勧めるように Azure Key Vault などにしまいます。

例の値と誤検知

例やテストのための作り物の値なら、Microsoft のページは、その前に Placeholder を付けるよう書いています。Aspire のリポジトリは、例の MongoDB のパスワードにそうしました(プルリクエスト 20790)。ただし、その変更をプッシュ保護に通したかはまだ確かめていない、と添えています。

そのまま残すしかない誤検知なら、同じページのとおりプッシュ保護を回避できます。コミット メッセージに skip-secret-scanning:true を入れます。Aspire の報告では、その文字列をメッセージに持つ新しいコミットを上に1つ足すと、フラグの付いたコミットごと履歴全体が通りました。それでも Azure DevOps は Advanced Security に秘密のアラートを出し、閉じるにはプロジェクト管理者の権限が要ります。本物の資格情報では回避しないでください。

IntelliJ IDEA や Rider からプルリクエストを作るなら

Azure DevOps Pull Requests は、Lesstep が作っている JetBrains IDE(2024.1 以降)と Android Studio のプラグインです。Git メニューに Azure DevOps のプルリクエストを作成… を足します。push が通ったら、今いるブランチから、選ばなければリポジトリの既定のブランチへ、下書きにもできるプルリクエストを作ります。ブランチがまだ Azure DevOps に無ければそう伝えて、先に IDE の push の画面を開きます。プルリクエストの作成は Pro(月 US$1・30日間の無料試用つき)、受信箱は無料です。画面は日本語です。

JetBrains Marketplace で入れる

Azure DevOps と Azure Repos は Microsoft Corporation の商標、IntelliJ IDEA と Rider は JetBrains s.r.o. の商標です。このページは Microsoft・JetBrains のいずれとも提携しておらず、承認も受けていません。

ほかに:「TF402455: Pushes to this branch are not permitted」 · 「TF401027: You need the Git 'GenericContribute' permission」 · English