Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove token enforcement for true tokenless endpoints #533

Merged
merged 13 commits into from
Nov 7, 2024
6 changes: 3 additions & 3 deletions codecov_cli/commands/process_test_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,9 +103,9 @@ def process_test_results(
dir, exclude_folders, files, disable_search, report_type="test_results"
)

upload_collection_results: List[
UploadCollectionResultFile
] = file_finder.find_files()
upload_collection_results: List[UploadCollectionResultFile] = (
file_finder.find_files()
)
if len(upload_collection_results) == 0:
raise click.ClickException(
"No JUnit XML files were found. Make sure to specify them using the --file option."
Expand Down
10 changes: 8 additions & 2 deletions codecov_cli/helpers/request.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,15 +102,21 @@ def send_get_request(
return request_result(get(url=url, headers=headers, params=params))


def get_token_header_or_fail(token: str) -> dict:
def get_token_header_or_fail(token: Optional[str]) -> dict:
"""
Rejects requests with no Authorization token. Prevents tokenless uploads.
"""
if token is None:
raise click.ClickException(
"Codecov token not found. Please provide Codecov token with -t flag."
)
return {"Authorization": f"token {token}"}


def get_token_header(token: str) -> Optional[dict]:
def get_token_header(token: Optional[str]) -> Optional[dict]:
"""
Allows requests with no Authorization token.
"""
if token is None:
return None
return {"Authorization": f"token {token}"}
Expand Down
8 changes: 4 additions & 4 deletions codecov_cli/services/commit/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import typing

from codecov_cli.helpers.config import CODECOV_INGEST_URL
from codecov_cli.helpers.encoder import decode_slug, encode_slug
from codecov_cli.helpers.encoder import encode_slug
from codecov_cli.helpers.request import (
get_token_header_or_fail,
get_token_header,
log_warnings_and_errors_if_any,
send_post_request,
)
Expand All @@ -19,7 +19,7 @@ def create_commit_logic(
pr: typing.Optional[str],
branch: typing.Optional[str],
slug: typing.Optional[str],
token: str,
token: typing.Optional[str],
service: typing.Optional[str],
enterprise_url: typing.Optional[str] = None,
fail_on_error: bool = False,
Expand Down Expand Up @@ -61,7 +61,7 @@ def send_commit_data(
branch = tokenless # type: ignore
logger.info("The PR is happening in a forked repo. Using tokenless upload.")
else:
headers = get_token_header_or_fail(token)
headers = get_token_header(token)

data = {
"branch": branch,
Expand Down
4 changes: 2 additions & 2 deletions codecov_cli/services/commit/base_picking.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from codecov_cli.helpers.config import CODECOV_API_URL
from codecov_cli.helpers.request import (
get_token_header_or_fail,
get_token_header,
log_warnings_and_errors_if_any,
send_put_request,
)
Expand All @@ -15,7 +15,7 @@ def base_picking_logic(base_sha, pr, slug, token, service, enterprise_url, args)
"cli_args": args,
"user_provided_base_sha": base_sha,
}
headers = get_token_header_or_fail(token)
headers = get_token_header(token)
upload_url = enterprise_url or CODECOV_API_URL
url = f"{upload_url}/api/v1/{service}/{slug}/pulls/{pr}"
sending_result = send_put_request(url=url, data=data, headers=headers)
Expand Down
4 changes: 2 additions & 2 deletions codecov_cli/services/empty_upload/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from codecov_cli.helpers.config import CODECOV_API_URL
from codecov_cli.helpers.encoder import encode_slug
from codecov_cli.helpers.request import (
get_token_header_or_fail,
get_token_header,
log_warnings_and_errors_if_any,
send_post_request,
)
Expand All @@ -23,7 +23,7 @@ def empty_upload_logic(
args,
):
encoded_slug = encode_slug(slug)
headers = get_token_header_or_fail(token)
headers = get_token_header(token)
upload_url = enterprise_url or CODECOV_API_URL
url = f"{upload_url}/upload/{git_service}/{encoded_slug}/commits/{commit_sha}/empty-upload"
sending_result = send_post_request(
Expand Down
14 changes: 6 additions & 8 deletions codecov_cli/services/report/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import json
import logging
import time

import requests
import typing

from codecov_cli.helpers import request
from codecov_cli.helpers.config import CODECOV_API_URL, CODECOV_INGEST_URL
from codecov_cli.helpers.encoder import decode_slug, encode_slug
from codecov_cli.helpers.encoder import encode_slug
from codecov_cli.helpers.request import (
get_token_header,
get_token_header_or_fail,
log_warnings_and_errors_if_any,
request_result,
send_post_request,
Expand All @@ -24,7 +22,7 @@ def create_report_logic(
code: str,
slug: str,
service: str,
token: str,
token: typing.Optional[str],
enterprise_url: str,
pull_request_number: int,
fail_on_error: bool = False,
Expand Down Expand Up @@ -70,7 +68,7 @@ def create_report_results_logic(
code: str,
slug: str,
service: str,
token: str,
token: typing.Optional[str],
enterprise_url: str,
fail_on_error: bool = False,
args: dict = None,
Expand Down Expand Up @@ -103,7 +101,7 @@ def send_reports_result_request(
data = {
"cli_args": args,
}
headers = get_token_header_or_fail(token)
headers = get_token_header(token)
upload_url = enterprise_url or CODECOV_API_URL
url = f"{upload_url}/upload/{service}/{encoded_slug}/commits/{commit_sha}/reports/{report_code}/results"
return send_post_request(url=url, data=data, headers=headers)
Expand All @@ -118,7 +116,7 @@ def send_reports_result_get_request(
enterprise_url,
fail_on_error=False,
):
headers = get_token_header_or_fail(token)
headers = get_token_header(token)
nora-codecov marked this conversation as resolved.
Show resolved Hide resolved
upload_url = enterprise_url or CODECOV_API_URL
url = f"{upload_url}/upload/{service}/{encoded_slug}/commits/{commit_sha}/reports/{report_code}/results"
number_tries = 0
Expand Down
2 changes: 1 addition & 1 deletion codecov_cli/services/upload/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ def do_upload_logic(
report_code: str,
slug: typing.Optional[str],
swift_project: typing.Optional[str],
token: str,
token: typing.Optional[str],
upload_file_type: str = "coverage",
use_legacy_uploader: bool = False,
):
Expand Down
2 changes: 1 addition & 1 deletion codecov_cli/services/upload/upload_sender.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def send_upload_data(
self,
upload_data: UploadCollectionResult,
commit_sha: str,
token: str,
token: typing.Optional[str],
env_vars: typing.Dict[str, str],
report_code: str,
upload_file_type: str = "coverage",
Expand Down
24 changes: 24 additions & 0 deletions tests/services/commit/test_base_picking.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,27 @@ def test_base_picking_command_error(mocker):
"error",
"Base picking failed: Unauthorized",
) in parse_outstreams_into_log_lines(result.output)


def test_base_picking_no_token(mocker):
mocked_response = mocker.patch(
"codecov_cli.services.commit.base_picking.send_put_request",
return_value=RequestResult(status_code=200, error=None, warnings=[], text=""),
)
runner = CliRunner()
result = runner.invoke(
pr_base_picking,
[
"--pr",
"11",
"--base-sha",
"9a6902ee94c18e8e27561ce316b16d75a02c7bc1",
"--service",
"github",
"--slug",
"owner/repo",
],
obj=mocker.MagicMock(), # context object
)
assert result.exit_code == 0
mocked_response.assert_called_once()
30 changes: 30 additions & 0 deletions tests/services/commit/test_commit_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,33 @@ def test_commit_sender_with_forked_repo(mocker):
},
headers=None,
)


def test_commit_without_token(mocker):
mocked_response = mocker.patch(
"codecov_cli.services.commit.send_post_request",
return_value=mocker.MagicMock(status_code=200, text="success"),
)

send_commit_data(
"commit_sha",
"parent_sha",
"1",
"branch",
"codecov::::codecov-cli",
None,
"github",
None,
None,
)
mocked_response.assert_called_with(
url="https://ingest.codecov.io/upload/github/codecov::::codecov-cli/commits",
data={
"branch": "branch",
"cli_args": None,
"commitid": "commit_sha",
"parent_commit_id": "parent_sha",
"pullid": "1",
},
headers=None,
)
30 changes: 30 additions & 0 deletions tests/services/empty_upload/test_empty_upload.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import json
import uuid

import click
import pytest
from click.testing import CliRunner

from codecov_cli.services.empty_upload import empty_upload_logic
Expand Down Expand Up @@ -147,3 +149,31 @@ def test_empty_upload_force(mocker):
assert res.error is None
assert res.warnings == []
mocked_response.assert_called_once()


def test_empty_upload_no_token(mocker):
res = {
"result": "All changed files are ignored. Triggering passing notifications.",
"non_ignored_files": [],
}
mocked_response = mocker.patch(
"codecov_cli.helpers.request.requests.post",
return_value=RequestResult(
status_code=200, error=None, warnings=[], text=json.dumps(res)
),
)
runner = CliRunner()
with runner.isolation() as outstreams:
res = empty_upload_logic(
"commit_sha", "owner/repo", None, "service", None, False, False, None
)

out_bytes = parse_outstreams_into_log_lines(outstreams[0].getvalue())
assert out_bytes == [
("info", "Process Empty Upload complete"),
("info", "All changed files are ignored. Triggering passing notifications."),
("info", "Non ignored files []"),
]
assert res.error is None
assert res.warnings == []
mocked_response.assert_called_once()
39 changes: 34 additions & 5 deletions tests/services/report/test_report_results.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,19 @@ def test_report_results_request_200(mocker):
mocked_response.assert_called_once()


def test_report_results_request_no_token(mocker):
mocked_response = mocker.patch(
"codecov_cli.helpers.request.requests.post",
return_value=mocker.MagicMock(status_code=200),
)
res = send_reports_result_request(
"commit_sha", "report_code", "encoded_slug", "service", None, None, None
)
assert res.error is None
assert res.warnings == []
mocked_response.assert_called_once()


def test_report_results_403(mocker):
mocked_response = mocker.patch(
"codecov_cli.helpers.request.requests.post",
Expand All @@ -127,7 +140,7 @@ def test_report_results_403(mocker):

def test_get_report_results_200_completed(mocker, capsys):
mocked_response = mocker.patch(
"codecov_cli.services.report.requests.get",
"codecov_cli.helpers.request.requests.get",
return_value=mocker.MagicMock(
status_code=200,
text='{"state": "completed", "result": {"state": "failure","message": "33.33% of diff hit (target 77.77%)"}}',
Expand All @@ -147,11 +160,27 @@ def test_get_report_results_200_completed(mocker, capsys):
) in output


def test_get_report_results_no_token(mocker, capsys):
mocked_response = mocker.patch(
"codecov_cli.helpers.request.requests.get",
return_value=mocker.MagicMock(
status_code=200,
text='{"state": "completed", "result": {"state": "failure","message": "33.33% of diff hit (target 77.77%)"}}',
),
)
res = send_reports_result_get_request(
"commit_sha", "report_code", "encoded_slug", "service", None, None
)
assert res.error is None
assert res.warnings == []
mocked_response.assert_called_once()


@patch("codecov_cli.services.report.MAX_NUMBER_TRIES", 1)
def test_get_report_results_200_pending(mocker, capsys):
mocker.patch("codecov_cli.services.report.time.sleep")
mocked_response = mocker.patch(
"codecov_cli.services.report.requests.get",
"codecov_cli.helpers.request.requests.get",
return_value=mocker.MagicMock(
status_code=200, text='{"state": "pending", "result": {}}'
),
Expand All @@ -169,7 +198,7 @@ def test_get_report_results_200_pending(mocker, capsys):

def test_get_report_results_200_error(mocker, capsys):
mocked_response = mocker.patch(
"codecov_cli.services.report.requests.get",
"codecov_cli.helpers.request.requests.get",
return_value=mocker.MagicMock(
status_code=200, text='{"state": "error", "result": {}}'
),
Expand All @@ -190,7 +219,7 @@ def test_get_report_results_200_error(mocker, capsys):

def test_get_report_results_200_undefined_state(mocker, capsys):
mocked_response = mocker.patch(
"codecov_cli.services.report.requests.get",
"codecov_cli.helpers.request.requests.get",
return_value=mocker.MagicMock(
status_code=200, text='{"state": "undefined_state", "result": {}}'
),
Expand All @@ -208,7 +237,7 @@ def test_get_report_results_200_undefined_state(mocker, capsys):

def test_get_report_results_401(mocker, capsys):
mocked_response = mocker.patch(
"codecov_cli.services.report.requests.get",
"codecov_cli.helpers.request.requests.get",
return_value=mocker.MagicMock(
status_code=401, text='{"detail": "Invalid token."}'
),
Expand Down
Loading
Loading