Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package apko for openSUSE:Factory checked in at 2024-12-20 15:27:37 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/apko (Old) and /work/SRC/openSUSE:Factory/.apko.new.1881 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "apko" Fri Dec 20 15:27:37 2024 rev:29 rq:1232752 version:0.22.3 Changes: -------- --- /work/SRC/openSUSE:Factory/apko/apko.changes 2024-12-16 19:11:09.127566056 +0100 +++ /work/SRC/openSUSE:Factory/.apko.new.1881/apko.changes 2024-12-20 15:28:12.650065912 +0100 @@ -1,0 +2,11 @@ +Fri Dec 20 05:52:08 UTC 2024 - opensuse_buildserv...@ojkastl.de + +- Update to version 0.22.3: + * Make GID its own type to prevent defaulting to 0 (#1449) + * Create codeql.yml (#1439) + * build(deps): bump google.golang.org/api from 0.211.0 to 0.213.0 + (#1446) + * Add a unit test for the sort ordering change. (#1444) + * Add an explicit sort to squash diffs. (#1443) + +------------------------------------------------------------------- Old: ---- apko-0.22.2.obscpio New: ---- apko-0.22.3.obscpio ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ apko.spec ++++++ --- /var/tmp/diff_new_pack.Zw3hjZ/_old 2024-12-20 15:28:13.530102172 +0100 +++ /var/tmp/diff_new_pack.Zw3hjZ/_new 2024-12-20 15:28:13.534102338 +0100 @@ -17,7 +17,7 @@ Name: apko -Version: 0.22.2 +Version: 0.22.3 Release: 0 Summary: Build OCI images from APK packages directly without Dockerfile License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.Zw3hjZ/_old 2024-12-20 15:28:13.566103656 +0100 +++ /var/tmp/diff_new_pack.Zw3hjZ/_new 2024-12-20 15:28:13.570103821 +0100 @@ -3,7 +3,7 @@ <param name="url">https://github.com/chainguard-dev/apko</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v0.22.2</param> + <param name="revision">v0.22.3</param> <param name="versionformat">@PARENT_TAG@</param> <param name="versionrewrite-pattern">v(.*)</param> <param name="changesgenerate">enable</param> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.Zw3hjZ/_old 2024-12-20 15:28:13.590104645 +0100 +++ /var/tmp/diff_new_pack.Zw3hjZ/_new 2024-12-20 15:28:13.590104645 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/chainguard-dev/apko</param> - <param name="changesrevision">559534fa1a0f3e719335aa06a9aa1dbd6609fa25</param></service></servicedata> + <param name="changesrevision">6f4d66c0f95794b0874da6a05d5334f1b17559ab</param></service></servicedata> (No newline at EOF) ++++++ apko-0.22.2.obscpio -> apko-0.22.3.obscpio ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.22.2/.github/workflows/codeql.yml new/apko-0.22.3/.github/workflows/codeql.yml --- old/apko-0.22.2/.github/workflows/codeql.yml 1970-01-01 01:00:00.000000000 +0100 +++ new/apko-0.22.3/.github/workflows/codeql.yml 2024-12-19 21:43:54.000000000 +0100 @@ -0,0 +1,57 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL Advanced" + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + schedule: + - cron: '36 8 * * 6' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: go + build-mode: autobuild + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.22.2/go.mod new/apko-0.22.3/go.mod --- old/apko-0.22.2/go.mod 2024-12-14 19:47:58.000000000 +0100 +++ new/apko-0.22.3/go.mod 2024-12-19 21:43:54.000000000 +0100 @@ -31,7 +31,7 @@ golang.org/x/sync v0.10.0 golang.org/x/sys v0.28.0 golang.org/x/time v0.8.0 - google.golang.org/api v0.211.0 + google.golang.org/api v0.213.0 gopkg.in/ini.v1 v1.67.0 gopkg.in/yaml.v3 v3.0.1 k8s.io/apimachinery v0.32.0 @@ -40,9 +40,9 @@ require ( chainguard.dev/go-grpc-kit v0.17.6 // indirect - cloud.google.com/go/auth v0.12.1 // indirect + cloud.google.com/go/auth v0.13.0 // indirect cloud.google.com/go/auth/oauth2adapt v0.2.6 // indirect - cloud.google.com/go/compute/metadata v0.5.2 // indirect + cloud.google.com/go/compute/metadata v0.6.0 // indirect dario.cat/mergo v1.0.1 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect @@ -159,7 +159,7 @@ golang.org/x/term v0.27.0 // indirect golang.org/x/text v0.21.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583 // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect google.golang.org/grpc v1.67.1 // indirect google.golang.org/protobuf v1.35.2 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.22.2/go.sum new/apko-0.22.3/go.sum --- old/apko-0.22.2/go.sum 2024-12-14 19:47:58.000000000 +0100 +++ new/apko-0.22.3/go.sum 2024-12-19 21:43:54.000000000 +0100 @@ -3,12 +3,12 @@ chainguard.dev/sdk v0.1.28 h1:xLQv0JxiGhqVKOL059DmTReTjrKFhUsP5U1W6cgr+jQ= chainguard.dev/sdk v0.1.28/go.mod h1:9EvGI9GY5UPDbZ5AhGbMO8865ixNu36afQYCZ5M95NM= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go/auth v0.12.1 h1:n2Bj25BUMM0nvE9D2XLTiImanwZhO3DkfWSYS/SAJP4= -cloud.google.com/go/auth v0.12.1/go.mod h1:BFMu+TNpF3DmvfBO9ClqTR/SiqVIm7LukKF9mbendF4= +cloud.google.com/go/auth v0.13.0 h1:8Fu8TZy167JkW8Tj3q7dIkr2v4cndv41ouecJx0PAHs= +cloud.google.com/go/auth v0.13.0/go.mod h1:COOjD9gwfKNKz+IIduatIhYJQIc0mG3H102r/EMxX6Q= cloud.google.com/go/auth/oauth2adapt v0.2.6 h1:V6a6XDu2lTwPZWOawrAa9HUK+DB2zfJyTuciBG5hFkU= cloud.google.com/go/auth/oauth2adapt v0.2.6/go.mod h1:AlmsELtlEBnaNTL7jCj8VQFLy6mbZv0s4Q7NGBeQ5E8= -cloud.google.com/go/compute/metadata v0.5.2 h1:UxK4uu/Tn+I3p2dYWTfiX4wva7aYlKixAHn3fyqngqo= -cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k= +cloud.google.com/go/compute/metadata v0.6.0 h1:A6hENjEsCDtC1k8byVsgwvVcioamEHvZ4j01OwKxG9I= +cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg= dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= @@ -504,8 +504,8 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.211.0 h1:IUpLjq09jxBSV1lACO33CGY3jsRcbctfGzhj+ZSE/Bg= -google.golang.org/api v0.211.0/go.mod h1:XOloB4MXFH4UTlQSGuNUxw0UT74qdENK8d6JNsXKLi0= +google.golang.org/api v0.213.0 h1:KmF6KaDyFqB417T68tMPbVmmwtIXs2VB60OJKIHB0xQ= +google.golang.org/api v0.213.0/go.mod h1:V0T5ZhNUUNpYAlL306gFZPFt5F5D/IeyLoktduYYnvQ= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= @@ -513,8 +513,8 @@ google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697 h1:pgr/4QbFyktUv9CtQ/Fq4gzEE6/Xs7iCXbktaGzLHbQ= google.golang.org/genproto/googleapis/api v0.0.0-20241118233622-e639e219e697/go.mod h1:+D9ySVjN8nY8YCVjc5O7PZDIdZporIDY3KaGfJunh88= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583 h1:IfdSdTcLFy4lqUQrQJLkLt1PB+AsqVz6lwkWPzWEz10= -google.golang.org/genproto/googleapis/rpc v0.0.0-20241206012308-a4fef0638583/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 h1:8ZmaLZE4XWrtU3MyClkYqqtl6Oegr3235h7jxsDyqCY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576/go.mod h1:5uTbfoYQed2U9p3KIj2/Zzm02PYhndfdmML0qC3q3FU= google.golang.org/grpc v1.18.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.22.2/pkg/build/accounts.go new/apko-0.22.3/pkg/build/accounts.go --- old/apko-0.22.2/pkg/build/accounts.go 2024-12-14 19:47:58.000000000 +0100 +++ new/apko-0.22.3/pkg/build/accounts.go 2024-12-19 21:43:54.000000000 +0100 @@ -44,10 +44,15 @@ if user.HomeDir == "" { user.HomeDir = "/home/" + user.UserName } + // Default the GID to the UID if not provided + gid := user.UID + if user.GID != nil { + gid = *user.GID + } return passwd.UserEntry{ UserName: user.UserName, UID: user.UID, - GID: user.GID, + GID: gid, HomeDir: user.HomeDir, Password: "x", Info: "Account created by apko", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.22.2/pkg/build/accounts_test.go new/apko-0.22.3/pkg/build/accounts_test.go --- old/apko-0.22.2/pkg/build/accounts_test.go 1970-01-01 01:00:00.000000000 +0100 +++ new/apko-0.22.3/pkg/build/accounts_test.go 2024-12-19 21:43:54.000000000 +0100 @@ -0,0 +1,80 @@ +// Copyright 2024 Chainguard, Inc. +// +// 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 build + +import ( + "testing" + + "chainguard.dev/apko/pkg/build/types" +) + +var ( + id0 = uint32(0) + id0T = types.GID(&id0) + id1234 = uint32(1234) + id1235 = uint32(1235) + id1235T = types.GID(&id1235) +) + +func Test_userToUserEntry_UID_GID_mapping(t *testing.T) { + for _, test := range []struct { + desc string + user types.User + expectedUID uint32 + expectedGID uint32 + }{ + { + desc: "Unique GID gets propogated", + user: types.User{ + UID: id1234, + GID: id1235T, + }, + expectedUID: id1234, + expectedGID: id1235, + }, + { + desc: "Nil GID defaults to UID", + user: types.User{ + UID: id1234, + }, + expectedUID: id1234, + expectedGID: id1234, + }, + { + desc: "Able to set GID to 0", + user: types.User{ + UID: id1234, + GID: id0T, + }, + expectedUID: id1234, + expectedGID: id0, + }, + { + // TODO: This may be unintentional but matches historical behavior + desc: "Missing UID and GID means both are 0", + user: types.User{}, + expectedUID: id0, + expectedGID: id0, + }, + } { + userEntry := userToUserEntry(test.user) + if userEntry.UID != test.expectedUID { + t.Errorf("%s: expected UID %d got UID %d", test.desc, test.expectedUID, userEntry.UID) + } + if userEntry.GID != test.expectedGID { + t.Errorf("%s: expected GID %d got GID %d", test.desc, test.expectedGID, userEntry.GID) + } + } +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.22.2/pkg/build/lock.go new/apko-0.22.3/pkg/build/lock.go --- old/apko-0.22.2/pkg/build/lock.go 2024-12-14 19:47:58.000000000 +0100 +++ new/apko-0.22.3/pkg/build/lock.go 2024-12-19 21:43:54.000000000 +0100 @@ -237,6 +237,10 @@ for _, pkg := range sets.List(acc.packages) { pl = append(pl, fmt.Sprintf("%s=%s", pkg, acc.versions[pkg])) } + // Sort the package list explicitly with the `=` included. + // This is because (foo, foo-bar) sorts differently than (foo=1, foo-bar=1) + // due to the presence or absence of the `=` character. + sort.Strings(pl) // "index" is a sentinel value for the intersectino of all architectures. // This is a reference to the OCI image index we'll be producing with it. @@ -247,6 +251,10 @@ for _, pkg := range sets.List(input.packages) { pl = append(pl, fmt.Sprintf("%s=%s", pkg, input.versions[pkg])) } + // Sort the package list explicitly with the `=` included. + // This is because (foo, foo-bar) sorts differently than (foo=1, foo-bar=1) + // due to the presence or absence of the `=` character. + sort.Strings(pl) byArch[input.arch] = pl } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.22.2/pkg/build/lock_test.go new/apko-0.22.3/pkg/build/lock_test.go --- old/apko-0.22.2/pkg/build/lock_test.go 2024-12-14 19:47:58.000000000 +0100 +++ new/apko-0.22.3/pkg/build/lock_test.go 2024-12-19 21:43:54.000000000 +0100 @@ -343,6 +343,29 @@ "amd64": {"intel-fast-as-f-math"}, "arm64": {"arm-energy-efficient-as-f-arithmetic"}, }, + }, { + name: "sorting with dashes", + originals: []string{"foo", "foo-bar"}, + inputs: []resolved{{ + arch: "amd64", + packages: sets.New("foo", "foo-bar"), + versions: map[string]string{ + "foo": "1.2.3", + "foo-bar": "2.4.6", + }, + }}, + want: map[string][]string{ + "amd64": { + // This comes first because '-' sorts before '='. + "foo-bar=2.4.6", + "foo=1.2.3", + }, + "index": { + // This comes first because '-' sorts before '='. + "foo-bar=2.4.6", + "foo=1.2.3", + }, + }, }} for _, test := range tests { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.22.2/pkg/build/types/image_configuration_test.go new/apko-0.22.3/pkg/build/types/image_configuration_test.go --- old/apko-0.22.2/pkg/build/types/image_configuration_test.go 2024-12-14 19:47:58.000000000 +0100 +++ new/apko-0.22.3/pkg/build/types/image_configuration_test.go 2024-12-19 21:43:54.000000000 +0100 @@ -11,6 +11,13 @@ "chainguard.dev/apko/pkg/build/types" ) +var ( + gid1000 = uint32(1000) + gid1001 = uint32(1001) + gid1000T = types.GID(&gid1000) + gid1001T = types.GID(&gid1001) +) + func TestOverlayWithEmptyContents(t *testing.T) { ctx := context.Background() @@ -152,7 +159,7 @@ Users: []types.User{{ UserName: "foo", UID: 1000, - GID: 1000, + GID: gid1000T, HomeDir: "/home/foo", }}, }, @@ -174,7 +181,7 @@ Users: []types.User{{ UserName: "bar", UID: 1001, - GID: 1001, + GID: gid1001T, HomeDir: "/home/bar", }}, }, @@ -200,12 +207,12 @@ Users: []types.User{{ UserName: "foo", UID: 1000, - GID: 1000, + GID: gid1000T, HomeDir: "/home/foo", }, { UserName: "bar", UID: 1001, - GID: 1001, + GID: gid1001T, HomeDir: "/home/bar", }}, }, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.22.2/pkg/build/types/types.go new/apko-0.22.3/pkg/build/types/types.go --- old/apko-0.22.2/pkg/build/types/types.go 2024-12-14 19:47:58.000000000 +0100 +++ new/apko-0.22.3/pkg/build/types/types.go 2024-12-19 21:43:54.000000000 +0100 @@ -29,13 +29,15 @@ // Required: The user ID UID uint32 `json:"uid,omitempty"` // Required: The user's group ID - GID uint32 `json:"gid,omitempty"` + GID GID `json:"gid,omitempty" yaml:"gid,omitempty"` // Optional: The user's shell Shell string `json:"shell,omitempty"` // Optional: The user's home directory HomeDir string `json:"homedir,omitempty"` } +type GID *uint32 + type Group struct { // Required: The name of the group GroupName string `json:"groupname,omitempty"` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/apko-0.22.2/pkg/build/types/types_test.go new/apko-0.22.3/pkg/build/types/types_test.go --- old/apko-0.22.2/pkg/build/types/types_test.go 2024-12-14 19:47:58.000000000 +0100 +++ new/apko-0.22.3/pkg/build/types/types_test.go 2024-12-19 21:43:54.000000000 +0100 @@ -15,9 +15,12 @@ package types import ( + "strings" "testing" + "github.com/google/go-cmp/cmp" "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" ) func TestParseArchitectures(t *testing.T) { @@ -91,3 +94,162 @@ }) } } + +var ( + id0 = uint32(0) + id0T = GID(&id0) + id1234 = uint32(1234) + id1235 = uint32(1235) + id1235T = GID(&id1235) +) + +// Ensure unmarshalling YAML into an ImageConfiguration +// does not result in unexpected GID=0 +func Test_YAML_Unmarshalling_UID_GID_mapping(t *testing.T) { + for _, test := range []struct { + desc string + expectedUID uint32 + expectedGID GID + rawYAML string + }{ + { + desc: "Unique GID gets propogated", + expectedUID: id1234, + expectedGID: id1235T, + rawYAML: ` +accounts: + users: + - username: testing + uid: 1234 + gid: 1235 +`, + }, + { + desc: "Nil GID is treated as nil (not 0)", + expectedUID: id1234, + expectedGID: nil, + rawYAML: ` +accounts: + users: + - username: testing + uid: 1234 +`, + }, + { + desc: "Able to set GID to 0", + expectedUID: id1234, + expectedGID: id0T, + rawYAML: ` +accounts: + users: + - username: testing + uid: 1234 + gid: 0 +`, + }, + { + // TODO: This may be unintentional but matches historical behavior + desc: "Missing UID and GID means UID is 0 and GID is nil", + expectedUID: 0, + expectedGID: nil, + rawYAML: ` +accounts: + users: + - username: testing +`, + }, + } { + var ic ImageConfiguration + if err := yaml.Unmarshal([]byte(test.rawYAML), &ic); err != nil { + t.Errorf("%s: unable to unmarshall: %v", test.desc, err) + continue + } + if numUsers := len(ic.Accounts.Users); numUsers != 1 { + t.Errorf("%s: expected 1 user, got %d", test.desc, numUsers) + continue + } + user := ic.Accounts.Users[0] + if test.expectedUID != user.UID { + t.Errorf("%s: expected UID %d got UID %d", test.desc, test.expectedUID, user.UID) + } + if diff := cmp.Diff(test.expectedGID, user.GID); diff != "" { + t.Errorf("%s: diff in GID: (-want, +got) = %s", test.desc, diff) + } + } +} + +// Ensure marshalling YAML from a User +// does not result in unexpected GID=0 +func Test_YAML_Marshalling_UID_GID_mapping(t *testing.T) { + for _, test := range []struct { + desc string + user User + expectedYAML string + }{ + { + desc: "Unique UID and GID", + user: User{ + UserName: "testing", + UID: id1234, + GID: id1235T, + }, + expectedYAML: ` +username: testing +uid: 1234 +gid: 1235 +shell: "" +homedir: "" +`, + }, + { + desc: "Nil GID gets omitted", + user: User{ + UserName: "testing", + UID: id1234, + }, + expectedYAML: ` +username: testing +uid: 1234 +shell: "" +homedir: "" +`, + }, + { + desc: "Able to set GID to 0", + user: User{ + UserName: "testing", + UID: id1234, + GID: id0T, + }, + expectedYAML: ` +username: testing +uid: 1234 +gid: 0 +shell: "" +homedir: "" +`, + }, + { + // TODO: This may be unintentional but matches historical behavior + desc: "Missing UID and GID means UID is 0 and GID gets omitted", + user: User{ + UserName: "testing", + }, + expectedYAML: ` +username: testing +uid: 0 +shell: "" +homedir: "" +`, + }, + } { + b, err := yaml.Marshal(test.user) + if err != nil { + t.Errorf("%s: unable to marshall: %v", test.desc, err) + continue + } + if diff := cmp.Diff(strings.TrimPrefix(test.expectedYAML, "\n"), string(b)); diff != "" { + t.Errorf("%s: diff in marshalled user YAML: (-want, +got) = %s", test.desc, diff) + } + } +} ++++++ apko.obsinfo ++++++ --- /var/tmp/diff_new_pack.Zw3hjZ/_old 2024-12-20 15:28:13.874116348 +0100 +++ /var/tmp/diff_new_pack.Zw3hjZ/_new 2024-12-20 15:28:13.878116512 +0100 @@ -1,5 +1,5 @@ name: apko -version: 0.22.2 -mtime: 1734202078 -commit: 559534fa1a0f3e719335aa06a9aa1dbd6609fa25 +version: 0.22.3 +mtime: 1734641034 +commit: 6f4d66c0f95794b0874da6a05d5334f1b17559ab ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/apko/vendor.tar.gz /work/SRC/openSUSE:Factory/.apko.new.1881/vendor.tar.gz differ: char 5, line 1