@@ -3042,6 +3042,10 @@ func Test_DeleteRepository(t *testing.T) {
30423042 sealer , err := requeststate .New (base64 .StdEncoding .EncodeToString ([]byte ("0123456789abcdef0123456789abcdef" )))
30433043 require .NoError (t , err )
30443044 client := NewMockedHTTPClient (
3045+ WithRequestMatchHandler (
3046+ GetReposByOwnerByRepo ,
3047+ mockResponse (t , http .StatusOK , map [string ]any {"id" : 123 }),
3048+ ),
30453049 WithRequestMatchHandler (
30463050 DeleteReposByOwnerByRepo ,
30473051 mockResponse (t , http .StatusNoContent , nil ),
@@ -3099,15 +3103,54 @@ func Test_DeleteRepository(t *testing.T) {
30993103 assert .Contains (t , getErrorResult (t , result ).Text , "state was invalid" )
31003104 })
31013105
3102- t .Run ("refuses a changed deletion target " , func (t * testing.T ) {
3106+ t .Run ("refuses expired deletion state " , func (t * testing.T ) {
31033107 sealer , err := requeststate .New (base64 .StdEncoding .EncodeToString ([]byte ("0123456789abcdef0123456789abcdef" )))
31043108 require .NoError (t , err )
3109+ stateJSON , err := json .Marshal (deleteRepositoryState {
3110+ Owner : "owner" ,
3111+ Repo : "repo" ,
3112+ RepositoryID : 123 ,
3113+ ExpiresAt : time .Now ().Add (- time .Minute ).Unix (),
3114+ })
3115+ require .NoError (t , err )
3116+ state , err := sealer .Seal (context .Background (), stateJSON )
3117+ require .NoError (t , err )
31053118 deps := BaseDeps {
31063119 Client : mustNewGHClient (t , NewMockedHTTPClient ()),
31073120 StateSealer : sealer ,
31083121 }
31093122 handler := serverTool .Handler (deps )
31103123
3124+ request := createMCPRequest (map [string ]any {"owner" : "owner" , "repo" : "repo" })
3125+ request .Params .RequestState = state
3126+ request .Params .InputResponses = mcp.InputResponseMap {
3127+ deleteRepositoryConfirmationID : & mcp.ElicitResult {
3128+ Action : "accept" ,
3129+ Content : map [string ]any {
3130+ deleteRepositoryConfirmationField : "owner/repo" ,
3131+ },
3132+ },
3133+ }
3134+ result , err := handler (ContextWithDeps (context .Background (), deps ), & request )
3135+ require .NoError (t , err )
3136+ require .True (t , result .IsError )
3137+ assert .Contains (t , getErrorResult (t , result ).Text , "confirmation expired" )
3138+ })
3139+
3140+ t .Run ("refuses a changed deletion target" , func (t * testing.T ) {
3141+ sealer , err := requeststate .New (base64 .StdEncoding .EncodeToString ([]byte ("0123456789abcdef0123456789abcdef" )))
3142+ require .NoError (t , err )
3143+ deps := BaseDeps {
3144+ Client : mustNewGHClient (t , NewMockedHTTPClient (
3145+ WithRequestMatchHandler (
3146+ GetReposByOwnerByRepo ,
3147+ mockResponse (t , http .StatusOK , map [string ]any {"id" : 123 }),
3148+ ),
3149+ )),
3150+ StateSealer : sealer ,
3151+ }
3152+ handler := serverTool .Handler (deps )
3153+
31113154 firstRequest := createMCPRequest (map [string ]any {"owner" : "owner" , "repo" : "repo" })
31123155 firstResult , err := handler (ContextWithDeps (context .Background (), deps ), & firstRequest )
31133156 require .NoError (t , err )
@@ -3128,6 +3171,50 @@ func Test_DeleteRepository(t *testing.T) {
31283171 assert .Contains (t , getErrorResult (t , result ).Text , "target changed" )
31293172 })
31303173
3174+ t .Run ("refuses a recreated repository" , func (t * testing.T ) {
3175+ sealer , err := requeststate .New (base64 .StdEncoding .EncodeToString ([]byte ("0123456789abcdef0123456789abcdef" )))
3176+ require .NoError (t , err )
3177+ var repositoryLookups int
3178+ client := NewMockedHTTPClient (
3179+ WithRequestMatchHandler (
3180+ GetReposByOwnerByRepo ,
3181+ http .HandlerFunc (func (w http.ResponseWriter , _ * http.Request ) {
3182+ repositoryLookups ++
3183+ id := 123
3184+ if repositoryLookups > 1 {
3185+ id = 456
3186+ }
3187+ w .WriteHeader (http .StatusOK )
3188+ require .NoError (t , json .NewEncoder (w ).Encode (map [string ]any {"id" : id }))
3189+ }),
3190+ ),
3191+ )
3192+ deps := BaseDeps {
3193+ Client : mustNewGHClient (t , client ),
3194+ StateSealer : sealer ,
3195+ }
3196+ handler := serverTool .Handler (deps )
3197+
3198+ firstRequest := createMCPRequest (map [string ]any {"owner" : "owner" , "repo" : "repo" })
3199+ firstResult , err := handler (ContextWithDeps (context .Background (), deps ), & firstRequest )
3200+ require .NoError (t , err )
3201+
3202+ retry := createMCPRequest (map [string ]any {"owner" : "owner" , "repo" : "repo" })
3203+ retry .Params .RequestState = firstResult .RequestState
3204+ retry .Params .InputResponses = mcp.InputResponseMap {
3205+ deleteRepositoryConfirmationID : & mcp.ElicitResult {
3206+ Action : "accept" ,
3207+ Content : map [string ]any {
3208+ deleteRepositoryConfirmationField : "owner/repo" ,
3209+ },
3210+ },
3211+ }
3212+ result , err := handler (ContextWithDeps (context .Background (), deps ), & retry )
3213+ require .NoError (t , err )
3214+ require .True (t , result .IsError )
3215+ assert .Contains (t , getErrorResult (t , result ).Text , "identity changed" )
3216+ })
3217+
31313218 t .Run ("completes multi-round-trip elicitation before deleting" , func (t * testing.T ) {
31323219 httpClient := NewMockedHTTPClient (
31333220 WithRequestMatchHandler (
0 commit comments