Skip to content

Commit fdb331b

Browse files
authored
Configurable timestamp (#2724)
* make timestamp configurable from configuration options and update README.md Signed-off-by: Gabriel Rau <[email protected]> * logic to add timestamp or not added unit test for config option Signed-off-by: Gabriel Rau <[email protected]> * refactor NewDocument method to specify config option for timestamp Signed-off-by: Gabriel Rau <[email protected]> * formatting Signed-off-by: Gabriel Rau <[email protected]> * remove already accounted for check Signed-off-by: Gabriel Rau <[email protected]> --------- Signed-off-by: Gabriel Rau <[email protected]>
1 parent 5e4c1f5 commit fdb331b

File tree

9 files changed

+43
-13
lines changed

9 files changed

+43
-13
lines changed

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -980,6 +980,9 @@ dev:
980980
db:
981981
# show sql queries in trace logging (requires -vv) (env: GRYPE_DEV_DB_DEBUG)
982982
debug: false
983+
984+
# include a timestamp (env: GRYPE_TIMESTAMP)
985+
timestamp: true
983986
```
984987

985988
## Future plans

cmd/grype/cli/commands/root.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ func runGrype(app clio.Application, opts *options.Grype, userInput string) (errs
236236
log.WithFields("time", time.Since(startTime)).Info("found vulnerability matches")
237237
startTime = time.Now()
238238

239-
model, err := models.NewDocument(app.ID(), packages, pkgContext, *remainingMatches, ignoredMatches, vp, opts, dbInfo(status, vp), models.SortStrategy(opts.SortBy.Criteria))
239+
model, err := models.NewDocument(app.ID(), packages, pkgContext, *remainingMatches, ignoredMatches, vp, opts, dbInfo(status, vp), models.SortStrategy(opts.SortBy.Criteria), opts.Timestamp)
240240
if err != nil {
241241
return fmt.Errorf("failed to create document: %w", err)
242242
}

cmd/grype/cli/options/grype.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ type Grype struct {
3838
VexAdd []string `yaml:"vex-add" json:"vex-add" mapstructure:"vex-add"` // GRYPE_VEX_ADD
3939
MatchUpstreamKernelHeaders bool `yaml:"match-upstream-kernel-headers" json:"match-upstream-kernel-headers" mapstructure:"match-upstream-kernel-headers"` // Show matches on kernel-headers packages where the match is on kernel upstream instead of marking them as ignored, default=false
4040
FixChannel FixChannels `yaml:"fix-channel" json:"fix-channel" mapstructure:"fix-channel"` // the fix channels to apply to the distro when matching
41+
Timestamp bool `yaml:"timestamp" json:"timestamp" mapstructure:"timestamp"`
4142
DatabaseCommand `yaml:",inline" json:",inline" mapstructure:",squash"`
4243
}
4344

@@ -68,6 +69,7 @@ func DefaultGrype(id clio.Identification) *Grype {
6869
VexAdd: []string{},
6970
MatchUpstreamKernelHeaders: false,
7071
SortBy: defaultSortBy(),
72+
Timestamp: true,
7173
}
7274
}
7375

grype/presenter/internal/test_helpers.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func GenerateAnalysis(t *testing.T, scheme SyftSource) (*sbom.SBOM, models.Docum
5858

5959
matches := generateMatches(t, grypePackages[0], grypePackages[1])
6060

61-
doc, err := models.NewDocument(clio.Identification{Name: "grype", Version: "[not provided]"}, grypePackages, context, matches, nil, models.NewMetadataMock(), nil, nil, models.SortByPackage)
61+
doc, err := models.NewDocument(clio.Identification{Name: "grype", Version: "[not provided]"}, grypePackages, context, matches, nil, models.NewMetadataMock(), nil, nil, models.SortByPackage, true)
6262
require.NoError(t, err)
6363

6464
return s, doc
@@ -79,7 +79,7 @@ func GenerateAnalysisWithIgnoredMatches(t *testing.T, scheme SyftSource) models.
7979
ignoredMatches := generateIgnoredMatches(t, grypePackages[1])
8080
context := generateContext(t, scheme)
8181

82-
doc, err := models.NewDocument(clio.Identification{Name: "grype", Version: "devel"}, grypePackages, context, matches, ignoredMatches, models.NewMetadataMock(), nil, nil, models.SortByPackage)
82+
doc, err := models.NewDocument(clio.Identification{Name: "grype", Version: "devel"}, grypePackages, context, matches, ignoredMatches, models.NewMetadataMock(), nil, nil, models.SortByPackage, true)
8383
require.NoError(t, err)
8484
return doc
8585
}

grype/presenter/json/presenter_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ func TestEmptyJsonPresenter(t *testing.T) {
9292
},
9393
}
9494

95-
doc, err := models.NewDocument(clio.Identification{Name: "grype", Version: "[not provided]"}, nil, ctx, match.NewMatches(), nil, models.NewMetadataMock(), nil, nil, models.SortByPackage)
95+
doc, err := models.NewDocument(clio.Identification{Name: "grype", Version: "[not provided]"}, nil, ctx, match.NewMatches(), nil, models.NewMetadataMock(), nil, nil, models.SortByPackage, true)
9696
require.NoError(t, err)
9797

9898
pb := models.PresenterConfig{

grype/presenter/models/descriptor.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@ type descriptor struct {
66
Version string `json:"version"`
77
Configuration any `json:"configuration,omitempty"`
88
DB any `json:"db,omitempty"`
9-
Timestamp string `json:"timestamp"`
9+
Timestamp string `json:"timestamp,omitempty"`
1010
}

grype/presenter/models/document.go

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,18 @@ type Document struct {
2121
}
2222

2323
// NewDocument creates and populates a new Document struct, representing the populated JSON document.
24-
func NewDocument(id clio.Identification, packages []pkg.Package, context pkg.Context, matches match.Matches, ignoredMatches []match.IgnoredMatch, metadataProvider vulnerability.MetadataProvider, appConfig any, dbInfo any, strategy SortStrategy) (Document, error) {
25-
timestamp, timestampErr := time.Now().Local().MarshalText()
26-
if timestampErr != nil {
27-
return Document{}, timestampErr
24+
func NewDocument(id clio.Identification, packages []pkg.Package, context pkg.Context, matches match.Matches, ignoredMatches []match.IgnoredMatch, metadataProvider vulnerability.MetadataProvider, appConfig any, dbInfo any, strategy SortStrategy, outputTimestamp bool) (Document, error) {
25+
var timestamp []byte
26+
27+
if !outputTimestamp {
28+
// can't be nil in string() call
29+
timestamp = []byte{}
30+
} else {
31+
var timestampErr error
32+
timestamp, timestampErr = time.Now().Local().MarshalText()
33+
if timestampErr != nil {
34+
return Document{}, timestampErr
35+
}
2836
}
2937

3038
// we must preallocate the findings to ensure the JSON document does not show "null" when no matches are found

grype/presenter/models/document_test.go

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func TestPackagesAreSorted(t *testing.T) {
7575
Metadata: syftSource.DirectoryMetadata{},
7676
},
7777
}
78-
doc, err := NewDocument(clio.Identification{}, packages, ctx, matches, nil, NewMetadataMock(), nil, nil, SortByPackage)
78+
doc, err := NewDocument(clio.Identification{}, packages, ctx, matches, nil, NewMetadataMock(), nil, nil, SortByPackage, true)
7979
if err != nil {
8080
t.Fatalf("unable to get document: %+v", err)
8181
}
@@ -131,7 +131,7 @@ func TestFixSuggestedVersion(t *testing.T) {
131131
Metadata: syftSource.DirectoryMetadata{},
132132
},
133133
}
134-
doc, err := NewDocument(clio.Identification{}, packages, ctx, matches, nil, NewMetadataMock(), nil, nil, SortByPackage)
134+
doc, err := NewDocument(clio.Identification{}, packages, ctx, matches, nil, NewMetadataMock(), nil, nil, SortByPackage, true)
135135
if err != nil {
136136
t.Fatalf("unable to get document: %+v", err)
137137
}
@@ -149,7 +149,7 @@ func TestTimestampValidFormat(t *testing.T) {
149149
Source: nil,
150150
}
151151

152-
doc, err := NewDocument(clio.Identification{}, nil, ctx, matches, nil, nil, nil, nil, SortByPackage)
152+
doc, err := NewDocument(clio.Identification{}, nil, ctx, matches, nil, nil, nil, nil, SortByPackage, true)
153153
if err != nil {
154154
t.Fatalf("unable to get document: %+v", err)
155155
}
@@ -162,3 +162,20 @@ func TestTimestampValidFormat(t *testing.T) {
162162
}
163163

164164
}
165+
166+
func TestConfigurableTimestamp(t *testing.T) {
167+
168+
matches := match.NewMatches()
169+
ctx := pkg.Context{
170+
Source: nil,
171+
Distro: nil,
172+
}
173+
174+
doc, err := NewDocument(clio.Identification{}, nil, ctx, matches, nil, nil, nil, nil, SortByPackage, false)
175+
if err != nil {
176+
t.Fatalf("unable to get document: %+v", err)
177+
}
178+
179+
assert.Empty(t, doc.Descriptor.Timestamp)
180+
181+
}

grype/presenter/table/presenter_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ func TestEmptyTablePresenter(t *testing.T) {
149149

150150
var buffer bytes.Buffer
151151

152-
doc, err := models.NewDocument(clio.Identification{}, nil, pkg.Context{}, match.NewMatches(), nil, nil, nil, nil, models.SortByPackage)
152+
doc, err := models.NewDocument(clio.Identification{}, nil, pkg.Context{}, match.NewMatches(), nil, nil, nil, nil, models.SortByPackage, true)
153153
require.NoError(t, err)
154154
pb := models.PresenterConfig{
155155
Document: doc,

0 commit comments

Comments
 (0)