Skip to content

Commit caab745

Browse files
committed
fix(materials): only annotate Scorecard score when present
Address review feedback: the aggregate score annotation was set unconditionally, so a nonconformant report missing "score" would be misrepresented as score 0 under --no-strict-validation. Make the score field a pointer so an absent score is distinguishable from a real 0.0, and only set the annotation when present. Assisted-by: Claude Code Signed-off-by: Miguel Martinez Trivino <miguel@chainloop.dev> Chainloop-Trace-Sessions: 234a5dc3-baba-4c3d-be42-dbabf15c5487
1 parent 48344e8 commit caab745

3 files changed

Lines changed: 32 additions & 7 deletions

File tree

pkg/attestation/crafter/materials/scorecard.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ type OSSFScorecardCrafter struct {
4040
// detection and annotations. Deep structural validation is delegated to the
4141
// embedded JSON Schema via schemavalidators.ValidateOSSFScorecard.
4242
type scorecardReport struct {
43-
Date string `json:"date"`
44-
Score float64 `json:"score"`
43+
Date string `json:"date"`
44+
// Score is a pointer so an absent aggregate score is distinguishable from a
45+
// legitimate 0.0, avoiding misrepresenting a nonconformant report as score 0.
46+
Score *float64 `json:"score"`
4547
Repo struct {
4648
Name string `json:"name"`
4749
Commit string `json:"commit"`
@@ -142,5 +144,7 @@ func (i *OSSFScorecardCrafter) injectAnnotations(m *api.Attestation_Material, re
142144
m.Annotations[AnnotationToolVersionKey] = report.Scorecard.Version
143145
}
144146

145-
m.Annotations["chainloop.material.scorecard.score"] = strconv.FormatFloat(report.Score, 'f', -1, 64)
147+
if report.Score != nil {
148+
m.Annotations["chainloop.material.scorecard.score"] = strconv.FormatFloat(*report.Score, 'f', -1, 64)
149+
}
146150
}

pkg/attestation/crafter/materials/scorecard_test.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,11 @@ func TestOSSFScorecardCrafter_Craft(t *testing.T) {
151151
// rejects arbitrary JSON, so non-Scorecard files are not misclassified.
152152
func TestOSSFScorecardCrafter_Craft_NoStrictValidation(t *testing.T) {
153153
testCases := []struct {
154-
name string
155-
filePath string
156-
wantErr string
154+
name string
155+
// noScoreAnnotation asserts the score annotation is absent (report had no score).
156+
filePath string
157+
wantErr string
158+
noScoreAnnotation bool
157159
}{
158160
{
159161
name: "non-scorecard json still rejected",
@@ -164,6 +166,11 @@ func TestOSSFScorecardCrafter_Craft_NoStrictValidation(t *testing.T) {
164166
name: "valid scorecard accepted",
165167
filePath: "./testdata/scorecard-chainloop.json",
166168
},
169+
{
170+
name: "report without score is not annotated as score 0",
171+
filePath: "./testdata/scorecard-no-score.json",
172+
noScoreAnnotation: true,
173+
},
167174
}
168175

169176
schema := &contractAPI.CraftingSchema_Material{
@@ -184,13 +191,17 @@ func TestOSSFScorecardCrafter_Craft_NoStrictValidation(t *testing.T) {
184191
crafter, err := materials.NewOSSFScorecardCrafter(schema, backend, &l, materials.WithOSSFScorecardNoStrictValidation(true))
185192
require.NoError(t, err)
186193

187-
_, err = crafter.Craft(context.TODO(), tc.filePath)
194+
got, err := crafter.Craft(context.TODO(), tc.filePath)
188195
if tc.wantErr != "" {
189196
assert.ErrorContains(t, err, tc.wantErr)
190197
return
191198
}
192199

193200
require.NoError(t, err)
201+
if tc.noScoreAnnotation {
202+
_, ok := got.Annotations["chainloop.material.scorecard.score"]
203+
assert.False(t, ok, "score annotation should be absent when report has no score")
204+
}
194205
})
195206
}
196207
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{
2+
"date": "2026-06-15T14:27:17+02:00",
3+
"repo": { "name": "github.com/chainloop-dev/chainloop", "commit": "892e78c" },
4+
"scorecard": { "version": "v5.5.0", "commit": "c395761" },
5+
"checks": [
6+
{ "details": null, "score": 10, "reason": "license file detected", "name": "License",
7+
"documentation": { "url": "https://example.com", "short": "x" } }
8+
],
9+
"metadata": null
10+
}

0 commit comments

Comments
 (0)