mirror of
https://github.com/ko-build/ko.git
synced 2024-11-19 18:01:46 +02:00
remove support for CycloneDX SBOMs
Signed-off-by: Jason Hall <jason@chainguard.dev>
This commit is contained in:
parent
9004ba1d6e
commit
2ceaa89b7e
32
.github/workflows/sbom.yaml
vendored
32
.github/workflows/sbom.yaml
vendored
@ -9,38 +9,6 @@ env:
|
||||
SPDX_TOOLS_VERSION: 1.1.0
|
||||
|
||||
jobs:
|
||||
cyclonedx:
|
||||
name: Validate CycloneDX SBOM
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
KO_DOCKER_REPO: localhost:1338
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@a5ac7e51b41094c92402da3b24376905380afc29 # v4.1.6
|
||||
- uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1
|
||||
with:
|
||||
go-version-file: 'go.mod'
|
||||
check-latest: true
|
||||
- uses: chainguard-dev/actions/setup-registry@main
|
||||
- uses: sigstore/cosign-installer@59acb6260d9c0ba8f4a2f9d9b48431a222b68e20 # v3.5.0
|
||||
|
||||
- name: Install CycloneDX
|
||||
run: |
|
||||
wget https://github.com/CycloneDX/cyclonedx-cli/releases/download/v0.22.0/cyclonedx-linux-x64
|
||||
chmod +x cyclonedx-linux-x64
|
||||
|
||||
- name: Generate and Validate
|
||||
run: |
|
||||
cosign download sbom $(go run ./ build --sbom=cyclonedx) | tee cyclonedx.json
|
||||
./cyclonedx-linux-x64 validate --input-file=cyclonedx.json --fail-on-errors
|
||||
|
||||
- uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
|
||||
if: ${{ always() }}
|
||||
with:
|
||||
name: cyclonedx.json
|
||||
path: cyclonedx.json
|
||||
|
||||
spdx:
|
||||
name: Validate SPDX SBOM
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -5,7 +5,7 @@ Having a list of dependencies can be helpful in determining whether any vulnerab
|
||||
|
||||
**From v0.9+, `ko` generates and uploads an SBOM for every image it produces by default.**
|
||||
|
||||
ko will generate an SBOM in the [SPDX](https://spdx.dev/) format by default, but you can select the [CycloneDX](https://cyclonedx.org/) format instead with the `--sbom=cyclonedx` flag. To disable SBOM generation, pass `--sbom=none`.
|
||||
ko will generate an SBOM in the [SPDX](https://spdx.dev/) format by default. To disable SBOM generation, pass `--sbom=none`.
|
||||
|
||||
These SBOMs can be downloaded using the [`cosign download sbom`](https://github.com/sigstore/cosign/blob/main/doc/cosign_download_sbom.md) command.
|
||||
|
||||
|
@ -60,7 +60,7 @@ ko apply -f FILENAME [flags]
|
||||
-P, --preserve-import-paths Whether to preserve the full import path after KO_DOCKER_REPO.
|
||||
--push Push images to KO_DOCKER_REPO (default true)
|
||||
-R, --recursive Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests organized within the same directory.
|
||||
--sbom string The SBOM media type to use (none will disable SBOM synthesis and upload, also supports: spdx, cyclonedx, go.version-m). (default "spdx")
|
||||
--sbom string The SBOM media type to use (none will disable SBOM synthesis and upload). (default "spdx")
|
||||
--sbom-dir string Path to file where the SBOM will be written.
|
||||
-l, --selector string Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)
|
||||
--tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated.
|
||||
|
@ -55,7 +55,7 @@ ko build IMPORTPATH... [flags]
|
||||
--platform strings Which platform to use when pulling a multi-platform base. Format: all | <os>[/<arch>[/<variant>]][,platform]*
|
||||
-P, --preserve-import-paths Whether to preserve the full import path after KO_DOCKER_REPO.
|
||||
--push Push images to KO_DOCKER_REPO (default true)
|
||||
--sbom string The SBOM media type to use (none will disable SBOM synthesis and upload, also supports: spdx, cyclonedx, go.version-m). (default "spdx")
|
||||
--sbom string The SBOM media type to use (none will disable SBOM synthesis and upload). (default "spdx")
|
||||
--sbom-dir string Path to file where the SBOM will be written.
|
||||
--tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated.
|
||||
-t, --tags strings Which tags to use for the produced image instead of the default 'latest' tag (may not work properly with --base-import-paths or --bare). (default [latest])
|
||||
|
@ -60,7 +60,7 @@ ko create -f FILENAME [flags]
|
||||
-P, --preserve-import-paths Whether to preserve the full import path after KO_DOCKER_REPO.
|
||||
--push Push images to KO_DOCKER_REPO (default true)
|
||||
-R, --recursive Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests organized within the same directory.
|
||||
--sbom string The SBOM media type to use (none will disable SBOM synthesis and upload, also supports: spdx, cyclonedx, go.version-m). (default "spdx")
|
||||
--sbom string The SBOM media type to use (none will disable SBOM synthesis and upload). (default "spdx")
|
||||
--sbom-dir string Path to file where the SBOM will be written.
|
||||
-l, --selector string Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)
|
||||
--tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated.
|
||||
|
@ -53,7 +53,7 @@ ko resolve -f FILENAME [flags]
|
||||
-P, --preserve-import-paths Whether to preserve the full import path after KO_DOCKER_REPO.
|
||||
--push Push images to KO_DOCKER_REPO (default true)
|
||||
-R, --recursive Process the directory used in -f, --filename recursively. Useful when you want to manage related manifests organized within the same directory.
|
||||
--sbom string The SBOM media type to use (none will disable SBOM synthesis and upload, also supports: spdx, cyclonedx, go.version-m). (default "spdx")
|
||||
--sbom string The SBOM media type to use (none will disable SBOM synthesis and upload). (default "spdx")
|
||||
--sbom-dir string Path to file where the SBOM will be written.
|
||||
-l, --selector string Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)
|
||||
--tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated.
|
||||
|
@ -43,7 +43,7 @@ ko run IMPORTPATH [flags]
|
||||
--platform strings Which platform to use when pulling a multi-platform base. Format: all | <os>[/<arch>[/<variant>]][,platform]*
|
||||
-P, --preserve-import-paths Whether to preserve the full import path after KO_DOCKER_REPO.
|
||||
--push Push images to KO_DOCKER_REPO (default true)
|
||||
--sbom string The SBOM media type to use (none will disable SBOM synthesis and upload, also supports: spdx, cyclonedx, go.version-m). (default "spdx")
|
||||
--sbom string The SBOM media type to use (none will disable SBOM synthesis and upload). (default "spdx")
|
||||
--sbom-dir string Path to file where the SBOM will be written.
|
||||
--tag-only Include tags but not digests in resolved image references. Useful when digests are not preserved when images are repopulated.
|
||||
-t, --tags strings Which tags to use for the produced image instead of the default 'latest' tag (may not work properly with --base-import-paths or --bare). (default [latest])
|
||||
|
@ -1,175 +0,0 @@
|
||||
// Copyright 2022 ko Build Authors 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 sbom
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
|
||||
"github.com/sigstore/cosign/v2/pkg/oci"
|
||||
)
|
||||
|
||||
func h1ToSHA256(s string) string {
|
||||
if !strings.HasPrefix(s, "h1:") {
|
||||
return ""
|
||||
}
|
||||
b, err := base64.StdEncoding.DecodeString(s[3:])
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
func GenerateImageCycloneDX(mod []byte) ([]byte, error) {
|
||||
var err error
|
||||
mod, err = massageGoVersionM(mod)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bi, err := debug.ParseBuildInfo(string(mod))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
doc := document{
|
||||
BOMFormat: "CycloneDX",
|
||||
SpecVersion: "1.4",
|
||||
Version: 1,
|
||||
Metadata: metadata{
|
||||
Component: component{
|
||||
BOMRef: bomRef(&bi.Main),
|
||||
Type: "application",
|
||||
Name: bi.Main.Path,
|
||||
Version: bi.Main.Version,
|
||||
Purl: bomRef(&bi.Main),
|
||||
ExternalReferences: []externalReference{{
|
||||
URL: "https://" + bi.Main.Path,
|
||||
Type: "vcs",
|
||||
}},
|
||||
},
|
||||
Properties: []property{{
|
||||
Name: "cdx:gomod:binary:name",
|
||||
Value: "out",
|
||||
}},
|
||||
// TODO: include all hashes
|
||||
// TODO: include go version
|
||||
// TODO: include bi.Settings?
|
||||
},
|
||||
Dependencies: []dependency{{
|
||||
Ref: bomRef(&bi.Main),
|
||||
}},
|
||||
Compositions: []composition{{
|
||||
Aggregate: "complete",
|
||||
Dependencies: []string{
|
||||
bomRef(&bi.Main),
|
||||
},
|
||||
}, {
|
||||
Aggregate: "unknown",
|
||||
Dependencies: []string{},
|
||||
}},
|
||||
}
|
||||
for _, dep := range bi.Deps {
|
||||
// Don't include replaced deps
|
||||
if dep.Replace != nil {
|
||||
continue
|
||||
}
|
||||
comp := component{
|
||||
BOMRef: bomRef(dep),
|
||||
Type: "library",
|
||||
Name: dep.Path,
|
||||
Version: dep.Version,
|
||||
Scope: "required",
|
||||
Purl: bomRef(dep),
|
||||
ExternalReferences: []externalReference{{
|
||||
URL: "https://" + dep.Path,
|
||||
Type: "vcs",
|
||||
}},
|
||||
}
|
||||
if dep.Sum != "" {
|
||||
comp.Hashes = []hash{{
|
||||
Alg: "SHA-256",
|
||||
Content: h1ToSHA256(dep.Sum),
|
||||
}}
|
||||
}
|
||||
doc.Components = append(doc.Components, comp)
|
||||
doc.Dependencies[0].DependsOn = append(doc.Dependencies[0].DependsOn, bomRef(dep))
|
||||
doc.Dependencies = append(doc.Dependencies, dependency{
|
||||
Ref: bomRef(dep),
|
||||
})
|
||||
|
||||
doc.Compositions[1].Dependencies = append(doc.Compositions[1].Dependencies, bomRef(dep))
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
enc := json.NewEncoder(&buf)
|
||||
enc.SetIndent("", " ")
|
||||
if err := enc.Encode(doc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return buf.Bytes(), nil
|
||||
}
|
||||
|
||||
func GenerateIndexCycloneDX(oci.SignedImageIndex) ([]byte, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
type document struct {
|
||||
BOMFormat string `json:"bomFormat"`
|
||||
SpecVersion string `json:"specVersion"`
|
||||
Version int `json:"version"`
|
||||
Metadata metadata `json:"metadata"`
|
||||
Components []component `json:"components,omitempty"`
|
||||
Dependencies []dependency `json:"dependencies,omitempty"`
|
||||
Compositions []composition `json:"compositions,omitempty"`
|
||||
}
|
||||
type metadata struct {
|
||||
Component component `json:"component"`
|
||||
Properties []property `json:"properties,omitempty"`
|
||||
}
|
||||
type component struct {
|
||||
BOMRef string `json:"bom-ref"`
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
Scope string `json:"scope,omitempty"`
|
||||
Hashes []hash `json:"hashes,omitempty"`
|
||||
Purl string `json:"purl"`
|
||||
ExternalReferences []externalReference `json:"externalReferences"`
|
||||
}
|
||||
type hash struct {
|
||||
Alg string `json:"alg"`
|
||||
Content string `json:"content"`
|
||||
}
|
||||
type externalReference struct {
|
||||
URL string `json:"url"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
type property struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
type dependency struct {
|
||||
Ref string `json:"ref"`
|
||||
DependsOn []string `json:"dependsOn,omitempty"`
|
||||
}
|
||||
type composition struct {
|
||||
Aggregate string `json:"aggregate"`
|
||||
Dependencies []string `json:"dependencies,omitempty"`
|
||||
}
|
@ -16,6 +16,8 @@ package sbom
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@ -51,6 +53,17 @@ func ociRef(path string, imgDigest v1.Hash, qual ...qualifier) string {
|
||||
return purl
|
||||
}
|
||||
|
||||
func h1ToSHA256(s string) string {
|
||||
if !strings.HasPrefix(s, "h1:") {
|
||||
return ""
|
||||
}
|
||||
b, err := base64.StdEncoding.DecodeString(s[3:])
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
return hex.EncodeToString(b)
|
||||
}
|
||||
|
||||
const dateFormat = "2006-01-02T15:04:05Z"
|
||||
|
||||
func GenerateImageSPDX(koVersion string, mod []byte, img oci.SignedImage) ([]byte, error) {
|
||||
|
1
main.go
1
main.go
@ -12,6 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
//go:generate go run ./cmd/help/main.go -d docs/reference/
|
||||
package main
|
||||
|
||||
import (
|
||||
|
@ -454,44 +454,6 @@ func writeSBOM(sbom []byte, appFileName, dir, ext string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func cycloneDX() sbomber {
|
||||
return func(ctx context.Context, file string, appPath string, appFileName string, se oci.SignedEntity, dir string) ([]byte, types.MediaType, error) {
|
||||
switch obj := se.(type) {
|
||||
case oci.SignedImage:
|
||||
b, _, err := goversionm(ctx, file, appPath, appFileName, obj, "")
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
b, err = sbom.GenerateImageCycloneDX(b)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if err := writeSBOM(b, appFileName, dir, "cyclonedx.json"); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
return b, ctypes.CycloneDXJSONMediaType, nil
|
||||
|
||||
case oci.SignedImageIndex:
|
||||
b, err := sbom.GenerateIndexCycloneDX(obj)
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
if err := writeSBOM(b, appFileName, dir, "cyclonedx.json"); err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
return b, ctypes.SPDXJSONMediaType, err
|
||||
|
||||
default:
|
||||
return nil, "", fmt.Errorf("unrecognized type: %T", se)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// buildEnv creates the environment variables used by the `go build` command.
|
||||
// From `os/exec.Cmd`: If there are duplicate environment keys, only the last
|
||||
// value in the slice for each duplicate key is used.
|
||||
|
@ -151,15 +151,6 @@ func withBuilder(b builder) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithGoVersionSBOM is a functional option to direct ko to use
|
||||
// go version -m for SBOM format.
|
||||
func WithGoVersionSBOM() Option {
|
||||
return func(gbo *gobuildOpener) error {
|
||||
gbo.sbom = goversionm
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithSPDX is a functional option to direct ko to use
|
||||
// SPDX for SBOM format.
|
||||
func WithSPDX(version string) Option {
|
||||
@ -169,15 +160,6 @@ func WithSPDX(version string) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithCycloneDX is a functional option to direct ko to use CycloneDX for SBOM
|
||||
// format.
|
||||
func WithCycloneDX() Option {
|
||||
return func(gbo *gobuildOpener) error {
|
||||
gbo.sbom = cycloneDX()
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// withSBOMber is a functional option for overriding the way SBOMs
|
||||
// are generated.
|
||||
func withSBOMber(sbom sbomber) Option {
|
||||
|
@ -87,7 +87,7 @@ func AddBuildOptions(cmd *cobra.Command, bo *BuildOptions) {
|
||||
cmd.Flags().BoolVar(&bo.DisableOptimizations, "disable-optimizations", bo.DisableOptimizations,
|
||||
"Disable optimizations when building Go code. Useful when you want to interactively debug the created container.")
|
||||
cmd.Flags().StringVar(&bo.SBOM, "sbom", "spdx",
|
||||
"The SBOM media type to use (none will disable SBOM synthesis and upload, also supports: spdx, cyclonedx, go.version-m).")
|
||||
"The SBOM media type to use (none will disable SBOM synthesis and upload).")
|
||||
cmd.Flags().StringVar(&bo.SBOMDir, "sbom-dir", "",
|
||||
"Path to file where the SBOM will be written.")
|
||||
cmd.Flags().StringSliceVar(&bo.Platforms, "platform", []string{},
|
||||
|
@ -104,10 +104,6 @@ func gobuildOptions(bo *options.BuildOptions) ([]build.Option, error) {
|
||||
switch bo.SBOM {
|
||||
case "none":
|
||||
opts = append(opts, build.WithDisabledSBOM())
|
||||
case "go.version-m":
|
||||
opts = append(opts, build.WithGoVersionSBOM())
|
||||
case "cyclonedx":
|
||||
opts = append(opts, build.WithCycloneDX())
|
||||
default: // "spdx"
|
||||
opts = append(opts, build.WithSPDX(version()))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user