Skip to content

Commit 3335a6f

Browse files
committed
feat: add a script to check VSA
Signed-off-by: behnazh-w <behnaz.hassanshahi@oracle.com>
1 parent 3d5e35b commit 3335a6f

File tree

6 files changed

+335
-0
lines changed

6 files changed

+335
-0
lines changed

docs/source/pages/tutorials/generate_verification_summary_attestation.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
.. Copyright (c) 2024 - 2024, Oracle and/or its affiliates. All rights reserved.
22
.. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
33
4+
.. _gen-vsa_tutorial:
5+
46
=========================================
57
Generate Verification Summary Attestation
68
=========================================

docs/source/pages/tutorials/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,5 @@ For the full list of supported technologies, such as CI services, registries, an
2222
npm_provenance
2323
detect_malicious_java_dep
2424
generate_verification_summary_attestation
25+
use_verification_summary_attestation
2526
exclude_include_checks
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
.. Copyright (c) 2024 - 2024, Oracle and/or its affiliates. All rights reserved.
2+
.. Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
3+
4+
============================================
5+
How to use Verification Summary Attestations
6+
============================================
7+
8+
This tutorial explains how to use the Verification Summary Attestations (VSA) generated by Macaron, using the VSAs for the `Graal Development Kit (GDK) <https://graal.cloud/gdk/>`_ artifacts as an example.
9+
10+
For more information about VSAs, please refer to the :ref:`Verification Summary Attestation page<vsa>`. To use Macaron to generate VSAs see this :ref:`tutorial <gen-vsa_tutorial>`.
11+
12+
* https://slsa.dev/spec/v1.0/verification_summary
13+
14+
--------
15+
Use case
16+
--------
17+
18+
Imagine you are a consumer of GDK artifacts and want to verify whether they are produced by a secure, :term:`SLSA`-compliant build service and sourced from a trusted source code repository. You need to confirm whether a provenance record for this artifact is published and has been verified. The GDK team must keep the details of their build pipeline confidential while still communicating that verification has occurred.
19+
20+
A VSA allows you to assess the security properties of an artifact without needing direct access to the provenance details. This process involves delegating the policy decision to Macaron. Macaron receives the provenance of the build as input, analyzes various aspects of the build, and verifies the gathered data against a Datalog policy. It then generates a VSA that attests to the artifacts produced by the build, which is published alongside the artifacts.
21+
22+
-------
23+
Example
24+
-------
25+
26+
GDK is an Oracle build of the open source Micronaut® framework. GDK provides a curated set of Micronaut framework modules which are built from source and published on the `Oracle Maven repository <https://maven.oracle.com/public>`_. If a GDK artifact is verified by Macaron, you should be able to to find a corresponding VSA on Oracle Maven repository. Let's consider, the ``io.micronaut/micronaut-core@4.6.3-oracle-00001`` JAR artifact which is published at `<https://maven.oracle.com/public/io/micronaut/micronaut-core/4.6.3-oracle-00001/micronaut-core-4.6.3-oracle-00001.jar>`_. In order to verify the artifact with Macaron, you can follow the following steps:
27+
28+
''''''''''''''''
29+
Download the VSA
30+
''''''''''''''''
31+
32+
Check wether a VSA is published for the artifact and download it for further examination.
33+
34+
.. code-block:: shell
35+
36+
curl -O https://maven.oracle.com/public/io/micronaut/micronaut-core/4.6.3-oracle-00001/vsa.intoto.jsonl
37+
38+
''''''''''''''''''''''''''''''''''''
39+
Manual inspection of the VSA content
40+
''''''''''''''''''''''''''''''''''''
41+
42+
.. code-block:: shell
43+
44+
cat vsa.intoto.jsonl | jq -r '.payload' | base64 -d | jq
45+
46+
The output of the this command should look like below:
47+
48+
.. toggle::
49+
50+
.. code-block:: json
51+
52+
{
53+
"_type": "https://in-toto.io/Statement/v1",
54+
"subject": [
55+
{
56+
"uri": "pkg:maven/io.micronaut/micronaut-core@4.6.3-oracle-00001?type=jar",
57+
"digest": {
58+
"sha256": "67ccb8e1a69da33ac7494b90d296db4ed3b2cdf3ccd267432dd2b7fac9b9bb12"
59+
}
60+
},
61+
{
62+
"uri": "pkg:maven/io.micronaut/micronaut-core@4.6.3-oracle-00001?type=pom",
63+
"digest": {
64+
"sha256": "c24499cbd1bc2aef1fbd961c6502304d183c43eba61f377ec1ddc89de6837f97"
65+
}
66+
},
67+
{
68+
"uri": "pkg:maven/io.micronaut/micronaut-core@4.6.3-oracle-00001?type=javadoc",
69+
"digest": {
70+
"sha256": "ed073facae8bf19d3e666e7f473ef01189784c974ebc2d017f157443ba09b33a"
71+
}
72+
},
73+
{
74+
"uri": "pkg:maven/io.micronaut/micronaut-core@4.6.3-oracle-00001?type=java-source",
75+
"digest": {
76+
"sha256": "3eee2a4434044702df9b1ab22a48322dc42707cda1558ab61d4a8760b96fd645"
77+
}
78+
}
79+
],
80+
"predicateType": "https://slsa.dev/verification_summary/v1",
81+
"predicate": {
82+
"verifier": {
83+
"id": "https://github.com/oracle/macaron",
84+
"version": {
85+
"macaron": "0.10.0"
86+
}
87+
},
88+
"timeVerified": "2024-08-25T06:36:24.654718+00:00",
89+
"resourceUri": "pkg:maven/io.micronaut/micronaut-core@4.6.3-oracle-00001",
90+
"policy": {
91+
"content": "#include \"prelude.dl\"\n\nPolicy(\"gdk_provenance_policy\", component_id, \"Policy for GDK builds\") :-\n check_passed(component_id, \"mcn_provenance_expectation_1\").\n\napply_policy_to(\"gdk_provenance_policy\", component_id) :-\n is_component(component_id, purl),\n match(\"^pkg:maven/io.micronaut/micronaut-core@.*$\", purl)."
92+
},
93+
"verificationResult": "PASSED",
94+
"verifiedLevels": []
95+
}
96+
}
97+
98+
99+
100+
The VSA adheres to the `schema <https://slsa.dev/spec/v1.0/verification_summary>`_ provided by SLSA. However, rather than specifying a URI for the policy, it includes the policy directly within the VSA under the ``predicate.policy.content`` field. Below is a pretty-printed format of the policy as it appears in the VSA.
101+
102+
.. toggle::
103+
104+
.. code-block:: prolog
105+
106+
#include "prelude.dl"
107+
108+
Policy("gdk_provenance_policy", component_id, "Policy for GDK builds") :-
109+
check_passed(component_id, "mcn_provenance_expectation_1")
110+
111+
apply_policy_to("has-hosted-build", component_id) :-
112+
is_component(component_id, purl),
113+
match("^pkg:maven/io.micronaut/micronaut-core@.*$", purl).
114+
115+
This policy makes sure the :ref:`mcn_provenance_expectation_1 <checks>` check, which verifies the content of the provenance file matches :ref:`CUE expectation <pages/using:Verifying provenance expectations in CUE language>`. You can find the template policy files for GDK builds below:
116+
117+
* `Template CUE expectation <https://github.com/oracle/macaron/tree/main/src/macaron/resources/policies/gdk/expectation.cue.template>`_
118+
* `Template Datalog policy file <https://github.com/oracle/macaron/tree/main/src/macaron/resources/policies/gdk/policy.dl.template>`_
119+
120+
The VSA also includes the list of subjects and their corresponding checksums that have been verified, the version of Macaron used, the timestamp of the verification, and the result of the verification.
121+
122+
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
123+
Automatically check the artifact checksum and verification result
124+
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
125+
126+
To verify that the artifact checksum matches the subject listed in the VSA and that the verification process has passed, follow these steps:
127+
128+
129+
**Download the check_vsa.sh script:**
130+
131+
.. code-block:: shell
132+
133+
curl -O https://raw.githubusercontent.com/oracle/macaron/main/scripts/release_scripts/check_vsa.sh
134+
135+
**Make the script executable:**
136+
137+
.. code-block:: shell
138+
139+
chmod +x check_vsa.sh
140+
141+
**Run the script with the appropriate arguments:**
142+
143+
.. code-block:: shell
144+
145+
./check_vsa.sh --artifact-path micronaut-core-4.6.3-oracle-00001.jar --vsa-path vsa.intoto.jsonl --purl "pkg:maven/io.micronaut/micronaut-core@4.6.3-oracle-00001?type=jar"
146+
147+
The artifact and VSA paths should be valid paths on your filesystem. Ensure you replace ``micronaut-core-4.6.3-oracle-00001.jar``, ``vsa.intoto.jsonl``, and ``pkg:maven/io.micronaut/micronaut-core@4.6.3-oracle-00001?type=jar`` with your actual file paths and package URL.
148+
149+
**Verify the output:**
150+
151+
If the verification is successful, the script will print:
152+
153+
.. code-block:: shell
154+
155+
The subject checksum matches the expected value.
156+
The VSA has been verified by Macaron.
157+
The verification has passed.
158+
159+
If there is an issue, the script will return an error code ``1`` and print an appropriate error message.
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
#!/usr/bin/env bash
2+
3+
# Copyright (c) 2024 - 2024, Oracle and/or its affiliates. All rights reserved.
4+
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/.
5+
6+
# This script checks the Verification Summary Attestation generated by Macaron.
7+
8+
# Strict bash options.
9+
#
10+
# -e: exit immediately if a command fails (with non-zero return code),
11+
# or if a function returns non-zero.
12+
#
13+
# -u: treat unset variables and parameters as error when performing
14+
# parameter expansion.
15+
# In case a variable ${VAR} is unset but we still need to expand,
16+
# use the syntax ${VAR:-} to expand it to an empty string.
17+
#
18+
# -o pipefail: set the return value of a pipeline to the value of the last
19+
# (rightmost) command to exit with a non-zero status, or zero
20+
# if all commands in the pipeline exit successfully.
21+
#
22+
# Reference: https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html.
23+
set -euo pipefail
24+
25+
# Log error (to stderr).
26+
log_err() {
27+
echo "[ERROR]: $*" >&2
28+
}
29+
30+
# Print usage message.
31+
print_help() {
32+
cat << EOF
33+
Usage: $(basename "$0") [OPTIONS]
34+
35+
This script checks the Verification Summary Attestation (VSA) generated by Macaron.
36+
37+
Options:
38+
--artifact-path PATH Path to the artifact file.
39+
--vsa-path PATH Path to the Verification Summary Attestation (VSA) file.
40+
--purl URL Package URL to match against the VSA.
41+
--help, -h Display this help message and exit.
42+
43+
Examples:
44+
$(basename "$0") --artifact-path /path/to/artifact --vsa-path /path/to/vsa --purl "package-url"
45+
46+
EOF
47+
}
48+
49+
# Assert that a file exists.
50+
#
51+
# Arguments:
52+
# $1: The path to the file.
53+
# $2: The argument from which the file is passed into this script.
54+
#
55+
# With the `set -e` option turned on, this function exits the script with
56+
# return code 1 if the file does not exist.
57+
function assert_file_exists() {
58+
if [[ ! -f "$1" ]]; then
59+
log_err "File $1 does not exist."
60+
return 1
61+
fi
62+
}
63+
64+
# Parse main arguments.
65+
while [[ $# -gt 0 ]]; do
66+
case $1 in
67+
--artifact-path)
68+
arg_artifact_path="$2"
69+
shift
70+
;;
71+
--vsa-path)
72+
arg_vsa_path="$2"
73+
shift
74+
;;
75+
--purl)
76+
purl="$2"
77+
shift
78+
;;
79+
-h | --help)
80+
print_help
81+
exit 0
82+
;;
83+
*)
84+
log_err "Unknown option: $1"
85+
print_help
86+
exit 1
87+
;;
88+
esac
89+
shift
90+
done
91+
92+
93+
# Check the artifact path and compute the checksum of the artifact.
94+
if [[ -n "${arg_artifact_path:-}" ]]; then
95+
assert_file_exists "$arg_artifact_path"
96+
artifact_checksum=$(shasum -a 256 "$arg_artifact_path" | awk '{print $1}')
97+
else
98+
log_err "Please provide the artifact path."
99+
print_help
100+
exit 1
101+
fi
102+
103+
# Check the VSA path.
104+
if [[ -n "${arg_vsa_path:-}" ]]; then
105+
assert_file_exists "$arg_vsa_path"
106+
else
107+
log_err "Please provide the VSA path."
108+
print_help
109+
exit 1
110+
fi
111+
112+
# Check the purl and obtain the matching subject.
113+
if [[ -n "${purl:-}" ]]; then
114+
subject_digest=$(cat "$arg_vsa_path" | jq -r ".payload" | base64 -d | jq -r ".subject[] | select(.uri == \"$purl\") | .digest.sha256")
115+
else
116+
log_err "Please provide the package URL."
117+
print_help
118+
exit 1
119+
fi
120+
121+
verify_result=$(cat "$arg_vsa_path" | jq -r ".payload" | base64 -d | jq -r ".predicate.verificationResult")
122+
verifier=$(cat "$arg_vsa_path" | jq -r ".payload" | base64 -d | jq -r ".predicate.verifier.id")
123+
124+
125+
# Check if the subject and artifact digests match.
126+
if [ "$subject_digest" = "$artifact_checksum" ]; then
127+
echo "The subject checksum matches the expected value."
128+
else
129+
echo "The subject checksum \"$subject_digest\" does not match the expected value \"$artifact_checksum\"."
130+
exit 1
131+
fi
132+
133+
# Check if verifier is Macaron.
134+
if [ "$verifier" = "https://github.com/oracle/macaron" ]; then
135+
echo "The VSA has been verified by Macaron."
136+
else
137+
echo "The VSA has not been verified by Macaron."
138+
exit 1
139+
fi
140+
141+
# Check whether the verification has passed.
142+
if [ "$verify_result" = "PASSED" ]; then
143+
echo "The verification has passed."
144+
else
145+
echo "The verification has failed."
146+
exit 1
147+
fi
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
target: "<EXPECTATION_PURL>",
3+
predicate: {
4+
attestations: [
5+
{
6+
attestation: {
7+
jobimage: =~"<IMAGE>:.*",
8+
projecturl: "https://<REPO_URL>",
9+
},
10+
},
11+
_,
12+
_,
13+
_,
14+
_,
15+
_
16+
]
17+
}
18+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include "prelude.dl"
2+
3+
Policy("gdk_provenance_policy", component_id, "Policy for GDK builds") :-
4+
check_passed(component_id, "mcn_provenance_expectation_1").
5+
6+
apply_policy_to("gcn_provenance_policy", component_id) :-
7+
is_component(component_id, purl),
8+
match("^<PACKAGE_PURL>@.*$", purl).

0 commit comments

Comments
 (0)