66 "fmt"
77 "os"
88 "runtime"
9+ "strings"
910
1011 clog "github.com/openshift/oc-mirror/v2/internal/pkg/log"
1112 "github.com/spf13/cobra"
2829 buildDate string
2930 // state of git tree, either "clean" or "dirty"
3031 gitTreeState string
32+
33+ // releaseVersionPadded may be replaced in the binary with Release
34+ // Metadata: Version that overrides defaultVersion as a null-terminated
35+ // string within the allowed character length. This allows a distributor to
36+ // override the version without having to rebuild the source.
37+ releaseVersionPadded = "\x00 _RELEASE_VERSION_LOCATION_\x00 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\x00 "
38+ releaseVersionPrefix = "\x00 _RELEASE_VERSION_LOCATION_\x00 "
39+ releaseVersionLength = len (releaseVersionPadded )
3140)
3241
42+ func Version () (string , error ) {
43+ if strings .HasPrefix (releaseVersionPadded , releaseVersionPrefix ) {
44+ return fmt .Sprintf ("unreleased-%s" , commitFromGit ), nil
45+ }
46+ nullTerminator := strings .IndexByte (releaseVersionPadded , '\x00' )
47+ if nullTerminator == - 1 {
48+ // the binary has been altered, but we didn't find a null terminator within the release name constant which is an error
49+ return commitFromGit , fmt .Errorf ("release name location was replaced but without a null terminator before %d bytes" , releaseVersionLength )
50+ } else if nullTerminator > releaseVersionLength {
51+ // the binary has been altered, but the null terminator is *longer* than the constant encoded in the library
52+ return commitFromGit , fmt .Errorf ("release name location contains no null-terminator and constant is corrupted" )
53+ }
54+ releaseName := releaseVersionPadded [:nullTerminator ]
55+ if len (releaseName ) == 0 {
56+ // the binary has been altered, but the replaced release name is empty which is incorrect
57+ // the oc binary will not be pinned to Release Metadata: Version
58+ return commitFromGit , fmt .Errorf ("release name was incorrectly replaced during extract" )
59+ }
60+ return releaseName , nil
61+ }
62+
3363type Info struct {
3464 Major string `json:"major"`
3565 Minor string `json:"minor"`
@@ -48,8 +78,8 @@ type VersionOptions struct {
4878 V2 bool
4979}
5080
51- // Version is a struct for version information
52- type Version struct {
81+ // VersionInfo is a struct for version information
82+ type VersionInfo struct {
5383 ClientVersion * Info `json:"clientVersion,omitempty" yaml:"clientVersion,omitempty"`
5484}
5585
@@ -98,15 +128,15 @@ func (o *VersionOptions) Validate() error {
98128}
99129
100130func (o * VersionOptions ) Run () error {
101- var versionInfo Version
131+ var versionInfo VersionInfo
102132
103133 clientVersion := Get ()
104134 versionInfo .ClientVersion = & clientVersion
105135
106136 switch o .Output {
107137 case "" :
108138 if o .Short {
109- fmt .Fprintf (os .Stdout , "Client Version: %s\n " , clientVersion .GitVersion )
139+ fmt .Fprintf (os .Stdout , "Client Version: %s\n " , clientVersion .Major )
110140 } else {
111141 fmt .Fprintf (os .Stderr , "WARNING: This version information is deprecated and will be replaced with the output from --short. Use --output=yaml|json to get the full version.\n " )
112142 fmt .Fprintf (os .Stdout , "Client Version: %#v\n " , clientVersion )
@@ -131,9 +161,13 @@ func (o *VersionOptions) Run() error {
131161}
132162
133163func Get () Info {
164+ version , err := Version ()
165+ if err != nil {
166+ panic (fmt .Errorf ("could not assembler binary version: %w" , err ))
167+ }
134168 return Info {
135- Major : majorFromGit ,
136- Minor : minorFromGit ,
169+ Major : version ,
170+ Minor : version ,
137171 GitCommit : commitFromGit ,
138172 GitVersion : versionFromGit ,
139173 GitTreeState : gitTreeState ,
0 commit comments