Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package google-osconfig-agent for 
openSUSE:Factory checked in at 2026-06-27 18:05:20
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/google-osconfig-agent (Old)
 and      /work/SRC/openSUSE:Factory/.google-osconfig-agent.new.11887 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "google-osconfig-agent"

Sat Jun 27 18:05:20 2026 rev:55 rq:1361799 version:20260624.01

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/google-osconfig-agent/google-osconfig-agent.changes  
    2026-06-17 16:24:18.346087897 +0200
+++ 
/work/SRC/openSUSE:Factory/.google-osconfig-agent.new.11887/google-osconfig-agent.changes
   2026-06-27 18:06:25.496636801 +0200
@@ -1,0 +2,18 @@
+Thu Jun 25 14:34:51 UTC 2026 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to version 20260624.01
+  * Add unit tests for agentendpoint/agentendpoint_beta.go (#983)
+- from version 20260624.00
+  * Replace yum install with yum update (#1009)
+- from version 20260623.02
+  * Bump github.com/containerd/containerd (#1013)
+- from version 20260623.01
+  * Add unit tests for policies/apt.go PART 2 (#957)
+- from version 20260623.00
+  * Add test cases for agentendpoint/task_state.go (#984)
+- from version 20260618.00
+  * Remove deprecated rhel-sap images and add new ones (#1007)
+- from version 20260616.00
+  * Add test cases for clog/clog.go (#986)
+
+-------------------------------------------------------------------

Old:
----
  osconfig-20260615.01.tar.gz

New:
----
  osconfig-20260624.01.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ google-osconfig-agent.spec ++++++
--- /var/tmp/diff_new_pack.WDbTT6/_old  2026-06-27 18:06:27.608708142 +0200
+++ /var/tmp/diff_new_pack.WDbTT6/_new  2026-06-27 18:06:27.616708412 +0200
@@ -19,7 +19,7 @@
 %define shortname osconfig
 
 Name:           google-osconfig-agent
-Version:        20260615.01
+Version:        20260624.01
 Release:        0
 Summary:        Google Cloud Guest Agent
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.WDbTT6/_old  2026-06-27 18:06:27.656709763 +0200
+++ /var/tmp/diff_new_pack.WDbTT6/_new  2026-06-27 18:06:27.660709899 +0200
@@ -3,8 +3,8 @@
     <param name="url">https://github.com/GoogleCloudPlatform/osconfig</param>
     <param name="scm">git</param>
     <param name="exclude">.git</param>
-    <param name="versionformat">20260615.01</param>
-    <param name="revision">20260615.01</param>
+    <param name="versionformat">20260624.01</param>
+    <param name="revision">20260624.01</param>
     <param name="changesgenerate">enable</param>
   </service>
   <service name="recompress" mode="disabled">
@@ -15,7 +15,7 @@
     <param name="basename">osconfig</param>
   </service>
   <service name="go_modules" mode="disabled">
-    <param name="archive">osconfig-20260615.01.tar.gz</param>
+    <param name="archive">osconfig-20260624.01.tar.gz</param>
   </service>
 </services>
 

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.WDbTT6/_old  2026-06-27 18:06:27.684710709 +0200
+++ /var/tmp/diff_new_pack.WDbTT6/_new  2026-06-27 18:06:27.688710844 +0200
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/GoogleCloudPlatform/osconfig</param>
-              <param 
name="changesrevision">5b74d2e70f06700a7a5b1901efd6f602d6ad0b84</param></service></servicedata>
+              <param 
name="changesrevision">ba0531cd3c14cb3fee9b40bde6ce8203c3abade3</param></service></servicedata>
 (No newline at EOF)
 

++++++ osconfig-20260615.01.tar.gz -> osconfig-20260624.01.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osconfig-20260615.01/agentendpoint/agentendpoint_beta.go 
new/osconfig-20260624.01/agentendpoint/agentendpoint_beta.go
--- old/osconfig-20260615.01/agentendpoint/agentendpoint_beta.go        
2026-06-15 22:34:32.000000000 +0200
+++ new/osconfig-20260624.01/agentendpoint/agentendpoint_beta.go        
2026-06-24 17:10:57.000000000 +0200
@@ -26,6 +26,7 @@
        "github.com/GoogleCloudPlatform/osconfig/osinfo"
        "github.com/GoogleCloudPlatform/osconfig/pretty"
        "github.com/GoogleCloudPlatform/osconfig/retryutil"
+       "github.com/googleapis/gax-go/v2"
        "google.golang.org/api/option"
        "google.golang.org/grpc"
        "google.golang.org/grpc/credentials"
@@ -33,9 +34,14 @@
        "cloud.google.com/go/osconfig/agentendpoint/apiv1beta/agentendpointpb"
 )
 
+type agentEndpointBetaClient interface {
+       LookupEffectiveGuestPolicy(context.Context, 
*agentendpointpb.LookupEffectiveGuestPolicyRequest, ...gax.CallOption) 
(*agentendpointpb.EffectiveGuestPolicy, error)
+       Close() error
+}
+
 // BetaClient is a an agentendpoint client.
 type BetaClient struct {
-       raw    *agentendpoint.Client
+       raw    agentEndpointBetaClient
        cancel context.CancelFunc
        noti   chan struct{}
        closed bool
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osconfig-20260615.01/agentendpoint/agentendpoint_beta_test.go 
new/osconfig-20260624.01/agentendpoint/agentendpoint_beta_test.go
--- old/osconfig-20260615.01/agentendpoint/agentendpoint_beta_test.go   
1970-01-01 01:00:00.000000000 +0100
+++ new/osconfig-20260624.01/agentendpoint/agentendpoint_beta_test.go   
2026-06-24 17:10:57.000000000 +0200
@@ -0,0 +1,90 @@
+//  Copyright 2026 Google Inc. All Rights Reserved.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+
+package agentendpoint
+
+import (
+       "errors"
+       "fmt"
+       "testing"
+
+       "cloud.google.com/go/osconfig/agentendpoint/apiv1beta/agentendpointpb"
+       utilmocks "github.com/GoogleCloudPlatform/osconfig/util/mocks"
+       "github.com/GoogleCloudPlatform/osconfig/util/utiltest"
+       "github.com/golang/mock/gomock"
+)
+
+func TestBetaClientClose(t *testing.T) {
+       ctrl := gomock.NewController(t)
+       defer ctrl.Finish()
+
+       mockClient := utilmocks.NewMockAgentEndpointBetaClient(ctrl)
+       client := &BetaClient{raw: mockClient, noti: make(chan struct{}, 1)}
+
+       if client.Closed() {
+               t.Errorf("Closed() = true, want false")
+       }
+
+       mockClient.EXPECT().Close().Return(nil)
+
+       if err := client.Close(); err != nil {
+               t.Errorf("Close() returned unexpected error: %v", err)
+       }
+
+       if !client.Closed() {
+               t.Errorf("Closed() = false, want true")
+       }
+}
+
+func TestLookupEffectiveGuestPolicies(t *testing.T) {
+       ctx := t.Context()
+       ctrl := gomock.NewController(t)
+       defer ctrl.Finish()
+
+       mockClient := utilmocks.NewMockAgentEndpointBetaClient(ctrl)
+       client := &BetaClient{raw: mockClient, noti: make(chan struct{}, 1)}
+
+       tests := []struct {
+               name       string
+               setup      func(*testing.T)
+               wantPolicy *agentendpointpb.EffectiveGuestPolicy
+               wantErr    error
+       }{
+               {
+                       name: "successful server response, expect non-nil 
policy",
+                       setup: func(t *testing.T) {
+                               
mockClient.EXPECT().LookupEffectiveGuestPolicy(gomock.Any(), 
gomock.Any()).Return(&agentendpointpb.EffectiveGuestPolicy{}, nil)
+                       },
+                       wantPolicy: &agentendpointpb.EffectiveGuestPolicy{},
+                       wantErr:    nil,
+               },
+               {
+                       name: "server returns error, expect error",
+                       setup: func(t *testing.T) {
+                               
mockClient.EXPECT().LookupEffectiveGuestPolicy(gomock.Any(), 
gomock.Any()).Return(nil, errors.New("mock error"))
+                       },
+                       wantErr: fmt.Errorf("error calling 
LookupEffectiveGuestPolicies: %w", errors.New("mock error")),
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       tt.setup(t)
+
+                       gotPolicy, gotErr := 
client.LookupEffectiveGuestPolicies(ctx)
+                       utiltest.AssertErrorMatch(t, gotErr, tt.wantErr)
+                       utiltest.AssertEquals(t, gotPolicy, tt.wantPolicy)
+               })
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osconfig-20260615.01/agentendpoint/agentendpoint_test.go 
new/osconfig-20260624.01/agentendpoint/agentendpoint_test.go
--- old/osconfig-20260615.01/agentendpoint/agentendpoint_test.go        
2026-06-15 22:34:32.000000000 +0200
+++ new/osconfig-20260624.01/agentendpoint/agentendpoint_test.go        
2026-06-24 17:10:57.000000000 +0200
@@ -334,8 +334,6 @@
        defer os.RemoveAll(td)
        taskStateFile = filepath.Join(td, "testState")
 
-       srv.streamSend <- struct{}{}
-
        // No state.
        if err := tc.client.loadTaskFromState(ctx); err != nil {
                t.Error(err)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osconfig-20260615.01/agentendpoint/task_state_test.go 
new/osconfig-20260624.01/agentendpoint/task_state_test.go
--- old/osconfig-20260615.01/agentendpoint/task_state_test.go   2026-06-15 
22:34:32.000000000 +0200
+++ new/osconfig-20260624.01/agentendpoint/task_state_test.go   2026-06-24 
17:10:57.000000000 +0200
@@ -15,16 +15,23 @@
 package agentendpoint
 
 import (
+       "encoding/json"
+       "errors"
+       "io/fs"
        "io/ioutil"
        "os"
        "path/filepath"
+       "reflect"
+       "syscall"
        "testing"
+       "time"
 
        "github.com/google/go-cmp/cmp"
        "github.com/google/go-cmp/cmp/cmpopts"
        "google.golang.org/protobuf/testing/protocmp"
 
        "cloud.google.com/go/osconfig/agentendpoint/apiv1/agentendpointpb"
+       "github.com/GoogleCloudPlatform/osconfig/util/utiltest"
 )
 
 var (
@@ -63,33 +70,53 @@
        // We don't test execTask as reboots during that task type is not 
supported.
        var tests = []struct {
                name    string
-               state   []byte
-               wantErr bool
+               setup   func(t *testing.T) string
+               wantErr error
                want    *taskState
        }{
                {
-                       "BlankState",
-                       []byte("{}"),
-                       false,
-                       &taskState{},
+                       name: "empty json, want blank state",
+                       setup: func(t *testing.T) string {
+                               if err := ioutil.WriteFile(testState, 
[]byte("{}"), 0600); err != nil {
+                                       t.Fatalf("error writing state: %v", err)
+                               }
+                               return testState
+                       },
+                       wantErr: nil,
+                       want:    &taskState{},
                },
                {
-                       "BadState",
-                       []byte("foo"),
-                       true,
-                       &taskState{},
+                       name: "invalid json, want json syntax error",
+                       setup: func(t *testing.T) string {
+                               if err := ioutil.WriteFile(testState, 
[]byte("foo"), 0600); err != nil {
+                                       t.Fatalf("error writing state: %v", err)
+                               }
+                               return testState
+                       },
+                       wantErr: json.Unmarshal([]byte("foo"), &taskState{}),
+                       want:    &taskState{},
                },
                {
-                       "PatchTask",
-                       []byte(testPatchTaskStateString),
-                       false,
-                       testPatchTaskState,
+                       name: "valid patch task json, want patch task state",
+                       setup: func(t *testing.T) string {
+                               if err := ioutil.WriteFile(testState, 
[]byte(testPatchTaskStateString), 0600); err != nil {
+                                       t.Fatalf("error writing state: %v", err)
+                               }
+                               return testState
+                       },
+                       wantErr: nil,
+                       want:    testPatchTaskState,
                },
                {
-                       "IgnoresOldRebootFieldName",
-                       
[]byte("{\"PatchTask\":{\"Task\":{},\"RebootCount\":1}}"),
-                       false,
-                       &taskState{
+                       name: "json with old reboot field, want state with zero 
reboot counts",
+                       setup: func(t *testing.T) string {
+                               if err := ioutil.WriteFile(testState, 
[]byte("{\"PatchTask\":{\"Task\":{},\"RebootCount\":1}}"), 0600); err != nil {
+                                       t.Fatalf("error writing state: %v", err)
+                               }
+                               return testState
+                       },
+                       wantErr: nil,
+                       want: &taskState{
                                PatchTask: &patchTask{
                                        Task: &applyPatchesTask{
                                                
&agentendpointpb.ApplyPatchesTask{},
@@ -99,20 +126,20 @@
                                },
                        },
                },
+               {
+                       name: "directory path, want path error",
+                       setup: func(t *testing.T) string {
+                               return td
+                       },
+                       wantErr: &fs.PathError{Op: "read", Path: td, Err: 
syscall.EISDIR},
+                       want:    nil,
+               },
        }
        for _, tt := range tests {
                t.Run(tt.name, func(t *testing.T) {
-                       if err := ioutil.WriteFile(testState, tt.state, 0600); 
err != nil {
-                               t.Fatalf("error writing state: %v", err)
-                       }
-
-                       st, err := loadState(testState)
-                       if err != nil && !tt.wantErr {
-                               t.Fatalf("unexpected error: %v", err)
-                       }
-                       if err == nil && tt.wantErr {
-                               t.Fatalf("expected error")
-                       }
+                       path := tt.setup(t)
+                       st, err := loadState(path)
+                       utiltest.AssertErrorMatch(t, err, tt.wantErr)
 
                        if diff := cmp.Diff(tt.want, st, 
cmpopts.IgnoreUnexported(patchTask{}), protocmp.Transform()); diff != "" {
                                t.Errorf("State does not match expectation: 
(-got +want)\n%s", diff)
@@ -145,55 +172,71 @@
 }
 
 func TestStateSave(t *testing.T) {
-       td, err := ioutil.TempDir(os.TempDir(), "")
-       if err != nil {
-               t.Fatalf("error creating temp dir: %v", err)
-       }
-       defer os.RemoveAll(td)
+       td := t.TempDir()
        testState := filepath.Join(td, "testState")
+       invalidDir := utiltest.WriteToTempFileMust(t, "invalidDir", []byte(""))
+       invalidPath := filepath.Join(invalidDir, "testState")
 
        var tests = []struct {
-               desc  string
-               state *taskState
-               want  string
+               desc    string
+               state   *taskState
+               path    string
+               want    string
+               wantErr error
        }{
                {
-                       "NilState",
-                       nil,
-                       "{}",
+                       desc:    "nil state, expect empty json",
+                       state:   nil,
+                       path:    testState,
+                       want:    "{}",
+                       wantErr: nil,
+               },
+               {
+                       desc:    "blank state, expect empty json",
+                       state:   &taskState{},
+                       path:    testState,
+                       want:    "{}",
+                       wantErr: nil,
                },
                {
-                       "BlankState",
-                       &taskState{},
-                       "{}",
+                       desc:    "patch task state, expect serialized patch 
task json",
+                       state:   testPatchTaskState,
+                       path:    testState,
+                       want:    testPatchTaskStateString,
+                       wantErr: nil,
                },
                {
-                       "PatchTask",
-                       testPatchTaskState,
-                       testPatchTaskStateString,
+                       desc:    "exec task state, expect serialized exec task 
json",
+                       state:   &taskState{ExecTask: &execTask{TaskID: "foo"}},
+                       path:    testState,
+                       want:    
"{\"ExecTask\":{\"StartedAt\":\"0001-01-01T00:00:00Z\",\"Task\":null,\"TaskID\":\"foo\"}}",
+                       wantErr: nil,
                },
                {
-                       "ExecTask",
-                       &taskState{ExecTask: &execTask{TaskID: "foo"}},
-                       
"{\"ExecTask\":{\"StartedAt\":\"0001-01-01T00:00:00Z\",\"Task\":null,\"TaskID\":\"foo\"}}",
+                       desc:    "invalid directory path, expect path error",
+                       state:   &taskState{},
+                       path:    invalidPath,
+                       want:    "",
+                       wantErr: &fs.PathError{Op: "mkdir", Path: invalidDir, 
Err: errors.New("not a directory")},
+               },
+               {
+                       // time.Time.MarshalJSON only supports years between 0 
and 9999.
+                       desc: "invalid input for json, expect marshal error",
+                       state: &taskState{
+                               ExecTask: &execTask{StartedAt: time.Date(10000, 
1, 1, 0, 0, 0, 0, time.UTC)},
+                       },
+                       path:    testState,
+                       want:    "",
+                       wantErr: &json.MarshalerError{Type: 
reflect.TypeOf(time.Time{}), Err: errors.New("Time.MarshalJSON: year outside of 
range [0,9999]")},
                },
        }
        for _, tt := range tests {
-               err := tt.state.save(testState)
-               if err != nil {
-                       t.Errorf("%s: unexpected save error: %v", tt.desc, err)
-                       continue
-               }
-
-               got, err := ioutil.ReadFile(testState)
-               if err != nil {
-                       t.Errorf("%s: error reading state: %v", tt.desc, err)
-                       continue
-               }
-
-               if string(got) != tt.want {
-                       t.Errorf("%s:\ngot:\n%q\nwant:\n%q", tt.desc, got, 
tt.want)
-               }
+               t.Run(tt.desc, func(t *testing.T) {
+                       gotErr := tt.state.save(tt.path)
+
+                       utiltest.AssertErrorMatchAndSkip(t, gotErr, tt.wantErr)
+                       utiltest.AssertFileContents(t, tt.path, tt.want)
+               })
        }
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osconfig-20260615.01/clog/clog_test.go 
new/osconfig-20260624.01/clog/clog_test.go
--- old/osconfig-20260615.01/clog/clog_test.go  2026-06-15 22:34:32.000000000 
+0200
+++ new/osconfig-20260624.01/clog/clog_test.go  2026-06-24 17:10:57.000000000 
+0200
@@ -16,13 +16,19 @@
 
 import (
        "context"
+       "fmt"
+       "io"
        "testing"
 
+       "github.com/GoogleCloudPlatform/guest-logging-go/logger"
+       "github.com/GoogleCloudPlatform/osconfig/util/utiltest"
        "github.com/google/go-cmp/cmp"
+       "google.golang.org/protobuf/proto"
+       "google.golang.org/protobuf/types/known/wrapperspb"
 )
 
 func TestWithLabels(t *testing.T) {
-       ctx := context.Background()
+       ctx := t.Context()
 
        tests := []struct {
                name   string
@@ -44,3 +50,126 @@
                })
        }
 }
+
+type testWriter struct {
+       logs string
+}
+
+func (w *testWriter) Write(p []byte) (n int, err error) {
+       w.logs = string(p)
+       return len(p), nil
+}
+
+// Initializes logger and returns testWriter
+func initTestLogger(ctx context.Context, t *testing.T) *testWriter {
+       t.Helper()
+       tw := &testWriter{}
+       err := logger.Init(ctx, logger.LogOpts{
+               LoggerName:          "test-logger",
+               Writers:             []io.Writer{tw},
+               DisableCloudLogging: true,
+               DisableLocalLogging: true,
+               Debug:               true,
+               FormatFunction: func(e logger.LogEntry) string {
+                       return fmt.Sprintf("[%s] %s", e.Severity, e.Message)
+               },
+       })
+       if err != nil {
+               t.Fatalf("logger.Init error: %v", err)
+       }
+       return tw
+}
+
+func TestDebugRPC(t *testing.T) {
+       utiltest.OverrideVariable(t, &DebugEnabled, true)
+       ctx := t.Context()
+       tw := initTestLogger(ctx, t)
+       req := wrapperspb.String("req message")
+       resp := wrapperspb.String("resp message")
+
+       tests := []struct {
+               name string
+               req  proto.Message
+               resp proto.Message
+               want string
+       }{
+               {
+                       name: "ReqAndRespMethod",
+                       req:  req,
+                       resp: resp,
+                       want: `(?s)^\[Debug\] Called: ReqAndRespMethod with 
request:.*"req message".*\nresponse:\n.*"resp message".*`,
+               },
+               {
+                       name: "RespOnlyMethod",
+                       req:  nil,
+                       resp: resp,
+                       want: `(?s)^\[Debug\] Called: RespOnlyMethod with 
response:\n.*"resp message".*`,
+               },
+               {
+                       name: "ReqOnlyMethod",
+                       req:  req,
+                       resp: nil,
+                       want: `(?s)^\[Debug\] Calling: ReqOnlyMethod with 
request:\n.*"req message".*`,
+               },
+               {
+                       name: "NoReqNoRespMethod",
+                       req:  nil,
+                       resp: nil,
+                       want: `^$`,
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       tw.logs = ""
+                       DebugRPC(ctx, tt.name, tt.req, tt.resp)
+                       utiltest.AssertFormatMatch(t, tw.logs, tt.want)
+               })
+       }
+}
+
+func TestLoggingFunctions(t *testing.T) {
+       ctx := t.Context()
+       tw := initTestLogger(ctx, t)
+       tests := []struct {
+               name    string
+               logFunc func(ctx context.Context)
+               want    string
+       }{
+               {
+                       name:    "Debugf",
+                       logFunc: func(ctx context.Context) { Debugf(ctx, "test 
debug %s", "msg") },
+                       want:    "[Debug] test debug msg\n",
+               },
+               {
+                       name:    "Infof",
+                       logFunc: func(ctx context.Context) { Infof(ctx, "test 
info %s", "msg") },
+                       want:    "[Info] test info msg\n",
+               },
+               {
+                       name:    "Warningf",
+                       logFunc: func(ctx context.Context) { Warningf(ctx, 
"test warn %s", "msg") },
+                       want:    "[Warning] test warn msg\n",
+               },
+               {
+                       name:    "Errorf",
+                       logFunc: func(ctx context.Context) { Errorf(ctx, "test 
error %s", "msg") },
+                       want:    "[Error] test error msg\n",
+               },
+               {
+                       name: "DebugStructured",
+                       logFunc: func(ctx context.Context) {
+                               DebugStructured(ctx, map[string]string{"key": 
"value"}, "test structured %s", "msg")
+                       },
+                       want: "[Debug] test structured msg\n",
+               },
+       }
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       tw.logs = ""
+                       tt.logFunc(ctx)
+                       utiltest.AssertEquals(t, tw.logs, tt.want)
+               })
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osconfig-20260615.01/e2e_tests/utils/utils.go 
new/osconfig-20260624.01/e2e_tests/utils/utils.go
--- old/osconfig-20260615.01/e2e_tests/utils/utils.go   2026-06-15 
22:34:32.000000000 +0200
+++ new/osconfig-20260624.01/e2e_tests/utils/utils.go   2026-06-24 
17:10:57.000000000 +0200
@@ -391,7 +391,6 @@
 var HeadEL8Images = map[string]string{
        "rhel-cloud/rhel-8": "projects/rhel-cloud/global/images/family/rhel-8",
 
-       "rhel-sap-cloud/rhel-8-6-sap":  
"projects/rhel-sap-cloud/global/images/family/rhel-8-6-sap-ha",
        "rhel-sap-cloud/rhel-8-8-sap":  
"projects/rhel-sap-cloud/global/images/family/rhel-8-8-sap-ha",
        "rhel-sap-cloud/rhel-8-10-sap": 
"projects/rhel-sap-cloud/global/images/family/rhel-8-10-sap-ha",
 
@@ -410,8 +409,9 @@
 
        "rhel-cloud/rhel-9": "projects/rhel-cloud/global/images/family/rhel-9",
 
-       "rhel-sap-cloud/rhel-9-0-sap": 
"projects/rhel-sap-cloud/global/images/family/rhel-9-0-sap-ha",
        "rhel-sap-cloud/rhel-9-2-sap": 
"projects/rhel-sap-cloud/global/images/family/rhel-9-2-sap-ha",
+       "rhel-sap-cloud/rhel-9-4-sap": 
"projects/rhel-sap-cloud/global/images/family/rhel-9-4-sap-ha",
+       "rhel-sap-cloud/rhel-9-6-sap": 
"projects/rhel-sap-cloud/global/images/family/rhel-9-6-sap-ha",
 
        "rocky-linux-cloud/rocky-linux-9":               
"projects/rocky-linux-cloud/global/images/family/rocky-linux-9",
        "rocky-linux-cloud/rocky-linux-9-optimized-gcp": 
"projects/rocky-linux-cloud/global/images/family/rocky-linux-9-optimized-gcp",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osconfig-20260615.01/go.mod 
new/osconfig-20260624.01/go.mod
--- old/osconfig-20260615.01/go.mod     2026-06-15 22:34:32.000000000 +0200
+++ new/osconfig-20260624.01/go.mod     2026-06-24 17:10:57.000000000 +0200
@@ -63,7 +63,7 @@
        github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5 // indirect
        github.com/compose-spec/compose-go/v2 v2.8.1 // indirect
        github.com/containerd/cgroups/v3 v3.1.2 // indirect
-       github.com/containerd/containerd v1.7.32 // indirect
+       github.com/containerd/containerd v1.7.33 // indirect
        github.com/containerd/containerd/api v1.10.0 // indirect
        github.com/containerd/continuity v0.4.5 // indirect
        github.com/containerd/errdefs v1.0.0 // indirect
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osconfig-20260615.01/go.sum 
new/osconfig-20260624.01/go.sum
--- old/osconfig-20260615.01/go.sum     2026-06-15 22:34:32.000000000 +0200
+++ new/osconfig-20260624.01/go.sum     2026-06-24 17:10:57.000000000 +0200
@@ -141,8 +141,8 @@
 github.com/compose-spec/compose-go/v2 v2.8.1/go.mod 
h1:veko/VB7URrg/tKz3vmIAQDaz+CGiXH8vZsW79NmAww=
 github.com/containerd/cgroups/v3 v3.1.2 
h1:OSosXMtkhI6Qove637tg1XgK4q+DhR0mX8Wi8EhrHa4=
 github.com/containerd/cgroups/v3 v3.1.2/go.mod 
h1:PKZ2AcWmSBsY/tJUVhtS/rluX0b1uq1GmPO1ElCmbOw=
-github.com/containerd/containerd v1.7.32 
h1:S54xuVcPxeLaYgaRABtpJ2VyVUVsy0IGf7qHBs+sbY8=
-github.com/containerd/containerd v1.7.32/go.mod 
h1:jdwD6s/BhV4XVJGrvtziNPVA+83n66TwptVaPKprq4E=
+github.com/containerd/containerd v1.7.33 
h1:iAkYGC/ifR/V+0eR4iXWHNGYUF0DF2PmGV5iz4Irj5M=
+github.com/containerd/containerd v1.7.33/go.mod 
h1:gSbSCVjPCdkfJCjyrzz7aRC+xFlqVbatNpfHfVCYGUM=
 github.com/containerd/containerd/api v1.10.0 
h1:5n0oHYVBwN4VhoX9fFykCV9dF1/BvAXeg2F8W6UYq1o=
 github.com/containerd/containerd/api v1.10.0/go.mod 
h1:NBm1OAk8ZL+LG8R0ceObGxT5hbUYj7CzTmR3xh0DlMM=
 github.com/containerd/continuity v0.4.5 
h1:ZRoN1sXq9u7V6QoHMcVWGhOwDFqZ4B9i5H6un1Wh0x4=
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osconfig-20260615.01/ospatch/yum_update.go 
new/osconfig-20260624.01/ospatch/yum_update.go
--- old/osconfig-20260615.01/ospatch/yum_update.go      2026-06-15 
22:34:32.000000000 +0200
+++ new/osconfig-20260624.01/ospatch/yum_update.go      2026-06-24 
17:10:57.000000000 +0200
@@ -131,7 +131,7 @@
 
        logOps(ctx, ops)
 
-       err = packages.InstallYumPackages(ctx, pkgNames)
+       err = packages.UpdateYumPackages(ctx, pkgNames)
        if err == nil {
                logSuccess(ctx, ops)
        } else {
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osconfig-20260615.01/ospatch/yum_update_test.go 
new/osconfig-20260624.01/ospatch/yum_update_test.go
--- old/osconfig-20260615.01/ospatch/yum_update_test.go 2026-06-15 
22:34:32.000000000 +0200
+++ new/osconfig-20260624.01/ospatch/yum_update_test.go 2026-06-24 
17:10:57.000000000 +0200
@@ -44,7 +44,7 @@
        packages.SetCommandRunner(mockCommandRunner)
        checkUpdateCall := mockCommandRunner.EXPECT().Run(ctx, 
utilmocks.EqCmd(exec.Command("/usr/bin/yum", []string{"check-update", 
"--assumeyes"}...))).Return([]byte("stdout"), []byte("stderr"), 
errExit100).Times(1)
        // yum install call to install package
-       mockCommandRunner.EXPECT().Run(ctx, 
utilmocks.EqCmd(exec.Command("/usr/bin/yum", []string{"install", "--assumeyes", 
"foo.noarch"}...))).After(checkUpdateCall).Return([]byte("stdout"), 
[]byte("stderr"), nil).Times(1)
+       mockCommandRunner.EXPECT().Run(ctx, 
utilmocks.EqCmd(exec.Command("/usr/bin/yum", []string{"update", "--assumeyes", 
"foo.noarch"}...))).After(checkUpdateCall).Return([]byte("stdout"), 
[]byte("stderr"), nil).Times(1)
 
        packages.SetPtyCommandRunner(mockCommandRunner)
        mockCommandRunner.EXPECT().Run(ctx, 
utilmocks.EqCmd(exec.Command("/usr/bin/yum", []string{"update", "--assumeno", 
"--color=never", "--security"}...))).Return(data, []byte("stderr"), 
nil).Times(1)
@@ -81,7 +81,7 @@
        packages.SetCommandRunner(mockCommandRunner)
        checkUpdateCall := mockCommandRunner.EXPECT().Run(ctx, 
utilmocks.EqCmd(exec.Command("/usr/bin/yum", []string{"check-update", 
"--assumeyes"}...))).Return([]byte("stdout"), []byte("stderr"), 
errExit100).Times(1)
        // yum install call to install package, make sure only 2 packages are 
installed.
-       mockCommandRunner.EXPECT().Run(ctx, 
utilmocks.EqCmd(exec.Command("/usr/bin/yum", []string{"install", "--assumeyes", 
"foo.noarch", 
"bar.x86_64"}...))).After(checkUpdateCall).Return([]byte("stdout"), 
[]byte("stderr"), nil).Times(1)
+       mockCommandRunner.EXPECT().Run(ctx, 
utilmocks.EqCmd(exec.Command("/usr/bin/yum", []string{"update", "--assumeyes", 
"foo.noarch", 
"bar.x86_64"}...))).After(checkUpdateCall).Return([]byte("stdout"), 
[]byte("stderr"), nil).Times(1)
 
        packages.SetPtyCommandRunner(mockCommandRunner)
        mockCommandRunner.EXPECT().Run(ctx, 
utilmocks.EqCmd(exec.Command("/usr/bin/yum", []string{"update", "--assumeno", 
"--color=never", "--security"}...))).Return(data, []byte("stderr"), 
nil).Times(1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osconfig-20260615.01/packages/yum.go 
new/osconfig-20260624.01/packages/yum.go
--- old/osconfig-20260615.01/packages/yum.go    2026-06-15 22:34:32.000000000 
+0200
+++ new/osconfig-20260624.01/packages/yum.go    2026-06-24 17:10:57.000000000 
+0200
@@ -34,6 +34,7 @@
 
        yumInstallArgs           = []string{"install", "--assumeyes"}
        yumRemoveArgs            = []string{"remove", "--assumeyes"}
+       yumUpdateArgs            = []string{"update", "--assumeyes"}
        yumCheckUpdateArgs       = []string{"check-update", "--assumeyes"}
        yumListUpdatesArgs       = []string{"update", "--assumeno", 
"--color=never"}
        yumListUpdateMinimalArgs = []string{"update-minimal", "--assumeno", 
"--color=never"}
@@ -76,6 +77,12 @@
        return err
 }
 
+// UpdateYumPackages updates yum packages.
+func UpdateYumPackages(ctx context.Context, pkgs []string) error {
+       _, err := run(ctx, yum, append(yumUpdateArgs, pkgs...))
+       return err
+}
+
 // RemoveYumPackages removes yum packages.
 func RemoveYumPackages(ctx context.Context, pkgs []string) error {
        _, err := run(ctx, yum, append(yumRemoveArgs, pkgs...))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osconfig-20260615.01/packages/yum_test.go 
new/osconfig-20260624.01/packages/yum_test.go
--- old/osconfig-20260615.01/packages/yum_test.go       2026-06-15 
22:34:32.000000000 +0200
+++ new/osconfig-20260624.01/packages/yum_test.go       2026-06-24 
17:10:57.000000000 +0200
@@ -45,6 +45,25 @@
        }
 }
 
+func TestUpdateYumPackages(t *testing.T) {
+       mockCtrl := gomock.NewController(t)
+       defer mockCtrl.Finish()
+
+       mockCommandRunner := utilmocks.NewMockCommandRunner(mockCtrl)
+       runner = mockCommandRunner
+       expectedCmd := utilmocks.EqCmd(exec.Command(yum, append(yumUpdateArgs, 
pkgs...)...))
+
+       mockCommandRunner.EXPECT().Run(testCtx, 
expectedCmd).Return([]byte("stdout"), []byte("stderr"), nil).Times(1)
+       if err := UpdateYumPackages(testCtx, pkgs); err != nil {
+               t.Errorf("unexpected error: %v", err)
+       }
+
+       mockCommandRunner.EXPECT().Run(testCtx, 
expectedCmd).Return([]byte("stdout"), []byte("stderr"), errors.New("could not 
update")).Times(1)
+       if err := UpdateYumPackages(testCtx, pkgs); err == nil {
+               t.Errorf("did not get expected error")
+       }
+}
+
 func TestRemoveYum(t *testing.T) {
        ctx := context.Background()
        mockCtrl := gomock.NewController(t)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osconfig-20260615.01/policies/apt_test.go 
new/osconfig-20260624.01/policies/apt_test.go
--- old/osconfig-20260615.01/policies/apt_test.go       2026-06-15 
22:34:32.000000000 +0200
+++ new/osconfig-20260624.01/policies/apt_test.go       2026-06-24 
17:10:57.000000000 +0200
@@ -15,140 +15,307 @@
 package policies
 
 import (
+       "bytes"
        "context"
        "errors"
-       "fmt"
-       "io/ioutil"
-       "os"
+       "io"
+       "net/http"
+       "net/http/httptest"
+       "net/url"
        "os/exec"
        "path/filepath"
-       "strings"
        "testing"
 
        "cloud.google.com/go/osconfig/agentendpoint/apiv1beta/agentendpointpb"
+       "github.com/GoogleCloudPlatform/guest-logging-go/logger"
        "github.com/GoogleCloudPlatform/osconfig/osinfo"
        "github.com/GoogleCloudPlatform/osconfig/packages"
        utilmocks "github.com/GoogleCloudPlatform/osconfig/util/mocks"
        "github.com/GoogleCloudPlatform/osconfig/util/utiltest"
        "github.com/golang/mock/gomock"
        "golang.org/x/crypto/openpgp"
+       "golang.org/x/crypto/openpgp/armor"
+       openpgp_errors "golang.org/x/crypto/openpgp/errors"
        "golang.org/x/crypto/openpgp/packet"
 )
 
-func runAptRepositories(ctx context.Context, repos 
[]*agentendpointpb.AptRepository) (string, error) {
-       td, err := ioutil.TempDir(os.TempDir(), "")
+func createTestGPGKey(t *testing.T) []byte {
+       t.Helper()
+       entity, err := openpgp.NewEntity("test", "test", "[email protected]", nil)
        if err != nil {
-               return "", fmt.Errorf("error creating temp dir: %v", err)
+               t.Fatal(err)
        }
-       defer os.RemoveAll(td)
-       testRepo := filepath.Join(td, "testRepo")
-
-       if err := aptRepositories(ctx, repos, testRepo); err != nil {
-               return "", fmt.Errorf("error running aptRepositories: %v", err)
+       var buf bytes.Buffer
+       if err := entity.Serialize(&buf); err != nil {
+               t.Fatal(err)
        }
+       return buf.Bytes()
+}
 
-       data, err := ioutil.ReadFile(testRepo)
+// createTestArmoredGPGKey generates a valid armored GPG key for testing.
+func createTestArmoredGPGKey(t *testing.T) []byte {
+       t.Helper()
+       entity, err := openpgp.NewEntity("test", "test", "[email protected]", nil)
        if err != nil {
-               return "", fmt.Errorf("error reading testRepo: %v", err)
+               t.Fatal(err)
+       }
+       var buf bytes.Buffer
+       w, err := armor.Encode(&buf, openpgp.PublicKeyType, nil)
+       if err != nil {
+               t.Fatal(err)
        }
+       if err := entity.Serialize(w); err != nil {
+               t.Fatal(err)
+       }
+       w.Close()
+       return buf.Bytes()
+}
+
+// setupAptRepositoriesTest sets up a test server and a test repository path.
+func setupAptRepositoriesTest(t *testing.T) (string, string) {
+       t.Helper()
+       validKey := createTestGPGKey(t)
+       srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, 
r *http.Request) {
+               switch r.URL.Path {
+               case "/valid-key":
+                       w.Write(validKey)
+               default:
+                       w.Write([]byte("fake-gpg-key"))
+               }
+       }))
+       t.Cleanup(srv.Close)
 
-       return string(data), nil
+       td := t.TempDir()
+       testRepo := filepath.Join(td, "testRepo")
+
+       return srv.URL, testRepo
 }
 
+// TestAptRepositories tests the adding of apt repository files.
 func TestAptRepositories(t *testing.T) {
-       debian10 := func() (string, string, string) {
-               return "debian", "Debian", "10"
-       }
-
-       debian12 := func() (string, string, string) {
-               return "debian", "Debian", "12"
-       }
+       ctx := context.Background()
+       srvURL, testRepo := setupAptRepositoriesTest(t)
 
        tests := []struct {
-               name                   string
-               repos                  []*agentendpointpb.AptRepository
-               nameAndVersionProvider func() (string, string, string)
-               want                   string
+               name           string
+               repos          []*agentendpointpb.AptRepository
+               provider       osinfo.Provider
+               repoFile       string
+               wantRepo       string
+               wantLogsRegexp string
        }{
                {
-                       name:                   "No repositories",
-                       nameAndVersionProvider: debian10,
-                       repos:                  
[]*agentendpointpb.AptRepository{},
-                       want:                   "# Repo file managed by Google 
OSConfig agent\n"},
+                       name: "no repositories, want header only",
+                       provider: stubOsInfoProvider{nameVersionProvider: 
func() (string, string, string) {
+                               return "debian", "Debian", "10"
+                       }},
+                       repos:          []*agentendpointpb.AptRepository{},
+                       wantRepo:       "# Repo file managed by Google OSConfig 
agent\n",
+                       wantLogsRegexp: "",
+               },
                {
-                       name:                   "1 repositoy, Debian 10",
-                       nameAndVersionProvider: debian10,
+                       name: "single deb repo on debian 10, want repo line 
without signed-by",
+                       provider: stubOsInfoProvider{nameVersionProvider: 
func() (string, string, string) {
+                               return "debian", "Debian", "10"
+                       }},
                        repos: []*agentendpointpb.AptRepository{
                                {Uri: "http://repo1-url/";, Distribution: 
"distribution", Components: []string{"component1"}},
                        },
-                       want: "# Repo file managed by Google OSConfig 
agent\n\ndeb http://repo1-url/ distribution component1\n",
+                       wantRepo:       "# Repo file managed by Google OSConfig 
agent\n\ndeb http://repo1-url/ distribution component1\n",
+                       wantLogsRegexp: "",
                },
                {
-                       name:                   "1 repositoy, Debian 12",
-                       nameAndVersionProvider: debian12,
+                       name: "single deb repo on debian 12, want repo line 
with signed-by",
+                       provider: stubOsInfoProvider{nameVersionProvider: 
func() (string, string, string) {
+                               return "debian", "Debian", "12"
+                       }},
                        repos: []*agentendpointpb.AptRepository{
                                {Uri: "http://repo1-url/";, Distribution: 
"distribution", Components: []string{"component1"}},
                        },
-                       want: "# Repo file managed by Google OSConfig 
agent\n\ndeb [signed-by=/etc/apt/trusted.gpg.d/osconfig_agent_managed.gpg] 
http://repo1-url/ distribution component1\n",
+                       wantRepo:       "# Repo file managed by Google OSConfig 
agent\n\ndeb [signed-by=/etc/apt/trusted.gpg.d/osconfig_agent_managed.gpg] 
http://repo1-url/ distribution component1\n",
+                       wantLogsRegexp: "",
+               },
+               {
+                       name: "unknown archive type, want default to deb",
+                       provider: stubOsInfoProvider{nameVersionProvider: 
func() (string, string, string) {
+                               return "debian", "Debian", "10"
+                       }},
+                       repos: []*agentendpointpb.AptRepository{
+                               {Uri: "http://repo";, Distribution: "dist", 
ArchiveType: agentendpointpb.AptRepository_ArchiveType(99)},
+                       },
+                       wantRepo:       "# Repo file managed by Google OSConfig 
agent\n\ndeb http://repo dist\n",
+                       wantLogsRegexp: "",
+               },
+               {
+                       name: "multiple repos and components, want multiple 
repo lines",
+                       provider: stubOsInfoProvider{nameVersionProvider: 
func() (string, string, string) {
+                               return "debian", "Debian", "10"
+                       }},
+                       repos: []*agentendpointpb.AptRepository{
+                               {Uri: "http://repo1";, Distribution: "dist1", 
Components: []string{"comp1"}, ArchiveType: 
agentendpointpb.AptRepository_DEB_SRC},
+                               {Uri: "http://repo2";, Distribution: "dist2", 
Components: []string{"comp1", "comp2"}},
+                       },
+                       wantRepo:       "# Repo file managed by Google OSConfig 
agent\n\ndeb-src http://repo1 dist1 comp1\n\ndeb http://repo2 dist2 comp1 
comp2\n",
+                       wantLogsRegexp: "",
                },
                {
-                       name:                   "2 repos, Debian 10",
-                       nameAndVersionProvider: debian10,
+                       name: "repo with valid gpg key, want repo line and gpg 
block coverage",
+                       provider: stubOsInfoProvider{nameVersionProvider: 
func() (string, string, string) {
+                               return "debian", "Debian", "10"
+                       }},
                        repos: []*agentendpointpb.AptRepository{
-                               {Uri: "http://repo1-url/";, Distribution: 
"distribution", Components: []string{"component1"}, ArchiveType: 
agentendpointpb.AptRepository_DEB_SRC},
-                               {Uri: "http://repo2-url/";, Distribution: 
"distribution", Components: []string{"component1", "component2"}, ArchiveType: 
agentendpointpb.AptRepository_DEB},
+                               {Uri: "http://repo";, Distribution: "dist", 
GpgKey: srvURL + "/valid-key"},
                        },
-                       want: "# Repo file managed by Google OSConfig 
agent\n\ndeb-src http://repo1-url/ distribution component1\n\ndeb 
http://repo2-url/ distribution component1 component2\n",
+                       wantRepo:       "# Repo file managed by Google OSConfig 
agent\n\ndeb http://repo dist\n",
+                       wantLogsRegexp: "",
                },
                {
-                       name:                   "2 repos, Debian 12",
-                       nameAndVersionProvider: debian12,
+                       name:     "osinfo error, want repo line without 
signed-by",
+                       provider: stubOsInfoProvider{err: errors.New("osinfo 
error")},
                        repos: []*agentendpointpb.AptRepository{
-                               {Uri: "http://repo1-url/";, Distribution: 
"distribution", Components: []string{"component1"}, ArchiveType: 
agentendpointpb.AptRepository_DEB_SRC},
-                               {Uri: "http://repo2-url/";, Distribution: 
"distribution", Components: []string{"component1", "component2"}, ArchiveType: 
agentendpointpb.AptRepository_DEB},
+                               {Uri: "http://repo1-url/";, Distribution: 
"distribution", Components: []string{"component1"}},
                        },
-                       want: "# Repo file managed by Google OSConfig 
agent\n\ndeb-src [signed-by=/etc/apt/trusted.gpg.d/osconfig_agent_managed.gpg] 
http://repo1-url/ distribution component1\n\ndeb 
[signed-by=/etc/apt/trusted.gpg.d/osconfig_agent_managed.gpg] http://repo2-url/ 
distribution component1 component2\n",
+                       wantRepo:       "# Repo file managed by Google OSConfig 
agent\n\ndeb http://repo1-url/ distribution component1\n",
+                       wantLogsRegexp: "",
+               },
+               {
+                       name: "invalid os version, want repo line without 
signed-by",
+                       provider: stubOsInfoProvider{nameVersionProvider: 
func() (string, string, string) {
+                               return "debian", "Debian", "invalid"
+                       }},
+                       repos: []*agentendpointpb.AptRepository{
+                               {Uri: "http://repo1-url/";, Distribution: 
"distribution", Components: []string{"component1"}},
+                       },
+                       wantRepo:       "# Repo file managed by Google OSConfig 
agent\n\ndeb http://repo1-url/ distribution component1\n",
+                       wantLogsRegexp: "",
+               },
+               {
+                       name: "gpg key fetch error, want error fetching gpg 
key",
+                       provider: stubOsInfoProvider{nameVersionProvider: 
func() (string, string, string) {
+                               return "debian", "Debian", "10"
+                       }},
+                       repos: []*agentendpointpb.AptRepository{
+                               {Uri: "http://repo";, Distribution: "dist", 
GpgKey: "http://invalid-url"},
+                       },
+                       wantRepo:       "# Repo file managed by Google OSConfig 
agent\n\ndeb http://repo dist\n",
+                       wantLogsRegexp: `.*Error fetching gpg key 
"http://invalid-url": Get "http://invalid-url": dial tcp: lookup invalid-url.*`,
+               },
+               {
+                       name: "invalid gpg key data, want error fetching gpg 
key",
+                       provider: stubOsInfoProvider{nameVersionProvider: 
func() (string, string, string) {
+                               return "debian", "Debian", "10"
+                       }},
+                       repos: []*agentendpointpb.AptRepository{
+                               {Uri: "http://repo";, Distribution: "dist", 
GpgKey: srvURL + "/invalid-key"},
+                       },
+                       wantRepo:       "# Repo file managed by Google OSConfig 
agent\n\ndeb http://repo dist\n",
+                       wantLogsRegexp: `.*Error fetching gpg key 
"http://127.0.0.1:.*/invalid-key": openpgp: invalid data: tag byte does not 
have MSB set.*`,
                },
        }
 
        for _, tt := range tests {
-               osInfoProviderActual := osInfoProvider
-               defer func() { osInfoProvider = osInfoProviderActual }()
-
-               osInfoStub := stubOsInfoProvider{nameVersionProvider: 
tt.nameAndVersionProvider}
-               osInfoProvider = osInfoStub
-
-               got, err := runAptRepositories(context.Background(), tt.repos)
-               if err != nil {
-                       t.Fatal(err)
-               }
+               t.Run(tt.name, func(t *testing.T) {
+                       var buf bytes.Buffer
+                       _ = logger.Init(ctx, logger.LogOpts{LoggerName: 
"trace_test", Debug: true, Writers: []io.Writer{&buf}})
+                       utiltest.OverrideVariable(t, &osInfoProvider, 
tt.provider)
+                       aptRepositories(ctx, tt.repos, testRepo)
+
+                       utiltest.AssertFileContents(t, testRepo, tt.wantRepo)
+                       utiltest.AssertFormatMatch(t, buf.String(), 
tt.wantLogsRegexp)
+               })
+       }
+}
 
-               if got != tt.want {
-                       t.Errorf("%s: got:\n%q\nwant:\n%q", tt.name, got, 
tt.want)
+// setupGetAptGPGKeyTest sets up a test server for GPG key retrieval tests.
+func setupGetAptGPGKeyTest(t *testing.T) string {
+       t.Helper()
+       validBinaryKey := createTestGPGKey(t)
+       validArmoredKey := createTestArmoredGPGKey(t)
+       srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, 
r *http.Request) {
+               switch r.URL.Path {
+               case "/valid_binary":
+                       w.Write(validBinaryKey)
+               case "/valid_armored":
+                       w.Write(validArmoredKey)
+               case "/large":
+                       w.Header().Set("Content-Length", "2000000")
+                       w.Write(make([]byte, 100))
+               case "/binary":
+                       w.Write([]byte{0x99, 0x01, 0x02})
+               case "/empty_armored":
+                       w.Write([]byte("-----BEGIN PGP PUBLIC KEY 
BLOCK-----\n\n-----END PGP PUBLIC KEY BLOCK-----"))
+               default:
+                       w.Write([]byte("invalid data"))
                }
-       }
+       }))
+       t.Cleanup(srv.Close)
+       return srv.URL
 }
 
+// TestGetAptGPGKey tests the retrieval and validation of apt GPG keys.
 func TestGetAptGPGKey(t *testing.T) {
-       key := "https://packages.cloud.google.com/apt/doc/apt-key.gpg";
+       srvURL := setupGetAptGPGKeyTest(t)
 
-       entityList, err := getAptGPGKey(key)
-       if err != nil {
-               t.Fatal(err)
-       }
-
-       // check if Artifact Regitry key exist or not
-       artifactRegistryKeyFound := false
-       for _, e := range entityList {
-               for key := range e.Identities {
-                       if strings.Contains(key, "Artifact Registry") {
-                               artifactRegistryKeyFound = true
-                       }
-               }
+       tests := []struct {
+               name     string
+               url      string
+               wantKeys int
+               wantErr  error
+       }{
+               {
+                       name:     "empty armored key, want nil error",
+                       url:      srvURL + "/empty_armored",
+                       wantKeys: 0,
+                       wantErr:  nil,
+               },
+               {
+                       name:     "valid binary key, want nil error",
+                       url:      srvURL + "/valid_binary",
+                       wantKeys: 1,
+                       wantErr:  nil,
+               },
+               {
+                       name:     "valid armored key, want nil error",
+                       url:      srvURL + "/valid_armored",
+                       wantKeys: 1,
+                       wantErr:  nil,
+               },
+               {
+                       name:     "invalid data, want invalid data error",
+                       url:      srvURL + "/invalid",
+                       wantKeys: 0,
+                       wantErr:  openpgp_errors.StructuralError("tag byte does 
not have MSB set"),
+               },
+               {
+                       name:     "invalid binary key, want unexpected EOF 
error",
+                       url:      srvURL + "/binary",
+                       wantKeys: 0,
+                       wantErr:  io.ErrUnexpectedEOF,
+               },
+               {
+                       name:     "large key, want too large error",
+                       url:      srvURL + "/large",
+                       wantKeys: 0,
+                       wantErr:  errors.New("key size of 2000000 too large"),
+               },
+               {
+                       name:     "invalid url, want parse error",
+                       url:      "http://invalid:url";,
+                       wantKeys: 0,
+                       wantErr: &url.Error{
+                               Op:  "parse",
+                               URL: "http://invalid:url";,
+                               Err: errors.New(`invalid port ":url" after 
host`),
+                       },
+               },
        }
 
-       if !artifactRegistryKeyFound {
-               t.Errorf("Expected to find Artifact Registry key in Google 
Cloud Public GPG key, but its missed.")
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       gotKeys, gotErr := getAptGPGKey(tt.url)
+                       utiltest.AssertErrorMatch(t, gotErr, tt.wantErr)
+                       utiltest.AssertEquals(t, len(gotKeys), tt.wantKeys)
+               })
        }
 }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osconfig-20260615.01/util/mocks/mock_agent_endpoint_beta_client.go 
new/osconfig-20260624.01/util/mocks/mock_agent_endpoint_beta_client.go
--- old/osconfig-20260615.01/util/mocks/mock_agent_endpoint_beta_client.go      
1970-01-01 01:00:00.000000000 +0100
+++ new/osconfig-20260624.01/util/mocks/mock_agent_endpoint_beta_client.go      
2026-06-24 17:10:57.000000000 +0200
@@ -0,0 +1,85 @@
+//  Copyright 2026 Google Inc. All Rights Reserved.
+//
+//  Licensed under the Apache License, Version 2.0 (the "License");
+//  you may not use this file except in compliance with the License.
+//  You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+//  Unless required by applicable law or agreed to in writing, software
+//  distributed under the License is distributed on an "AS IS" BASIS,
+//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//  See the License for the specific language governing permissions and
+//  limitations under the License.
+
+// Code generated by MockGen. DO NOT EDIT.
+// Source: cloud.google.com/go/osconfig/agentendpoint (interfaces: 
agentEndpointBetaClient)
+
+// Package utilmocks is a generated GoMock package.
+package utilmocks
+
+import (
+       context "context"
+       reflect "reflect"
+
+       agentendpointpb 
"cloud.google.com/go/osconfig/agentendpoint/apiv1beta/agentendpointpb"
+       gomock "github.com/golang/mock/gomock"
+       gax "github.com/googleapis/gax-go/v2"
+)
+
+// MockAgentEndpointBetaClient is a mock of agentEndpointBetaClient interface.
+type MockAgentEndpointBetaClient struct {
+       ctrl     *gomock.Controller
+       recorder *MockAgentEndpointBetaClientMockRecorder
+}
+
+// MockAgentEndpointBetaClientMockRecorder is the mock recorder for 
MockAgentEndpointBetaClient.
+type MockAgentEndpointBetaClientMockRecorder struct {
+       mock *MockAgentEndpointBetaClient
+}
+
+// NewMockAgentEndpointBetaClient creates a new mock instance.
+func NewMockAgentEndpointBetaClient(ctrl *gomock.Controller) 
*MockAgentEndpointBetaClient {
+       mock := &MockAgentEndpointBetaClient{ctrl: ctrl}
+       mock.recorder = &MockAgentEndpointBetaClientMockRecorder{mock}
+       return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockAgentEndpointBetaClient) EXPECT() 
*MockAgentEndpointBetaClientMockRecorder {
+       return m.recorder
+}
+
+// Close mocks base method.
+func (m *MockAgentEndpointBetaClient) Close() error {
+       m.ctrl.T.Helper()
+       ret := m.ctrl.Call(m, "Close")
+       ret0, _ := ret[0].(error)
+       return ret0
+}
+
+// Close indicates an expected call of Close.
+func (mr *MockAgentEndpointBetaClientMockRecorder) Close() *gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", 
reflect.TypeOf((*MockAgentEndpointBetaClient)(nil).Close))
+}
+
+// LookupEffectiveGuestPolicy mocks base method.
+func (m *MockAgentEndpointBetaClient) LookupEffectiveGuestPolicy(arg0 
context.Context, arg1 *agentendpointpb.LookupEffectiveGuestPolicyRequest, arg2 
...gax.CallOption) (*agentendpointpb.EffectiveGuestPolicy, error) {
+       m.ctrl.T.Helper()
+       varargs := []interface{}{arg0, arg1}
+       for _, a := range arg2 {
+               varargs = append(varargs, a)
+       }
+       ret := m.ctrl.Call(m, "LookupEffectiveGuestPolicy", varargs...)
+       ret0, _ := ret[0].(*agentendpointpb.EffectiveGuestPolicy)
+       ret1, _ := ret[1].(error)
+       return ret0, ret1
+}
+
+// LookupEffectiveGuestPolicy indicates an expected call of 
LookupEffectiveGuestPolicy.
+func (mr *MockAgentEndpointBetaClientMockRecorder) 
LookupEffectiveGuestPolicy(arg0, arg1 interface{}, arg2 ...interface{}) 
*gomock.Call {
+       mr.mock.ctrl.T.Helper()
+       varargs := append([]interface{}{arg0, arg1}, arg2...)
+       return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, 
"LookupEffectiveGuestPolicy", 
reflect.TypeOf((*MockAgentEndpointBetaClient)(nil).LookupEffectiveGuestPolicy), 
varargs...)
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osconfig-20260615.01/util/utiltest/utiltest.go 
new/osconfig-20260624.01/util/utiltest/utiltest.go
--- old/osconfig-20260615.01/util/utiltest/utiltest.go  2026-06-15 
22:34:32.000000000 +0200
+++ new/osconfig-20260624.01/util/utiltest/utiltest.go  2026-06-24 
17:10:57.000000000 +0200
@@ -14,6 +14,7 @@
        "github.com/golang/mock/gomock"
        "github.com/google/go-cmp/cmp"
        "github.com/kr/pretty"
+       "google.golang.org/protobuf/testing/protocmp"
 )
 
 // AssertFormatMatch verifies that the got matches the wantFormat regular 
expression.
@@ -113,7 +114,7 @@
 // AssertEquals checks if got and want are deeply equal. If not, it fails the 
test.
 func AssertEquals(t *testing.T, got interface{}, want interface{}) {
        t.Helper()
-       if diff := cmp.Diff(want, got); diff != "" {
+       if diff := cmp.Diff(want, got, protocmp.Transform()); diff != "" {
                t.Errorf("got != want (-want +got):\n%s", diff)
        }
 }

++++++ vendor.tar.gz ++++++
/work/SRC/openSUSE:Factory/google-osconfig-agent/vendor.tar.gz 
/work/SRC/openSUSE:Factory/.google-osconfig-agent.new.11887/vendor.tar.gz 
differ: char 14, line 1

Reply via email to