mirror of
https://github.com/quay/quay.git
synced 2025-07-28 20:22:05 +03:00
chore: update werkzeug and related package versions (PROJQUAY-5098) (#1982)
* chore: update werkzeug and related package versions (PROJQUAY-5098) Path converter related change reference: https://github.com/pallets/werkzeug/issues/2506 * Update query count
This commit is contained in:
committed by
GitHub
parent
8314a58515
commit
72f7c64ed6
4
app.py
4
app.py
@ -99,7 +99,7 @@ app.config.update(environ_config)
|
|||||||
|
|
||||||
# Fix remote address handling for Flask.
|
# Fix remote address handling for Flask.
|
||||||
if app.config.get("PROXY_COUNT", 1):
|
if app.config.get("PROXY_COUNT", 1):
|
||||||
app.wsgi_app = ProxyFix(app.wsgi_app)
|
app.wsgi_app = ProxyFix(app.wsgi_app) # type: ignore[method-assign]
|
||||||
|
|
||||||
# Allow user to define a custom storage preference for the local instance.
|
# Allow user to define a custom storage preference for the local instance.
|
||||||
_distributed_storage_preference = os.environ.get("QUAY_DISTRIBUTED_STORAGE_PREFERENCE", "").split()
|
_distributed_storage_preference = os.environ.get("QUAY_DISTRIBUTED_STORAGE_PREFERENCE", "").split()
|
||||||
@ -124,7 +124,7 @@ features.import_features(app.config)
|
|||||||
# Register additional experimental artifact types.
|
# Register additional experimental artifact types.
|
||||||
# TODO: extract this into a real, dynamic registration system.
|
# TODO: extract this into a real, dynamic registration system.
|
||||||
if features.GENERAL_OCI_SUPPORT:
|
if features.GENERAL_OCI_SUPPORT:
|
||||||
for media_type, layer_types in app.config.get("ALLOWED_OCI_ARTIFACT_TYPES").items():
|
for media_type, layer_types in app.config["ALLOWED_OCI_ARTIFACT_TYPES"].items():
|
||||||
register_artifact_type(media_type, layer_types)
|
register_artifact_type(media_type, layer_types)
|
||||||
|
|
||||||
if features.HELM_OCI_SUPPORT:
|
if features.HELM_OCI_SUPPORT:
|
||||||
|
@ -6,7 +6,8 @@ import jwt
|
|||||||
import pytest
|
import pytest
|
||||||
from cryptography.hazmat.primitives import serialization
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
|
||||||
from app import app, instance_keys
|
from app import app as flask_app
|
||||||
|
from app import instance_keys
|
||||||
from auth.auth_context_type import ValidatedAuthContext
|
from auth.auth_context_type import ValidatedAuthContext
|
||||||
from auth.registry_jwt_auth import InvalidJWTException, identity_from_bearer_token
|
from auth.registry_jwt_auth import InvalidJWTException, identity_from_bearer_token
|
||||||
from data import model # TODO: remove this after service keys are decoupled
|
from data import model # TODO: remove this after service keys are decoupled
|
||||||
@ -15,7 +16,7 @@ from initdb import finished_database_for_testing, setup_database_for_testing
|
|||||||
from util.morecollections import AttrDict
|
from util.morecollections import AttrDict
|
||||||
from util.security.registry_jwt import ANONYMOUS_SUB, build_context_and_subject
|
from util.security.registry_jwt import ANONYMOUS_SUB, build_context_and_subject
|
||||||
|
|
||||||
TEST_AUDIENCE = app.config["SERVER_HOSTNAME"]
|
TEST_AUDIENCE = flask_app.config["SERVER_HOSTNAME"]
|
||||||
TEST_USER = AttrDict({"username": "joeuser", "uuid": "foobar", "enabled": True})
|
TEST_USER = AttrDict({"username": "joeuser", "uuid": "foobar", "enabled": True})
|
||||||
MAX_SIGNED_S = 3660
|
MAX_SIGNED_S = 3660
|
||||||
TOKEN_VALIDITY_LIFETIME_S = 60 * 60 # 1 hour
|
TOKEN_VALIDITY_LIFETIME_S = 60 * 60 # 1 hour
|
||||||
|
@ -33,7 +33,7 @@ class UserfilesHandlers(View):
|
|||||||
buffered,
|
buffered,
|
||||||
mimetype=self._magic.from_buffer(file_header_bytes),
|
mimetype=self._magic.from_buffer(file_header_bytes),
|
||||||
as_attachment=True,
|
as_attachment=True,
|
||||||
attachment_filename=file_id,
|
download_name=file_id,
|
||||||
)
|
)
|
||||||
except IOError:
|
except IOError:
|
||||||
logger.exception("Error reading user file")
|
logger.exception("Error reading user file")
|
||||||
|
@ -4,6 +4,7 @@ from calendar import timegm
|
|||||||
from email.utils import formatdate
|
from email.utils import formatdate
|
||||||
from functools import partial, wraps
|
from functools import partial, wraps
|
||||||
|
|
||||||
|
import pytz
|
||||||
from flask import Blueprint, request, session
|
from flask import Blueprint, request, session
|
||||||
from flask_restful import Api, Resource, abort, reqparse
|
from flask_restful import Api, Resource, abort, reqparse
|
||||||
from flask_restful.utils import unpack
|
from flask_restful.utils import unpack
|
||||||
@ -438,7 +439,7 @@ def require_fresh_login(func):
|
|||||||
)
|
)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
last_login >= valid_span
|
last_login.replace(tzinfo=pytz.UTC) >= valid_span.replace(tzinfo=pytz.UTC)
|
||||||
or not authentication.supports_fresh_login
|
or not authentication.supports_fresh_login
|
||||||
or not authentication.has_password_set(user.username)
|
or not authentication.has_password_set(user.username)
|
||||||
):
|
):
|
||||||
|
@ -7,8 +7,8 @@ from endpoints.api.test.shared import conduct_api_call
|
|||||||
from endpoints.test.shared import client_with_identity
|
from endpoints.test.shared import client_with_identity
|
||||||
|
|
||||||
|
|
||||||
def test_app_specific_tokens(app, client):
|
def test_app_specific_tokens(app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
# Add an app specific token.
|
# Add an app specific token.
|
||||||
token_data = {"title": "Testing 123"}
|
token_data = {"title": "Testing 123"}
|
||||||
resp = conduct_api_call(cl, AppTokens, "POST", None, token_data, 200).json
|
resp = conduct_api_call(cl, AppTokens, "POST", None, token_data, 200).json
|
||||||
@ -41,11 +41,11 @@ def test_app_specific_tokens(app, client):
|
|||||||
conduct_api_call(cl, AppToken, "GET", {"token_uuid": token_uuid}, None, 404)
|
conduct_api_call(cl, AppToken, "GET", {"token_uuid": token_uuid}, None, 404)
|
||||||
|
|
||||||
|
|
||||||
def test_delete_expired_app_token(app, client):
|
def test_delete_expired_app_token(app):
|
||||||
user = model.user.get_user("devtable")
|
user = model.user.get_user("devtable")
|
||||||
expiration = datetime.now() - timedelta(seconds=10)
|
expiration = datetime.now() - timedelta(seconds=10)
|
||||||
token = model.appspecifictoken.create_token(user, "some token", expiration)
|
token = model.appspecifictoken.create_token(user, "some token", expiration)
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
# Delete the token.
|
# Delete the token.
|
||||||
conduct_api_call(cl, AppToken, "DELETE", {"token_uuid": token.uuid}, None, 204)
|
conduct_api_call(cl, AppToken, "DELETE", {"token_uuid": token.uuid}, None, 204)
|
||||||
|
@ -85,7 +85,7 @@ FIELD_ARGS = {"trigger_uuid": "1234", "field_name": "foobar"}
|
|||||||
(BuildTriggerSourceNamespaces, "get", TRIGGER_ARGS),
|
(BuildTriggerSourceNamespaces, "get", TRIGGER_ARGS),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_disallowed_for_apps(resource, method, params, client):
|
def test_disallowed_for_apps(resource, method, params, app):
|
||||||
namespace = "devtable"
|
namespace = "devtable"
|
||||||
repository = "someapprepo"
|
repository = "someapprepo"
|
||||||
|
|
||||||
@ -95,5 +95,5 @@ def test_disallowed_for_apps(resource, method, params, client):
|
|||||||
params = params or {}
|
params = params or {}
|
||||||
params["repository"] = "%s/%s" % (namespace, repository)
|
params["repository"] = "%s/%s" % (namespace, repository)
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
conduct_api_call(cl, resource, method, params, None, 501)
|
conduct_api_call(cl, resource, method, params, None, 501)
|
||||||
|
@ -58,7 +58,7 @@ FIELD_ARGS = {"trigger_uuid": "1234", "field_name": "foobar"}
|
|||||||
(BuildTriggerSources, "post", TRIGGER_ARGS),
|
(BuildTriggerSources, "post", TRIGGER_ARGS),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_disallowed_for_nonnormal(state, resource, method, params, client):
|
def test_disallowed_for_nonnormal(state, resource, method, params, app):
|
||||||
namespace = "devtable"
|
namespace = "devtable"
|
||||||
repository = "somenewstaterepo"
|
repository = "somenewstaterepo"
|
||||||
|
|
||||||
@ -70,5 +70,5 @@ def test_disallowed_for_nonnormal(state, resource, method, params, client):
|
|||||||
params = params or {}
|
params = params or {}
|
||||||
params["repository"] = "%s/%s" % (namespace, repository)
|
params["repository"] = "%s/%s" % (namespace, repository)
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
conduct_api_call(cl, resource, method, params, {}, 503)
|
conduct_api_call(cl, resource, method, params, {}, 503)
|
||||||
|
@ -48,10 +48,10 @@ def test_entity_search(auth_engine, requires_email, client):
|
|||||||
assert entity["kind"] == "external"
|
assert entity["kind"] == "external"
|
||||||
|
|
||||||
|
|
||||||
def test_link_external_entity(auth_engine, requires_email, client):
|
def test_link_external_entity(auth_engine, requires_email, app):
|
||||||
with auth_engine(requires_email=requires_email) as auth:
|
with auth_engine(requires_email=requires_email) as auth:
|
||||||
with patch("endpoints.api.search.authentication", auth):
|
with patch("endpoints.api.search.authentication", auth):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
# Try an unknown user.
|
# Try an unknown user.
|
||||||
conduct_api_call(
|
conduct_api_call(
|
||||||
cl,
|
cl,
|
||||||
|
@ -15,16 +15,15 @@ from endpoints.test.shared import client_with_identity
|
|||||||
os.environ.get("TEST_DATABASE_URI", "").find("mysql") >= 0,
|
os.environ.get("TEST_DATABASE_URI", "").find("mysql") >= 0,
|
||||||
reason="Queue code is very sensitive to times on MySQL, making this flaky",
|
reason="Queue code is very sensitive to times on MySQL, making this flaky",
|
||||||
)
|
)
|
||||||
def test_export_logs(client):
|
def test_export_logs(app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
timecode = time.time()
|
||||||
assert export_action_logs_queue.get() is None
|
|
||||||
|
|
||||||
timecode = time.time()
|
def get_time():
|
||||||
|
return timecode - 2
|
||||||
|
|
||||||
def get_time():
|
with patch("time.time", get_time):
|
||||||
return timecode - 2
|
with client_with_identity("devtable", app) as cl:
|
||||||
|
assert export_action_logs_queue.get() is None
|
||||||
with patch("time.time", get_time):
|
|
||||||
# Call to export logs.
|
# Call to export logs.
|
||||||
body = {
|
body = {
|
||||||
"callback_url": "http://some/url",
|
"callback_url": "http://some/url",
|
||||||
@ -39,13 +38,13 @@ def test_export_logs(client):
|
|||||||
assert export_action_logs_queue.get() is not None
|
assert export_action_logs_queue.get() is not None
|
||||||
|
|
||||||
|
|
||||||
def test_invalid_date_range(client):
|
def test_invalid_date_range(app):
|
||||||
starttime = "02/02/2020"
|
starttime = "02/02/2020"
|
||||||
endtime = "01/01/2020"
|
endtime = "01/01/2020"
|
||||||
parsed_starttime, parsed_endtime = _validate_logs_arguments(starttime, endtime)
|
parsed_starttime, parsed_endtime = _validate_logs_arguments(starttime, endtime)
|
||||||
assert parsed_starttime >= parsed_endtime
|
assert parsed_starttime >= parsed_endtime
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
conduct_api_call(
|
conduct_api_call(
|
||||||
cl,
|
cl,
|
||||||
OrgLogs,
|
OrgLogs,
|
||||||
|
@ -6,8 +6,8 @@ from endpoints.api.test.shared import conduct_api_call
|
|||||||
from endpoints.test.shared import client_with_identity
|
from endpoints.test.shared import client_with_identity
|
||||||
|
|
||||||
|
|
||||||
def test_repository_manifest(client):
|
def test_repository_manifest(app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
repo_ref = registry_model.lookup_repository("devtable", "simple")
|
repo_ref = registry_model.lookup_repository("devtable", "simple")
|
||||||
tags = registry_model.list_all_active_repository_tags(repo_ref)
|
tags = registry_model.list_all_active_repository_tags(repo_ref)
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
|
@ -49,7 +49,7 @@ def _setup_mirror():
|
|||||||
("admin", "admin"),
|
("admin", "admin"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_create_mirror_sets_permissions(existing_robot_permission, expected_permission, client):
|
def test_create_mirror_sets_permissions(existing_robot_permission, expected_permission, app):
|
||||||
mirror_bot, _ = model.user.create_robot(
|
mirror_bot, _ = model.user.create_robot(
|
||||||
"newmirrorbot", model.user.get_namespace_user("devtable")
|
"newmirrorbot", model.user.get_namespace_user("devtable")
|
||||||
)
|
)
|
||||||
@ -59,7 +59,7 @@ def test_create_mirror_sets_permissions(existing_robot_permission, expected_perm
|
|||||||
mirror_bot.username, "devtable", "simple", existing_robot_permission
|
mirror_bot.username, "devtable", "simple", existing_robot_permission
|
||||||
)
|
)
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"repository": "devtable/simple"}
|
params = {"repository": "devtable/simple"}
|
||||||
request_body = {
|
request_body = {
|
||||||
"external_reference": "quay.io/foobar/barbaz",
|
"external_reference": "quay.io/foobar/barbaz",
|
||||||
@ -78,25 +78,25 @@ def test_create_mirror_sets_permissions(existing_robot_permission, expected_perm
|
|||||||
assert config.root_rule.rule_value == ["latest", "foo", "bar"]
|
assert config.root_rule.rule_value == ["latest", "foo", "bar"]
|
||||||
|
|
||||||
|
|
||||||
def test_get_mirror_does_not_exist(client):
|
def test_get_mirror_does_not_exist(app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"repository": "devtable/simple"}
|
params = {"repository": "devtable/simple"}
|
||||||
resp = conduct_api_call(cl, RepoMirrorResource, "GET", params, None, 404)
|
resp = conduct_api_call(cl, RepoMirrorResource, "GET", params, None, 404)
|
||||||
|
|
||||||
|
|
||||||
def test_get_repo_does_not_exist(client):
|
def test_get_repo_does_not_exist(app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"repository": "devtable/unicorn"}
|
params = {"repository": "devtable/unicorn"}
|
||||||
resp = conduct_api_call(cl, RepoMirrorResource, "GET", params, None, 404)
|
resp = conduct_api_call(cl, RepoMirrorResource, "GET", params, None, 404)
|
||||||
|
|
||||||
|
|
||||||
def test_get_mirror(client):
|
def test_get_mirror(app):
|
||||||
"""
|
"""
|
||||||
Verify that performing a `GET` request returns expected and accurate data.
|
Verify that performing a `GET` request returns expected and accurate data.
|
||||||
"""
|
"""
|
||||||
mirror = _setup_mirror()
|
mirror = _setup_mirror()
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"repository": "devtable/simple"}
|
params = {"repository": "devtable/simple"}
|
||||||
resp = conduct_api_call(cl, RepoMirrorResource, "GET", params, None, 200).json
|
resp = conduct_api_call(cl, RepoMirrorResource, "GET", params, None, 200).json
|
||||||
|
|
||||||
@ -171,13 +171,13 @@ def test_get_mirror(client):
|
|||||||
("root_rule", {"rule_kind": "incorrect", "rule_value": ["3.1", "3.1*"]}, 400),
|
("root_rule", {"rule_kind": "incorrect", "rule_value": ["3.1", "3.1*"]}, 400),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_change_config(key, value, expected_status, client):
|
def test_change_config(key, value, expected_status, app):
|
||||||
"""
|
"""
|
||||||
Verify that changing each attribute works as expected.
|
Verify that changing each attribute works as expected.
|
||||||
"""
|
"""
|
||||||
mirror = _setup_mirror()
|
mirror = _setup_mirror()
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"repository": "devtable/simple"}
|
params = {"repository": "devtable/simple"}
|
||||||
if key in ("http_proxy", "https_proxy", "no_proxy"):
|
if key in ("http_proxy", "https_proxy", "no_proxy"):
|
||||||
request_body = {"external_registry_config": {"proxy": {key: value}}}
|
request_body = {"external_registry_config": {"proxy": {key: value}}}
|
||||||
@ -187,7 +187,7 @@ def test_change_config(key, value, expected_status, client):
|
|||||||
request_body = {key: value}
|
request_body = {key: value}
|
||||||
conduct_api_call(cl, RepoMirrorResource, "PUT", params, request_body, expected_status)
|
conduct_api_call(cl, RepoMirrorResource, "PUT", params, request_body, expected_status)
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"repository": "devtable/simple"}
|
params = {"repository": "devtable/simple"}
|
||||||
resp = conduct_api_call(cl, RepoMirrorResource, "GET", params, None, 200)
|
resp = conduct_api_call(cl, RepoMirrorResource, "GET", params, None, 200)
|
||||||
|
|
||||||
@ -240,12 +240,12 @@ def test_change_config(key, value, expected_status, client):
|
|||||||
({"external_registry_username": "", "external_registry_password": ""}, 201),
|
({"external_registry_username": "", "external_registry_password": ""}, 201),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_change_credentials(request_body, expected_status, client):
|
def test_change_credentials(request_body, expected_status, app):
|
||||||
"""
|
"""
|
||||||
Verify credentials can only be modified as a pair.
|
Verify credentials can only be modified as a pair.
|
||||||
"""
|
"""
|
||||||
mirror = _setup_mirror()
|
mirror = _setup_mirror()
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"repository": "devtable/simple"}
|
params = {"repository": "devtable/simple"}
|
||||||
conduct_api_call(cl, RepoMirrorResource, "PUT", params, request_body, expected_status)
|
conduct_api_call(cl, RepoMirrorResource, "PUT", params, request_body, expected_status)
|
||||||
|
@ -17,8 +17,8 @@ from endpoints.test.shared import client_with_identity
|
|||||||
(100000000000000000000, 400),
|
(100000000000000000000, 400),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_change_tag_expiration(expiration, expected_code, client):
|
def test_change_tag_expiration(expiration, expected_code, app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
conduct_api_call(
|
conduct_api_call(
|
||||||
cl,
|
cl,
|
||||||
Organization,
|
Organization,
|
||||||
@ -29,10 +29,10 @@ def test_change_tag_expiration(expiration, expected_code, client):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_get_organization_collaborators(client):
|
def test_get_organization_collaborators(app):
|
||||||
params = {"orgname": "buynlarge"}
|
params = {"orgname": "buynlarge"}
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
resp = conduct_api_call(cl, OrganizationCollaboratorList, "GET", params)
|
resp = conduct_api_call(cl, OrganizationCollaboratorList, "GET", params)
|
||||||
|
|
||||||
collaborator_names = [c["name"] for c in resp.json["collaborators"]]
|
collaborator_names = [c["name"] for c in resp.json["collaborators"]]
|
||||||
|
@ -18,8 +18,8 @@ from endpoints.test.shared import client_with_identity
|
|||||||
pytest.param("buynlarge/orgrepo", "buynlarge+coolrobot", 200, id="valid robot under org"),
|
pytest.param("buynlarge/orgrepo", "buynlarge+coolrobot", 200, id="valid robot under org"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_robot_permission(repository, username, expected_code, client):
|
def test_robot_permission(repository, username, expected_code, app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
conduct_api_call(
|
conduct_api_call(
|
||||||
cl,
|
cl,
|
||||||
RepositoryUserPermission,
|
RepositoryUserPermission,
|
||||||
|
@ -19,29 +19,29 @@ from features import FeatureNameValue
|
|||||||
("invalid_req", False, 400),
|
("invalid_req", False, 400),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_post_changetrust(trust_enabled, repo_found, expected_status, client):
|
def test_post_changetrust(trust_enabled, repo_found, expected_status, app):
|
||||||
with patch("endpoints.api.repository.tuf_metadata_api") as mock_tuf:
|
with patch("endpoints.api.repository.tuf_metadata_api") as mock_tuf:
|
||||||
with patch(
|
with patch(
|
||||||
"endpoints.api.repository_models_pre_oci.model.repository.get_repository"
|
"endpoints.api.repository_models_pre_oci.model.repository.get_repository"
|
||||||
) as mock_model:
|
) as mock_model:
|
||||||
mock_model.return_value = MagicMock() if repo_found else None
|
mock_model.return_value = MagicMock() if repo_found else None
|
||||||
mock_tuf.get_default_tags_with_expiration.return_value = ["tags", "expiration"]
|
mock_tuf.get_default_tags_with_expiration.return_value = ["tags", "expiration"]
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"repository": "devtable/repo"}
|
params = {"repository": "devtable/repo"}
|
||||||
request_body = {"trust_enabled": trust_enabled}
|
request_body = {"trust_enabled": trust_enabled}
|
||||||
conduct_api_call(cl, RepositoryTrust, "POST", params, request_body, expected_status)
|
conduct_api_call(cl, RepositoryTrust, "POST", params, request_body, expected_status)
|
||||||
|
|
||||||
|
|
||||||
def test_signing_disabled(client):
|
def test_signing_disabled(app):
|
||||||
with patch("features.SIGNING", FeatureNameValue("SIGNING", False)):
|
with patch("features.SIGNING", FeatureNameValue("SIGNING", False)):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"repository": "devtable/simple"}
|
params = {"repository": "devtable/simple"}
|
||||||
response = conduct_api_call(cl, Repository, "GET", params).json
|
response = conduct_api_call(cl, Repository, "GET", params).json
|
||||||
assert not response["trust_enabled"]
|
assert not response["trust_enabled"]
|
||||||
|
|
||||||
|
|
||||||
def test_list_starred_repos(client):
|
def test_list_starred_repos(app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {
|
params = {
|
||||||
"starred": "true",
|
"starred": "true",
|
||||||
}
|
}
|
||||||
@ -70,8 +70,8 @@ def test_list_starred_repos(client):
|
|||||||
assert "public/publicrepo" not in repos
|
assert "public/publicrepo" not in repos
|
||||||
|
|
||||||
|
|
||||||
def test_list_repos(client, initialized_db):
|
def test_list_repos(initialized_db, app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"starred": "true", "repo_kind": "application"}
|
params = {"starred": "true", "repo_kind": "application"}
|
||||||
response = conduct_api_call(cl, RepositoryList, "GET", params).json
|
response = conduct_api_call(cl, RepositoryList, "GET", params).json
|
||||||
repo_states = {r["state"] for r in response["repositories"]}
|
repo_states = {r["state"] for r in response["repositories"]}
|
||||||
@ -79,8 +79,8 @@ def test_list_repos(client, initialized_db):
|
|||||||
assert state in ["NORMAL", "MIRROR", "READ_ONLY", "MARKED_FOR_DELETION"]
|
assert state in ["NORMAL", "MIRROR", "READ_ONLY", "MARKED_FOR_DELETION"]
|
||||||
|
|
||||||
|
|
||||||
def test_list_starred_app_repos(client, initialized_db):
|
def test_list_starred_app_repos(initialized_db, app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"starred": "true", "repo_kind": "application"}
|
params = {"starred": "true", "repo_kind": "application"}
|
||||||
|
|
||||||
devtable = model.user.get_user("devtable")
|
devtable = model.user.get_user("devtable")
|
||||||
@ -94,8 +94,8 @@ def test_list_starred_app_repos(client, initialized_db):
|
|||||||
assert "devtable/someappr" in repos
|
assert "devtable/someappr" in repos
|
||||||
|
|
||||||
|
|
||||||
def test_list_repositories_last_modified(client):
|
def test_list_repositories_last_modified(app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {
|
params = {
|
||||||
"namespace": "devtable",
|
"namespace": "devtable",
|
||||||
"last_modified": "true",
|
"last_modified": "true",
|
||||||
@ -127,12 +127,12 @@ def test_list_repositories_last_modified(client):
|
|||||||
pytest.param("devtable/nested1/nested2", True, 201, id="Slashes Allowed Multiple Levels"),
|
pytest.param("devtable/nested1/nested2", True, 201, id="Slashes Allowed Multiple Levels"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_create_repository(repo_name, extended_repo_names, expected_status, client):
|
def test_create_repository(repo_name, extended_repo_names, expected_status, app):
|
||||||
with patch(
|
with patch(
|
||||||
"features.EXTENDED_REPOSITORY_NAMES",
|
"features.EXTENDED_REPOSITORY_NAMES",
|
||||||
FeatureNameValue("EXTENDED_REPOSITORY_NAMES", extended_repo_names),
|
FeatureNameValue("EXTENDED_REPOSITORY_NAMES", extended_repo_names),
|
||||||
):
|
):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
body = {
|
body = {
|
||||||
"namespace": "devtable",
|
"namespace": "devtable",
|
||||||
"repository": repo_name,
|
"repository": repo_name,
|
||||||
@ -141,7 +141,7 @@ def test_create_repository(repo_name, extended_repo_names, expected_status, clie
|
|||||||
}
|
}
|
||||||
|
|
||||||
result = conduct_api_call(
|
result = conduct_api_call(
|
||||||
client, RepositoryList, "post", None, body, expected_code=expected_status
|
cl, RepositoryList, "post", None, body, expected_code=expected_status
|
||||||
).json
|
).json
|
||||||
if expected_status == 201:
|
if expected_status == 201:
|
||||||
assert result["name"] == repo_name
|
assert result["name"] == repo_name
|
||||||
@ -155,8 +155,8 @@ def test_create_repository(repo_name, extended_repo_names, expected_status, clie
|
|||||||
False,
|
False,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_get_repo(has_tag_manifest, client, initialized_db):
|
def test_get_repo(has_tag_manifest, initialized_db, app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"repository": "devtable/simple"}
|
params = {"repository": "devtable/simple"}
|
||||||
response = conduct_api_call(cl, Repository, "GET", params).json
|
response = conduct_api_call(cl, Repository, "GET", params).json
|
||||||
assert response["kind"] == "image"
|
assert response["kind"] == "image"
|
||||||
@ -171,8 +171,8 @@ def test_get_repo(has_tag_manifest, client, initialized_db):
|
|||||||
(database.RepositoryState.MIRROR, False),
|
(database.RepositoryState.MIRROR, False),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_get_repo_state_can_write(state, can_write, client, initialized_db):
|
def test_get_repo_state_can_write(state, can_write, initialized_db, app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"repository": "devtable/simple"}
|
params = {"repository": "devtable/simple"}
|
||||||
response = conduct_api_call(cl, Repository, "GET", params).json
|
response = conduct_api_call(cl, Repository, "GET", params).json
|
||||||
assert response["can_write"]
|
assert response["can_write"]
|
||||||
@ -181,14 +181,14 @@ def test_get_repo_state_can_write(state, can_write, client, initialized_db):
|
|||||||
repo.state = state
|
repo.state = state
|
||||||
repo.save()
|
repo.save()
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"repository": "devtable/simple"}
|
params = {"repository": "devtable/simple"}
|
||||||
response = conduct_api_call(cl, Repository, "GET", params).json
|
response = conduct_api_call(cl, Repository, "GET", params).json
|
||||||
assert response["can_write"] == can_write
|
assert response["can_write"] == can_write
|
||||||
|
|
||||||
|
|
||||||
def test_delete_repo(client, initialized_db):
|
def test_delete_repo(initialized_db, app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
resp = conduct_api_call(cl, RepositoryList, "GET", {"namespace": "devtable"}).json
|
resp = conduct_api_call(cl, RepositoryList, "GET", {"namespace": "devtable"}).json
|
||||||
repos = {repo["name"] for repo in resp["repositories"]}
|
repos = {repo["name"] for repo in resp["repositories"]}
|
||||||
assert "simple" in repos
|
assert "simple" in repos
|
||||||
|
@ -14,8 +14,8 @@ from endpoints.test.shared import client_with_identity
|
|||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def authd_client(client):
|
def authd_client(app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
yield cl
|
yield cl
|
||||||
|
|
||||||
|
|
||||||
|
@ -28,8 +28,8 @@ from util.names import parse_robot_username
|
|||||||
{"description": "this is a description", "unstructured_metadata": {"foo": "bar"}},
|
{"description": "this is a description", "unstructured_metadata": {"foo": "bar"}},
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_create_robot_with_metadata(endpoint, body, client):
|
def test_create_robot_with_metadata(endpoint, body, app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
# Create the robot with the specified body.
|
# Create the robot with the specified body.
|
||||||
conduct_api_call(
|
conduct_api_call(
|
||||||
cl,
|
cl,
|
||||||
@ -63,8 +63,8 @@ def test_create_robot_with_metadata(endpoint, body, client):
|
|||||||
(OrgRobot, {"orgname": "buynlarge", "robot_shortname": "coolrobot"}),
|
(OrgRobot, {"orgname": "buynlarge", "robot_shortname": "coolrobot"}),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_retrieve_robot(endpoint, params, app, client):
|
def test_retrieve_robot(endpoint, params, app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
result = conduct_api_call(cl, endpoint, "GET", params, None)
|
result = conduct_api_call(cl, endpoint, "GET", params, None)
|
||||||
assert result.json["token"] is not None
|
assert result.json["token"] is not None
|
||||||
|
|
||||||
@ -91,13 +91,13 @@ def test_retrieve_robot(endpoint, params, app, client):
|
|||||||
5,
|
5,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_retrieve_robots(endpoint, params, bot_endpoint, include_token, limit, app, client):
|
def test_retrieve_robots(endpoint, params, bot_endpoint, include_token, limit, app):
|
||||||
params["token"] = "true" if include_token else "false"
|
params["token"] = "true" if include_token else "false"
|
||||||
|
|
||||||
if limit is not None:
|
if limit is not None:
|
||||||
params["limit"] = limit
|
params["limit"] = limit
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
result = conduct_api_call(cl, endpoint, "GET", params, None)
|
result = conduct_api_call(cl, endpoint, "GET", params, None)
|
||||||
|
|
||||||
if limit is not None:
|
if limit is not None:
|
||||||
@ -126,8 +126,8 @@ def test_retrieve_robots(endpoint, params, bot_endpoint, include_token, limit, a
|
|||||||
False,
|
False,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_retrieve_robots_token_permission(username, is_admin, with_permissions, app, client):
|
def test_retrieve_robots_token_permission(username, is_admin, with_permissions, app):
|
||||||
with client_with_identity(username, client) as cl:
|
with client_with_identity(username, app) as cl:
|
||||||
params = {"orgname": "buynlarge", "token": "true"}
|
params = {"orgname": "buynlarge", "token": "true"}
|
||||||
if with_permissions:
|
if with_permissions:
|
||||||
params["permissions"] = "true"
|
params["permissions"] = "true"
|
||||||
|
@ -19,12 +19,12 @@ from endpoints.test.shared import client_with_identity
|
|||||||
("repository"),
|
("repository"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_repository_search(query, client):
|
def test_repository_search(query, app):
|
||||||
# Prime the caches.
|
# Prime the caches.
|
||||||
database.Repository.kind.get_id("image")
|
database.Repository.kind.get_id("image")
|
||||||
database.Repository.kind.get_name(1)
|
database.Repository.kind.get_name(1)
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"query": query}
|
params = {"query": query}
|
||||||
with assert_query_count(4):
|
with assert_query_count(4):
|
||||||
result = conduct_api_call(cl, ConductRepositorySearch, "GET", params, None, 200).json
|
result = conduct_api_call(cl, ConductRepositorySearch, "GET", params, None, 200).json
|
||||||
@ -41,8 +41,8 @@ def test_repository_search(query, client):
|
|||||||
("repository"),
|
("repository"),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_search_query_count(query, client):
|
def test_search_query_count(query, app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"query": query}
|
params = {"query": query}
|
||||||
with assert_query_count(10):
|
with assert_query_count(10):
|
||||||
result = conduct_api_call(cl, ConductSearch, "GET", params, None, 200).json
|
result = conduct_api_call(cl, ConductSearch, "GET", params, None, 200).json
|
||||||
@ -62,7 +62,7 @@ def test_search_query_count(query, client):
|
|||||||
6,
|
6,
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_repository_search_pagination(page_count, client):
|
def test_repository_search_pagination(page_count, app):
|
||||||
# Create at least a few pages of results.
|
# Create at least a few pages of results.
|
||||||
all_repositories = set()
|
all_repositories = set()
|
||||||
user = model.user.get_user("devtable")
|
user = model.user.get_user("devtable")
|
||||||
@ -71,7 +71,7 @@ def test_repository_search_pagination(page_count, client):
|
|||||||
all_repositories.add(repo_name)
|
all_repositories.add(repo_name)
|
||||||
model.repository.create_repository("devtable", repo_name, user)
|
model.repository.create_repository("devtable", repo_name, user)
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
for page_index in range(0, page_count):
|
for page_index in range(0, page_count):
|
||||||
params = {"query": "somerepo", "page": page_index + 1}
|
params = {"query": "somerepo", "page": page_index + 1}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ from endpoints.api.namespacequota import *
|
|||||||
|
|
||||||
from endpoints.api.repository import Repository
|
from endpoints.api.repository import Repository
|
||||||
|
|
||||||
from test.fixtures import *
|
from test.fixtures import * # type: ignore[assignment] # isort: skip
|
||||||
|
|
||||||
ORG_PARAMS = {"orgname": "buynlarge"}
|
ORG_PARAMS = {"orgname": "buynlarge"}
|
||||||
TEAM_PARAMS = {"orgname": "buynlarge", "teamname": "owners"}
|
TEAM_PARAMS = {"orgname": "buynlarge", "teamname": "owners"}
|
||||||
@ -6062,8 +6062,8 @@ SECURITY_TESTS: List[
|
|||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("resource,method,params,body,identity,expected", SECURITY_TESTS)
|
@pytest.mark.parametrize("resource,method,params,body,identity,expected", SECURITY_TESTS)
|
||||||
def test_api_security(resource, method, params, body, identity, expected, client):
|
def test_api_security(resource, method, params, body, identity, expected, app):
|
||||||
with client_with_identity(identity, client) as cl:
|
with client_with_identity(identity, app) as cl:
|
||||||
conduct_api_call(cl, resource, method, params, body, expected)
|
conduct_api_call(cl, resource, method, params, body, expected)
|
||||||
|
|
||||||
|
|
||||||
@ -6122,13 +6122,13 @@ def test_all_apis_tested(app):
|
|||||||
("DELETE", 200),
|
("DELETE", 200),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_team_sync_security(is_superuser, allow_nonsuperuser, method, expected, client):
|
def test_team_sync_security(is_superuser, allow_nonsuperuser, method, expected, app):
|
||||||
def is_superuser_method(_):
|
def is_superuser_method(_):
|
||||||
return is_superuser
|
return is_superuser
|
||||||
|
|
||||||
with patch("auth.permissions.usermanager.is_superuser", is_superuser_method):
|
with patch("auth.permissions.usermanager.is_superuser", is_superuser_method):
|
||||||
with toggle_feature("NONSUPERUSER_TEAM_SYNCING_SETUP", allow_nonsuperuser):
|
with toggle_feature("NONSUPERUSER_TEAM_SYNCING_SETUP", allow_nonsuperuser):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
expect_success = is_superuser or allow_nonsuperuser
|
expect_success = is_superuser or allow_nonsuperuser
|
||||||
expected_status = expected if expect_success else 403
|
expected_status = expected if expect_success else 403
|
||||||
conduct_api_call(
|
conduct_api_call(
|
||||||
|
@ -47,10 +47,10 @@ def tags_equal(expected, actual):
|
|||||||
(None, {"delegations": None}), # API returns None on exceptions
|
(None, {"delegations": None}), # API returns None on exceptions
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_get_signatures(targets_map, expected, client):
|
def test_get_signatures(targets_map, expected, app):
|
||||||
with patch("endpoints.api.signing.tuf_metadata_api") as mock_tuf:
|
with patch("endpoints.api.signing.tuf_metadata_api") as mock_tuf:
|
||||||
mock_tuf.get_all_tags_with_expiration.return_value = targets_map
|
mock_tuf.get_all_tags_with_expiration.return_value = targets_map
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"repository": "devtable/trusted"}
|
params = {"repository": "devtable/trusted"}
|
||||||
assert tags_equal(
|
assert tags_equal(
|
||||||
expected, conduct_api_call(cl, RepositorySignatures, "GET", params, None, 200).json
|
expected, conduct_api_call(cl, RepositorySignatures, "GET", params, None, 200).json
|
||||||
|
@ -19,8 +19,8 @@ from endpoints.test.shared import client_with_identity
|
|||||||
(False),
|
(False),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_list_all_users(disabled, client):
|
def test_list_all_users(disabled, app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"disabled": disabled}
|
params = {"disabled": disabled}
|
||||||
result = conduct_api_call(cl, SuperUserList, "GET", params, None, 200).json
|
result = conduct_api_call(cl, SuperUserList, "GET", params, None, 200).json
|
||||||
assert len(result["users"])
|
assert len(result["users"])
|
||||||
@ -29,14 +29,14 @@ def test_list_all_users(disabled, client):
|
|||||||
assert user["enabled"]
|
assert user["enabled"]
|
||||||
|
|
||||||
|
|
||||||
def test_list_all_orgs(client):
|
def test_list_all_orgs(app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
result = conduct_api_call(cl, SuperUserOrganizationList, "GET", None, None, 200).json
|
result = conduct_api_call(cl, SuperUserOrganizationList, "GET", None, None, 200).json
|
||||||
assert len(result["organizations"]) == 5
|
assert len(result["organizations"]) == 5
|
||||||
|
|
||||||
|
|
||||||
def test_paginate_orgs(client):
|
def test_paginate_orgs(app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"limit": 3}
|
params = {"limit": 3}
|
||||||
firstResult = conduct_api_call(cl, SuperUserOrganizationList, "GET", params, None, 200).json
|
firstResult = conduct_api_call(cl, SuperUserOrganizationList, "GET", params, None, 200).json
|
||||||
assert len(firstResult["organizations"]) == 3
|
assert len(firstResult["organizations"]) == 3
|
||||||
@ -49,8 +49,8 @@ def test_paginate_orgs(client):
|
|||||||
assert secondResult.get("next_page", None) is None
|
assert secondResult.get("next_page", None) is None
|
||||||
|
|
||||||
|
|
||||||
def test_paginate_test_list_all_users(client):
|
def test_paginate_test_list_all_users(app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"limit": 6}
|
params = {"limit": 6}
|
||||||
firstResult = conduct_api_call(cl, SuperUserList, "GET", params, None, 200).json
|
firstResult = conduct_api_call(cl, SuperUserList, "GET", params, None, 200).json
|
||||||
assert len(firstResult["users"]) == 6
|
assert len(firstResult["users"]) == 6
|
||||||
@ -61,8 +61,8 @@ def test_paginate_test_list_all_users(client):
|
|||||||
assert secondResult.get("next_page", None) is None
|
assert secondResult.get("next_page", None) is None
|
||||||
|
|
||||||
|
|
||||||
def test_change_install_user(client):
|
def test_change_install_user(app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {"username": "randomuser"}
|
params = {"username": "randomuser"}
|
||||||
body = {"email": "new_email123@test.com"}
|
body = {"email": "new_email123@test.com"}
|
||||||
result = conduct_api_call(cl, SuperUserManagement, "PUT", params, body, 200).json
|
result = conduct_api_call(cl, SuperUserManagement, "PUT", params, body, 200).json
|
||||||
|
@ -17,8 +17,8 @@ from endpoints.test.shared import client_with_identity
|
|||||||
("aksdjhasd", 400),
|
("aksdjhasd", 400),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_change_tag_expiration_default(expiration_time, expected_status, client, app):
|
def test_change_tag_expiration_default(expiration_time, expected_status, app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {
|
params = {
|
||||||
"repository": "devtable/simple",
|
"repository": "devtable/simple",
|
||||||
"tag": "latest",
|
"tag": "latest",
|
||||||
@ -31,8 +31,8 @@ def test_change_tag_expiration_default(expiration_time, expected_status, client,
|
|||||||
conduct_api_call(cl, RepositoryTag, "put", params, request_body, expected_status)
|
conduct_api_call(cl, RepositoryTag, "put", params, request_body, expected_status)
|
||||||
|
|
||||||
|
|
||||||
def test_change_tag_expiration(client, app):
|
def test_change_tag_expiration(app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params = {
|
params = {
|
||||||
"repository": "devtable/simple",
|
"repository": "devtable/simple",
|
||||||
"tag": "latest",
|
"tag": "latest",
|
||||||
@ -68,8 +68,8 @@ def test_change_tag_expiration(client, app):
|
|||||||
(True, "newtag", 201),
|
(True, "newtag", 201),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_move_tag(manifest_exists, test_tag, expected_status, client, app):
|
def test_move_tag(manifest_exists, test_tag, expected_status, app):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
test_image = "unknown"
|
test_image = "unknown"
|
||||||
if manifest_exists:
|
if manifest_exists:
|
||||||
repo_ref = registry_model.lookup_repository("devtable", "simple")
|
repo_ref = registry_model.lookup_repository("devtable", "simple")
|
||||||
@ -98,12 +98,12 @@ def test_move_tag(manifest_exists, test_tag, expected_status, client, app):
|
|||||||
("buynlarge", "anotherorgrepo", 6), # +2 for permissions checks.
|
("buynlarge", "anotherorgrepo", 6), # +2 for permissions checks.
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_list_repo_tags(repo_namespace, repo_name, client, query_count, app):
|
def test_list_repo_tags(repo_namespace, repo_name, query_count, app):
|
||||||
# Pre-cache media type loads to ensure consistent query count.
|
# Pre-cache media type loads to ensure consistent query count.
|
||||||
Manifest.media_type.get_name(1)
|
Manifest.media_type.get_name(1)
|
||||||
|
|
||||||
params = {"repository": repo_namespace + "/" + repo_name}
|
params = {"repository": repo_namespace + "/" + repo_name}
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
with assert_query_count(query_count):
|
with assert_query_count(query_count):
|
||||||
tags = conduct_api_call(cl, ListRepositoryTags, "get", params).json["tags"]
|
tags = conduct_api_call(cl, ListRepositoryTags, "get", params).json["tags"]
|
||||||
|
|
||||||
@ -118,22 +118,22 @@ def test_list_repo_tags(repo_namespace, repo_name, client, query_count, app):
|
|||||||
("devtable", "gargantuan", 4),
|
("devtable", "gargantuan", 4),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_list_repo_tags_filter(repo_namespace, repo_name, client, query_count, app):
|
def test_list_repo_tags_filter(repo_namespace, repo_name, query_count, app):
|
||||||
Manifest.media_type.get_name(1)
|
Manifest.media_type.get_name(1)
|
||||||
|
|
||||||
params = {"repository": repo_namespace + "/" + repo_name}
|
params = {"repository": repo_namespace + "/" + repo_name}
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
with assert_query_count(query_count):
|
with assert_query_count(query_count):
|
||||||
params["filter_tag_name"] = "like:v"
|
params["filter_tag_name"] = "like:v"
|
||||||
tags = conduct_api_call(cl, ListRepositoryTags, "get", params).json["tags"]
|
tags = conduct_api_call(cl, ListRepositoryTags, "get", params).json["tags"]
|
||||||
assert len(tags) == 5
|
assert len(tags) == 5
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
with assert_query_count(query_count):
|
with assert_query_count(query_count - 1):
|
||||||
params["filter_tag_name"] = "eq:prod"
|
params["filter_tag_name"] = "eq:prod"
|
||||||
tags = conduct_api_call(cl, ListRepositoryTags, "get", params).json["tags"]
|
tags = conduct_api_call(cl, ListRepositoryTags, "get", params).json["tags"]
|
||||||
assert len(tags) == 1
|
assert len(tags) == 1
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
params["filter_tag_name"] = "random"
|
params["filter_tag_name"] = "random"
|
||||||
resp = conduct_api_call(cl, ListRepositoryTags, "get", params, None, expected_code=400)
|
resp = conduct_api_call(cl, ListRepositoryTags, "get", params, None, expected_code=400)
|
||||||
|
@ -15,10 +15,10 @@ SYNCED_TEAM_PARAMS = {"orgname": "sellnsmall", "teamname": "synced"}
|
|||||||
UNSYNCED_TEAM_PARAMS = {"orgname": "sellnsmall", "teamname": "owners"}
|
UNSYNCED_TEAM_PARAMS = {"orgname": "sellnsmall", "teamname": "owners"}
|
||||||
|
|
||||||
|
|
||||||
def test_team_syncing(client):
|
def test_team_syncing(app):
|
||||||
with mock_ldap() as ldap:
|
with mock_ldap() as ldap:
|
||||||
with patch("endpoints.api.team.authentication", ldap):
|
with patch("endpoints.api.team.authentication", ldap):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
config = {
|
config = {
|
||||||
"group_dn": "cn=AwesomeFolk",
|
"group_dn": "cn=AwesomeFolk",
|
||||||
}
|
}
|
||||||
@ -42,25 +42,32 @@ def test_team_syncing(client):
|
|||||||
assert sync_info is None
|
assert sync_info is None
|
||||||
|
|
||||||
|
|
||||||
def test_team_member_sync_info(client):
|
def test_team_member_sync_info_unsynced_superuser(app):
|
||||||
with mock_ldap() as ldap:
|
with mock_ldap() as ldap:
|
||||||
with patch("endpoints.api.team.authentication", ldap):
|
with patch("endpoints.api.team.authentication", ldap):
|
||||||
# Check for an unsynced team, with superuser.
|
# Check for an unsynced team, with superuser.
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
resp = conduct_api_call(cl, TeamMemberList, "GET", UNSYNCED_TEAM_PARAMS)
|
resp = conduct_api_call(cl, TeamMemberList, "GET", UNSYNCED_TEAM_PARAMS)
|
||||||
assert "can_sync" in resp.json
|
assert "can_sync" in resp.json
|
||||||
assert resp.json["can_sync"]["service"] == "ldap"
|
assert resp.json["can_sync"]["service"] == "ldap"
|
||||||
|
|
||||||
assert "synced" not in resp.json
|
assert "synced" not in resp.json
|
||||||
|
|
||||||
|
|
||||||
|
def test_team_member_sync_info_unsynced_nonsuperuser(app):
|
||||||
|
with mock_ldap() as ldap:
|
||||||
|
with patch("endpoints.api.team.authentication", ldap):
|
||||||
# Check for an unsynced team, with non-superuser.
|
# Check for an unsynced team, with non-superuser.
|
||||||
with client_with_identity("randomuser", client) as cl:
|
with client_with_identity("randomuser", app) as cl:
|
||||||
resp = conduct_api_call(cl, TeamMemberList, "GET", UNSYNCED_TEAM_PARAMS)
|
resp = conduct_api_call(cl, TeamMemberList, "GET", UNSYNCED_TEAM_PARAMS)
|
||||||
assert "can_sync" not in resp.json
|
assert "can_sync" not in resp.json
|
||||||
assert "synced" not in resp.json
|
assert "synced" not in resp.json
|
||||||
|
|
||||||
|
|
||||||
|
def test_team_member_sync_info_synced_superuser(app):
|
||||||
|
with mock_ldap() as ldap:
|
||||||
|
with patch("endpoints.api.team.authentication", ldap):
|
||||||
# Check for a synced team, with superuser.
|
# Check for a synced team, with superuser.
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
resp = conduct_api_call(cl, TeamMemberList, "GET", SYNCED_TEAM_PARAMS)
|
resp = conduct_api_call(cl, TeamMemberList, "GET", SYNCED_TEAM_PARAMS)
|
||||||
assert "can_sync" in resp.json
|
assert "can_sync" in resp.json
|
||||||
assert resp.json["can_sync"]["service"] == "ldap"
|
assert resp.json["can_sync"]["service"] == "ldap"
|
||||||
@ -69,8 +76,12 @@ def test_team_member_sync_info(client):
|
|||||||
assert "last_updated" in resp.json["synced"]
|
assert "last_updated" in resp.json["synced"]
|
||||||
assert "group_dn" in resp.json["synced"]["config"]
|
assert "group_dn" in resp.json["synced"]["config"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_team_member_sync_info_synced_nonsuperuser(app):
|
||||||
|
with mock_ldap() as ldap:
|
||||||
|
with patch("endpoints.api.team.authentication", ldap):
|
||||||
# Check for a synced team, with non-superuser.
|
# Check for a synced team, with non-superuser.
|
||||||
with client_with_identity("randomuser", client) as cl:
|
with client_with_identity("randomuser", app) as cl:
|
||||||
resp = conduct_api_call(cl, TeamMemberList, "GET", SYNCED_TEAM_PARAMS)
|
resp = conduct_api_call(cl, TeamMemberList, "GET", SYNCED_TEAM_PARAMS)
|
||||||
assert "can_sync" not in resp.json
|
assert "can_sync" not in resp.json
|
||||||
|
|
||||||
@ -79,11 +90,11 @@ def test_team_member_sync_info(client):
|
|||||||
assert "config" not in resp.json["synced"]
|
assert "config" not in resp.json["synced"]
|
||||||
|
|
||||||
|
|
||||||
def test_organization_teams_sync_bool(client):
|
def test_organization_teams_sync_bool(app):
|
||||||
with mock_ldap() as ldap:
|
with mock_ldap() as ldap:
|
||||||
with patch("endpoints.api.organization.authentication", ldap):
|
with patch("endpoints.api.organization.authentication", ldap):
|
||||||
# Ensure synced teams are marked as such in the organization teams list.
|
# Ensure synced teams are marked as such in the organization teams list.
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
resp = conduct_api_call(cl, Organization, "GET", {"orgname": "sellnsmall"})
|
resp = conduct_api_call(cl, Organization, "GET", {"orgname": "sellnsmall"})
|
||||||
|
|
||||||
assert not resp.json["teams"]["owners"]["is_synced"]
|
assert not resp.json["teams"]["owners"]["is_synced"]
|
||||||
|
@ -32,7 +32,7 @@ def test_super_user_build_endpoints(context, dockerfile_path, expected):
|
|||||||
assert is_parent(context, dockerfile_path) == expected
|
assert is_parent(context, dockerfile_path) == expected
|
||||||
|
|
||||||
|
|
||||||
def test_enabled_disabled_trigger(app, client):
|
def test_enabled_disabled_trigger(app):
|
||||||
trigger = model.build.list_build_triggers("devtable", "building")[0]
|
trigger = model.build.list_build_triggers("devtable", "building")[0]
|
||||||
trigger.config = json.dumps({"hook_id": "someid"})
|
trigger.config = json.dumps({"hook_id": "someid"})
|
||||||
trigger.save()
|
trigger.save()
|
||||||
@ -46,7 +46,7 @@ def test_enabled_disabled_trigger(app, client):
|
|||||||
"enabled": False,
|
"enabled": False,
|
||||||
}
|
}
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
result = conduct_api_call(cl, BuildTrigger, "PUT", params, body, 200).json
|
result = conduct_api_call(cl, BuildTrigger, "PUT", params, body, 200).json
|
||||||
assert not result["enabled"]
|
assert not result["enabled"]
|
||||||
|
|
||||||
@ -54,6 +54,6 @@ def test_enabled_disabled_trigger(app, client):
|
|||||||
"enabled": True,
|
"enabled": True,
|
||||||
}
|
}
|
||||||
|
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
result = conduct_api_call(cl, BuildTrigger, "PUT", params, body, 200).json
|
result = conduct_api_call(cl, BuildTrigger, "PUT", params, body, 200).json
|
||||||
assert result["enabled"]
|
assert result["enabled"]
|
||||||
|
@ -10,9 +10,9 @@ from endpoints.test.shared import client_with_identity, conduct_call
|
|||||||
from features import FeatureNameValue
|
from features import FeatureNameValue
|
||||||
|
|
||||||
|
|
||||||
def test_user_metadata_update(client):
|
def test_user_metadata_update(app):
|
||||||
with patch("features.USER_METADATA", FeatureNameValue("USER_METADATA", True)):
|
with patch("features.USER_METADATA", FeatureNameValue("USER_METADATA", True)):
|
||||||
with client_with_identity("devtable", client) as cl:
|
with client_with_identity("devtable", app) as cl:
|
||||||
metadata = {
|
metadata = {
|
||||||
"given_name": "Quay",
|
"given_name": "Quay",
|
||||||
"family_name": "User",
|
"family_name": "User",
|
||||||
|
@ -6,7 +6,8 @@ import logging
|
|||||||
import os
|
import os
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
|
|
||||||
from flask import abort, make_response, request
|
from flask import request
|
||||||
|
from ua_parser import user_agent_parser
|
||||||
|
|
||||||
import features
|
import features
|
||||||
from app import app, ip_resolver, model_cache, usermanager
|
from app import app, ip_resolver, model_cache, usermanager
|
||||||
@ -235,11 +236,40 @@ def require_xhr_from_browser(func):
|
|||||||
text attacks.
|
text attacks.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# https://github.com/pallets/werkzeug/issues/2078
|
||||||
|
browsers = (
|
||||||
|
"aol",
|
||||||
|
"ask",
|
||||||
|
"camino",
|
||||||
|
"chrome",
|
||||||
|
"firefox",
|
||||||
|
"galeon",
|
||||||
|
"google",
|
||||||
|
"kmeleon",
|
||||||
|
"konqueror",
|
||||||
|
"links",
|
||||||
|
"lynx",
|
||||||
|
"msie",
|
||||||
|
"msn",
|
||||||
|
"netscape",
|
||||||
|
"opera",
|
||||||
|
"safari",
|
||||||
|
"seamonkey",
|
||||||
|
"webkit",
|
||||||
|
"yahoo",
|
||||||
|
)
|
||||||
|
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def wrapper(*args, **kwargs):
|
def wrapper(*args, **kwargs):
|
||||||
if app.config.get("BROWSER_API_CALLS_XHR_ONLY", False):
|
if app.config.get("BROWSER_API_CALLS_XHR_ONLY", False):
|
||||||
if request.method == "GET" and request.user_agent.browser:
|
if (
|
||||||
|
request.method == "GET"
|
||||||
|
and request.user_agent.string
|
||||||
|
and user_agent_parser.ParseUserAgent(request.user_agent.string)["family"].lower()
|
||||||
|
in browsers
|
||||||
|
):
|
||||||
has_xhr_header = request.headers.get("X-Requested-With") == "XMLHttpRequest"
|
has_xhr_header = request.headers.get("X-Requested-With") == "XMLHttpRequest"
|
||||||
|
|
||||||
if not has_xhr_header and not app.config.get("DEBUGGING") == True:
|
if not has_xhr_header and not app.config.get("DEBUGGING") == True:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Disallowed possible RTA to URL %s with user agent %s",
|
"Disallowed possible RTA to URL %s with user agent %s",
|
||||||
|
@ -12,21 +12,21 @@ CSRF_TOKEN_KEY = "_csrf_token"
|
|||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def client_with_identity(auth_username, client):
|
def client_with_identity(auth_username, app):
|
||||||
with client.session_transaction() as sess:
|
if auth_username and auth_username is not None:
|
||||||
if auth_username and auth_username is not None:
|
loaded = model.user.get_user(auth_username)
|
||||||
loaded = model.user.get_user(auth_username)
|
else:
|
||||||
sess["user_id"] = loaded.uuid
|
loaded = None
|
||||||
sess["login_time"] = datetime.datetime.now()
|
|
||||||
else:
|
|
||||||
sess["user_id"] = "anonymous"
|
|
||||||
|
|
||||||
yield client
|
with app.test_client(user=loaded) as cl:
|
||||||
|
yield cl
|
||||||
|
|
||||||
with client.session_transaction() as sess:
|
with cl.session_transaction() as sess:
|
||||||
sess["user_id"] = None
|
sess["_user_id"] = None
|
||||||
sess["login_time"] = None
|
sess["user_id"] = None
|
||||||
sess[CSRF_TOKEN_KEY] = None
|
sess["_fresh"] = False
|
||||||
|
sess["login_time"] = None
|
||||||
|
sess[CSRF_TOKEN_KEY] = None
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
|
@ -18,7 +18,15 @@ def test_verify_blueprint(blueprint):
|
|||||||
self.first_registration = True
|
self.first_registration = True
|
||||||
self.app = app
|
self.app = app
|
||||||
|
|
||||||
def add_url_rule(self, rule, endpoint, view_function, methods=None):
|
def add_url_rule(
|
||||||
|
self,
|
||||||
|
rule,
|
||||||
|
endpoint=None,
|
||||||
|
view_function=None,
|
||||||
|
methods=None,
|
||||||
|
provide_automatic_options=None,
|
||||||
|
**options,
|
||||||
|
):
|
||||||
result = "__anon_protected" in dir(view_function) or "__anon_allowed" in dir(
|
result = "__anon_protected" in dir(view_function) or "__anon_allowed" in dir(
|
||||||
view_function
|
view_function
|
||||||
)
|
)
|
||||||
|
@ -15,7 +15,11 @@ from endpoints.test.shared import conduct_call
|
|||||||
("curl/whatever", False, 200),
|
("curl/whatever", False, 200),
|
||||||
("Mozilla/whatever", True, 200),
|
("Mozilla/whatever", True, 200),
|
||||||
("Mozilla/5.0", True, 200),
|
("Mozilla/5.0", True, 200),
|
||||||
("Mozilla/5.0 (Windows NT 5.1; Win64; x64)", False, 400),
|
(
|
||||||
|
"Mozilla/5.0 (Unknown; Linux x86_64) AppleWebKit/534.34 (KHTML, like Gecko) Safari/534.34",
|
||||||
|
False,
|
||||||
|
400,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
def test_require_xhr_from_browser(user_agent, include_header, expected_code, app, client):
|
def test_require_xhr_from_browser(user_agent, include_header, expected_code, app, client):
|
||||||
|
3
mypy.ini
3
mypy.ini
@ -183,6 +183,9 @@ ignore_missing_imports = True
|
|||||||
[mypy-tldextract]
|
[mypy-tldextract]
|
||||||
ignore_missing_imports = True
|
ignore_missing_imports = True
|
||||||
|
|
||||||
|
[mypy-ua_parser]
|
||||||
|
ignore_missing_imports = True
|
||||||
|
|
||||||
[mypy-werkzeug.*]
|
[mypy-werkzeug.*]
|
||||||
ignore_missing_imports = True
|
ignore_missing_imports = True
|
||||||
|
|
||||||
|
@ -6,11 +6,7 @@ import logging
|
|||||||
from io import StringIO
|
from io import StringIO
|
||||||
|
|
||||||
from requests import Response
|
from requests import Response
|
||||||
|
from werkzeug.exceptions import Unauthorized
|
||||||
try:
|
|
||||||
from werkzeug.exceptions import Unauthorized
|
|
||||||
except ImportError:
|
|
||||||
Unauthorized = Exception
|
|
||||||
|
|
||||||
from oauth import utils
|
from oauth import utils
|
||||||
|
|
||||||
|
@ -3,7 +3,15 @@ from werkzeug.routing import BaseConverter
|
|||||||
import features
|
import features
|
||||||
|
|
||||||
|
|
||||||
class APIRepositoryPathConverter(BaseConverter):
|
class QuayBaseConverter(BaseConverter):
|
||||||
|
def __init_subclass__(cls, **kwargs):
|
||||||
|
super().__init_subclass__(**kwargs)
|
||||||
|
|
||||||
|
if "part_isolating" not in cls.__dict__:
|
||||||
|
cls.part_isolating = "/" not in cls.regex
|
||||||
|
|
||||||
|
|
||||||
|
class APIRepositoryPathConverter(QuayBaseConverter):
|
||||||
"""
|
"""
|
||||||
Converter for handling repository paths.
|
Converter for handling repository paths.
|
||||||
|
|
||||||
@ -17,7 +25,7 @@ class APIRepositoryPathConverter(BaseConverter):
|
|||||||
|
|
||||||
|
|
||||||
# TODO(kleesc): Remove after fully deprecating V1 push/pull
|
# TODO(kleesc): Remove after fully deprecating V1 push/pull
|
||||||
class V1CreateRepositoryPathConverter(BaseConverter):
|
class V1CreateRepositoryPathConverter(QuayBaseConverter):
|
||||||
"""
|
"""
|
||||||
Converter for handling PUT repository path.
|
Converter for handling PUT repository path.
|
||||||
Handles both library and non-library paths (if configured).
|
Handles both library and non-library paths (if configured).
|
||||||
@ -41,7 +49,7 @@ class V1CreateRepositoryPathConverter(BaseConverter):
|
|||||||
self.regex = r"([^/]+(/[^/]+)+)(?<!auth)(?<!tags)(?<!images)"
|
self.regex = r"([^/]+(/[^/]+)+)(?<!auth)(?<!tags)(?<!images)"
|
||||||
|
|
||||||
|
|
||||||
class RepositoryPathConverter(BaseConverter):
|
class RepositoryPathConverter(QuayBaseConverter):
|
||||||
"""
|
"""
|
||||||
Converter for handling repository paths.
|
Converter for handling repository paths.
|
||||||
Handles both library and non-library paths (if configured).
|
Handles both library and non-library paths (if configured).
|
||||||
@ -59,7 +67,7 @@ class RepositoryPathConverter(BaseConverter):
|
|||||||
self.regex = r"([^/]+(/[^/]+)+)"
|
self.regex = r"([^/]+(/[^/]+)+)"
|
||||||
|
|
||||||
|
|
||||||
class RegexConverter(BaseConverter):
|
class RegexConverter(QuayBaseConverter):
|
||||||
"""
|
"""
|
||||||
Converter for handling custom regular expression patterns in paths.
|
Converter for handling custom regular expression patterns in paths.
|
||||||
"""
|
"""
|
||||||
@ -69,7 +77,7 @@ class RegexConverter(BaseConverter):
|
|||||||
self.regex = regex_value
|
self.regex = regex_value
|
||||||
|
|
||||||
|
|
||||||
class RepositoryPathRedirectConverter(BaseConverter):
|
class RepositoryPathRedirectConverter(QuayBaseConverter):
|
||||||
"""
|
"""
|
||||||
Converter for handling redirect paths that don't match any other routes.
|
Converter for handling redirect paths that don't match any other routes.
|
||||||
|
|
||||||
@ -97,6 +105,7 @@ class RepositoryPathRedirectConverter(BaseConverter):
|
|||||||
|
|
||||||
def __init__(self, url_map):
|
def __init__(self, url_map):
|
||||||
super().__init__(url_map)
|
super().__init__(url_map)
|
||||||
|
|
||||||
self.weight = 200
|
self.weight = 200
|
||||||
|
|
||||||
if features.LIBRARY_SUPPORT:
|
if features.LIBRARY_SUPPORT:
|
||||||
|
@ -12,7 +12,7 @@ ipdb
|
|||||||
ipython
|
ipython
|
||||||
mock==3.0.5
|
mock==3.0.5
|
||||||
mypy==1.3.0
|
mypy==1.3.0
|
||||||
moto==2.0.1
|
moto==4.1.4
|
||||||
parameterized==0.8.1
|
parameterized==0.8.1
|
||||||
pre-commit==2.20.0
|
pre-commit==2.20.0
|
||||||
pytest
|
pytest
|
||||||
|
@ -11,7 +11,7 @@ bcrypt==3.1.7
|
|||||||
beautifulsoup4==4.11.1
|
beautifulsoup4==4.11.1
|
||||||
bintrees==2.1.0
|
bintrees==2.1.0
|
||||||
bitmath==1.3.3.1
|
bitmath==1.3.3.1
|
||||||
blinker==1.4
|
blinker==1.6.2
|
||||||
boto3==1.21.42
|
boto3==1.21.42
|
||||||
botocore==1.24.42
|
botocore==1.24.42
|
||||||
cachetools==4.0.0
|
cachetools==4.0.0
|
||||||
@ -19,7 +19,7 @@ certifi==2023.7.22
|
|||||||
cffi==1.14.3
|
cffi==1.14.3
|
||||||
chardet==3.0.4
|
chardet==3.0.4
|
||||||
charset-normalizer==2.0.12
|
charset-normalizer==2.0.12
|
||||||
click==8.0.0
|
click==8.1.3
|
||||||
cryptography==41.0.3
|
cryptography==41.0.3
|
||||||
DateTime==4.3
|
DateTime==4.3
|
||||||
debtcollector==1.22.0
|
debtcollector==1.22.0
|
||||||
@ -28,8 +28,8 @@ Deprecated==1.2.7
|
|||||||
dumb-init==1.2.2
|
dumb-init==1.2.2
|
||||||
elasticsearch==7.6.0
|
elasticsearch==7.6.0
|
||||||
elasticsearch-dsl==7.0.0
|
elasticsearch-dsl==7.0.0
|
||||||
Flask==1.1.1
|
Flask==2.3.2
|
||||||
Flask-Login==0.4.1
|
Flask-Login==0.6.2
|
||||||
Flask-Mail==0.9.1
|
Flask-Mail==0.9.1
|
||||||
Flask-Principal==0.4.0
|
Flask-Principal==0.4.0
|
||||||
Flask-RESTful==0.3.9
|
Flask-RESTful==0.3.9
|
||||||
@ -42,11 +42,11 @@ gunicorn==20.1.0
|
|||||||
hashids==1.2.0
|
hashids==1.2.0
|
||||||
html5lib==1.1
|
html5lib==1.1
|
||||||
idna==3.4
|
idna==3.4
|
||||||
importlib-metadata==1.4.0
|
importlib-metadata==6.7.0
|
||||||
iso8601==0.1.12
|
iso8601==0.1.12
|
||||||
isodate==0.6.1
|
isodate==0.6.1
|
||||||
itsdangerous==1.1.0
|
itsdangerous==2.1.2
|
||||||
Jinja2==2.11.3
|
Jinja2==3.1.2
|
||||||
jmespath==0.9.4
|
jmespath==0.9.4
|
||||||
jsonpath-rw==1.4.0
|
jsonpath-rw==1.4.0
|
||||||
jsonpointer==2.0
|
jsonpointer==2.0
|
||||||
@ -54,7 +54,7 @@ jsonschema==3.2.0
|
|||||||
kafka-python==1.4.7
|
kafka-python==1.4.7
|
||||||
keystoneauth1==3.18.0
|
keystoneauth1==3.18.0
|
||||||
Mako==1.2.2
|
Mako==1.2.2
|
||||||
MarkupSafe==1.1.1
|
MarkupSafe==2.1.3
|
||||||
maxminddb==1.5.2
|
maxminddb==1.5.2
|
||||||
mixpanel==4.5.0
|
mixpanel==4.5.0
|
||||||
msgpack==0.6.2
|
msgpack==0.6.2
|
||||||
@ -124,11 +124,12 @@ text-unidecode==1.3
|
|||||||
tldextract==2.2.2
|
tldextract==2.2.2
|
||||||
toposort==1.5
|
toposort==1.5
|
||||||
tzlocal==2.0.0
|
tzlocal==2.0.0
|
||||||
|
ua-parser==0.18.0
|
||||||
urllib3==1.26.9
|
urllib3==1.26.9
|
||||||
webencodings==0.5.1
|
webencodings==0.5.1
|
||||||
WebOb==1.8.6
|
WebOb==1.8.6
|
||||||
websocket-client==0.57.0
|
websocket-client==0.57.0
|
||||||
Werkzeug==1.0.0
|
Werkzeug==2.3.6
|
||||||
wrapt==1.13.3
|
wrapt==1.13.3
|
||||||
xhtml2pdf==0.2.6
|
xhtml2pdf==0.2.6
|
||||||
zipp==2.1.0
|
zipp==2.1.0
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import datetime
|
||||||
import inspect
|
import inspect
|
||||||
import os
|
import os
|
||||||
import shutil
|
import shutil
|
||||||
@ -6,6 +7,7 @@ from test.testconfig import FakeTransaction
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from flask import Flask, jsonify
|
from flask import Flask, jsonify
|
||||||
|
from flask.testing import FlaskClient
|
||||||
from flask_login import LoginManager
|
from flask_login import LoginManager
|
||||||
from flask_mail import Mail
|
from flask_mail import Mail
|
||||||
from flask_principal import Principal, identity_loaded
|
from flask_principal import Principal, identity_loaded
|
||||||
@ -292,6 +294,29 @@ def initialized_db(appconfig):
|
|||||||
yield
|
yield
|
||||||
|
|
||||||
|
|
||||||
|
class _FlaskLoginClient(FlaskClient):
|
||||||
|
"""
|
||||||
|
A Flask test client that knows how to log in users
|
||||||
|
using the Flask-Login extension.
|
||||||
|
https://github.com/maxcountryman/flask-login/pull/470
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
user = kwargs.pop("user", None)
|
||||||
|
fresh = kwargs.pop("fresh_login", True)
|
||||||
|
|
||||||
|
super(_FlaskLoginClient, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
with self.session_transaction() as sess:
|
||||||
|
if user:
|
||||||
|
sess["_user_id"] = user.uuid
|
||||||
|
sess["user_id"] = user.uuid
|
||||||
|
sess["_fresh"] = fresh
|
||||||
|
sess["login_time"] = datetime.datetime.now()
|
||||||
|
else:
|
||||||
|
sess["_user_id"] = "anonymous"
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture()
|
@pytest.fixture()
|
||||||
def app(appconfig, initialized_db):
|
def app(appconfig, initialized_db):
|
||||||
"""
|
"""
|
||||||
@ -299,6 +324,7 @@ def app(appconfig, initialized_db):
|
|||||||
"""
|
"""
|
||||||
app = Flask(__name__)
|
app = Flask(__name__)
|
||||||
login_manager = LoginManager(app)
|
login_manager = LoginManager(app)
|
||||||
|
login_manager.init_app(app)
|
||||||
|
|
||||||
@app.errorhandler(model.DataModelException)
|
@app.errorhandler(model.DataModelException)
|
||||||
def handle_dme(ex):
|
def handle_dme(ex):
|
||||||
@ -314,6 +340,8 @@ def app(appconfig, initialized_db):
|
|||||||
def on_identity_loaded_for_test(sender, identity):
|
def on_identity_loaded_for_test(sender, identity):
|
||||||
on_identity_loaded(sender, identity)
|
on_identity_loaded(sender, identity)
|
||||||
|
|
||||||
|
app.test_client_class = _FlaskLoginClient
|
||||||
|
|
||||||
Principal(app, use_sessions=False)
|
Principal(app, use_sessions=False)
|
||||||
|
|
||||||
app.url_map.converters["regex"] = RegexConverter
|
app.url_map.converters["regex"] = RegexConverter
|
||||||
|
@ -459,7 +459,7 @@ class TestUserStarredRepositoryList(ApiTestCase):
|
|||||||
self.login(READ_ACCESS_USER)
|
self.login(READ_ACCESS_USER)
|
||||||
|
|
||||||
# Queries: Base + the list query
|
# Queries: Base + the list query
|
||||||
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 1):
|
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT):
|
||||||
self.getJsonResponse(StarredRepositoryList, expected_code=200)
|
self.getJsonResponse(StarredRepositoryList, expected_code=200)
|
||||||
|
|
||||||
def test_star_repo_guest(self):
|
def test_star_repo_guest(self):
|
||||||
@ -476,7 +476,7 @@ class TestUserStarredRepositoryList(ApiTestCase):
|
|||||||
self.login(READ_ACCESS_USER)
|
self.login(READ_ACCESS_USER)
|
||||||
|
|
||||||
# Queries: Base + the list query
|
# Queries: Base + the list query
|
||||||
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 1):
|
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT):
|
||||||
json = self.getJsonResponse(StarredRepositoryList)
|
json = self.getJsonResponse(StarredRepositoryList)
|
||||||
assert json["repositories"] == []
|
assert json["repositories"] == []
|
||||||
|
|
||||||
@ -2188,7 +2188,7 @@ class TestListRepos(ApiTestCase):
|
|||||||
# Queries: Base + the list query + the popularity and last modified queries + full perms load
|
# Queries: Base + the list query + the popularity and last modified queries + full perms load
|
||||||
# TODO: Add quota queries
|
# TODO: Add quota queries
|
||||||
with patch("features.QUOTA_MANAGEMENT", False):
|
with patch("features.QUOTA_MANAGEMENT", False):
|
||||||
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 5):
|
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 4):
|
||||||
json = self.getJsonResponse(
|
json = self.getJsonResponse(
|
||||||
RepositoryList,
|
RepositoryList,
|
||||||
params=dict(
|
params=dict(
|
||||||
@ -2553,11 +2553,11 @@ class TestGetRepository(ApiTestCase):
|
|||||||
self.login(ADMIN_ACCESS_USER)
|
self.login(ADMIN_ACCESS_USER)
|
||||||
|
|
||||||
# base + repo + is_starred + tags
|
# base + repo + is_starred + tags
|
||||||
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 4):
|
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 3):
|
||||||
self.getJsonResponse(Repository, params=dict(repository=ADMIN_ACCESS_USER + "/simple"))
|
self.getJsonResponse(Repository, params=dict(repository=ADMIN_ACCESS_USER + "/simple"))
|
||||||
|
|
||||||
# base + repo + is_starred + tags
|
# base + repo + is_starred + tags
|
||||||
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 4):
|
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 3):
|
||||||
json = self.getJsonResponse(
|
json = self.getJsonResponse(
|
||||||
Repository, params=dict(repository=ADMIN_ACCESS_USER + "/gargantuan")
|
Repository, params=dict(repository=ADMIN_ACCESS_USER + "/gargantuan")
|
||||||
)
|
)
|
||||||
@ -2799,7 +2799,7 @@ class TestRepoBuilds(ApiTestCase):
|
|||||||
self.login(ADMIN_ACCESS_USER)
|
self.login(ADMIN_ACCESS_USER)
|
||||||
|
|
||||||
# Queries: Permission + the list query + app check
|
# Queries: Permission + the list query + app check
|
||||||
with assert_query_count(3):
|
with assert_query_count(2):
|
||||||
json = self.getJsonResponse(
|
json = self.getJsonResponse(
|
||||||
RepositoryBuildList, params=dict(repository=ADMIN_ACCESS_USER + "/simple")
|
RepositoryBuildList, params=dict(repository=ADMIN_ACCESS_USER + "/simple")
|
||||||
)
|
)
|
||||||
@ -2810,7 +2810,7 @@ class TestRepoBuilds(ApiTestCase):
|
|||||||
self.login(ADMIN_ACCESS_USER)
|
self.login(ADMIN_ACCESS_USER)
|
||||||
|
|
||||||
# Queries: Permission + the list query + app check
|
# Queries: Permission + the list query + app check
|
||||||
with assert_query_count(3):
|
with assert_query_count(2):
|
||||||
json = self.getJsonResponse(
|
json = self.getJsonResponse(
|
||||||
RepositoryBuildList, params=dict(repository=ADMIN_ACCESS_USER + "/building")
|
RepositoryBuildList, params=dict(repository=ADMIN_ACCESS_USER + "/building")
|
||||||
)
|
)
|
||||||
@ -3687,11 +3687,11 @@ class TestUserRobots(ApiTestCase):
|
|||||||
self.putJsonResponse(UserRobot, params=dict(robot_shortname="coolbot"), expected_code=201)
|
self.putJsonResponse(UserRobot, params=dict(robot_shortname="coolbot"), expected_code=201)
|
||||||
|
|
||||||
# Queries: Base + the lookup query
|
# Queries: Base + the lookup query
|
||||||
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 1):
|
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT):
|
||||||
self.getJsonResponse(UserRobotList)
|
self.getJsonResponse(UserRobotList)
|
||||||
|
|
||||||
# Queries: Base + the lookup query
|
# Queries: Base + the lookup query
|
||||||
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT + 1):
|
with assert_query_count(BASE_LOGGEDIN_QUERY_COUNT):
|
||||||
self.getJsonResponse(UserRobotList, params=dict(permissions=True))
|
self.getJsonResponse(UserRobotList, params=dict(permissions=True))
|
||||||
|
|
||||||
def test_robots(self):
|
def test_robots(self):
|
||||||
|
@ -231,7 +231,8 @@ class WebhookEndpointTestCase(EndpointTestCase):
|
|||||||
"webhooks.build_trigger_webhook",
|
"webhooks.build_trigger_webhook",
|
||||||
trigger_uuid=trigger.uuid,
|
trigger_uuid=trigger.uuid,
|
||||||
expected_code=400,
|
expected_code=400,
|
||||||
headers={"Authorization": auth_header},
|
headers={"Authorization": auth_header, "Content-Type": "application/json"},
|
||||||
|
data={},
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_valid_build_trigger_webhook_invalid_payload(self):
|
def test_valid_build_trigger_webhook_invalid_payload(self):
|
||||||
@ -663,7 +664,14 @@ class KeyServerTestCase(EndpointTestCase):
|
|||||||
def test_put_service_key(self):
|
def test_put_service_key(self):
|
||||||
# No Authorization header should yield a 400
|
# No Authorization header should yield a 400
|
||||||
self.putResponse(
|
self.putResponse(
|
||||||
"key_server.put_service_key", service="sample_service", kid="kid420", expected_code=400
|
"key_server.put_service_key",
|
||||||
|
service="sample_service",
|
||||||
|
kid="kid420",
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
data={},
|
||||||
|
expected_code=400,
|
||||||
)
|
)
|
||||||
|
|
||||||
# Mint a JWT with our test payload
|
# Mint a JWT with our test payload
|
||||||
|
@ -6,11 +6,7 @@ from xhtml2pdf import pisa
|
|||||||
|
|
||||||
from app import app
|
from app import app
|
||||||
|
|
||||||
jinja_options = {
|
env = Environment(loader=FileSystemLoader("util"))
|
||||||
"loader": FileSystemLoader("util"),
|
|
||||||
}
|
|
||||||
|
|
||||||
env = Environment(**jinja_options)
|
|
||||||
|
|
||||||
|
|
||||||
def renderInvoiceToPdf(invoice, user):
|
def renderInvoiceToPdf(invoice, user):
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
from urllib.parse import urljoin
|
|
||||||
|
|
||||||
from flask import url_for
|
|
||||||
|
|
||||||
|
|
||||||
def get_blob_download_uri_getter(context, url_scheme_and_hostname):
|
|
||||||
"""
|
|
||||||
Returns a function with context to later generate the uri for a download blob.
|
|
||||||
|
|
||||||
:param context: Flask RequestContext
|
|
||||||
:param url_scheme_and_hostname: URLSchemeAndHostname class instance
|
|
||||||
:return: function (repository_and_namespace, checksum) -> uri
|
|
||||||
"""
|
|
||||||
|
|
||||||
def create_uri(repository_and_namespace, checksum):
|
|
||||||
"""
|
|
||||||
Creates a uri for a download blob from a repository, namespace, and checksum from earlier
|
|
||||||
context.
|
|
||||||
"""
|
|
||||||
with context:
|
|
||||||
relative_layer_url = url_for(
|
|
||||||
"v2.download_blob", repository=repository_and_namespace, digest=checksum
|
|
||||||
)
|
|
||||||
return urljoin(url_scheme_and_hostname.get_url(), relative_layer_url)
|
|
||||||
|
|
||||||
return create_uri
|
|
@ -1,28 +0,0 @@
|
|||||||
import pytest
|
|
||||||
|
|
||||||
from app import app
|
|
||||||
from util.config import URLSchemeAndHostname
|
|
||||||
from util.secscan.secscan_util import get_blob_download_uri_getter
|
|
||||||
|
|
||||||
from test.fixtures import *
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"url_scheme_and_hostname, repo_namespace, checksum, expected_value,",
|
|
||||||
[
|
|
||||||
(
|
|
||||||
URLSchemeAndHostname("http", "localhost:5000"),
|
|
||||||
"devtable/simple",
|
|
||||||
"tarsum+sha256:123",
|
|
||||||
"http://localhost:5000/v2/devtable/simple/blobs/tarsum%2Bsha256:123",
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_blob_download_uri_getter(
|
|
||||||
app, url_scheme_and_hostname, repo_namespace, checksum, expected_value
|
|
||||||
):
|
|
||||||
blob_uri_getter = get_blob_download_uri_getter(
|
|
||||||
app.test_request_context("/"), url_scheme_and_hostname
|
|
||||||
)
|
|
||||||
|
|
||||||
assert blob_uri_getter(repo_namespace, checksum) == expected_value
|
|
Reference in New Issue
Block a user