diff --git a/auth/decorators.py b/auth/decorators.py index 2c61c8aa6..5fc966140 100644 --- a/auth/decorators.py +++ b/auth/decorators.py @@ -60,6 +60,7 @@ process_oauth = _auth_decorator(handlers=[validate_bearer_auth, validate_session process_auth = _auth_decorator(handlers=[validate_signed_grant, validate_basic_auth]) process_auth_or_cookie = _auth_decorator(handlers=[validate_basic_auth, validate_session_cookie]) process_basic_auth = _auth_decorator(handlers=[validate_basic_auth], pass_result=True) +process_basic_auth_no_pass = _auth_decorator(handlers=[validate_basic_auth]) def require_session_login(func): diff --git a/endpoints/api/secscan.py b/endpoints/api/secscan.py index a5ae88043..aa19ada07 100644 --- a/endpoints/api/secscan.py +++ b/endpoints/api/secscan.py @@ -4,6 +4,7 @@ import logging import features from app import secscan_api +from auth.decorators import process_basic_auth_no_pass from data.registry_model import registry_model from data.registry_model.datatypes import SecurityScanStatus from endpoints.api import (require_repo_read, path_param, @@ -53,6 +54,7 @@ def _security_info(manifest_or_legacy_image, include_vulnerabilities=True): class RepositoryImageSecurity(RepositoryParamResource): """ Operations for managing the vulnerabilities in a repository image. """ + @process_basic_auth_no_pass @require_repo_read @nickname('getRepoImageSecurity') @disallow_for_app_repositories @@ -79,6 +81,7 @@ class RepositoryImageSecurity(RepositoryParamResource): class RepositoryManifestSecurity(RepositoryParamResource): """ Operations for managing the vulnerabilities in a repository manifest. """ + @process_basic_auth_no_pass @require_repo_read @nickname('getRepoManifestSecurity') @disallow_for_app_repositories diff --git a/endpoints/api/test/shared.py b/endpoints/api/test/shared.py index 1d35cdbc5..c5a553f09 100644 --- a/endpoints/api/test/shared.py +++ b/endpoints/api/test/shared.py @@ -1,10 +1,11 @@ from endpoints.test.shared import conduct_call from endpoints.api import api -def conduct_api_call(client, resource, method, params, body=None, expected_code=200): +def conduct_api_call(client, resource, method, params, body=None, expected_code=200, headers=None): """ Conducts an API call to the given resource via the given client, and ensures its returned status matches the code given. Returns the response. """ - return conduct_call(client, resource, api.url_for, method, params, body, expected_code) + return conduct_call(client, resource, api.url_for, method, params, body, expected_code, + headers=headers) diff --git a/endpoints/api/test/test_secscan.py b/endpoints/api/test/test_secscan.py new file mode 100644 index 000000000..40afa6ac3 --- /dev/null +++ b/endpoints/api/test/test_secscan.py @@ -0,0 +1,30 @@ +import base64 + +import pytest + +from data.registry_model import registry_model +from endpoints.api.test.shared import conduct_api_call +from endpoints.api.secscan import RepositoryImageSecurity, RepositoryManifestSecurity + +from test.fixtures import * + +@pytest.mark.parametrize('endpoint', [ + RepositoryImageSecurity, + RepositoryManifestSecurity, +]) +def test_get_security_info_with_pull_secret(endpoint, client): + repository_ref = registry_model.lookup_repository('devtable', 'simple') + tag = registry_model.get_repo_tag(repository_ref, 'latest', include_legacy_image=True) + manifest = registry_model.get_manifest_for_tag(tag, backfill_if_necessary=True) + + params = { + 'repository': 'devtable/simple', + 'imageid': tag.legacy_image.docker_image_id, + 'manifestref': manifest.digest, + } + + headers = { + 'Authorization': 'Basic %s' % base64.b64encode('devtable:password'), + } + + conduct_api_call(client, endpoint, 'GET', params, None, headers=headers, expected_code=200)