diff --git a/tests/core/pm-module/test_ens_integration.py b/tests/core/pm-module/test_ens_integration.py index 239171f413..6ec0a60d21 100644 --- a/tests/core/pm-module/test_ens_integration.py +++ b/tests/core/pm-module/test_ens_integration.py @@ -137,8 +137,8 @@ def test_web3_ens(ens): actual_addr = ens.address('tester.eth') w3.pm.set_registry('tester.eth') assert w3.pm.registry.address == to_canonical_address(actual_addr) - w3.pm.release_package('pkg', 'v1', 'website.com') - pkg_name, version, manifest_uri = w3.pm.get_release_data('pkg', 'v1') - assert pkg_name == 'pkg' - assert version == 'v1' - assert manifest_uri == 'website.com' + w3.pm.release_package('owned', '1.0.0', 'ipfs://QmbeVyFLSuEUxiXKwSsEjef6icpdTdA4kGG9BcrJXKNKUW') + pkg_name, version, manifest_uri = w3.pm.get_release_data('owned', '1.0.0') + assert pkg_name == 'owned' + assert version == '1.0.0' + assert manifest_uri == 'ipfs://QmbeVyFLSuEUxiXKwSsEjef6icpdTdA4kGG9BcrJXKNKUW' diff --git a/tests/core/pm-module/test_registry_integration.py b/tests/core/pm-module/test_registry_integration.py index 20d9ff8903..4993ab0d12 100644 --- a/tests/core/pm-module/test_registry_integration.py +++ b/tests/core/pm-module/test_registry_integration.py @@ -62,7 +62,7 @@ def test_pm_set_solidity_registry(empty_sol_registry, fresh_w3): def test_pm_must_set_registry_before_all_registry_interaction_functions(fresh_w3): with pytest.raises(PMError): fresh_w3.pm.release_package( - "package", "1.0.0", "ipfs://Qme4otpS88NV8yQi8TfTP89EsQC5bko3F5N1yhRoi6cwGe" + "package", "1.0.0", "ipfs://QmbeVyFLSuEUxiXKwSsEjef6icpdTdA4kGG9BcrJXKNKUW" ) with pytest.raises(PMError): fresh_w3.pm.get_release_id_data(b"invalid_release_id") @@ -88,21 +88,21 @@ def test_pm_must_set_registry_before_all_registry_interaction_functions(fresh_w3 def test_pm_release_package(registry_getter, w3): w3.pm.registry = registry_getter w3.pm.release_package( - "package123", "1.0.0", "ipfs://Qme4otpS88NV8yQi8TfTP89EsQC5bko3F5N1yhRoi6cwGE" + "escrow", "1.0.0", "ipfs://QmPDwMHk8e1aMEZg3iKsUiPSkhHkywpGB3KHKM52RtGrkv" ) w3.pm.release_package( - "package456", "1.0.0", "ipfs://Qme4otpS88NV8yQi8TfTP89EsQC5bko3F5N1yhRoi6cwGI" + "owned", "1.0.0", "ipfs://QmbeVyFLSuEUxiXKwSsEjef6icpdTdA4kGG9BcrJXKNKUW" ) - release_id_1 = w3.pm.get_release_id("package123", "1.0.0") - release_id_2 = w3.pm.get_release_id("package456", "1.0.0") + release_id_1 = w3.pm.get_release_id("escrow", "1.0.0") + release_id_2 = w3.pm.get_release_id("owned", "1.0.0") package_data_1 = w3.pm.get_release_id_data(release_id_1) package_data_2 = w3.pm.get_release_id_data(release_id_2) - assert package_data_1[0] == "package123" + assert package_data_1[0] == "escrow" assert package_data_1[1] == "1.0.0" - assert package_data_1[2] == "ipfs://Qme4otpS88NV8yQi8TfTP89EsQC5bko3F5N1yhRoi6cwGE" - assert package_data_2[0] == "package456" + assert package_data_1[2] == "ipfs://QmPDwMHk8e1aMEZg3iKsUiPSkhHkywpGB3KHKM52RtGrkv" + assert package_data_2[0] == "owned" assert package_data_2[1] == "1.0.0" - assert package_data_2[2] == "ipfs://Qme4otpS88NV8yQi8TfTP89EsQC5bko3F5N1yhRoi6cwGI" + assert package_data_2[2] == "ipfs://QmbeVyFLSuEUxiXKwSsEjef6icpdTdA4kGG9BcrJXKNKUW" @pytest.mark.parametrize( diff --git a/web3/exceptions.py b/web3/exceptions.py index 475d56bdfc..3faebb49c7 100644 --- a/web3/exceptions.py +++ b/web3/exceptions.py @@ -114,3 +114,10 @@ class PMError(Exception): Raised when an error occurs in the PM module. """ pass + + +class ManifestValidationError(PMError): + """ + Raised when a provided manifest cannot be published, since it's invalid. + """ + pass diff --git a/web3/pm.py b/web3/pm.py index 9fb212b90b..9cd5e45e1e 100644 --- a/web3/pm.py +++ b/web3/pm.py @@ -33,6 +33,19 @@ Address, Manifest, ) +from ethpm.utils.backend import ( + resolve_uri_contents, +) +from ethpm.utils.ipfs import ( + is_ipfs_uri, +) +from ethpm.utils.manifest_validation import ( + validate_manifest_against_schema, + validate_raw_manifest_format, +) +from ethpm.utils.uri import ( + is_valid_content_addressed_github_uri, +) from ethpm.validation import ( validate_package_name, validate_package_version, @@ -45,6 +58,7 @@ from web3.exceptions import ( InvalidAddress, NameNotFound, + ManifestValidationError, PMError, ) from web3.module import ( @@ -463,12 +477,28 @@ def release_package( to be the registry owner. * Parameters: - * ``package_name``: Must be a valid package name. - * ``version``: Must be a valid package version. - * ``manifest_uri``: Must be a valid manifest URI. - """ - validate_package_name(package_name) - validate_package_version(version) + * ``package_name``: Must be a valid package name, matching the given manifest. + * ``version``: Must be a valid package version, matching the given manifest. + * ``manifest_uri``: Must be a valid content-addressed URI. Currently, only IPFS + and Github content-addressed URIs are supported. + """ + validate_is_supported_manifest_uri(manifest_uri) + raw_manifest = to_text(resolve_uri_contents(manifest_uri)) + validate_raw_manifest_format(raw_manifest) + manifest = json.loads(raw_manifest) + validate_manifest_against_schema(manifest) + if package_name != manifest['package_name']: + raise ManifestValidationError( + f"Provided package name: {package_name} does not match the package name " + f"found in the manifest: {manifest['package_name']}." + ) + + if version != manifest['version']: + raise ManifestValidationError( + f"Provided package version: {version} does not match the package version " + f"found in the manifest: {manifest['version']}." + ) + self._validate_set_registry() return self.registry._release(package_name, version, manifest_uri) @@ -597,6 +627,14 @@ def get_solidity_registry_manifest() -> Dict[str, Any]: return json.loads((ASSETS_DIR / "registry" / "1.0.0.json").read_text()) +def validate_is_supported_manifest_uri(uri): + if not is_ipfs_uri(uri) and not is_valid_content_addressed_github_uri(uri): + raise ManifestValidationError( + f"URI: {uri} is not a valid content-addressed URI. " + "Currently only IPFS and Github content-addressed URIs are supported." + ) + + @to_tuple def process_vyper_args(*args: List[str]) -> Iterable[bytes]: for arg in args: