-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathcreate.go
144 lines (116 loc) · 4.33 KB
/
create.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/*
Copyright 2022 The OpenVEX Authors
SPDX-License-Identifier: Apache-2.0
*/
package cmd
import (
"errors"
"fmt"
"github.com/spf13/cobra"
"github.com/openvex/go-vex/pkg/vex"
)
type createOptions struct {
vexDocOptions
vexStatementOptions
outFileOption
}
// Validates the options in context with arguments
func (o *createOptions) Validate() error {
return errors.Join(
o.vexStatementOptions.Validate(),
o.outFileOption.Validate(),
o.vexDocOptions.Validate(),
)
}
func (o *createOptions) AddFlags(cmd *cobra.Command) {
o.vexDocOptions.AddFlags(cmd)
o.vexStatementOptions.AddFlags(cmd)
o.outFileOption.AddFlags(cmd)
}
func addCreate(parentCmd *cobra.Command) {
opts := createOptions{}
createCmd := &cobra.Command{
Short: fmt.Sprintf("%s create: creates a new VEX document", appname),
Long: fmt.Sprintf(`%s create: creates a new VEX document
The create subcommand generates a single statement document
from the command line. This is intended for simple use cases
or to get a base document to get started.
You can specify multiple products and customize the metadata of
the document via the command line flags. %s will honor the
SOURCE_DATE_EPOCH environment variable and use that date for
the document (it can be formatted in UNIX time or RFC3339).
If you don't specify an ID for the document, one will be generated
using its canonicalization hash.
Examples:
# Generate a document stating that CVE-2023-12345 was fixed in the
# git package of Wolfi:
%s create "pkg:apk/wolfi/[email protected]?arch=x86_64" CVE-2023-12345 fixed
# You can specify more than one product. %s will read one from
# the argument but you can control all parameters through command line
# flags. Here's an example with two products in the same document:
%s create --product="pkg:apk/wolfi/[email protected]?arch=x86_64" \
--product="pkg:apk/wolfi/[email protected]?arch=armv7" \
--vuln="CVE-2023-12345" \
--status="fixed"
# not_affected statements need a justification:
%s create --product="pkg:apk/wolfi/[email protected]?arch=x86_64" \
--vuln="CVE-2023-12345" \
--status="not_affected" \
--justification="component_not_present"
`, appname, appname, appname, appname, appname, appname),
Use: "create [flags] [product_id [vuln_id [status]]]",
Example: fmt.Sprintf("%s create \"pkg:apk/wolfi/[email protected]?arch=x86_64\" CVE-2022-39260 fixed ", appname),
SilenceUsage: false,
SilenceErrors: true,
PersistentPreRunE: initLogging,
RunE: func(_ *cobra.Command, args []string) error {
// If we have arguments, add them
for i := range args {
switch i {
case 0:
if len(opts.Products) > 0 && args[i] != "" {
return errors.New("multiple products can only be specified using the --product flag")
}
// Specifying multiple products through args is not supported as we can't tell how many products are provided:
// e.g the second argument could be a vulnerability or a status instead of a product, for example.
// When using args only the first one is considered a product.
// To specify multiple products, use the --product flag multiple times instead.
opts.Products = append(opts.Products, args[i])
case 1:
if opts.Vulnerability != "" && opts.Vulnerability != args[i] {
return errors.New("vulnerability can only be specified once")
}
opts.Vulnerability = args[i]
case 2:
if opts.Status != "" && opts.Status != args[i] {
return errors.New("status can only be specified once")
}
opts.Status = args[i]
}
}
if err := opts.Validate(); err != nil {
return err
}
newDoc := vex.New()
newDoc.Metadata.Author = opts.Author
newDoc.Metadata.AuthorRole = opts.AuthorRole
if opts.DocumentID != "" {
newDoc.Metadata.ID = opts.DocumentID
}
statement := opts.ToStatement()
if err := statement.Validate(); err != nil {
return fmt.Errorf("invalid statement: %w", err)
}
newDoc.Statements = append(newDoc.Statements, statement)
if _, err := newDoc.GenerateCanonicalID(); err != nil {
return fmt.Errorf("generating document id: %w", err)
}
if err := writeDocument(&newDoc, opts.outFilePath); err != nil {
return fmt.Errorf("writing openvex document: %w", err)
}
return nil
},
}
opts.AddFlags(createCmd)
parentCmd.AddCommand(createCmd)
}