Skip to content

Commit

Permalink
feat: find SLSA provenance v0.2 published on npm registry
Browse files Browse the repository at this point in the history
Signed-off-by: behnazh-w <[email protected]>
  • Loading branch information
behnazh-w committed Nov 14, 2023
1 parent 96e5e87 commit 8a26af1
Show file tree
Hide file tree
Showing 16 changed files with 1,056 additions and 94 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@ test-go:
go test ./golang/...

# Run the integration tests.
# Note: to disable npm tests set `NO_NPM` environment variable.
.PHONY: integration-test
integration-test:
scripts/dev_scripts/integration_tests.sh $(REPO_PATH) "${HOME}"
Expand Down
18 changes: 18 additions & 0 deletions scripts/dev_scripts/integration_tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ function check_or_update_expected_output() {
fi
}

# Check if npm-related tests should be disabled.
if [[ ! -z "$NO_NPM" ]]; then
echo "Note: NO_NPM environment variable is set, so npm tests will be skipped."
fi
NO_NPM_TEST=$NO_NPM


function log_fail() {
printf "Error: FAILED integration test (line ${BASH_LINENO}) %s\n" $@
RESULT_CODE=1
Expand Down Expand Up @@ -66,6 +73,17 @@ $RUN_MACARON analyze -rp https://github.com/micronaut-projects/micronaut-core -b

check_or_update_expected_output $COMPARE_JSON_OUT $JSON_RESULT $JSON_EXPECTED || log_fail

if [[ -z "$NO_NPM_TEST" ]]; then
echo -e "\n----------------------------------------------------------------------------------"
echo "sigstore/[email protected]: Analyzing the PURL when automatic dependency resolution is skipped."
echo -e "----------------------------------------------------------------------------------\n"
JSON_EXPECTED=$WORKSPACE/tests/e2e/expected_results/purl/npm/sigstore/mock/mock.json
JSON_RESULT=$WORKSPACE/output/reports/npm/_sigstore/mock/mock.json
$RUN_MACARON analyze -purl pkg:npm/@sigstore/[email protected] --skip-deps || log_fail

check_or_update_expected_output $COMPARE_JSON_OUT $JSON_RESULT $JSON_EXPECTED || log_fail
fi

echo -e "\n----------------------------------------------------------------------------------"
echo "gitlab.com/tinyMediaManager/tinyMediaManager: Analyzing the repo path and the branch name when automatic dependency resolution is skipped."
echo -e "----------------------------------------------------------------------------------\n"
Expand Down
9 changes: 9 additions & 0 deletions src/macaron/config/defaults.ini
Original file line number Diff line number Diff line change
Expand Up @@ -465,3 +465,12 @@ hostname = search.maven.org
# The search REST API. See https://central.sonatype.org/search/rest-api-guide/
search_endpoint = solrsearch/select
request_timeout = 20

[package_registry.npm]
# Set `enabled=False` to disable making REST API calls to the npm registry.
enabled = True
# npm registry host name.
hostname = registry.npmjs.org
# The attestation REST API.
attestation_endpoint = -/npm/v1/attestations
request_timeout = 20
17 changes: 11 additions & 6 deletions src/macaron/slsa_analyzer/analyze_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import logging
import os
from collections import defaultdict
from typing import TypedDict

from macaron.database.table_definitions import Component, SLSALevel
Expand All @@ -16,6 +17,8 @@
from macaron.slsa_analyzer.git_service.base_git_service import NoneGitService
from macaron.slsa_analyzer.levels import SLSALevels
from macaron.slsa_analyzer.provenance.expectations.expectation import Expectation
from macaron.slsa_analyzer.provenance.intoto.v01 import InTotoV01Statement
from macaron.slsa_analyzer.provenance.intoto.v1 import InTotoV1Statement
from macaron.slsa_analyzer.slsa_req import ReqName, SLSAReqStatus, create_requirement_status_dict
from macaron.slsa_analyzer.specs.build_spec import BuildSpec
from macaron.slsa_analyzer.specs.ci_spec import CIInfo
Expand Down Expand Up @@ -91,25 +94,27 @@ def __init__(
)

@property
def provenances(self) -> dict:
def provenances(self) -> dict[str, list[InTotoV01Statement | InTotoV1Statement]]:
"""Return the provenances data as a dictionary.
Returns
-------
dict
dict[str : list[InTotoV01Statement]]
A dictionary in which each key is a CI service's name and each value is
the corresponding provenance payload.
"""
try:
ci_services = self.dynamic_data["ci_services"]
result = {}

# By default, initialize every key with an empty list.
result: dict[str, list[InTotoV01Statement | InTotoV1Statement]] = defaultdict(lambda: [])
for ci_info in ci_services:
result[ci_info["service"].name] = [payload.statement for payload in ci_info["provenances"]]
result[ci_info["service"].name].extend(payload.statement for payload in ci_info["provenances"])
package_registry_entries = self.dynamic_data["package_registries"]
for package_registry_entry in package_registry_entries:
result[package_registry_entry.package_registry.name] = [
result[package_registry_entry.package_registry.name].extend(
provenance.payload.statement for provenance in package_registry_entry.provenances
]
)
return result
except KeyError:
return {}
Expand Down
9 changes: 9 additions & 0 deletions src/macaron/slsa_analyzer/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import logging
import os
import sys
import urllib.parse
from datetime import datetime, timezone
from pathlib import Path
from typing import Any, NamedTuple
Expand Down Expand Up @@ -540,6 +541,14 @@ def to_analysis_target(config: Configuration, available_domains: list[str]) -> A
except ValueError as error:
raise InvalidPURLError(f"Invalid input PURL: {config.get_value('purl')}") from error

# Validate the purl object, which is user-controllable.
if parsed_purl:
purl_str = parsed_purl.to_string()
# The urlparse API sanitizes unsafe characters.
parsed_url = urllib.parse.urlparse(purl_str)
if purl_str != parsed_url.geturl():
raise ValueError("The PURL provided as input has unsafe characters.")

repo_path_input: str = config.get_value("path")
input_branch: str = config.get_value("branch")
input_digest: str = config.get_value("digest")
Expand Down
Loading

0 comments on commit 8a26af1

Please sign in to comment.