Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions app/cli/documentation/cli-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -252,7 +252,7 @@ Options
--annotation strings additional annotation in the format of key=value
--attestation-id string Unique identifier of the in-progress attestation
-h, --help help for add
--kind string kind of the material to be recorded: ["ARTIFACT" "ASYNCAPI_SPEC" "ATTESTATION" "BLACKDUCK_SCA_JSON" "CHAINLOOP_AI_AGENT_CONFIG" "CHAINLOOP_AI_CODING_SESSION" "CHAINLOOP_PR_INFO" "CHAINLOOP_RUNNER_CONTEXT" "CONTAINER_IMAGE" "CSAF_INFORMATIONAL_ADVISORY" "CSAF_SECURITY_ADVISORY" "CSAF_SECURITY_INCIDENT_RESPONSE" "CSAF_VEX" "EVIDENCE" "GHAS_CODE_SCAN" "GHAS_DEPENDENCY_SCAN" "GHAS_SECRET_SCAN" "GITLAB_SECURITY_REPORT" "GITLEAKS_JSON" "GRAPHQL_SPEC" "HELM_CHART" "JACOCO_XML" "JUNIT_XML" "OPENAPI_SPEC" "OPENVEX" "SARIF" "SBOM_CYCLONEDX_JSON" "SBOM_SPDX_JSON" "SLSA_PROVENANCE" "STRING" "SYSINTERNALS_ACCESSCHK" "SYSINTERNALS_SIGCHECK" "TWISTCLI_SCAN_JSON" "YELP_DETECT_SECRETS_BASELINE" "ZAP_DAST_ZIP"]
--kind string kind of the material to be recorded: ["ARTIFACT" "ASYNCAPI_SPEC" "ATTESTATION" "BLACKDUCK_SCA_JSON" "CERTCC_DRANZER" "CHAINLOOP_AI_AGENT_CONFIG" "CHAINLOOP_AI_CODING_SESSION" "CHAINLOOP_PR_INFO" "CHAINLOOP_RUNNER_CONTEXT" "CONTAINER_IMAGE" "CSAF_INFORMATIONAL_ADVISORY" "CSAF_SECURITY_ADVISORY" "CSAF_SECURITY_INCIDENT_RESPONSE" "CSAF_VEX" "EVIDENCE" "GHAS_CODE_SCAN" "GHAS_DEPENDENCY_SCAN" "GHAS_SECRET_SCAN" "GITLAB_SECURITY_REPORT" "GITLEAKS_JSON" "GRAPHQL_SPEC" "HELM_CHART" "JACOCO_XML" "JUNIT_XML" "OPENAPI_SPEC" "OPENVEX" "SARIF" "SBOM_CYCLONEDX_JSON" "SBOM_SPDX_JSON" "SLSA_PROVENANCE" "STRING" "SYSINTERNALS_ACCESSCHK" "SYSINTERNALS_SIGCHECK" "TWISTCLI_SCAN_JSON" "YELP_DETECT_SECRETS_BASELINE" "ZAP_DAST_ZIP"]
--name string name of the material as shown in the contract
--no-strict-validation skip strict schema validation for structured materials (SBOM_CYCLONEDX_JSON, OPENAPI_SPEC, ASYNCAPI_SPEC)
--registry-password string registry password, ($CHAINLOOP_REGISTRY_PASSWORD)
Expand Down Expand Up @@ -3025,7 +3025,7 @@ Options
--annotation strings Key-value pairs of material annotations (key=value)
-h, --help help for eval
--input stringArray Key-value pairs of policy inputs (key=value)
--kind string Kind of the material: ["ARTIFACT" "ASYNCAPI_SPEC" "ATTESTATION" "BLACKDUCK_SCA_JSON" "CHAINLOOP_AI_AGENT_CONFIG" "CHAINLOOP_AI_CODING_SESSION" "CHAINLOOP_PR_INFO" "CHAINLOOP_RUNNER_CONTEXT" "CONTAINER_IMAGE" "CSAF_INFORMATIONAL_ADVISORY" "CSAF_SECURITY_ADVISORY" "CSAF_SECURITY_INCIDENT_RESPONSE" "CSAF_VEX" "EVIDENCE" "GHAS_CODE_SCAN" "GHAS_DEPENDENCY_SCAN" "GHAS_SECRET_SCAN" "GITLAB_SECURITY_REPORT" "GITLEAKS_JSON" "GRAPHQL_SPEC" "HELM_CHART" "JACOCO_XML" "JUNIT_XML" "OPENAPI_SPEC" "OPENVEX" "SARIF" "SBOM_CYCLONEDX_JSON" "SBOM_SPDX_JSON" "SLSA_PROVENANCE" "STRING" "SYSINTERNALS_ACCESSCHK" "SYSINTERNALS_SIGCHECK" "TWISTCLI_SCAN_JSON" "YELP_DETECT_SECRETS_BASELINE" "ZAP_DAST_ZIP"]
--kind string Kind of the material: ["ARTIFACT" "ASYNCAPI_SPEC" "ATTESTATION" "BLACKDUCK_SCA_JSON" "CERTCC_DRANZER" "CHAINLOOP_AI_AGENT_CONFIG" "CHAINLOOP_AI_CODING_SESSION" "CHAINLOOP_PR_INFO" "CHAINLOOP_RUNNER_CONTEXT" "CONTAINER_IMAGE" "CSAF_INFORMATIONAL_ADVISORY" "CSAF_SECURITY_ADVISORY" "CSAF_SECURITY_INCIDENT_RESPONSE" "CSAF_VEX" "EVIDENCE" "GHAS_CODE_SCAN" "GHAS_DEPENDENCY_SCAN" "GHAS_SECRET_SCAN" "GITLAB_SECURITY_REPORT" "GITLEAKS_JSON" "GRAPHQL_SPEC" "HELM_CHART" "JACOCO_XML" "JUNIT_XML" "OPENAPI_SPEC" "OPENVEX" "SARIF" "SBOM_CYCLONEDX_JSON" "SBOM_SPDX_JSON" "SLSA_PROVENANCE" "STRING" "SYSINTERNALS_ACCESSCHK" "SYSINTERNALS_SIGCHECK" "TWISTCLI_SCAN_JSON" "YELP_DETECT_SECRETS_BASELINE" "ZAP_DAST_ZIP"]
--material string Path to material or attestation file
-p, --policy string Policy reference (./my-policy.yaml, https://my-domain.com/my-policy.yaml, chainloop://my-stored-policy) (default "policy.yaml")
--project string Project name to use as engine context for chainloop.* built-ins
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 @@ -170,6 +170,8 @@ message CraftingSchema {
SYSINTERNALS_SIGCHECK = 34;
// Sysinternals AccessChk text output https://learn.microsoft.com/en-us/sysinternals/downloads/accesschk
SYSINTERNALS_ACCESSCHK = 35;
// CERT/CC dranzer ActiveX/COM control test report (plain text) https://github.com/CERTCC/dranzer
CERTCC_DRANZER = 36;
}
}
}
Expand Down
95 changes: 53 additions & 42 deletions pkg/attestation/crafter/api/attestation/v1/crafting_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
v1 "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
"github.com/chainloop-dev/chainloop/pkg/attestation/crafter/materials/accesschk"
"github.com/chainloop-dev/chainloop/pkg/attestation/crafter/materials/attestation"
"github.com/chainloop-dev/chainloop/pkg/attestation/crafter/materials/dranzer"
"github.com/chainloop-dev/chainloop/pkg/attestation/crafter/materials/jacoco"
materialsjunit "github.com/chainloop-dev/chainloop/pkg/attestation/crafter/materials/junit"
"github.com/chainloop-dev/chainloop/pkg/attestation/crafter/materials/sigcheck"
Expand Down Expand Up @@ -124,48 +125,11 @@ 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 := materialsjunit.Ingest(value)
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)
}
case v1.CraftingSchema_Material_SYSINTERNALS_SIGCHECK:
report, ierr := sigcheck.Parse(rawMaterial)
if ierr != nil {
return nil, fmt.Errorf("failed to ingest sigcheck report: %w", ierr)
}
rawMaterial, err = report.JSON()
if err != nil {
return nil, fmt.Errorf("failed to marshal sigcheck report: %w", err)
}
case v1.CraftingSchema_Material_SYSINTERNALS_ACCESSCHK:
// AccessChk emits plain text; project it to JSON so the policy engine,
// which only consumes JSON, can evaluate it. The raw text is preserved
// in the projection's "raw" field for string-matching fallbacks.
report, perr := accesschk.Parse(rawMaterial)
if perr != nil {
return nil, fmt.Errorf("invalid accesschk material: %w", perr)
}
rawMaterial, err = json.Marshal(report)
if err != nil {
return nil, fmt.Errorf("failed to marshal accesschk material: %w", err)
}
// Non-JSON materials (XML- or text-based formats) are projected to the JSON
// the policy engine consumes; JSON-native materials pass through unchanged.
rawMaterial, err = m.ingestMaterialToJSON(rawMaterial, value)
if err != nil {
return nil, err
}

// if raw material is empty (container images, for example), let's create an empty json
Expand Down Expand Up @@ -206,6 +170,53 @@ func (m *Attestation_Material) GetEvaluableContent(value string) ([]byte, error)
return result, nil
}

// ingestMaterialToJSON projects materials that are not natively JSON (XML- or
// text-based formats) into the JSON structure the policy engine consumes.
// Materials that are already JSON are returned unchanged.
func (m *Attestation_Material) ingestMaterialToJSON(rawMaterial []byte, value string) ([]byte, error) {
switch m.MaterialType {
case v1.CraftingSchema_Material_JUNIT_XML:
suites, err := materialsjunit.Ingest(value)
if err != nil {
return nil, fmt.Errorf("failed to ingest junit xml: %w", err)
}
// this will render a json array
return json.Marshal(suites)
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)
}
return json.Marshal(&report)
case v1.CraftingSchema_Material_SYSINTERNALS_SIGCHECK:
report, err := sigcheck.Parse(rawMaterial)
if err != nil {
return nil, fmt.Errorf("failed to ingest sigcheck report: %w", err)
}
return report.JSON()
case v1.CraftingSchema_Material_SYSINTERNALS_ACCESSCHK:
// AccessChk emits plain text; project it to JSON so the policy engine,
// which only consumes JSON, can evaluate it. The raw text is preserved
// in the projection's "raw" field for string-matching fallbacks.
report, err := accesschk.Parse(rawMaterial)
if err != nil {
return nil, fmt.Errorf("invalid accesschk material: %w", err)
}
return json.Marshal(report)
case v1.CraftingSchema_Material_CERTCC_DRANZER:
// dranzer emits plain text; project it to JSON so the policy engine,
// which only consumes JSON, can evaluate it. The raw text is preserved
// in the projection's "raw" field for string-matching fallbacks.
report, err := dranzer.Parse(rawMaterial)
if err != nil {
return nil, fmt.Errorf("invalid dranzer material: %w", err)
}
return json.Marshal(report)
}

return rawMaterial, nil
}

// CraftingStateToIntotoDescriptor creates an intoto descriptor from a material in crafting state
func (m *Attestation_Material) CraftingStateToIntotoDescriptor(name string) (*intoto.ResourceDescriptor, error) {
material := &intoto.ResourceDescriptor{}
Expand Down
14 changes: 14 additions & 0 deletions pkg/attestation/crafter/api/attestation/v1/crafting_state_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,20 @@ func TestGetEvaluableContentWithMetadata(t *testing.T) {
},
testField: "objects",
},
{
name: "dranzer text material projected to json",
material: &Attestation_Material{
MaterialType: schemaapi.CraftingSchema_Material_CERTCC_DRANZER,
M: &Attestation_Material_Artifact_{
Artifact: &Attestation_Material_Artifact{
Name: "name", Digest: "sha256:deadbeef", IsSubject: true,
Content: []byte("Testing COM Object - {11111111-2222-3333-4444-555555555555} Example.WidgetControl\nCOM Object Filename : example.ocx\n"),
},
},
InlineCas: true,
},
testField: "objects",
},
}

for _, tc := range cases {
Expand Down
Loading
Loading