Skip to content

Commit 37067c0

Browse files
author
Trong Nhan Mai
authored
fix: use artifact filenames as keys for verifying jfrog assets in provenance_witness_l1_check (#796)
Signed-off-by: Trong Nhan Mai <trong.nhan.mai@oracle.com>
1 parent 7d22a4d commit 37067c0

File tree

6 files changed

+308
-56
lines changed

6 files changed

+308
-56
lines changed

src/macaron/slsa_analyzer/checks/provenance_witness_l1_check.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from sqlalchemy.orm import Mapped, mapped_column
1010

1111
from macaron.database.table_definitions import CheckFacts
12+
from macaron.errors import MacaronError
1213
from macaron.slsa_analyzer.analyze_context import AnalyzeContext
1314
from macaron.slsa_analyzer.checks.base_check import BaseCheck
1415
from macaron.slsa_analyzer.checks.check_result import CheckResultData, CheckResultType, Confidence, JustificationType
@@ -27,6 +28,10 @@
2728
logger: logging.Logger = logging.getLogger(__name__)
2829

2930

31+
class WitnessProvenanceException(MacaronError):
32+
"""When there is an error while processing a Witness provenance."""
33+
34+
3035
class WitnessProvenanceAvailableFacts(CheckFacts):
3136
"""The ORM mapping for justifications in provenance l3 check."""
3237

@@ -66,20 +71,32 @@ def verify_artifact_assets(
6671
-------
6772
bool
6873
True if verification succeeds and False otherwise.
74+
75+
Raises
76+
------
77+
WitnessProvenanceException
78+
If a subject is not a file attested by the Witness product attestor.
6979
"""
7080
# A look-up table to verify:
7181
# 1. if the name of the artifact appears in any subject of the witness provenance, then
7282
# 2. if the digest of the artifact could be found
7383
look_up: dict[str, dict[str, InTotoV01Subject]] = {}
7484

7585
for subject in subjects:
76-
if subject["name"] not in look_up:
77-
look_up[subject["name"]] = {}
78-
look_up[subject["name"]][subject["digest"]["sha256"]] = subject
86+
if not subject["name"].startswith("https://witness.dev/attestations/product/v0.1/file:"):
87+
raise WitnessProvenanceException(
88+
f"{subject['name']} is not a file attested by the Witness product attestor."
89+
)
90+
91+
# Get the artifact name, which should be the last part of the artifact subject value.
92+
_, _, artifact_filename = subject["name"].rpartition("/")
93+
if artifact_filename not in look_up:
94+
look_up[artifact_filename] = {}
95+
look_up[artifact_filename][subject["digest"]["sha256"]] = subject
7996

8097
for asset in artifact_assets:
8198
if asset.name not in look_up:
82-
message = f"Could not find subject with name {asset.name} in the provenance."
99+
message = f"Could not find subject for asset {asset.name} in the provenance."
83100
logger.info(message)
84101
return False
85102

@@ -169,7 +186,16 @@ def run_check(self, ctx: AnalyzeContext) -> CheckResultData:
169186
)
170187
subjects = extract_build_artifacts_from_witness_subjects(provenance.payload)
171188

172-
if not verify_artifact_assets(artifact_assets, subjects):
189+
try:
190+
verify_status = verify_artifact_assets(artifact_assets, subjects)
191+
except WitnessProvenanceException as err:
192+
logger.error(err)
193+
return CheckResultData(
194+
result_tables=result_tables,
195+
result_type=CheckResultType.UNKNOWN,
196+
)
197+
198+
if not verify_status:
173199
return CheckResultData(
174200
result_tables=result_tables,
175201
result_type=CheckResultType.FAILED,

src/macaron/slsa_analyzer/provenance/witness/__init__.py

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -82,21 +82,6 @@ def is_witness_provenance_payload(
8282
return isinstance(payload, InTotoV01Payload) and payload.statement["predicateType"] in predicate_types
8383

8484

85-
class WitnessProvenanceSubject(NamedTuple):
86-
"""A helper class to store elements of the ``subject`` list in the provenances."""
87-
88-
#: The ``"name"`` field of each ``subject``.
89-
subject_name: str
90-
#: The SHA256 digest of the corresponding asset to the subject.
91-
sha256_digest: str
92-
93-
@property
94-
def artifact_name(self) -> str:
95-
"""Get the artifact name, which should be the last part of the subject."""
96-
_, _, artifact_name = self.subject_name.rpartition("/")
97-
return artifact_name
98-
99-
10085
def extract_repo_url(witness_payload: InTotoPayload) -> str | None:
10186
"""Extract the repo URL from the witness provenance payload.
10287

tests/integration/cases/behnazh-w_example-maven-app/policy.dl

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,11 @@ Policy("example_maven_app_policy", component_id, "Policy for github Maven projec
77
check_passed(component_id, "mcn_build_service_1"),
88
check_passed(component_id, "mcn_build_script_1"),
99
check_passed(component_id, "mcn_provenance_available_1"),
10-
check_passed(component_id, "mcn_provenance_expectation_1").
10+
check_passed(component_id, "mcn_provenance_expectation_1"),
11+
// We expect mcn_provenance_witness_level_one_1 to fail because at the moment
12+
// it tries to discover the witness provenance even when the provenance is provided as input.
13+
// TODO: address this policy once the issue with mcn_provenance_witness_level_one_1 is addressed.
14+
check_failed(component_id, "mcn_provenance_witness_level_one_1").
1115

1216
apply_policy_to("example_maven_app_policy", component_id) :-
1317
is_repo(
Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"component_satisfies_policy": [
33
[
4-
"176",
4+
"1",
55
"pkg:maven/io.github.behnazh-w.demo/example-maven-app@1.0-SNAPSHOT?type=jar",
66
"example_maven_app_policy"
77
],
@@ -11,11 +11,11 @@
1111
"example_maven_app_policy"
1212
]
1313
],
14-
"component_violates_policy": [],
15-
"failed_policies": [],
1614
"passed_policies": [
1715
[
1816
"example_maven_app_policy"
1917
]
20-
]
18+
],
19+
"component_violates_policy": [],
20+
"failed_policies": []
2121
}
Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,33 @@
11
{
2-
"_type": "https://in-toto.io/Statement/v1",
3-
"subject": [
4-
{
5-
"uri": "pkg:maven/io.github.behnazh-w.demo/example-maven-app@1.0-SNAPSHOT?type=jar",
6-
"digest": {
7-
"sha256": "19986144a60f3d16d1e8d96bc1807c42bb7c91068ab3018b85033f62c2845921"
8-
}
9-
},
10-
{
11-
"uri": "pkg:maven/io.github.behnazh-w.demo/example-maven-app@1.0?type=jar",
12-
"digest": {
13-
"sha256": "759a3c7f76ef2c467cedb814ed3fd38cb9125126664f66f9a62d1cfa0e54b6b7"
14-
}
2+
"_type": "https://in-toto.io/Statement/v1",
3+
"subject": [
4+
{
5+
"uri": "pkg:maven/io.github.behnazh-w.demo/example-maven-app@1.0-SNAPSHOT?type=jar",
6+
"digest": {
7+
"sha256": "19986144a60f3d16d1e8d96bc1807c42bb7c91068ab3018b85033f62c2845921"
8+
}
9+
},
10+
{
11+
"uri": "pkg:maven/io.github.behnazh-w.demo/example-maven-app@1.0?type=jar",
12+
"digest": {
13+
"sha256": "759a3c7f76ef2c467cedb814ed3fd38cb9125126664f66f9a62d1cfa0e54b6b7"
14+
}
15+
}
16+
],
17+
"predicateType": "https://slsa.dev/verification_summary/v1",
18+
"predicate": {
19+
"verifier": {
20+
"id": "https://github.com/oracle/macaron",
21+
"version": {
22+
"macaron": "0.11.0"
23+
}
24+
},
25+
"timeVerified": "2024-07-23T05:34:41.564563+00:00",
26+
"resourceUri": "",
27+
"policy": {
28+
"content": "/* Copyright (c) 2024 - 2024, Oracle and/or its affiliates. All rights reserved. */\n/* Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. */\n\n#include \"prelude.dl\"\n\nPolicy(\"example_maven_app_policy\", component_id, \"Policy for github Maven project with Witness and GitHub provenances\") :-\n check_passed(component_id, \"mcn_build_service_1\"),\n check_passed(component_id, \"mcn_build_script_1\"),\n check_passed(component_id, \"mcn_provenance_available_1\"),\n check_passed(component_id, \"mcn_provenance_expectation_1\"),\n // We expect mcn_provenance_witness_level_one_1 to fail because at the moment\n // it tries to discover the witness provenance even when the provenance is provided as input.\n // TODO: address this policy once the issue with mcn_provenance_witness_level_one_1 is addressed.\n check_failed(component_id, \"mcn_provenance_witness_level_one_1\").\n\napply_policy_to(\"example_maven_app_policy\", component_id) :-\n is_repo(\n _, // repo_id\n \"github.com/behnazh-w/example-maven-app\", // http URL to the repo but without the \"http://\"\n component_id\n ).\n"
29+
},
30+
"verificationResult": "PASSED",
31+
"verifiedLevels": []
1532
}
16-
],
17-
"predicateType": "https://slsa.dev/verification_summary/v1",
18-
"predicate": {
19-
"verifier": {
20-
"id": "https://github.com/oracle/macaron",
21-
"version": {
22-
"macaron": "0.9.0"
23-
}
24-
},
25-
"timeVerified": "2024-05-07T05:32:42.105941+00:00",
26-
"resourceUri": "",
27-
"policy": {
28-
"content": "/* Copyright (c) 2024 - 2024, Oracle and/or its affiliates. All rights reserved. */\n/* Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/. */\n\n#include \"prelude.dl\"\n\nPolicy(\"example_maven_app_policy\", component_id, \"Policy for github Maven project with Witness and GitHub provenances\") :-\n check_passed(component_id, \"mcn_build_service_1\"),\n check_passed(component_id, \"mcn_build_script_1\"),\n check_passed(component_id, \"mcn_provenance_available_1\"),\n check_passed(component_id, \"mcn_provenance_expectation_1\").\n\napply_policy_to(\"example_maven_app_policy\", component_id) :-\n is_repo(\n _, // repo_id\n \"github.com/behnazh-w/example-maven-app\", // http URL to the repo but without the \"http://\"\n component_id\n ).\n"
29-
},
30-
"verificationResult": "PASSED",
31-
"verifiedLevels": []
32-
}
3333
}

0 commit comments

Comments
 (0)