Skip to content
This repository was archived by the owner on Jul 16, 2025. It is now read-only.

Commit 74c67b6

Browse files
feat: support new tokenless protocol (#447)
* feat: add new tokenless support We no longer have to send the X-Tokenless header anymore. Signed-off-by: joseph-sentry <[email protected]> * fix: remove github API call from tokenless we no longer want to make the github API call to check if the current ref we are uploading from is a PR to determine what to set the tokenless header to. It's no longer necessary and all that is needed for tokenless is to pass the correct branch name (containing a ':') to the create commit step so that tokenless works. The CLI will automatically check if the TOKENLESS env var has been set by the action. The action will set this env var when it detects it's running on a fork. Signed-off-by: joseph-sentry <[email protected]> * fix: address feedback * fix: add clarifying comment Signed-off-by: joseph-sentry <[email protected]> * test: fix tests * chore: make lint Signed-off-by: joseph-sentry <[email protected]> * chore: make lint --------- Signed-off-by: joseph-sentry <[email protected]>
1 parent 24d49dd commit 74c67b6

File tree

11 files changed

+44
-210
lines changed

11 files changed

+44
-210
lines changed

codecov_cli/helpers/git.py

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -95,22 +95,3 @@ def parse_git_service(remote_repo_url: str):
9595
extra=dict(remote_repo_url=remote_repo_url),
9696
)
9797
return None
98-
99-
100-
def is_fork_pr(pull_dict: PullDict) -> bool:
101-
"""
102-
takes in dict: pull_dict
103-
returns true if PR is made in a fork context, false if not.
104-
"""
105-
return pull_dict and pull_dict["head"]["slug"] != pull_dict["base"]["slug"]
106-
107-
108-
def get_pull(service, slug, pr_num) -> Optional[PullDict]:
109-
"""
110-
takes in str git service e.g. github, gitlab etc., slug in the owner/repo format, and the pull request number
111-
returns the pull request info gotten from the git service provider if successful, None if not
112-
"""
113-
git_service = get_git_service(service)
114-
if git_service:
115-
pull_dict = git_service.get_pull_request(slug, pr_num)
116-
return pull_dict

codecov_cli/helpers/request.py

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22
from sys import exit
33
from time import sleep
4+
from typing import Optional
45

56
import click
67
import requests
@@ -15,7 +16,7 @@
1516
USER_AGENT = f"codecov-cli/{__version__}"
1617

1718

18-
def _set_user_agent(headers: dict = None) -> dict:
19+
def _set_user_agent(headers: Optional[dict] = None) -> dict:
1920
headers = headers or {}
2021
headers.setdefault("User-Agent", USER_AGENT)
2122
return headers
@@ -37,7 +38,10 @@ def put(url: str, data: dict = None, headers: dict = None) -> requests.Response:
3738

3839

3940
def post(
40-
url: str, data: dict = None, headers: dict = None, params: dict = None
41+
url: str,
42+
data: Optional[dict] = None,
43+
headers: Optional[dict] = None,
44+
params: Optional[dict] = None,
4145
) -> requests.Response:
4246
headers = _set_user_agent(headers)
4347
return requests.post(url, json=data, headers=headers, params=params)
@@ -82,7 +86,10 @@ def wrapper(*args, **kwargs):
8286

8387
@retry_request
8488
def send_post_request(
85-
url: str, data: dict = None, headers: dict = None, params: dict = None
89+
url: str,
90+
data: Optional[dict] = None,
91+
headers: Optional[dict] = None,
92+
params: Optional[dict] = None,
8693
):
8794
return request_result(post(url=url, data=data, headers=headers, params=params))
8895

@@ -95,6 +102,12 @@ def get_token_header_or_fail(token: str) -> dict:
95102
return {"Authorization": f"token {token}"}
96103

97104

105+
def get_token_header(token: str) -> Optional[dict]:
106+
if token is None:
107+
return None
108+
return {"Authorization": f"token {token}"}
109+
110+
98111
@retry_request
99112
def send_put_request(
100113
url: str,

codecov_cli/services/commit/__init__.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import logging
2+
import os
23
import typing
34

45
from codecov_cli.helpers.config import CODECOV_API_URL
56
from codecov_cli.helpers.encoder import decode_slug, encode_slug
6-
from codecov_cli.helpers.git import get_pull, is_fork_pr
77
from codecov_cli.helpers.request import (
88
get_token_header_or_fail,
99
log_warnings_and_errors_if_any,
@@ -43,11 +43,12 @@ def create_commit_logic(
4343
def send_commit_data(
4444
commit_sha, parent_sha, pr, branch, slug, token, service, enterprise_url
4545
):
46-
decoded_slug = decode_slug(slug)
47-
pull_dict = get_pull(service, decoded_slug, pr) if not token else None
48-
if is_fork_pr(pull_dict):
49-
headers = {"X-Tokenless": pull_dict["head"]["slug"], "X-Tokenless-PR": pr}
50-
branch = pull_dict["head"]["slug"] + ":" + branch
46+
# this is how the CLI receives the username of the user to whom the fork belongs
47+
# to and the branch name from the action
48+
tokenless = os.environ.get("TOKENLESS")
49+
if tokenless:
50+
headers = None # type: ignore
51+
branch = tokenless # type: ignore
5152
logger.info("The PR is happening in a forked repo. Using tokenless upload.")
5253
else:
5354
headers = get_token_header_or_fail(token)

codecov_cli/services/report/__init__.py

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from codecov_cli.helpers import request
88
from codecov_cli.helpers.config import CODECOV_API_URL
99
from codecov_cli.helpers.encoder import decode_slug, encode_slug
10-
from codecov_cli.helpers.git import get_pull, is_fork_pr
1110
from codecov_cli.helpers.request import (
1211
get_token_header_or_fail,
1312
log_warnings_and_errors_if_any,
@@ -47,17 +46,7 @@ def send_create_report_request(
4746
commit_sha, code, service, token, encoded_slug, enterprise_url, pull_request_number
4847
):
4948
data = {"code": code}
50-
decoded_slug = decode_slug(encoded_slug)
51-
pull_dict = (
52-
get_pull(service, decoded_slug, pull_request_number) if not token else None
53-
)
54-
if is_fork_pr(pull_dict):
55-
headers = {
56-
"X-Tokenless": pull_dict["head"]["slug"],
57-
"X-Tokenless-PR": pull_request_number,
58-
}
59-
else:
60-
headers = get_token_header_or_fail(token)
49+
headers = get_token_header_or_fail(token)
6150
upload_url = enterprise_url or CODECOV_API_URL
6251
url = f"{upload_url}/upload/{service}/{encoded_slug}/commits/{commit_sha}/reports"
6352
return send_post_request(url=url, headers=headers, data=data)

codecov_cli/services/upload/upload_sender.py

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@
88
from codecov_cli import __version__ as codecov_cli_version
99
from codecov_cli.helpers.config import CODECOV_API_URL
1010
from codecov_cli.helpers.encoder import encode_slug
11-
from codecov_cli.helpers.git import get_pull, is_fork_pr
1211
from codecov_cli.helpers.request import (
13-
get_token_header_or_fail,
12+
get_token_header,
1413
send_post_request,
1514
send_put_request,
1615
)
@@ -53,19 +52,7 @@ def send_upload_data(
5352
"version": codecov_cli_version,
5453
"ci_service": ci_service,
5554
}
56-
57-
# Data to upload to Codecov
58-
pull_dict = (
59-
get_pull(git_service, slug, pull_request_number) if not token else None
60-
)
61-
62-
if is_fork_pr(pull_dict):
63-
headers = {
64-
"X-Tokenless": pull_dict["head"]["slug"],
65-
"X-Tokenless-PR": pull_request_number,
66-
}
67-
else:
68-
headers = get_token_header_or_fail(token)
55+
headers = get_token_header(token)
6956
encoded_slug = encode_slug(slug)
7057
upload_url = enterprise_url or CODECOV_API_URL
7158
url, data = self.get_url_and_possibly_update_data(

codecov_cli/services/upload_completion/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from codecov_cli.helpers.config import CODECOV_API_URL
55
from codecov_cli.helpers.encoder import encode_slug
66
from codecov_cli.helpers.request import (
7-
get_token_header_or_fail,
7+
get_token_header,
88
log_warnings_and_errors_if_any,
99
send_post_request,
1010
)
@@ -16,7 +16,7 @@ def upload_completion_logic(
1616
commit_sha, slug, token, git_service, enterprise_url, fail_on_error=False
1717
):
1818
encoded_slug = encode_slug(slug)
19-
headers = get_token_header_or_fail(token)
19+
headers = get_token_header(token)
2020
upload_url = enterprise_url or CODECOV_API_URL
2121
url = f"{upload_url}/upload/{git_service}/{encoded_slug}/commits/{commit_sha}/upload-complete"
2222
sending_result = send_post_request(url=url, headers=headers)

tests/helpers/test_git.py

Lines changed: 0 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -135,82 +135,3 @@ def test_get_git_service_class():
135135
assert git.get_git_service("bitbucket") == None
136136

137137

138-
def test_pr_is_not_fork_pr(mocker):
139-
def mock_request(*args, headers={}, **kwargs):
140-
assert headers["X-GitHub-Api-Version"] == "2022-11-28"
141-
res = {
142-
"url": "https://api.github.com/repos/codecov/codecov-cli/pulls/1",
143-
"head": {
144-
"sha": "123",
145-
"label": "codecov-cli:branch",
146-
"ref": "branch",
147-
"repo": {"full_name": "codecov/codecov-cli"},
148-
},
149-
"base": {
150-
"sha": "123",
151-
"label": "codecov-cli:main",
152-
"ref": "main",
153-
"repo": {"full_name": "codecov/codecov-cli"},
154-
},
155-
}
156-
response = Response()
157-
response.status_code = 200
158-
response._content = json.dumps(res).encode("utf-8")
159-
return response
160-
161-
mocker.patch.object(
162-
requests,
163-
"get",
164-
side_effect=mock_request,
165-
)
166-
pull_dict = git.get_pull("github", "codecov/codecov-cli", 1)
167-
assert not git.is_fork_pr(pull_dict)
168-
169-
170-
def test_pr_is_fork_pr(mocker):
171-
def mock_request(*args, headers={}, **kwargs):
172-
assert headers["X-GitHub-Api-Version"] == "2022-11-28"
173-
res = {
174-
"url": "https://api.github.com/repos/codecov/codecov-cli/pulls/1",
175-
"head": {
176-
"sha": "123",
177-
"label": "codecov-cli:branch",
178-
"ref": "branch",
179-
"repo": {"full_name": "user_forked_repo/codecov-cli"},
180-
},
181-
"base": {
182-
"sha": "123",
183-
"label": "codecov-cli:main",
184-
"ref": "main",
185-
"repo": {"full_name": "codecov/codecov-cli"},
186-
},
187-
}
188-
response = Response()
189-
response.status_code = 200
190-
response._content = json.dumps(res).encode("utf-8")
191-
return response
192-
193-
mocker.patch.object(
194-
requests,
195-
"get",
196-
side_effect=mock_request,
197-
)
198-
pull_dict = git.get_pull("github", "codecov/codecov-cli", 1)
199-
assert git.is_fork_pr(pull_dict)
200-
201-
202-
def test_pr_not_found(mocker):
203-
def mock_request(*args, headers={}, **kwargs):
204-
assert headers["X-GitHub-Api-Version"] == "2022-11-28"
205-
response = Response()
206-
response.status_code = 404
207-
response._content = b"not-found"
208-
return response
209-
210-
mocker.patch.object(
211-
requests,
212-
"get",
213-
side_effect=mock_request,
214-
)
215-
pull_dict = git.get_pull("github", "codecov/codecov-cli", 1)
216-
assert not git.is_fork_pr(pull_dict)

tests/helpers/test_request.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
from codecov_cli import __version__
88
from codecov_cli.helpers.request import (
99
get,
10+
get_token_header,
1011
get_token_header_or_fail,
1112
log_warnings_and_errors_if_any,
1213
)
@@ -69,6 +70,17 @@ def test_get_token_header_or_fail():
6970
== "Codecov token not found. Please provide Codecov token with -t flag."
7071
)
7172

73+
def test_get_token_header():
74+
# Test with a valid UUID token
75+
token = uuid.uuid4()
76+
result = get_token_header(token)
77+
assert result == {"Authorization": f"token {str(token)}"}
78+
79+
# Test with a None token
80+
token = None
81+
result = get_token_header(token)
82+
assert result is None
83+
7284

7385
def test_request_retry(mocker, valid_response):
7486
expected_response = request_result(valid_response)

tests/helpers/test_upload_sender.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -231,14 +231,8 @@ def test_upload_sender_post_called_with_right_parameters_tokenless(
231231
mocked_storage_server,
232232
mocker,
233233
):
234-
headers = {"X-Tokenless": "user-forked/repo", "X-Tokenless-PR": "pr"}
235-
mock_get_pull = mocker.patch(
236-
"codecov_cli.services.upload.upload_sender.get_pull",
237-
return_value={
238-
"head": {"slug": "user-forked/repo"},
239-
"base": {"slug": "org/repo"},
240-
},
241-
)
234+
headers = {}
235+
242236
mocked_legacy_upload_endpoint.match = [
243237
matchers.json_params_matcher(request_data),
244238
matchers.header_matcher(headers),
@@ -263,7 +257,6 @@ def test_upload_sender_post_called_with_right_parameters_tokenless(
263257
assert (
264258
post_req_made.headers.items() >= headers.items()
265259
) # test dict is a subset of the other
266-
mock_get_pull.assert_called()
267260

268261
def test_upload_sender_put_called_with_right_parameters(
269262
self, mocked_responses, mocked_legacy_upload_endpoint, mocked_storage_server

tests/services/commit/test_commit_service.py

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -150,33 +150,7 @@ def test_commit_sender_with_forked_repo(mocker):
150150
return_value=mocker.MagicMock(status_code=200, text="success"),
151151
)
152152

153-
def mock_request(*args, headers={}, **kwargs):
154-
assert headers["X-GitHub-Api-Version"] == "2022-11-28"
155-
res = {
156-
"url": "https://api.github.com/repos/codecov/codecov-cli/pulls/1",
157-
"head": {
158-
"sha": "123",
159-
"label": "codecov-cli:branch",
160-
"ref": "branch",
161-
"repo": {"full_name": "user_forked_repo/codecov-cli"},
162-
},
163-
"base": {
164-
"sha": "123",
165-
"label": "codecov-cli:main",
166-
"ref": "main",
167-
"repo": {"full_name": "codecov/codecov-cli"},
168-
},
169-
}
170-
response = Response()
171-
response.status_code = 200
172-
response._content = json.dumps(res).encode("utf-8")
173-
return response
174-
175-
mocker.patch.object(
176-
requests,
177-
"get",
178-
side_effect=mock_request,
179-
)
153+
mocker.patch("os.environ", dict(TOKENLESS="user_forked_repo/codecov-cli:branch"))
180154
res = send_commit_data(
181155
"commit_sha",
182156
"parent_sha",
@@ -195,5 +169,5 @@ def mock_request(*args, headers={}, **kwargs):
195169
"pullid": "1",
196170
"branch": "user_forked_repo/codecov-cli:branch",
197171
},
198-
headers={"X-Tokenless": "user_forked_repo/codecov-cli", "X-Tokenless-PR": "1"},
172+
headers=None,
199173
)

0 commit comments

Comments
 (0)