Skip to content

Commit

Permalink
remove the pinned starlette version (#270)
Browse files Browse the repository at this point in the history
* remove the pinned starlette version

It removes the pinned starlette dependency version

This pinned version was applied as a workaround for issue #183

The startelle version is updated to the latest version, which fixes a
security issue GHSA-74m5-2c7w-9w3x

The solution requires to install the new `httpx` development
dependency to support the unit tests using the FastAPI TestClient as
described in this link: https://fastapi.tiangolo.com/tutorial/testing/

A workaround needs to be applied to the tests which uses `DELETE`
method.

Signed-off-by: Kairo de Araujo <kdearaujo@vmware.com>

* update using `make requirements`

Signed-off-by: Kairo de Araujo <kdearaujo@vmware.com>

---------

Signed-off-by: Kairo de Araujo <kdearaujo@vmware.com>
  • Loading branch information
kairoaraujo committed Feb 27, 2023
1 parent 0fbb6f7 commit 3484a58
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 32 deletions.
2 changes: 1 addition & 1 deletion Pipfile
Expand Up @@ -14,7 +14,6 @@ python-jose = "*"
sqlalchemy = "*"
redis = "*"
bcrypt = "*"
starlette = "==0.20.4"

[dev-packages]
black = "*"
Expand All @@ -40,6 +39,7 @@ mistune = "==0.8.4"
myst-parser = "*"
pre-commit = "*"
bandit = "*"
httpx = "*"

[requires]
python_version = "3.10"
66 changes: 58 additions & 8 deletions Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 8 additions & 5 deletions requirements-dev.txt
@@ -1,5 +1,6 @@
-i https://pypi.org/simple
alabaster==0.7.13 ; python_version >= '3.6'
anyio==3.6.2 ; python_full_version >= '3.6.2'
attrs==22.2.0 ; python_version >= '3.6'
babel==2.11.0 ; python_version >= '3.6'
bandit==1.7.4
Expand All @@ -21,6 +22,9 @@ filelock==3.9.0 ; python_version >= '3.7'
flake8==6.0.0
gitdb==4.0.10 ; python_version >= '3.7'
gitpython==3.1.31 ; python_version >= '3.7'
h11==0.14.0 ; python_version >= '3.7'
httpcore==0.16.3 ; python_version >= '3.7'
httpx==0.23.3
identify==2.5.18 ; python_version >= '3.7'
idna==3.4 ; python_version >= '3.5'
imagesize==1.4.1 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
Expand Down Expand Up @@ -55,9 +59,11 @@ pytest==7.2.1
pytz==2022.7.1
pyyaml==6.0 ; python_version >= '3.6'
requests==2.28.2 ; python_version >= '3.7' and python_version < '4'
rfc3986[idna2008]==1.5.0
setuptools==67.4.0 ; python_version >= '3.7'
six==1.16.0 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
smmap==5.0.0 ; python_version >= '3.6'
sniffio==1.3.0 ; python_version >= '3.7'
snowballstemmer==2.2.0
sphinx==5.3.0
sphinx-rtd-theme==1.2.0
Expand All @@ -79,7 +85,6 @@ urllib3==1.26.14 ; python_version >= '2.7' and python_version not in '3.0, 3.1,
virtualenv==20.19.0 ; python_version >= '3.7'
voluptuous==0.13.1
amqp==5.1.1 ; python_version >= '3.6'
anyio==3.6.2 ; python_full_version >= '3.6.2'
async-timeout==4.0.2 ; python_version >= '3.6'
bcrypt==4.0.1
billiard==3.6.4.0
Expand All @@ -90,9 +95,8 @@ click-repl==0.2.0
configobj==5.0.8
dynaconf==3.1.11
ecdsa==0.18.0 ; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'
fastapi==0.86.0
fastapi==0.92.0
greenlet==2.0.2 ; platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32')))))
h11==0.14.0 ; python_version >= '3.7'
kombu==5.2.4 ; python_version >= '3.7'
prompt-toolkit==3.0.37 ; python_full_version >= '3.7.0'
pyasn1==0.4.8
Expand All @@ -101,9 +105,8 @@ python-jose==3.3.0
python-multipart==0.0.5
redis==4.5.1
rsa==4.9 ; python_version >= '3.6' and python_version < '4'
sniffio==1.3.0 ; python_version >= '3.7'
sqlalchemy==2.0.4
starlette==0.20.4
starlette==0.25.0 ; python_version >= '3.7'
uvicorn==0.20.0
vine==5.0.0 ; python_version >= '3.6'
wcwidth==0.2.6
4 changes: 2 additions & 2 deletions requirements.txt
Expand Up @@ -12,7 +12,7 @@ click-repl==0.2.0
configobj==5.0.8
dynaconf==3.1.11
ecdsa==0.18.0 ; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'
fastapi==0.86.0
fastapi==0.92.0
greenlet==2.0.2 ; platform_machine == 'aarch64' or (platform_machine == 'ppc64le' or (platform_machine == 'x86_64' or (platform_machine == 'amd64' or (platform_machine == 'AMD64' or (platform_machine == 'win32' or platform_machine == 'WIN32')))))
h11==0.14.0 ; python_version >= '3.7'
idna==3.4 ; python_version >= '3.5'
Expand All @@ -28,7 +28,7 @@ rsa==4.9 ; python_version >= '3.6' and python_version < '4'
six==1.16.0 ; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
sniffio==1.3.0 ; python_version >= '3.7'
sqlalchemy==2.0.4
starlette==0.20.4
starlette==0.25.0 ; python_version >= '3.7'
typing-extensions==4.5.0 ; python_version >= '3.7'
uvicorn==0.20.0
vine==5.0.0 ; python_version >= '3.6'
Expand Down
13 changes: 5 additions & 8 deletions tests/unit/api/test_bootstrap.py
Expand Up @@ -12,7 +12,6 @@ class TestGetBoostrap:
def test_get_boostrap_available(
self, test_client, token_headers, monkeypatch
):

url = "/api/v1/bootstrap/"
mocked_check_metadata = pretend.call_recorder(lambda: False)
monkeypatch.setattr(
Expand All @@ -22,7 +21,7 @@ def test_get_boostrap_available(

response = test_client.get(url, headers=token_headers)
assert response.status_code == status.HTTP_200_OK
assert response.url == test_client.base_url + url
assert response.url == f"{test_client.base_url}{url}"
assert response.json() == {
"data": {"bootstrap": False},
"message": "System available for bootstrap.",
Expand All @@ -32,7 +31,6 @@ def test_get_boostrap_available(
def test_get_boostrap_not_available(
self, test_client, monkeypatch, token_headers
):

url = "/api/v1/bootstrap/"

mocked_check_metadata = pretend.call_recorder(lambda: True)
Expand All @@ -43,15 +41,14 @@ def test_get_boostrap_not_available(

response = test_client.get(url, headers=token_headers)
assert response.status_code == status.HTTP_200_OK
assert response.url == test_client.base_url + url
assert response.url == f"{test_client.base_url}{url}"
assert response.json() == {
"data": {"bootstrap": True},
"message": "System LOCKED for bootstrap.",
}
assert mocked_check_metadata.calls == [pretend.call()]

def test_get_boostrap_invalid_token(self, test_client, monkeypatch):

url = "/api/v1/bootstrap/"
mocked_check_metadata = pretend.call_recorder(lambda: False)
monkeypatch.setattr(
Expand Down Expand Up @@ -129,7 +126,7 @@ def test_post_bootstrap(self, test_client, monkeypatch, token_headers):
response = test_client.post(url, json=payload, headers=token_headers)

assert response.status_code == status.HTTP_202_ACCEPTED
assert response.url == test_client.base_url + url
assert response.url == f"{test_client.base_url}{url}"
assert response.json() == {
"message": "Bootstrap accepted.",
"data": {"task_id": "123"},
Expand All @@ -153,7 +150,7 @@ def test_post_bootstrap_already_bootstrap(
response = test_client.post(url, json=payload, headers=token_headers)

assert response.status_code == status.HTTP_200_OK
assert response.url == test_client.base_url + url
assert response.url == f"{test_client.base_url}{url}"
assert response.json() == {
"detail": {"error": "System already has a Metadata."}
}
Expand All @@ -164,7 +161,7 @@ def test_post_bootstrap_empty_payload(self, test_client, token_headers):
response = test_client.post(url, json={}, headers=token_headers)

assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY
assert response.url == test_client.base_url + url
assert response.url == f"{test_client.base_url}{url}"
assert response.json() == {
"detail": [
{
Expand Down
36 changes: 30 additions & 6 deletions tests/unit/api/test_targets.py
Expand Up @@ -303,7 +303,11 @@ def test_delete(self, monkeypatch, test_client, token_headers):
"repository_service_tuf_api.targets.datetime", fake_datetime
)

response = test_client.delete(url, json=payload, headers=token_headers)
# https://github.com/tiangolo/fastapi/issues/5649
response = test_client.request(
"DELETE", url, json=payload, headers=token_headers
)

assert response.status_code == status.HTTP_202_ACCEPTED
assert response.json() == {
"data": {
Expand Down Expand Up @@ -359,7 +363,11 @@ def test_delete_publish_targets_false(
"repository_service_tuf_api.targets.datetime", fake_datetime
)

response = test_client.delete(url, json=payload, headers=token_headers)
# https://github.com/tiangolo/fastapi/issues/5649
response = test_client.request(
"DELETE", url, json=payload, headers=token_headers
)

assert response.status_code == status.HTTP_202_ACCEPTED
msg = (
"Remove Target(s) successfully submitted. "
Expand Down Expand Up @@ -397,7 +405,11 @@ def test_delete_without_bootstrap(
"repository_service_tuf_api.targets.is_bootstrap_done",
lambda: False,
)
response = test_client.delete(url, json=payload, headers=token_headers)
# https://github.com/tiangolo/fastapi/issues/5649
response = test_client.request(
"DELETE", url, json=payload, headers=token_headers
)

assert response.status_code == status.HTTP_200_OK
assert response.json() == {
"detail": {"error": "System has not a Repository Metadata"}
Expand All @@ -408,7 +420,11 @@ def test_delete_missing_required_field(self, test_client, token_headers):

payload = {"paths": ["file-v1.0.0_i683.tar.gz", "v0.4.1/file.tar.gz"]}

response = test_client.delete(url, json=payload, headers=token_headers)
# https://github.com/tiangolo/fastapi/issues/5649
response = test_client.request(
"DELETE", url, json=payload, headers=token_headers
)

assert response.status_code == status.HTTP_422_UNPROCESSABLE_ENTITY

def test_delete_unauthorized_invalid_token(self, test_client):
Expand All @@ -421,7 +437,11 @@ def test_delete_unauthorized_invalid_token(self, test_client):
"targets": ["file-v1.0.0_i683.tar.gz", "v0.4.1/file.tar.gz"]
}

response = test_client.delete(url, json=payload, headers=headers)
# https://github.com/tiangolo/fastapi/issues/5649
response = test_client.request(
"DELETE", url, json=payload, headers=headers
)

assert response.status_code == status.HTTP_401_UNAUTHORIZED
assert response.json() == {
"detail": {"error": "Failed to validate token"}
Expand All @@ -444,7 +464,11 @@ def test_post_forbidden_user_incorrect_scope_token(self, test_client):
"targets": ["file-v1.0.0_i683.tar.gz", "v0.4.1/file.tar.gz"]
}

response = test_client.delete(url, json=payload, headers=headers)
# https://github.com/tiangolo/fastapi/issues/5649
response = test_client.request(
"DELETE", url, json=payload, headers=headers
)

assert response.status_code == status.HTTP_403_FORBIDDEN
assert response.json() == {
"detail": {"error": "scope 'delete:targets' not allowed"}
Expand Down
4 changes: 2 additions & 2 deletions tests/unit/test_app.py
Expand Up @@ -8,14 +8,14 @@
def test_root(test_client):
response = test_client.get("/")

assert response.url == test_client.base_url + "/"
assert response.url == f"{test_client.base_url}/"
assert response.status_code == status.HTTP_200_OK
assert "Repository Service for TUF API" in response.text


def test_default_notfound(test_client):
response = test_client.get("/invalid_url")

assert response.url == test_client.base_url + "/invalid_url"
assert response.url == f"{test_client.base_url}/invalid_url"
assert response.status_code == status.HTTP_404_NOT_FOUND
assert response.json() == {"detail": "Not Found"}

0 comments on commit 3484a58

Please sign in to comment.