Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package google-guest-agent for 
openSUSE:Factory checked in at 2021-12-01 20:47:16
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/google-guest-agent (Old)
 and      /work/SRC/openSUSE:Factory/.google-guest-agent.new.31177 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "google-guest-agent"

Wed Dec  1 20:47:16 2021 rev:9 rq:934874 version:20211116.00

Changes:
--------
--- /work/SRC/openSUSE:Factory/google-guest-agent/google-guest-agent.changes    
2021-10-23 00:52:10.785153225 +0200
+++ 
/work/SRC/openSUSE:Factory/.google-guest-agent.new.31177/google-guest-agent.changes
 2021-12-02 02:13:50.658920685 +0100
@@ -1,0 +2,17 @@
+Thu Nov 18 13:33:12 UTC 2021 - John Paul Adrian Glaubitz 
<adrian.glaub...@suse.com>
+
+- Update to version 20211116.00 (bsc#1193257, bsc#1193258)
+  * dont duplicate logs (#146)
+  * Add WantedBy network dependencies to google-guest-agent service (#136)
+  * dont try dhcpv6 when not needed (#145)
+  * Integration tests: instance setup (#143)
+  * Integration test: test create and remove google user (#128)
+  * handle comm errors in script runner (#140)
+  * enforce script ordering (#138)
+  * enable ipv6 on secondary interfaces (#133)
+- from version 20211103.00
+  * Integration tests: instance setup (#143)
+- from version 20211027.00
+  * Integration test: test create and remove google user (#128)
+
+-------------------------------------------------------------------

Old:
----
  guest-agent-20211019.00.tar.gz

New:
----
  guest-agent-20211116.00.tar.gz

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

Other differences:
------------------
++++++ google-guest-agent.spec ++++++
--- /var/tmp/diff_new_pack.vaPcnv/_old  2021-12-02 02:13:51.270918818 +0100
+++ /var/tmp/diff_new_pack.vaPcnv/_new  2021-12-02 02:13:51.274918807 +0100
@@ -24,7 +24,7 @@
 %global import_path     %{provider_prefix}
 
 Name:           google-guest-agent
-Version:        20211019.00
+Version:        20211116.00
 Release:        0
 Summary:        Google Cloud Guest Agent
 License:        Apache-2.0

++++++ _service ++++++
--- /var/tmp/diff_new_pack.vaPcnv/_old  2021-12-02 02:13:51.306918709 +0100
+++ /var/tmp/diff_new_pack.vaPcnv/_new  2021-12-02 02:13:51.306918709 +0100
@@ -3,8 +3,8 @@
     <param 
name="url">https://github.com/GoogleCloudPlatform/guest-agent/</param>
     <param name="scm">git</param>
     <param name="exclude">.git</param>
-    <param name="versionformat">20211019.00</param>
-    <param name="revision">20211019.00</param>
+    <param name="versionformat">20211116.00</param>
+    <param name="revision">20211116.00</param>
     <param name="changesgenerate">enable</param>
   </service>
   <service name="recompress" mode="disabled">
@@ -15,6 +15,6 @@
     <param name="basename">guest-agent</param>
   </service>
   <service name="go_modules" mode="disabled">
-    <param name="archive">guest-agent-20211019.00.tar.gz</param>
+    <param name="archive">guest-agent-20211116.00.tar.gz</param>
   </service>
 </services>

++++++ _servicedata ++++++
--- /var/tmp/diff_new_pack.vaPcnv/_old  2021-12-02 02:13:51.322918660 +0100
+++ /var/tmp/diff_new_pack.vaPcnv/_new  2021-12-02 02:13:51.322918660 +0100
@@ -1,4 +1,4 @@
 <servicedata>
 <service name="tar_scm">
                 <param 
name="url">https://github.com/GoogleCloudPlatform/guest-agent/</param>
-              <param 
name="changesrevision">a1c10d174f1e9cb026585c6b141e1d4c8349e1ba</param></service></servicedata>
\ No newline at end of file
+              <param 
name="changesrevision">b0c8cbdfb9e74a4ef05e0ac09faf20e83eddbbcc</param></service></servicedata>
\ No newline at end of file

++++++ guest-agent-20211019.00.tar.gz -> guest-agent-20211116.00.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/guest-agent-20211019.00/google-guest-agent.service 
new/guest-agent-20211116.00/google-guest-agent.service
--- old/guest-agent-20211019.00/google-guest-agent.service      2021-10-20 
00:09:13.000000000 +0200
+++ new/guest-agent-20211116.00/google-guest-agent.service      2021-11-11 
20:48:43.000000000 +0100
@@ -17,8 +17,8 @@
 ExecStart=/usr/bin/google_guest_agent
 OOMScoreAdjust=-999
 Restart=always
-StandardOutput=journal+console
 
 [Install]
 WantedBy=sshd.service
 WantedBy=multi-user.target
+WantedBy=network.service networking.service NetworkManager.service 
systemd-networkd.service
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/guest-agent-20211019.00/google-shutdown-scripts.service 
new/guest-agent-20211116.00/google-shutdown-scripts.service
--- old/guest-agent-20211019.00/google-shutdown-scripts.service 2021-10-20 
00:09:13.000000000 +0200
+++ new/guest-agent-20211116.00/google-shutdown-scripts.service 2021-11-11 
20:48:43.000000000 +0100
@@ -11,7 +11,6 @@
 ExecStop=/usr/bin/google_metadata_script_runner shutdown
 TimeoutStopSec=0
 KillMode=process
-StandardOutput=journal+console
 
 [Install]
 WantedBy=multi-user.target
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/guest-agent-20211019.00/google-startup-scripts.service 
new/guest-agent-20211116.00/google-startup-scripts.service
--- old/guest-agent-20211019.00/google-startup-scripts.service  2021-10-20 
00:09:13.000000000 +0200
+++ new/guest-agent-20211116.00/google-startup-scripts.service  2021-11-11 
20:48:43.000000000 +0100
@@ -9,7 +9,6 @@
 ExecStart=/usr/bin/google_metadata_script_runner startup
 #TimeoutStartSec is ignored for Type=oneshot service units.
 KillMode=process
-StandardOutput=journal+console
 
 [Install]
 WantedBy=multi-user.target
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/guest-agent-20211019.00/google_guest_agent/accounts_test.go 
new/guest-agent-20211116.00/google_guest_agent/accounts_test.go
--- old/guest-agent-20211019.00/google_guest_agent/accounts_test.go     
2021-10-20 00:09:13.000000000 +0200
+++ new/guest-agent-20211116.00/google_guest_agent/accounts_test.go     
1970-01-01 01:00:00.000000000 +0100
@@ -1,247 +0,0 @@
-//  Copyright 2017 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 main
-
-import (
-       "crypto/rand"
-       "crypto/rsa"
-       "crypto/sha1"
-       "crypto/sha256"
-       "crypto/sha512"
-       "encoding/base64"
-       "hash"
-       "math/big"
-       "reflect"
-       "testing"
-       "time"
-       "unicode"
-
-       "github.com/go-ini/ini"
-)
-
-func mkptr(b bool) *bool {
-       ret := b
-       return &ret
-}
-
-func TestExpired(t *testing.T) {
-       var tests = []struct {
-               sTime string
-               e     bool
-       }{
-               {time.Now().Add(5 * time.Minute).Format(time.RFC3339), false},
-               {time.Now().Add(-5 * time.Minute).Format(time.RFC3339), true},
-               {"some bad time", true},
-       }
-
-       for _, tt := range tests {
-               k := windowsKey{ExpireOn: tt.sTime}
-               if tt.e != k.expired() {
-                       t.Errorf("windowsKey.expired() with ExpiredOn %q should 
return %t", k.ExpireOn, tt.e)
-               }
-       }
-}
-
-func TestAccountsDisabled(t *testing.T) {
-       var tests = []struct {
-               name string
-               data []byte
-               md   *metadata
-               want bool
-       }{
-               {"not explicitly disabled", []byte(""), &metadata{}, false},
-               {"enabled in cfg only", 
[]byte("[accountManager]\ndisable=false"), &metadata{}, false},
-               {"disabled in cfg only", 
[]byte("[accountManager]\ndisable=true"), &metadata{}, true},
-               {"disabled in cfg, enabled in instance metadata", 
[]byte("[accountManager]\ndisable=true"), &metadata{Instance: 
instance{Attributes: attributes{DisableAccountManager: mkptr(false)}}}, true},
-               {"enabled in cfg, disabled in instance metadata", 
[]byte("[accountManager]\ndisable=false"), &metadata{Instance: 
instance{Attributes: attributes{DisableAccountManager: mkptr(true)}}}, false},
-               {"enabled in instance metadata only", []byte(""), 
&metadata{Instance: instance{Attributes: attributes{DisableAccountManager: 
mkptr(false)}}}, false},
-               {"enabled in project metadata only", []byte(""), 
&metadata{Project: project{Attributes: attributes{DisableAccountManager: 
mkptr(false)}}}, false},
-               {"disabled in instance metadata only", []byte(""), 
&metadata{Instance: instance{Attributes: attributes{DisableAccountManager: 
mkptr(true)}}}, true},
-               {"enabled in instance metadata, disabled in project metadata", 
[]byte(""), &metadata{Instance: instance{Attributes: 
attributes{DisableAccountManager: mkptr(false)}}, Project: project{Attributes: 
attributes{DisableAccountManager: mkptr(true)}}}, false},
-               {"disabled in project metadata only", []byte(""), 
&metadata{Project: project{Attributes: attributes{DisableAccountManager: 
mkptr(true)}}}, true},
-       }
-
-       for _, tt := range tests {
-               cfg, err := ini.InsensitiveLoad(tt.data)
-               if err != nil {
-                       t.Errorf("test case %q: error parsing config: %v", 
tt.name, err)
-                       continue
-               }
-               if cfg == nil {
-                       cfg = &ini.File{}
-               }
-               newMetadata = tt.md
-               config = cfg
-               got := (&winAccountsMgr{}).disabled("windows")
-               if got != tt.want {
-                       t.Errorf("test case %q, accounts.disabled() got: %t, 
want: %t", tt.name, got, tt.want)
-               }
-       }
-       got := (&winAccountsMgr{}).disabled("linux")
-       if got != true {
-               t.Errorf("winAccountsMgr.disabled(\"linux\") got: %t, want: 
true", got)
-       }
-}
-
-// rename this with leading disabled because this is a resource
-// intensive test. this test takes approx. 141 seconds to complete, next
-// longest test is 0.43 seconds.
-func disabledTestNewPwd(t *testing.T) {
-       minPasswordLength := 15
-       maxPasswordLength := 255
-       var tests = []struct {
-               name               string
-               passwordLength     int
-               wantPasswordLength int
-       }{
-               {"0 characters, default value", 0, minPasswordLength},
-               {"5 characters, below min", 5, minPasswordLength},
-               {"15 characters", 5, minPasswordLength},
-               {"30 characters", 30, 30},
-               {"127 characters", 127, 127},
-               {"254 characters", 254, 254},
-               {"256 characters", 256, maxPasswordLength},
-       }
-
-       for _, tt := range tests {
-               for i := 0; i < 100000; i++ {
-                       pwd, err := newPwd(tt.passwordLength)
-                       if err != nil {
-                               t.Fatal(err)
-                       }
-                       if len(pwd) != tt.wantPasswordLength {
-                               t.Errorf("Password is not %d characters: 
len(%s)=%d", tt.wantPasswordLength, pwd, len(pwd))
-                       }
-                       var l, u, n, s int
-                       for _, r := range pwd {
-                               switch {
-                               case unicode.IsLower(r):
-                                       l = 1
-                               case unicode.IsUpper(r):
-                                       u = 1
-                               case unicode.IsDigit(r):
-                                       n = 1
-                               case unicode.IsPunct(r) || unicode.IsSymbol(r):
-                                       s = 1
-                               }
-                       }
-                       if l+u+n+s < 3 {
-                               t.Errorf("Password does not have at least one 
character from 3 categories: '%v'", pwd)
-                       }
-               }
-       }
-}
-
-func TestCreatecredsJSON(t *testing.T) {
-       pwd := "password"
-       prv, err := rsa.GenerateKey(rand.Reader, 2048)
-       if err != nil {
-               t.Fatalf("error generating key: %v", err)
-       }
-       k := windowsKey{
-               Email:    "email",
-               ExpireOn: "expire",
-               Exponent: 
base64.StdEncoding.EncodeToString(new(big.Int).SetInt64(int64(prv.PublicKey.E)).Bytes()),
-               Modulus:  
base64.StdEncoding.EncodeToString(prv.PublicKey.N.Bytes()),
-               UserName: "username",
-       }
-       for name, hashFunc := range map[string]hash.Hash{"": sha1.New(), 
"sha1": sha1.New(), "sha256": sha256.New(), "sha512": sha512.New()} {
-               k.HashFunction = name
-               c, err := createcredsJSON(k, pwd)
-               if err != nil {
-                       t.Fatalf("error running createcredsJSON: %v", err)
-               }
-               if k.HashFunction == "" {
-                       k.HashFunction = "sha1"
-               }
-
-               bPwd, err := 
base64.StdEncoding.DecodeString(c.EncryptedPassword)
-               if err != nil {
-                       t.Fatalf("error base64 decoding encoded pwd: %v", err)
-               }
-               decPwd, err := rsa.DecryptOAEP(hashFunc, rand.Reader, prv, 
bPwd, nil)
-               if err != nil {
-                       t.Fatalf("error decrypting password: %v", err)
-               }
-               if pwd != string(decPwd) {
-                       t.Errorf("decrypted password does not match expected 
for hash func %q, got: %s, want: %s", name, string(decPwd), pwd)
-               }
-               if k.UserName != c.UserName {
-                       t.Errorf("returned credsJSON UserName field unexpected, 
got: %s, want: %s", c.UserName, k.UserName)
-               }
-               if k.HashFunction != c.HashFunction {
-                       t.Errorf("returned credsJSON HashFunction field 
unexpected, got: %s, want: %s", c.HashFunction, k.HashFunction)
-               }
-               if !c.PasswordFound {
-                       t.Error("returned credsJSON PasswordFound field is not 
true")
-               }
-       }
-}
-
-func TestCompareAccounts(t *testing.T) {
-       var tests = []struct {
-               newKeys    windowsKeys
-               oldStrKeys []string
-               wantAdd    windowsKeys
-       }{
-               // These should return toAdd:
-               // In MD, not Reg
-               {windowsKeys{{UserName: "foo"}}, nil, windowsKeys{{UserName: 
"foo"}}},
-               {windowsKeys{{UserName: "foo"}}, 
[]string{`{"UserName":"bar"}`}, windowsKeys{{UserName: "foo"}}},
-
-               // These should return nothing:
-               // In Reg and MD
-               {windowsKeys{{UserName: "foo"}}, 
[]string{`{"UserName":"foo"}`}, nil},
-               // In Reg, not MD
-               {nil, []string{`{UserName":"foo"}`}, nil},
-       }
-
-       for _, tt := range tests {
-               toAdd := compareAccounts(tt.newKeys, tt.oldStrKeys)
-               if !reflect.DeepEqual(tt.wantAdd, toAdd) {
-                       t.Errorf("toAdd does not match expected: newKeys: %v, 
oldStrKeys: %q, got: %v, want: %v", tt.newKeys, tt.oldStrKeys, toAdd, 
tt.wantAdd)
-               }
-       }
-}
-
-func TestRemoveExpiredKeys(t *testing.T) {
-       var tests = []struct {
-               key   string
-               valid bool
-       }{
-               {`user:ssh-rsa [KEY] google-ssh {"userName":"u...@email.com", 
"expireOn":"2028-11-08T19:30:47+0000"}`, true},
-               {`user:ssh-rsa [KEY] google-ssh {"userName":"u...@email.com", 
"expireOn":"2028-11-08T19:30:47+0700"}`, true},
-               {`user:ssh-rsa [KEY] google-ssh {"userName":"u...@email.com", 
"expireOn":"2028-11-08T19:30:47+0700", "futureField": 
"UNUSED_FIELDS_IGNORED"}`, true},
-               {`user:ssh-rsa [KEY] google-ssh {"userName":"u...@email.com", 
"expireOn":"2018-11-08T19:30:46+0000"}`, false},
-               {`user:ssh-rsa [KEY] google-ssh {"userName":"u...@email.com", 
"expireOn":"2018-11-08T19:30:46+0700"}`, false},
-               {`user:ssh-rsa [KEY] google-ssh {"userName":"u...@email.com", 
"expireOn":"INVALID_TIMESTAMP"}`, false},
-               {`user:ssh-rsa [KEY] google-ssh`, false},
-               {`user:ssh-rsa [KEY] user`, true},
-               {`user:ssh-rsa [KEY]`, true},
-               {},
-       }
-
-       for _, tt := range tests {
-               ret := removeExpiredKeys([]string{tt.key})
-               if tt.valid {
-                       if len(ret) == 0 || ret[0] != tt.key {
-                               t.Errorf("valid key was removed: %q", tt.key)
-                       }
-               }
-               if !tt.valid && len(ret) == 1 {
-                       t.Errorf("invalid key was kept: %q", tt.key)
-               }
-       }
-}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/guest-agent-20211019.00/google_guest_agent/addresses.go 
new/guest-agent-20211116.00/google_guest_agent/addresses.go
--- old/guest-agent-20211019.00/google_guest_agent/addresses.go 2021-10-20 
00:09:13.000000000 +0200
+++ new/guest-agent-20211116.00/google_guest_agent/addresses.go 2021-11-11 
20:48:43.000000000 +0100
@@ -431,7 +431,7 @@
 func configureIPv6() error {
        var newNi, oldNi networkInterfaces
        if len(newMetadata.Instance.NetworkInterfaces) == 0 {
-               return fmt.Errorf("No interfaces found in metadata")
+               return fmt.Errorf("no interfaces found in metadata")
        }
        newNi = newMetadata.Instance.NetworkInterfaces[0]
        if len(oldMetadata.Instance.NetworkInterfaces) > 0 {
@@ -543,6 +543,10 @@
                        return err
                }
 
+               if len(googleIpv6Interfaces) == 0 {
+                       return nil
+               }
+
                var dhclientArgs6 []string
                dhclientArgs6 = append([]string{"-6"}, googleIpv6Interfaces...)
                return runCmd(exec.Command("dhclient", dhclientArgs6...))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/guest-agent-20211019.00/google_guest_agent/instance_setup_integ_test.go 
new/guest-agent-20211116.00/google_guest_agent/instance_setup_integ_test.go
--- old/guest-agent-20211019.00/google_guest_agent/instance_setup_integ_test.go 
1970-01-01 01:00:00.000000000 +0100
+++ new/guest-agent-20211116.00/google_guest_agent/instance_setup_integ_test.go 
2021-11-11 20:48:43.000000000 +0100
@@ -0,0 +1,235 @@
+//  Copyright 2021 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.
+
+// +build integration
+
+package main
+
+import (
+       "context"
+       "io/ioutil"
+       "os"
+       "strings"
+       "testing"
+)
+
+const (
+       botoCfg = "/etc/boto.cfg"
+)
+
+// TestInstanceSetupSSHKeys validates SSH keys are generated on first boot and 
not changed afterward.
+func TestInstanceSetupSSHKeys(t *testing.T) {
+       cfg, err := parseConfig("") // get empty config
+       if err != nil {
+               t.Fatal("failed to init config object")
+       }
+       config = cfg                    // set the global
+       defer func() { config = nil }() // unset at end of test
+
+       tempdir, err := ioutil.TempDir("/tmp", "test_instance_setup")
+       if err != nil {
+               t.Fatal("failed to create working dir")
+       }
+
+       // Configure a non-standard instance ID dir for us to play with.
+       config.Section("Instance").Key("instance_id_dir").SetValue(tempdir)
+       config.Section("InstanceSetup").Key("host_key_dir").SetValue(tempdir)
+
+       ctx := context.Background()
+       agentInit(ctx)
+
+       if _, err := os.Stat(tempdir + "/google_instance_id"); err != nil {
+               t.Fatal("instance ID File was not created by agentInit")
+       }
+
+       dir, err := os.Open(tempdir)
+       if err != nil {
+               t.Fatal("failed to open working dir")
+       }
+       defer dir.Close()
+
+       files, err := dir.Readdirnames(0)
+       if err != nil {
+               t.Fatal("failed to read files")
+       }
+
+       var keys []string
+       for _, file := range files {
+               if strings.HasPrefix(file, "ssh_host_") {
+                       keys = append(keys, file)
+               }
+       }
+
+       if len(keys) == 0 {
+               t.Fatal("instance setup didn't create SSH host keys")
+       }
+
+       // Remove one key file and run again to confirm SSH keys have not
+       // changed because the instance ID file has not changed.
+       if err := os.Remove(tempdir + "/" + keys[0]); err != nil {
+               t.Fatal("failed to remove key file")
+       }
+
+       agentInit(ctx)
+
+       if _, err := dir.Seek(0, 0); err != nil {
+               t.Fatal("failed to rewind dir for second check")
+       }
+       files2, err := dir.Readdirnames(0)
+       if err != nil {
+               t.Fatal("failed to read files")
+       }
+
+       var keys2 []string
+       for _, file := range files2 {
+               if strings.HasPrefix(file, "ssh_host_") {
+                       keys2 = append(keys2, file)
+               }
+               if file == keys[0] {
+                       t.Fatalf("agentInit recreated key %s", file)
+               }
+       }
+
+       if len(keys) == len(keys2) {
+               t.Fatal("agentInit recreated SSH host keys")
+       }
+}
+
+// TestInstanceSetupSSHKeysDisabled validates the config option to disable host
+// key generation is respected.
+func TestInstanceSetupSSHKeysDisabled(t *testing.T) {
+       cfg, err := parseConfig("") // get empty config
+       if err != nil {
+               t.Fatal("failed to init config object")
+       }
+       config = cfg                    // set the global
+       defer func() { config = nil }() // unset at end of test
+
+       tempdir, err := ioutil.TempDir("/tmp", "test_instance_setup")
+       if err != nil {
+               t.Fatal("failed to create working dir")
+       }
+
+       // Configure a non-standard instance ID dir for us to play with.
+       config.Section("Instance").Key("instance_id_dir").SetValue(tempdir)
+       config.Section("InstanceSetup").Key("host_key_dir").SetValue(tempdir)
+
+       // Disable SSH host key generation.
+       config.Section("InstanceSetup").Key("set_host_keys").SetValue("false")
+
+       ctx := context.Background()
+       agentInit(ctx)
+
+       dir, err := os.Open(tempdir)
+       if err != nil {
+               t.Fatal("failed to open working dir")
+       }
+       defer dir.Close()
+
+       files, err := dir.Readdirnames(0)
+       if err != nil {
+               t.Fatal("failed to read files")
+       }
+
+       for _, file := range files {
+               if strings.HasPrefix(file, "ssh_host_") {
+                       t.Fatal("agentInit created SSH host keys when disabled")
+               }
+       }
+}
+
+func TestInstanceSetupBotoConfig(t *testing.T) {
+       cfg, err := parseConfig("") // get empty config
+       if err != nil {
+               t.Fatal("failed to init config object")
+       }
+       config = cfg                    // set the global
+       defer func() { config = nil }() // unset at end of test
+
+       tempdir, err := ioutil.TempDir("/tmp", "test_instance_setup")
+       if err != nil {
+               t.Fatal("failed to create working dir")
+       }
+
+       // Configure a non-standard instance ID dir for us to play with.
+       config.Section("Instance").Key("instance_id_dir").SetValue(tempdir)
+       config.Section("InstanceSetup").Key("host_key_dir").SetValue(tempdir)
+
+       ctx := context.Background()
+
+       if err := os.Rename(botoCfg, botoCfg+".bak"); err != nil {
+               t.Fatalf("failed to move boto config: %v", err)
+       }
+       defer func() {
+               // Restore file at end of test.
+               if err := os.Rename(botoCfg+".bak", botoCfg); err != nil {
+                       t.Fatalf("failed to restore boto config: %v", err)
+               }
+       }()
+
+       // Test it is created by default on first boot
+       agentInit(ctx)
+       if _, err := os.Stat(botoCfg); err != nil {
+               t.Fatal("boto config was not created on first boot")
+       }
+
+       // Test it is not recreated on subsequent invocations
+       if err := os.Remove(botoCfg); err != nil {
+               t.Fatal("failed to remove boto config")
+       }
+       agentInit(ctx)
+       if _, err := os.Stat(botoCfg); err == nil || !os.IsNotExist(err) {
+               // If we didn't get an error, or if we got some other kind of 
error
+               t.Fatal("boto config was recreated after first boot")
+       }
+}
+
+func TestInstanceSetupBotoConfigDisabled(t *testing.T) {
+       cfg, err := parseConfig("") // get empty config
+       if err != nil {
+               t.Fatal("failed to init config object")
+       }
+       config = cfg                    // set the global
+       defer func() { config = nil }() // unset at end of test
+
+       tempdir, err := ioutil.TempDir("/tmp", "test_instance_setup")
+       if err != nil {
+               t.Fatal("failed to create working dir")
+       }
+
+       // Configure a non-standard instance ID dir for us to play with.
+       config.Section("Instance").Key("instance_id_dir").SetValue(tempdir)
+       config.Section("InstanceSetup").Key("host_key_dir").SetValue(tempdir)
+
+       ctx := context.Background()
+
+       if err := os.Rename(botoCfg, botoCfg+".bak"); err != nil {
+               t.Fatalf("failed to move boto config: %v", err)
+       }
+       defer func() {
+               // Restore file at end of test.
+               if err := os.Rename(botoCfg+".bak", botoCfg); err != nil {
+                       t.Fatalf("failed to restore boto config: %v", err)
+               }
+       }()
+
+       // Test it is not created if disabled in config.
+       config.Section("InstanceSetup").Key("set_boto_config").SetValue("false")
+       agentInit(ctx)
+
+       if _, err := os.Stat(botoCfg); err == nil || !os.IsNotExist(err) {
+               // If we didn't get an error, or if we got some other kind of 
error
+               t.Fatal("boto config was created when disabled in config")
+       }
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/guest-agent-20211019.00/google_guest_agent/non_windows_accounts.go 
new/guest-agent-20211116.00/google_guest_agent/non_windows_accounts.go
--- old/guest-agent-20211019.00/google_guest_agent/non_windows_accounts.go      
2021-10-20 00:09:13.000000000 +0200
+++ new/guest-agent-20211116.00/google_guest_agent/non_windows_accounts.go      
2021-11-11 20:48:43.000000000 +0100
@@ -390,7 +390,6 @@
        }
        gpasswddel := 
config.Section("Accounts").Key("gpasswd_remove_cmd").MustString("gpasswd -d 
{user} {group}")
        return runCmd(createUserGroupCmd(gpasswddel, user, "google-sudoers"))
-
 }
 
 // createSudoersFile creates the google_sudoers configuration file if it does
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/guest-agent-20211019.00/google_guest_agent/non_windows_accounts_integ_test.go
 
new/guest-agent-20211116.00/google_guest_agent/non_windows_accounts_integ_test.go
--- 
old/guest-agent-20211019.00/google_guest_agent/non_windows_accounts_integ_test.go
   2021-10-20 00:09:13.000000000 +0200
+++ 
new/guest-agent-20211116.00/google_guest_agent/non_windows_accounts_integ_test.go
   2021-11-11 20:48:43.000000000 +0100
@@ -3,10 +3,58 @@
 package main
 
 import (
+       "fmt"
+       "os"
        "os/exec"
+       "strings"
        "testing"
 )
 
+const (
+       testUser           = "integration-test-user"
+       defaultgroupstring = "adm,dip,docker,lxd,plugdev,video,google-sudoers"
+)
+
+func TestCreateAndRemoveGoogleUser(t *testing.T) {
+       if exist, err := userExists(testUser); err != nil && exist {
+               t.Fatalf("test user should not exist")
+       }
+       if err := createGoogleUser(testUser); err != nil {
+               t.Errorf("createGoogleUser failed creating test user")
+       }
+       if exist, err := userExists(testUser); exist != true || err != nil {
+               t.Errorf("test user should exist")
+       }
+       cmd := exec.Command("groups", testUser)
+       ret := runCmdOutput(cmd)
+       if ret.ExitCode() != 0 {
+               t.Errorf("failed looking up groups for user: stdout:%s 
stderr:%s", ret.Stdout(), ret.Stderr())
+       }
+       groups := strings.Split(strings.TrimSpace(strings.Split(ret.Stdout(), 
":")[1]), " ")
+       expectedGroupString := 
config.Section("Accounts").Key("groups").MustString(defaultgroupstring)
+       expectedGroups := strings.Split(expectedGroupString, ",")
+       for _, group := range groups {
+               if !contains(group, expectedGroups) {
+                       t.Errorf("test user has been added to an unexpected 
group %s", group)
+               }
+       }
+       if _, err := os.Stat(fmt.Sprintf("/home/%s", testUser)); err != nil {
+               t.Errorf("test user home directory does not exist")
+       }
+       if err := createGoogleUser(testUser); err == nil {
+               t.Errorf("createGoogleUser did not return error when creating 
user that already exists")
+       }
+       if err := removeGoogleUser(testUser); err != nil {
+               t.Errorf("removeGoogleUser did not remove user")
+       }
+       if exist, err := userExists(testUser); err != nil && exist == true {
+               t.Errorf("test user should not exist")
+       }
+       if err := removeGoogleUser(testUser); err == nil {
+               t.Errorf("removeGoogleUser did not return error when removing 
user that doesn't exist")
+       }
+}
+
 func TestGroupaddDuplicates(t *testing.T) {
        cmd := exec.Command("groupadd", "integ-test-group")
        ret := runCmdOutput(cmd)
@@ -19,3 +67,12 @@
                t.Fatalf("got wrong exit code running \"groupadd 
integ-test-group\", expected 9 got %v\n", ret.ExitCode())
        }
 }
+
+func contains(target string, expected []string) bool {
+       for _, e := range expected {
+               if e == target {
+                       return true
+               }
+       }
+       return false
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/guest-agent-20211019.00/google_guest_agent/windows_accounts_test.go 
new/guest-agent-20211116.00/google_guest_agent/windows_accounts_test.go
--- old/guest-agent-20211019.00/google_guest_agent/windows_accounts_test.go     
1970-01-01 01:00:00.000000000 +0100
+++ new/guest-agent-20211116.00/google_guest_agent/windows_accounts_test.go     
2021-11-11 20:48:43.000000000 +0100
@@ -0,0 +1,247 @@
+//  Copyright 2017 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 main
+
+import (
+       "crypto/rand"
+       "crypto/rsa"
+       "crypto/sha1"
+       "crypto/sha256"
+       "crypto/sha512"
+       "encoding/base64"
+       "hash"
+       "math/big"
+       "reflect"
+       "testing"
+       "time"
+       "unicode"
+
+       "github.com/go-ini/ini"
+)
+
+func mkptr(b bool) *bool {
+       ret := b
+       return &ret
+}
+
+func TestExpired(t *testing.T) {
+       var tests = []struct {
+               sTime string
+               e     bool
+       }{
+               {time.Now().Add(5 * time.Minute).Format(time.RFC3339), false},
+               {time.Now().Add(-5 * time.Minute).Format(time.RFC3339), true},
+               {"some bad time", true},
+       }
+
+       for _, tt := range tests {
+               k := windowsKey{ExpireOn: tt.sTime}
+               if tt.e != k.expired() {
+                       t.Errorf("windowsKey.expired() with ExpiredOn %q should 
return %t", k.ExpireOn, tt.e)
+               }
+       }
+}
+
+func TestAccountsDisabled(t *testing.T) {
+       var tests = []struct {
+               name string
+               data []byte
+               md   *metadata
+               want bool
+       }{
+               {"not explicitly disabled", []byte(""), &metadata{}, false},
+               {"enabled in cfg only", 
[]byte("[accountManager]\ndisable=false"), &metadata{}, false},
+               {"disabled in cfg only", 
[]byte("[accountManager]\ndisable=true"), &metadata{}, true},
+               {"disabled in cfg, enabled in instance metadata", 
[]byte("[accountManager]\ndisable=true"), &metadata{Instance: 
instance{Attributes: attributes{DisableAccountManager: mkptr(false)}}}, true},
+               {"enabled in cfg, disabled in instance metadata", 
[]byte("[accountManager]\ndisable=false"), &metadata{Instance: 
instance{Attributes: attributes{DisableAccountManager: mkptr(true)}}}, false},
+               {"enabled in instance metadata only", []byte(""), 
&metadata{Instance: instance{Attributes: attributes{DisableAccountManager: 
mkptr(false)}}}, false},
+               {"enabled in project metadata only", []byte(""), 
&metadata{Project: project{Attributes: attributes{DisableAccountManager: 
mkptr(false)}}}, false},
+               {"disabled in instance metadata only", []byte(""), 
&metadata{Instance: instance{Attributes: attributes{DisableAccountManager: 
mkptr(true)}}}, true},
+               {"enabled in instance metadata, disabled in project metadata", 
[]byte(""), &metadata{Instance: instance{Attributes: 
attributes{DisableAccountManager: mkptr(false)}}, Project: project{Attributes: 
attributes{DisableAccountManager: mkptr(true)}}}, false},
+               {"disabled in project metadata only", []byte(""), 
&metadata{Project: project{Attributes: attributes{DisableAccountManager: 
mkptr(true)}}}, true},
+       }
+
+       for _, tt := range tests {
+               cfg, err := ini.InsensitiveLoad(tt.data)
+               if err != nil {
+                       t.Errorf("test case %q: error parsing config: %v", 
tt.name, err)
+                       continue
+               }
+               if cfg == nil {
+                       cfg = &ini.File{}
+               }
+               newMetadata = tt.md
+               config = cfg
+               got := (&winAccountsMgr{}).disabled("windows")
+               if got != tt.want {
+                       t.Errorf("test case %q, accounts.disabled() got: %t, 
want: %t", tt.name, got, tt.want)
+               }
+       }
+       got := (&winAccountsMgr{}).disabled("linux")
+       if got != true {
+               t.Errorf("winAccountsMgr.disabled(\"linux\") got: %t, want: 
true", got)
+       }
+}
+
+// rename this with leading disabled because this is a resource
+// intensive test. this test takes approx. 141 seconds to complete, next
+// longest test is 0.43 seconds.
+func disabledTestNewPwd(t *testing.T) {
+       minPasswordLength := 15
+       maxPasswordLength := 255
+       var tests = []struct {
+               name               string
+               passwordLength     int
+               wantPasswordLength int
+       }{
+               {"0 characters, default value", 0, minPasswordLength},
+               {"5 characters, below min", 5, minPasswordLength},
+               {"15 characters", 5, minPasswordLength},
+               {"30 characters", 30, 30},
+               {"127 characters", 127, 127},
+               {"254 characters", 254, 254},
+               {"256 characters", 256, maxPasswordLength},
+       }
+
+       for _, tt := range tests {
+               for i := 0; i < 100000; i++ {
+                       pwd, err := newPwd(tt.passwordLength)
+                       if err != nil {
+                               t.Fatal(err)
+                       }
+                       if len(pwd) != tt.wantPasswordLength {
+                               t.Errorf("Password is not %d characters: 
len(%s)=%d", tt.wantPasswordLength, pwd, len(pwd))
+                       }
+                       var l, u, n, s int
+                       for _, r := range pwd {
+                               switch {
+                               case unicode.IsLower(r):
+                                       l = 1
+                               case unicode.IsUpper(r):
+                                       u = 1
+                               case unicode.IsDigit(r):
+                                       n = 1
+                               case unicode.IsPunct(r) || unicode.IsSymbol(r):
+                                       s = 1
+                               }
+                       }
+                       if l+u+n+s < 3 {
+                               t.Errorf("Password does not have at least one 
character from 3 categories: '%v'", pwd)
+                       }
+               }
+       }
+}
+
+func TestCreatecredsJSON(t *testing.T) {
+       pwd := "password"
+       prv, err := rsa.GenerateKey(rand.Reader, 2048)
+       if err != nil {
+               t.Fatalf("error generating key: %v", err)
+       }
+       k := windowsKey{
+               Email:    "email",
+               ExpireOn: "expire",
+               Exponent: 
base64.StdEncoding.EncodeToString(new(big.Int).SetInt64(int64(prv.PublicKey.E)).Bytes()),
+               Modulus:  
base64.StdEncoding.EncodeToString(prv.PublicKey.N.Bytes()),
+               UserName: "username",
+       }
+       for name, hashFunc := range map[string]hash.Hash{"": sha1.New(), 
"sha1": sha1.New(), "sha256": sha256.New(), "sha512": sha512.New()} {
+               k.HashFunction = name
+               c, err := createcredsJSON(k, pwd)
+               if err != nil {
+                       t.Fatalf("error running createcredsJSON: %v", err)
+               }
+               if k.HashFunction == "" {
+                       k.HashFunction = "sha1"
+               }
+
+               bPwd, err := 
base64.StdEncoding.DecodeString(c.EncryptedPassword)
+               if err != nil {
+                       t.Fatalf("error base64 decoding encoded pwd: %v", err)
+               }
+               decPwd, err := rsa.DecryptOAEP(hashFunc, rand.Reader, prv, 
bPwd, nil)
+               if err != nil {
+                       t.Fatalf("error decrypting password: %v", err)
+               }
+               if pwd != string(decPwd) {
+                       t.Errorf("decrypted password does not match expected 
for hash func %q, got: %s, want: %s", name, string(decPwd), pwd)
+               }
+               if k.UserName != c.UserName {
+                       t.Errorf("returned credsJSON UserName field unexpected, 
got: %s, want: %s", c.UserName, k.UserName)
+               }
+               if k.HashFunction != c.HashFunction {
+                       t.Errorf("returned credsJSON HashFunction field 
unexpected, got: %s, want: %s", c.HashFunction, k.HashFunction)
+               }
+               if !c.PasswordFound {
+                       t.Error("returned credsJSON PasswordFound field is not 
true")
+               }
+       }
+}
+
+func TestCompareAccounts(t *testing.T) {
+       var tests = []struct {
+               newKeys    windowsKeys
+               oldStrKeys []string
+               wantAdd    windowsKeys
+       }{
+               // These should return toAdd:
+               // In MD, not Reg
+               {windowsKeys{{UserName: "foo"}}, nil, windowsKeys{{UserName: 
"foo"}}},
+               {windowsKeys{{UserName: "foo"}}, 
[]string{`{"UserName":"bar"}`}, windowsKeys{{UserName: "foo"}}},
+
+               // These should return nothing:
+               // In Reg and MD
+               {windowsKeys{{UserName: "foo"}}, 
[]string{`{"UserName":"foo"}`}, nil},
+               // In Reg, not MD
+               {nil, []string{`{UserName":"foo"}`}, nil},
+       }
+
+       for _, tt := range tests {
+               toAdd := compareAccounts(tt.newKeys, tt.oldStrKeys)
+               if !reflect.DeepEqual(tt.wantAdd, toAdd) {
+                       t.Errorf("toAdd does not match expected: newKeys: %v, 
oldStrKeys: %q, got: %v, want: %v", tt.newKeys, tt.oldStrKeys, toAdd, 
tt.wantAdd)
+               }
+       }
+}
+
+func TestRemoveExpiredKeys(t *testing.T) {
+       var tests = []struct {
+               key   string
+               valid bool
+       }{
+               {`user:ssh-rsa [KEY] google-ssh {"userName":"u...@email.com", 
"expireOn":"2028-11-08T19:30:47+0000"}`, true},
+               {`user:ssh-rsa [KEY] google-ssh {"userName":"u...@email.com", 
"expireOn":"2028-11-08T19:30:47+0700"}`, true},
+               {`user:ssh-rsa [KEY] google-ssh {"userName":"u...@email.com", 
"expireOn":"2028-11-08T19:30:47+0700", "futureField": 
"UNUSED_FIELDS_IGNORED"}`, true},
+               {`user:ssh-rsa [KEY] google-ssh {"userName":"u...@email.com", 
"expireOn":"2018-11-08T19:30:46+0000"}`, false},
+               {`user:ssh-rsa [KEY] google-ssh {"userName":"u...@email.com", 
"expireOn":"2018-11-08T19:30:46+0700"}`, false},
+               {`user:ssh-rsa [KEY] google-ssh {"userName":"u...@email.com", 
"expireOn":"INVALID_TIMESTAMP"}`, false},
+               {`user:ssh-rsa [KEY] google-ssh`, false},
+               {`user:ssh-rsa [KEY] user`, true},
+               {`user:ssh-rsa [KEY]`, true},
+               {},
+       }
+
+       for _, tt := range tests {
+               ret := removeExpiredKeys([]string{tt.key})
+               if tt.valid {
+                       if len(ret) == 0 || ret[0] != tt.key {
+                               t.Errorf("valid key was removed: %q", tt.key)
+                       }
+               }
+               if !tt.valid && len(ret) == 1 {
+                       t.Errorf("invalid key was kept: %q", tt.key)
+               }
+       }
+}

++++++ vendor.tar.gz ++++++

Reply via email to