github.com/yogeshkumararora/slsa-github-generator@v1.10.1-0.20240520161934-11278bd5afb4/internal/builders/go/main.go (about) 1 // Copyright 2022 SLSA Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package main 16 17 import ( 18 "bytes" 19 "crypto/sha256" 20 "encoding/hex" 21 "flag" 22 "fmt" 23 "io" 24 "os" 25 "os/exec" 26 27 "github.com/yogeshkumararora/slsa-github-generator/github" 28 "github.com/yogeshkumararora/slsa-github-generator/signing/sigstore" 29 30 // Enable the GitHub OIDC auth provider. 31 _ "github.com/sigstore/cosign/v2/pkg/providers/github" 32 33 "github.com/yogeshkumararora/slsa-github-generator/internal/builders/go/pkg" 34 "github.com/yogeshkumararora/slsa-github-generator/internal/utils" 35 ) 36 37 func usage(p string) { 38 panic(fmt.Sprintf(`Usage: 39 %s build [--dry] slsa-releaser.yml 40 %s provenance --binary-name $NAME --digest $DIGEST --command $COMMAND --env $ENV`, p, p)) 41 } 42 43 func check(e error) { 44 if e != nil { 45 fmt.Fprint(os.Stderr, e.Error()) 46 os.Exit(1) 47 } 48 } 49 50 func runBuild(dry bool, configFile, evalEnvs string) error { 51 goc, err := exec.LookPath("go") 52 if err != nil { 53 return err 54 } 55 56 cfg, err := pkg.ConfigFromFile(configFile) 57 if err != nil { 58 return err 59 } 60 fmt.Println(cfg) 61 62 gobuild := pkg.GoBuildNew(goc, cfg) 63 64 // Set env variables encoded as arguments. 65 err = gobuild.SetArgEnvVariables(evalEnvs) 66 if err != nil { 67 return err 68 } 69 70 err = gobuild.Run(dry) 71 if err != nil { 72 return err 73 } 74 75 return nil 76 } 77 78 func runProvenanceGeneration(subject, digest, commands, envs, workingDir, rekor string) error { 79 r := sigstore.NewRekor(rekor) 80 s := sigstore.NewDefaultFulcio() 81 attBytes, err := pkg.GenerateProvenance(subject, digest, 82 commands, envs, workingDir, s, r, nil) 83 if err != nil { 84 return err 85 } 86 87 filename := fmt.Sprintf("%s.intoto.jsonl", subject) 88 f, err := utils.CreateNewFileUnderCurrentDirectory(filename, os.O_WRONLY) 89 if err != nil { 90 return err 91 } 92 _, err = f.Write(attBytes) 93 if err != nil { 94 return err 95 } 96 97 if err := github.SetOutput("signed-provenance-name", filename); err != nil { 98 return err 99 } 100 101 h, err := computeSHA256(attBytes) 102 if err != nil { 103 return err 104 } 105 106 return github.SetOutput("signed-provenance-sha256", h) 107 } 108 109 func main() { 110 // Build command. 111 buildCmd := flag.NewFlagSet("build", flag.ExitOnError) 112 buildDry := buildCmd.Bool("dry", false, "dry run of the build without invoking compiler") 113 114 // Provenance command. 115 provenanceCmd := flag.NewFlagSet("provenance", flag.ExitOnError) 116 provenanceName := provenanceCmd.String("binary-name", "", "untrusted binary name of the artifact built") 117 provenanceDigest := provenanceCmd.String("digest", "", "sha256 digest of the untrusted binary") 118 provenanceCommand := provenanceCmd.String("command", "", "command used to compile the binary") 119 provenanceEnv := provenanceCmd.String("env", "", "env variables used to compile the binary") 120 provenanceWorkingDir := provenanceCmd.String("workingDir", "", "working directory used to issue compilation commands") 121 provenanceRekor := provenanceCmd.String("rekor", sigstore.DefaultRekorAddr, "rekor server to use for provenance") 122 123 // Expect a sub-command. 124 if len(os.Args) < 2 { 125 usage(os.Args[0]) 126 } 127 128 switch os.Args[1] { 129 case buildCmd.Name(): 130 check(buildCmd.Parse(os.Args[2:])) 131 if len(buildCmd.Args()) < 1 { 132 usage(os.Args[0]) 133 } 134 configFile := buildCmd.Args()[0] 135 evaluatedEnvs := buildCmd.Args()[1] 136 137 check(runBuild(*buildDry, configFile, evaluatedEnvs)) 138 139 case provenanceCmd.Name(): 140 check(provenanceCmd.Parse(os.Args[2:])) 141 // Note: *provenanceEnv may be empty. 142 if *provenanceName == "" || *provenanceDigest == "" || 143 *provenanceCommand == "" || *provenanceWorkingDir == "" { 144 usage(os.Args[0]) 145 } 146 147 err := runProvenanceGeneration(*provenanceName, *provenanceDigest, 148 *provenanceCommand, *provenanceEnv, *provenanceWorkingDir, *provenanceRekor) 149 check(err) 150 151 default: 152 fmt.Println("expected 'build' or 'provenance' subcommands") 153 os.Exit(1) 154 } 155 } 156 157 func computeSHA256(data []byte) (string, error) { 158 hash := sha256.New() 159 if _, err := io.Copy(hash, bytes.NewReader(data)); err != nil { 160 return "", err 161 } 162 return hex.EncodeToString(hash.Sum(nil)), nil 163 }