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-11-13 18:32:13
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/google-osconfig-agent (Old)
 and      /work/SRC/openSUSE:Factory/.google-osconfig-agent.new.1251 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "google-osconfig-agent"

Fri Nov 13 18:32:13 2026 rev:70 rq:1397094 version:20261105.03

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/google-osconfig-agent/google-osconfig-agent.changes  
    2026-11-10 16:30:02.823855961 +0100
+++ 
/work/SRC/openSUSE:Factory/.google-osconfig-agent.new.1251/google-osconfig-agent.changes
    2026-11-13 18:36:19.498823900 +0100
@@ -1,0 +2,11 @@
+Thu Nov 12 08:05:13 UTC 2026 - John Paul Adrian Glaubitz 
<[email protected]>
+
+- Update to version 20261105.03 (bsc#1289973, bsc#1290117)
+  * E2E tests v2 redesign: migrate PackageResource Googet tests (#1073)
+- from version 20261105.01
+  * Fix race between osconfig reboot and Windows TrustedInstaller
+    reboot (#1082)
+- from version 20261105.00
+  * E2E tests v2 redesign: migrate PackageResource Msi tests (#1074)
+
+-------------------------------------------------------------------

Old:
----
  osconfig-20261103.02.tar.gz

New:
----
  osconfig-20261105.03.tar.gz

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

Other differences:
------------------
++++++ google-osconfig-agent.spec ++++++
--- /var/tmp/diff_new_pack.vqUvpl/_old  2026-11-13 18:36:22.520951850 +0100
+++ /var/tmp/diff_new_pack.vqUvpl/_new  2026-11-13 18:36:22.522951935 +0100
@@ -19,7 +19,7 @@
 %define shortname osconfig
 
 Name:           google-osconfig-agent
-Version:        20261103.02
+Version:        20261105.03
 Release:        0
 Summary:        Google Cloud Guest Agent
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.vqUvpl/_old  2026-11-13 18:36:22.570953967 +0100
+++ /var/tmp/diff_new_pack.vqUvpl/_new  2026-11-13 18:36:22.574954137 +0100
@@ -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">20261103.02</param>
-    <param name="revision">20261103.02</param>
+    <param name="versionformat">20261105.03</param>
+    <param name="revision">20261105.03</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-20261103.02.tar.gz</param>
+    <param name="archive">osconfig-20261105.03.tar.gz</param>
     <param 
name="replace">github.com/containerd/containerd=github.com/containerd/[email protected]</param>
     <param 
name="replace">github.com/go-jose/go-jose/v4=github.com/go-jose/go-jose/[email protected]</param>
     <param 
name="replace">github.com/klauspost/compress=github.com/klauspost/[email protected]</param>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.vqUvpl/_old  2026-11-13 18:36:22.600955238 +0100
+++ /var/tmp/diff_new_pack.vqUvpl/_new  2026-11-13 18:36:22.603955365 +0100
@@ -1,6 +1,6 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/GoogleCloudPlatform/osconfig</param>
-              <param 
name="changesrevision">edd1aa80c72c57959515158882591548e6eed61c</param></service></servicedata>
+              <param 
name="changesrevision">b68b9ac88e9756c74749dd01895f53e77565b9e3</param></service></servicedata>
 (No newline at EOF)
 

++++++ osconfig-20261103.02.tar.gz -> osconfig-20261105.03.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osconfig-20261103.02/agentendpoint/patch_task.go 
new/osconfig-20261105.03/agentendpoint/patch_task.go
--- old/osconfig-20261103.02/agentendpoint/patch_task.go        2026-11-03 
21:12:42.000000000 +0100
+++ new/osconfig-20261105.03/agentendpoint/patch_task.go        2026-11-05 
13:20:03.000000000 +0100
@@ -217,7 +217,7 @@
                clog.Warningf(ctx, "Failed to report REBOOTING state: %v", err)
        }
 
-       if err := rebootSystem(); err != nil {
+       if err := rebootSystem(ctx); err != nil {
                return fmt.Errorf("failed to reboot system: %v", err)
        }
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osconfig-20261103.02/agentendpoint/reboot_linux.go 
new/osconfig-20261105.03/agentendpoint/reboot_linux.go
--- old/osconfig-20261103.02/agentendpoint/reboot_linux.go      2026-11-03 
21:12:42.000000000 +0100
+++ new/osconfig-20261105.03/agentendpoint/reboot_linux.go      2026-11-05 
13:20:03.000000000 +0100
@@ -15,6 +15,7 @@
 package agentendpoint
 
 import (
+       "context"
        "os/exec"
        "syscall"
 
@@ -27,16 +28,17 @@
        shutdown  = "/bin/shutdown"
 )
 
-func rebootSystem() error {
+func rebootSystem(ctx context.Context) error {
+       ctx = context.WithoutCancel(ctx)
        // Start with systemctl and work down a list of reboot methods.
        if e := util.Exists(systemctl); e {
-               return exec.Command(systemctl, "reboot").Start()
+               return exec.CommandContext(ctx, systemctl, "reboot").Start()
        }
        if e := util.Exists(reboot); e {
-               return exec.Command(reboot).Run()
+               return exec.CommandContext(ctx, reboot).Run()
        }
        if e := util.Exists(shutdown); e {
-               return exec.Command(shutdown, "-r", "-t", "0").Run()
+               return exec.CommandContext(ctx, shutdown, "-r", "-t", "0").Run()
        }
 
        // Fall back to reboot(2) system call
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/osconfig-20261103.02/agentendpoint/reboot_windows.go 
new/osconfig-20261105.03/agentendpoint/reboot_windows.go
--- old/osconfig-20261103.02/agentendpoint/reboot_windows.go    2026-11-03 
21:12:42.000000000 +0100
+++ new/osconfig-20261105.03/agentendpoint/reboot_windows.go    2026-11-05 
13:20:03.000000000 +0100
@@ -18,15 +18,57 @@
 package agentendpoint
 
 import (
+       "context"
+       "errors"
        "os"
        "os/exec"
        "path/filepath"
+
+       "github.com/GoogleCloudPlatform/osconfig/clog"
+       "golang.org/x/sys/windows"
 )
 
-func rebootSystem() error {
+var runShutdownCmd = func(ctx context.Context, root string) (int, bool, error) 
{
+       err := exec.CommandContext(ctx, filepath.Join(root, 
`System32\shutdown.exe`), "/r", "/t", "00", "/f", "/d", "p:2:3").Run()
+       var exitErr *exec.ExitError
+       if errors.As(err, &exitErr) {
+               return exitErr.ExitCode(), true, err
+       }
+       return 0, false, err
+}
+
+// isShutdownAlreadyInProgress reports whether a shutdown.exe exit code
+// indicates that a system shutdown or reboot is already scheduled or underway:
+//   - ERROR_SHUTDOWN_IN_PROGRESS (1115): A system shutdown is in progress.
+//   - ERROR_SHUTDOWN_IS_SCHEDULED (1190): A system shutdown has already been 
scheduled.
+//   - RPC_S_UNKNOWN_IF (1717): wininit.exe has already unregistered the 
InitShutdown
+//     RPC interface during an active system shutdown/preshutdown sequence.
+//   - STATUS_DLL_INIT_FAILED_LOGOFF (0xC000026B): shutdown.exe failed to 
initialize
+//     DLLs because the window station is already shutting down.
+func isShutdownAlreadyInProgress(code int) bool {
+       switch uint32(code) {
+       case uint32(windows.ERROR_SHUTDOWN_IN_PROGRESS),
+               uint32(windows.ERROR_SHUTDOWN_IS_SCHEDULED),
+               uint32(windows.RPC_S_UNKNOWN_IF),
+               uint32(windows.STATUS_DLL_INIT_FAILED_LOGOFF):
+               return true
+       default:
+               return false
+       }
+}
+
+func rebootSystem(ctx context.Context) error {
+       ctx = context.WithoutCancel(ctx)
        root := os.Getenv("SystemRoot")
        if root == "" {
                root = `C:\Windows`
        }
-       return exec.Command(filepath.Join(root, `System32\shutdown.exe`), "/r", 
"/t", "00", "/f", "/d", "p:2:3").Run()
+       if code, hasCode, err := runShutdownCmd(ctx, root); err != nil {
+               if hasCode && isShutdownAlreadyInProgress(code) {
+                       clog.Warningf(ctx, "System reboot/shutdown is already 
in progress (shutdown.exe exit status %d): %v", code, err)
+                       return nil
+               }
+               return err
+       }
+       return nil
 }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osconfig-20261103.02/agentendpoint/reboot_windows_test.go 
new/osconfig-20261105.03/agentendpoint/reboot_windows_test.go
--- old/osconfig-20261103.02/agentendpoint/reboot_windows_test.go       
1970-01-01 01:00:00.000000000 +0100
+++ new/osconfig-20261105.03/agentendpoint/reboot_windows_test.go       
2026-11-05 13:20:03.000000000 +0100
@@ -0,0 +1,104 @@
+//  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.
+
+//go:build windows
+// +build windows
+
+package agentendpoint
+
+import (
+       "context"
+       "errors"
+       "fmt"
+       "testing"
+
+       "github.com/GoogleCloudPlatform/osconfig/util/utiltest"
+       "golang.org/x/sys/windows"
+)
+
+func TestRebootSystemWindows(t *testing.T) {
+       ctx := t.Context()
+       dllInitFailedLogoff := uint32(windows.STATUS_DLL_INIT_FAILED_LOGOFF)
+
+       tests := []struct {
+               name    string
+               code    int
+               hasCode bool
+               cmdErr  error
+               wantErr error
+       }{
+               {
+                       name:    "shutdown succeeds",
+                       code:    0,
+                       hasCode: false,
+                       cmdErr:  nil,
+                       wantErr: nil,
+               },
+               {
+                       name:    "ERROR_SHUTDOWN_IN_PROGRESS (1115) treated as 
non-fatal",
+                       code:    int(windows.ERROR_SHUTDOWN_IN_PROGRESS),
+                       hasCode: true,
+                       cmdErr:  fmt.Errorf("exit status %d", 
windows.ERROR_SHUTDOWN_IN_PROGRESS),
+                       wantErr: nil,
+               },
+               {
+                       name:    "ERROR_SHUTDOWN_IS_SCHEDULED (1190) treated as 
non-fatal",
+                       code:    int(windows.ERROR_SHUTDOWN_IS_SCHEDULED),
+                       hasCode: true,
+                       cmdErr:  fmt.Errorf("exit status %d", 
windows.ERROR_SHUTDOWN_IS_SCHEDULED),
+                       wantErr: nil,
+               },
+               {
+                       name:    "RPC_S_UNKNOWN_IF (1717) treated as non-fatal",
+                       code:    int(windows.RPC_S_UNKNOWN_IF),
+                       hasCode: true,
+                       cmdErr:  fmt.Errorf("exit status %d", 
windows.RPC_S_UNKNOWN_IF),
+                       wantErr: nil,
+               },
+               {
+                       name:    "STATUS_DLL_INIT_FAILED_LOGOFF (0xC000026B) 
treated as non-fatal",
+                       code:    int(dllInitFailedLogoff),
+                       hasCode: true,
+                       cmdErr:  fmt.Errorf("exit status %d", 
dllInitFailedLogoff),
+                       wantErr: nil,
+               },
+               {
+                       name:    "unexpected exit code returns error",
+                       code:    int(windows.ERROR_ACCESS_DENIED),
+                       hasCode: true,
+                       cmdErr:  errors.New("exit status 5"),
+                       wantErr: errors.New("exit status 5"),
+               },
+               {
+                       name:    "command launch error without exit code 
returns error",
+                       code:    0,
+                       hasCode: false,
+                       cmdErr:  errors.New("executable file not found"),
+                       wantErr: errors.New("executable file not found"),
+               },
+       }
+
+       origRunShutdownCmd := runShutdownCmd
+       t.Cleanup(func() { runShutdownCmd = origRunShutdownCmd })
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       runShutdownCmd = func(_ context.Context, _ string) 
(int, bool, error) {
+                               return tt.code, tt.hasCode, tt.cmdErr
+                       }
+                       err := rebootSystem(ctx)
+                       utiltest.AssertErrorMatch(t, err, tt.wantErr)
+               })
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osconfig-20261103.02/e2e_tests_v2/ospolicies_package_googet_test.go 
new/osconfig-20261105.03/e2e_tests_v2/ospolicies_package_googet_test.go
--- old/osconfig-20261103.02/e2e_tests_v2/ospolicies_package_googet_test.go     
1970-01-01 01:00:00.000000000 +0100
+++ new/osconfig-20261105.03/e2e_tests_v2/ospolicies_package_googet_test.go     
2026-11-05 13:20:03.000000000 +0100
@@ -0,0 +1,158 @@
+//go:build e2e
+
+//  Copyright 2026 Google LLC
+//
+//  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 e2etests_test
+
+import (
+       "context"
+       "testing"
+       "time"
+
+       "github.com/GoogleCloudPlatform/osconfig/e2e_tests_v2/internal/gcp"
+       "github.com/GoogleCloudPlatform/osconfig/e2e_tests_v2/internal/testenv"
+       "google.golang.org/api/osconfig/v1"
+)
+
+const ensureGooGetTestStateScript = `$svc = Get-Service google_osconfig_agent 
-ErrorAction SilentlyContinue
+if ($svc -and $svc.Status -eq 'Running') {
+    Stop-Service google_osconfig_agent -Force -ErrorAction SilentlyContinue
+}
+
+googet -noconfirm install certgen
+googet -noconfirm remove google-compute-engine-ssh`
+
+type ospoliciesPackageGooGetTestCase struct {
+       name        string
+       image       string
+       machineType string
+       timeout     time.Duration
+}
+
+// osPolicyPackageGooGetTestCases returns the list of test cases for GooGet 
package policy tests.
+func osPolicyPackageGooGetTestCases() []ospoliciesPackageGooGetTestCase {
+       return []ospoliciesPackageGooGetTestCase{
+               // Windows Server
+               {
+                       name:        "windows-2016",
+                       image:       
"projects/windows-cloud/global/images/family/windows-2016",
+                       machineType: "e2-standard-4",
+                       timeout:     25 * time.Minute,
+               },
+               {
+                       name:        "windows-2019",
+                       image:       
"projects/windows-cloud/global/images/family/windows-2019",
+                       machineType: "e2-standard-4",
+                       timeout:     25 * time.Minute,
+               },
+               {
+                       name:        "windows-2022",
+                       image:       
"projects/windows-cloud/global/images/family/windows-2022",
+                       machineType: "e2-standard-4",
+                       timeout:     25 * time.Minute,
+               },
+       }
+}
+
+// buildGooGetPackageOSPolicyAssignment constructs the OSPolicyAssignment for 
testing GooGet packages.
+// It enforces that "google-compute-engine-ssh" is INSTALLED and "certgen" is 
REMOVED on the target VM.
+func buildGooGetPackageOSPolicyAssignment(vmName string) 
*osconfig.OSPolicyAssignment {
+       return &osconfig.OSPolicyAssignment{
+               InstanceFilter: &osconfig.OSPolicyAssignmentInstanceFilter{
+                       InclusionLabels: []*osconfig.OSPolicyAssignmentLabelSet{
+                               {
+                                       Labels: map[string]string{"name": 
vmName},
+                               },
+                       },
+               },
+               Rollout: &osconfig.OSPolicyAssignmentRollout{
+                       DisruptionBudget: &osconfig.FixedOrPercent{Percent: 
100},
+                       MinWaitDuration:  "0s",
+               },
+               OsPolicies: []*osconfig.OSPolicy{
+                       {
+                               Id:   "packageresourcegooget",
+                               Mode: "ENFORCEMENT",
+                               ResourceGroups: 
[]*osconfig.OSPolicyResourceGroup{
+                                       {
+                                               Resources: 
[]*osconfig.OSPolicyResource{
+                                                       {
+                                                               Id: 
"install-package",
+                                                               Pkg: 
&osconfig.OSPolicyResourcePackageResource{
+                                                                       
DesiredState: "INSTALLED",
+                                                                       Googet: 
&osconfig.OSPolicyResourcePackageResourceGooGet{
+                                                                               
Name: "google-compute-engine-ssh",
+                                                                       },
+                                                               },
+                                                       },
+                                                       {
+                                                               Id: 
"remove-package",
+                                                               Pkg: 
&osconfig.OSPolicyResourcePackageResource{
+                                                                       
DesiredState: "REMOVED",
+                                                                       Googet: 
&osconfig.OSPolicyResourcePackageResourceGooGet{
+                                                                               
Name: "certgen",
+                                                                       },
+                                                               },
+                                                       },
+                                               },
+                                       },
+                               },
+                       },
+               },
+       }
+}
+
+// TestOSPolicyPackageResourceGooGet verifies that the OS Config agent 
enforces GooGet package policies:
+// installing a missing package ("google-compute-engine-ssh") and removing an 
installed package ("certgen").
+func TestOSPolicyPackageResourceGooGet(t *testing.T) {
+       const wantCompliances = 1
+       tests := osPolicyPackageGooGetTestCases()
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       t.Parallel()
+
+                       test := testenv.New(t, tt.timeout)
+
+                       var vm *gcp.VM
+                       test.Step("create VM", func(ctx context.Context) error {
+                               scriptKey, scriptContent := 
gcp.StartupScript(tt.image, ensureGooGetTestStateScript, "")
+                               customMetadata := map[string]string{
+                                       "osconfig-disabled-features": 
"guestpolicies",
+                                       scriptKey:                    
scriptContent,
+                               }
+                               var err error
+                               vm, err = test.CreateVM(tt.image, 
tt.machineType, customMetadata)
+                               return err
+                       })
+
+                       test.Step("wait for initial package state in 
inventory", func(ctx context.Context) error {
+                               return test.WaitForPackages(vm, 
[]string{"certgen"}, []string{"google-compute-engine-ssh"})
+                       })
+
+                       test.Step("create os policy assignment", func(ctx 
context.Context) error {
+                               return test.CreateOSPolicyAssignment(vm, 
buildGooGetPackageOSPolicyAssignment(vm.Name))
+                       })
+
+                       test.Step("wait for os policy compliance report", 
func(ctx context.Context) error {
+                               return test.WaitForOSPolicyCompliance(vm, 
wantCompliances)
+                       })
+
+                       test.Step("verify packages via inventory", func(ctx 
context.Context) error {
+                               return test.WaitForPackages(vm, 
[]string{"google-compute-engine-ssh"}, []string{"certgen"})
+                       })
+               })
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/osconfig-20261103.02/e2e_tests_v2/ospolicies_package_msi_test.go 
new/osconfig-20261105.03/e2e_tests_v2/ospolicies_package_msi_test.go
--- old/osconfig-20261103.02/e2e_tests_v2/ospolicies_package_msi_test.go        
1970-01-01 01:00:00.000000000 +0100
+++ new/osconfig-20261105.03/e2e_tests_v2/ospolicies_package_msi_test.go        
2026-11-05 13:20:03.000000000 +0100
@@ -0,0 +1,168 @@
+//go:build e2e
+
+//  Copyright 2026 Google LLC
+//
+//  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 e2etests_test
+
+import (
+       "context"
+       "fmt"
+       "strings"
+       "testing"
+       "time"
+
+       "github.com/GoogleCloudPlatform/osconfig/e2e_tests_v2/internal/gcp"
+       "github.com/GoogleCloudPlatform/osconfig/e2e_tests_v2/internal/testenv"
+       "google.golang.org/api/osconfig/v1"
+)
+
+type ospoliciesPackageMsiTestCase struct {
+       name        string
+       image       string
+       machineType string
+       timeout     time.Duration
+}
+
+// osPolicyPackageMsiTestCases returns the list of test cases for Msi package 
policy tests.
+func osPolicyPackageMsiTestCases() []ospoliciesPackageMsiTestCase {
+       return []ospoliciesPackageMsiTestCase{
+               // Windows Server
+               {
+                       name:        "windows-2016",
+                       image:       
"projects/windows-cloud/global/images/family/windows-2016",
+                       machineType: "e2-standard-4",
+                       timeout:     25 * time.Minute,
+               },
+               {
+                       name:        "windows-2019",
+                       image:       
"projects/windows-cloud/global/images/family/windows-2019",
+                       machineType: "e2-standard-4",
+                       timeout:     25 * time.Minute,
+               },
+               {
+                       name:        "windows-2022",
+                       image:       
"projects/windows-cloud/global/images/family/windows-2022",
+                       machineType: "e2-standard-4",
+                       timeout:     25 * time.Minute,
+               },
+       }
+}
+
+// buildMsiPackageOSPolicyAssignment constructs the OSPolicyAssignment for 
testing MSI packages.
+// It installs Chrome Enterprise MSI from GCS on the target VM.
+func buildMsiPackageOSPolicyAssignment(vmName string) 
*osconfig.OSPolicyAssignment {
+       return &osconfig.OSPolicyAssignment{
+               InstanceFilter: &osconfig.OSPolicyAssignmentInstanceFilter{
+                       InclusionLabels: []*osconfig.OSPolicyAssignmentLabelSet{
+                               {
+                                       Labels: map[string]string{"name": 
vmName},
+                               },
+                       },
+               },
+               Rollout: &osconfig.OSPolicyAssignmentRollout{
+                       DisruptionBudget: &osconfig.FixedOrPercent{Percent: 
100},
+                       MinWaitDuration:  "0s",
+               },
+               OsPolicies: []*osconfig.OSPolicy{
+                       {
+                               Id:   "packageresourcemsi",
+                               Mode: "ENFORCEMENT",
+                               ResourceGroups: 
[]*osconfig.OSPolicyResourceGroup{
+                                       {
+                                               Resources: 
[]*osconfig.OSPolicyResource{
+                                                       {
+                                                               Id: 
"install-package",
+                                                               Pkg: 
&osconfig.OSPolicyResourcePackageResource{
+                                                                       
DesiredState: "INSTALLED",
+                                                                       Msi: 
&osconfig.OSPolicyResourcePackageResourceMSI{
+                                                                               
Source: &osconfig.OSPolicyResourceFile{
+                                                                               
        Gcs: &osconfig.OSPolicyResourceFileGcs{
+                                                                               
                Bucket:     "osconfig-agent-end2end-test-resources",
+                                                                               
                Object:     "OSPolicies/googlechromestandaloneenterprise64.msi",
+                                                                               
                Generation: 1720172515592258,
+                                                                               
        },
+                                                                               
},
+                                                                       },
+                                                               },
+                                                       },
+                                               },
+                                       },
+                               },
+                       },
+               },
+       }
+}
+
+func waitForWindowsApplication(ctx context.Context, test *testenv.Test, vm 
*gcp.VM, appName string) error {
+       return gcp.PollUntil(ctx, test.Suite.Config.PollInterval, 
fmt.Sprintf("windows application %s on %s", appName, vm.Name), func(ctx 
context.Context) (string, bool, error) {
+               inv, err := test.Suite.Compute.GetInventory(ctx, vm.Project, 
vm.Zone, vm.Name, "FULL")
+               if err != nil {
+                       if gcp.IsNotFound(err) || 
gcp.IsTransientComputeError(err) {
+                               return fmt.Sprintf("inventory not yet published 
(%v)", err), false, nil
+                       }
+                       return "", false, fmt.Errorf("failed to read inventory: 
%w", err)
+               }
+               for _, item := range inv.Items {
+                       if item.InstalledPackage != nil && 
item.InstalledPackage.WindowsApplication != nil {
+                               if 
strings.Contains(strings.ToLower(item.InstalledPackage.WindowsApplication.DisplayName),
 strings.ToLower(appName)) {
+                                       return fmt.Sprintf("found application 
%q", item.InstalledPackage.WindowsApplication.DisplayName), true, nil
+                               }
+                       }
+               }
+               return fmt.Sprintf("waiting for application %q in inventory", 
appName), false, nil
+       })
+}
+
+// TestOSPolicyPackageResourceMsi verifies that the OS Config agent installs 
an MSI package
+// (Chrome Enterprise MSI from GCS) on Windows VM instances.
+func TestOSPolicyPackageResourceMsi(t *testing.T) {
+       const wantCompliances = 1
+       tests := osPolicyPackageMsiTestCases()
+
+       for _, tt := range tests {
+               t.Run(tt.name, func(t *testing.T) {
+                       t.Parallel()
+
+                       test := testenv.New(t, tt.timeout)
+
+                       var vm *gcp.VM
+                       test.Step("create VM", func(ctx context.Context) error {
+                               customMetadata := map[string]string{
+                                       "osconfig-disabled-features": 
"guestpolicies",
+                               }
+                               var err error
+                               vm, err = test.CreateVM(tt.image, 
tt.machineType, customMetadata)
+                               return err
+                       })
+
+                       test.Step("wait for agent inventory", func(ctx 
context.Context) error {
+                               _, err := test.WaitForInventory(vm)
+                               return err
+                       })
+
+                       test.Step("create os policy assignment", func(ctx 
context.Context) error {
+                               return test.CreateOSPolicyAssignment(vm, 
buildMsiPackageOSPolicyAssignment(vm.Name))
+                       })
+
+                       test.Step("wait for os policy compliance report", 
func(ctx context.Context) error {
+                               return test.WaitForOSPolicyCompliance(vm, 
wantCompliances)
+                       })
+
+                       test.Step("verify package installed via inventory", 
func(ctx context.Context) error {
+                               return waitForWindowsApplication(ctx, test, vm, 
"Google Chrome")
+                       })
+               })
+       }
+}

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

Reply via email to