98 lines
2.9 KiB
Go
98 lines
2.9 KiB
Go
// Command sbom converts `go list -m -json all` output into a deterministic SPDX 2.3 inventory.
|
|
package main
|
|
|
|
import (
|
|
"crypto/sha256"
|
|
"encoding/base64"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
type module struct {
|
|
Path string
|
|
Version string
|
|
Sum string
|
|
}
|
|
|
|
type document struct {
|
|
SPDXVersion string `json:"spdxVersion"`
|
|
DataLicense string `json:"dataLicense"`
|
|
SPDXID string `json:"SPDXID"`
|
|
Name string `json:"name"`
|
|
DocumentNamespace string `json:"documentNamespace"`
|
|
CreationInfo creationInfo `json:"creationInfo"`
|
|
Packages []packageInfo `json:"packages"`
|
|
}
|
|
|
|
type creationInfo struct {
|
|
Created string `json:"created"`
|
|
Creators []string `json:"creators"`
|
|
}
|
|
|
|
type packageInfo struct {
|
|
Name string `json:"name"`
|
|
SPDXID string `json:"SPDXID"`
|
|
VersionInfo string `json:"versionInfo,omitempty"`
|
|
DownloadLocation string `json:"downloadLocation"`
|
|
FilesAnalyzed bool `json:"filesAnalyzed"`
|
|
Checksums []checksum `json:"checksums,omitempty"`
|
|
}
|
|
|
|
type checksum struct {
|
|
Algorithm string `json:"algorithm"`
|
|
ChecksumValue string `json:"checksumValue"`
|
|
}
|
|
|
|
func main() {
|
|
decoder := json.NewDecoder(os.Stdin)
|
|
var modules []module
|
|
for {
|
|
var value module
|
|
if err := decoder.Decode(&value); err != nil {
|
|
if errors.Is(err, io.EOF) {
|
|
break
|
|
}
|
|
fatal(err)
|
|
}
|
|
modules = append(modules, value)
|
|
}
|
|
epoch, err := strconv.ParseInt(os.Getenv("SOURCE_DATE_EPOCH"), 10, 64)
|
|
if err != nil {
|
|
fatal(fmt.Errorf("SOURCE_DATE_EPOCH: %w", err))
|
|
}
|
|
digest := sha256.Sum256([]byte(fmt.Sprint(modules)))
|
|
doc := document{
|
|
SPDXVersion: "SPDX-2.3", DataLicense: "CC0-1.0", SPDXID: "SPDXRef-DOCUMENT",
|
|
Name: "DoGaMa Go module inventory", DocumentNamespace: "https://dogama.invalid/spdx/" + hex.EncodeToString(digest[:]),
|
|
CreationInfo: creationInfo{Created: time.Unix(epoch, 0).UTC().Format(time.RFC3339), Creators: []string{"Tool: dogama-release"}},
|
|
}
|
|
for index, value := range modules {
|
|
pkg := packageInfo{Name: value.Path, SPDXID: fmt.Sprintf("SPDXRef-Package-%d", index), VersionInfo: value.Version, DownloadLocation: "https://proxy.golang.org/" + strings.ToLower(value.Path), FilesAnalyzed: false}
|
|
if strings.HasPrefix(value.Sum, "h1:") {
|
|
sum, decodeErr := base64.StdEncoding.DecodeString(strings.TrimPrefix(value.Sum, "h1:"))
|
|
if decodeErr != nil || len(sum) != sha256.Size {
|
|
fatal(fmt.Errorf("invalid module checksum for %s", value.Path))
|
|
}
|
|
pkg.Checksums = []checksum{{Algorithm: "SHA256", ChecksumValue: hex.EncodeToString(sum)}}
|
|
}
|
|
doc.Packages = append(doc.Packages, pkg)
|
|
}
|
|
encoder := json.NewEncoder(os.Stdout)
|
|
encoder.SetIndent("", " ")
|
|
if err := encoder.Encode(doc); err != nil {
|
|
fatal(err)
|
|
}
|
|
}
|
|
|
|
func fatal(err error) {
|
|
fmt.Fprintln(os.Stderr, err)
|
|
os.Exit(1)
|
|
}
|