Skip to content

Commit

Permalink
feat(materials): New JACOCO_XML material type and support for policies (
Browse files Browse the repository at this point in the history
chainloop-dev#1624)

Signed-off-by: Jose I. Paris <[email protected]>
  • Loading branch information
jiparis authored Dec 6, 2024
1 parent 92ebce3 commit e1b9dc5
Show file tree
Hide file tree
Showing 25 changed files with 366 additions and 36 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ Chainloop supports the collection of the following list of evidence types. For t
- [CSAF VEX](https://docs.oasis-open.org/csaf/csaf/v2.0/os/csaf-v2.0-os.html#45-profile-5-vex)
- [Gitlab Security report](https://docs.gitlab.com/ee/user/application_security/)
- [JUnit](https://www.ibm.com/docs/en/developer-for-zos/14.1?topic=formats-junit-xml-format)
- [JaCoCo XML Coverage Reports](https://www.jacoco.org/jacoco/trunk/doc/)
- Attestation: existing Chainloop attestations.
- Artifact Type: It represents a software artifact.
- Custom Evidence Type: Custom piece of evidence that doesn't fit in any other category, for instance, an approval report in json format, etc.
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 9 additions & 4 deletions app/controlplane/api/workflowcontract/v1/crafting_schema.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ message CraftingSchema {
GHAS_SECRET_SCAN = 21;
// https://docs.github.com/en/rest/dependabot/alerts?apiVersion=2022-11-28
GHAS_DEPENDENCY_SCAN = 22;
// Jacoco coverage reports https://www.jacoco.org/userdoc/importexport.html
JACOCO_XML = 23;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ var CraftingMaterialInValidationOrder = []CraftingSchema_Material_MaterialType{
CraftingSchema_Material_CSAF_SECURITY_INCIDENT_RESPONSE,
CraftingSchema_Material_GITLAB_SECURITY_REPORT,
CraftingSchema_Material_JUNIT_XML,
CraftingSchema_Material_JACOCO_XML,
CraftingSchema_Material_HELM_CHART,
CraftingSchema_Material_SARIF,
CraftingSchema_Material_BLACKDUCK_SCA_JSON,
Expand Down
5 changes: 5 additions & 0 deletions docs/docs/partials/materials.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@
"link": "https://www.ibm.com/docs/en/developer-for-zos/14.1?topic=formats-junit-xml-format",
"id": "JUNIT_XML"
},
{
"name": "JaCoCo XML Report",
"link": "https://www.jacoco.org/jacoco/trunk/doc/",
"id": "JACOCO_XML"
},
{
"name": "Helm Chart",
"link": "https://helm.sh/docs/topics/charts/",
Expand Down
26 changes: 26 additions & 0 deletions pkg/attestation/crafter/api/attestation/v1/crafting_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ package v1
import (
"bytes"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"os"
"strings"

v1 "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
"github.com/chainloop-dev/chainloop/pkg/attestation/crafter/materials/jacoco"
intoto "github.com/in-toto/attestation/go/v1"
"github.com/joshdk/go-junit"
"github.com/secure-systems-lab/go-securesystemslib/dsse"
"google.golang.org/protobuf/types/known/structpb"
)
Expand Down Expand Up @@ -104,6 +107,29 @@ func (m *Attestation_Material) GetEvaluableContent(value string) ([]byte, error)
}
}

// For XML based materials, we need to ingest them and read as json-like structure
switch m.MaterialType {
case v1.CraftingSchema_Material_JUNIT_XML:
suites, err := junit.Ingest(rawMaterial)
if err != nil {
return nil, fmt.Errorf("failed to ingest junit xml: %w", err)
}
// this will render a json array
rawMaterial, err = json.Marshal(suites)
if err != nil {
return nil, fmt.Errorf("failed to marshal junit xml: %w", err)
}
case v1.CraftingSchema_Material_JACOCO_XML:
var report jacoco.Report
if err := xml.Unmarshal(rawMaterial, &report); err != nil {
return nil, fmt.Errorf("invalid Jacoco report file: %w", err)
}
rawMaterial, err = json.Marshal(&report)
if err != nil {
return nil, fmt.Errorf("failed to marshal to json Jacoco report file: %w", err)
}
}

// if raw material is empty (container images, for example), let's create an empty json
if len(rawMaterial) == 0 {
rawMaterial = []byte(`{}`)
Expand Down
74 changes: 74 additions & 0 deletions pkg/attestation/crafter/materials/jacoco.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//
// Copyright 2024 The Chainloop Authors.
//
// 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 materials

import (
"context"
"encoding/xml"
"fmt"
"io"
"os"
"slices"

schemaapi "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
"github.com/chainloop-dev/chainloop/internal/casclient"
api "github.com/chainloop-dev/chainloop/pkg/attestation/crafter/api/attestation/v1"
"github.com/chainloop-dev/chainloop/pkg/attestation/crafter/materials/jacoco"
"github.com/rs/zerolog"
)

type JacocoCrafter struct {
*crafterCommon
backend *casclient.CASBackend
}

func NewJacocoCrafter(schema *schemaapi.CraftingSchema_Material, backend *casclient.CASBackend, l *zerolog.Logger) *JacocoCrafter {
return &JacocoCrafter{
crafterCommon: &crafterCommon{logger: l, input: schema},
backend: backend,
}
}

func (c *JacocoCrafter) Craft(ctx context.Context, filePath string) (*api.Attestation_Material, error) {
f, err := os.Open(filePath)
if err != nil {
return nil, fmt.Errorf("can't open the file: %w", err)
}
defer f.Close()

bytes, err := io.ReadAll(f)
if err != nil {
return nil, fmt.Errorf("can't read the file: %w", err)
}

var report jacoco.Report

if err := xml.Unmarshal(bytes, &report); err != nil {
return nil, fmt.Errorf("invalid Jacoco report file: %w", ErrInvalidMaterialType)
}

if len(report.Counters) == 0 {
return nil, fmt.Errorf("invalid Jacoco report file, no counters found: %w", ErrInvalidMaterialType)
}
// At least "instruction" counter should be available according to the documentation
// https://www.eclemma.org/jacoco/trunk/doc/counters.html
if !slices.ContainsFunc(report.Counters, func(counter *jacoco.Counter) bool {
return counter.Type == "INSTRUCTION"
}) {
return nil, fmt.Errorf("invalid Jacoco report file: %w", ErrInvalidMaterialType)
}
return uploadAndCraft(ctx, c.input, c.backend, filePath, c.logger)
}
Loading

0 comments on commit e1b9dc5

Please sign in to comment.