From fe70f0a7db9d4c21f9eefdd2a05e9a715abe908d Mon Sep 17 00:00:00 2001 From: Vasist10 <155972527+Vasist10@users.noreply.github.com> Date: Wed, 3 Dec 2025 21:08:35 +0530 Subject: [PATCH] fix: prevent zero-byte remote state writes (#37947) --- internal/states/remote/remote_grpc.go | 9 ++++++++ internal/states/remote/remote_grpc_test.go | 25 ++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/internal/states/remote/remote_grpc.go b/internal/states/remote/remote_grpc.go index 468e1c05a2..8d6b92b58d 100644 --- a/internal/states/remote/remote_grpc.go +++ b/internal/states/remote/remote_grpc.go @@ -79,6 +79,15 @@ func (g *grpcClient) Get() (*Payload, tfdiags.Diagnostics) { // // Implementation of remote.Client func (g *grpcClient) Put(state []byte) tfdiags.Diagnostics { + if len(state) == 0 { + var diags tfdiags.Diagnostics + return diags.Append(tfdiags.Sourceless( + tfdiags.Error, + "Refusing to write empty remote state snapshot", + "Terraform produced an empty state file and will not upload it to remote storage. This indicates a bug in Terraform; please report it.", + )) + } + req := providers.WriteStateBytesRequest{ TypeName: g.typeName, StateId: g.stateId, diff --git a/internal/states/remote/remote_grpc_test.go b/internal/states/remote/remote_grpc_test.go index e5c60ca3ae..b7366eb9b7 100644 --- a/internal/states/remote/remote_grpc_test.go +++ b/internal/states/remote/remote_grpc_test.go @@ -221,6 +221,31 @@ func Test_grpcClient_Put(t *testing.T) { t.Fatalf("expected error to contain %q, but got: %s", expectedErr, err.Error()) } }) + + t.Run("grpcClient refuses zero-byte writes", func(t *testing.T) { + provider := testing_provider.MockProvider{ + ConfigureProviderCalled: true, + ConfigureStateStoreCalled: true, + WriteStateBytesFn: func(req providers.WriteStateBytesRequest) providers.WriteStateBytesResponse { + t.Fatal("expected WriteStateBytes not to be called for zero-byte payload") + return providers.WriteStateBytesResponse{} + }, + } + + client := &grpcClient{ + provider: &provider, + typeName: typeName, + stateId: stateId, + } + + diags := client.Put(nil) + if !diags.HasErrors() { + t.Fatalf("expected diagnostics when attempting to write zero bytes") + } + if provider.WriteStateBytesCalled { + t.Fatalf("provider WriteStateBytes should not be called") + } + }) } // Testing grpcClient's Delete method.