Skip to content

Commit

Permalink
#31 Clean up naming
Browse files Browse the repository at this point in the history
  • Loading branch information
mcsken committed Nov 27, 2024
1 parent da69bc7 commit 344f2de
Show file tree
Hide file tree
Showing 9 changed files with 42 additions and 50 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,8 @@ For an organization project:
```yaml
project_url: "https://github.com/orgs/my_username/projects/1/views/1"
check_done_github_app_id: "1234567"
check_done_github_app_private_key: "-----BEGIN RSA PRIVATE KEY-----
github_app_id: "1234567"
github_app_private_key: "-----BEGIN RSA PRIVATE KEY-----
something_something
-----END RSA PRIVATE KEY-----
"
Expand Down
14 changes: 7 additions & 7 deletions check_done/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ class ConfigurationInfo:
personal_access_token: str | None = None

# Required for organization owned project
check_done_github_app_id: str | None = None
check_done_github_app_private_key: str | None = None
github_app_id: str | None = None
github_app_private_key: str | None = None

# Optional
project_status_name_to_check: str | None = None
Expand All @@ -51,8 +51,8 @@ class ConfigurationInfo:
"project_url",
"project_status_name_to_check",
"personal_access_token",
"check_done_github_app_id",
"check_done_github_app_private_key",
"github_app_id",
"github_app_private_key",
mode="before",
)
def value_from_env(cls, value: Any | None):
Expand All @@ -76,8 +76,8 @@ def validate_authentication_and_set_project_details(self):
self.personal_access_token is not None and not self.is_project_owner_of_type_organization
)
has_organizational_authentication = (
self.check_done_github_app_id is not None
and self.check_done_github_app_private_key is not None
self.github_app_id is not None
and self.github_app_private_key is not None
and self.is_project_owner_of_type_organization
)
if not has_user_authentication ^ has_organizational_authentication:
Expand Down Expand Up @@ -138,7 +138,7 @@ def default_config_path() -> Path:
previous_config_folder = None
result = None
while result is None and config_folder != previous_config_folder:
# TODO#32 Check yaml and yml.
# TODO#32 Check yaml and yml, if both exist yaml is picked over yml.
config_path_to_check = (config_folder / CONFIG_BASE_NAME).with_suffix(".yaml")
if config_path_to_check.is_file():
result = config_path_to_check
Expand Down
8 changes: 3 additions & 5 deletions check_done/done_project_items_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ def done_project_items_info(configuration_info: ConfigurationInfo) -> list[Proje

is_project_owner_of_type_organization = configuration_info.is_project_owner_of_type_organization
if is_project_owner_of_type_organization:
check_done_github_app_id = configuration_info.check_done_github_app_id
check_done_github_app_private_key = configuration_info.check_done_github_app_private_key
access_token = resolve_organization_access_token(
project_owner_name, check_done_github_app_id, check_done_github_app_private_key
)
github_app_id = configuration_info.github_app_id
github_app_private_key = configuration_info.github_app_private_key
access_token = resolve_organization_access_token(project_owner_name, github_app_id, github_app_private_key)
else:
access_token = configuration_info.personal_access_token

Expand Down
24 changes: 9 additions & 15 deletions check_done/organization_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,44 +17,38 @@ class AuthenticationError(Exception):
"""Error raised due to failed JWT authentication process."""


def resolve_organization_access_token(
organization_name: str, check_done_github_app_id: str, check_done_github_app_private_key: str
) -> str:
def resolve_organization_access_token(organization_name: str, github_app_id: str, github_app_private_key: str) -> str:
"""
Generates the necessary access token for an organization from the installed GitHub app instance in said organization
"""
jwt_token = generate_jwt_token(check_done_github_app_id, check_done_github_app_private_key)
jwt_token = generate_jwt_token(github_app_id, github_app_private_key)
session = requests.Session()
session.headers = {"Accept": "application/vnd.github+json"}
session.auth = HttpBearerAuth(jwt_token)
try:
check_done_github_app_installation_id = resolve_check_done_github_app_installation_id(
session, organization_name
)
result = resolve_access_token_from_check_done_github_app_installation_id(
session, check_done_github_app_installation_id
)
github_app_installation_id = resolve_github_app_installation_id(session, organization_name)
result = resolve_access_token_from_github_app_installation_id(session, github_app_installation_id)
except Exception as error:
raise AuthenticationError(
f"Cannot resolve organization access token from JWT authentication process: {error}"
) from error
return result


def generate_jwt_token(check_done_github_app_id: str, check_done_github_app_private_key: str) -> str:
def generate_jwt_token(github_app_id: str, github_app_private_key: str) -> str:
"""Generates a JWT token for authentication with GitHub."""
try:
payload = {
"exp": _EXPIRES_AT,
"iat": _ISSUED_AT,
"iss": check_done_github_app_id,
"iss": github_app_id,
}
return jwt.encode(payload, check_done_github_app_private_key, algorithm="RS256")
return jwt.encode(payload, github_app_private_key, algorithm="RS256")
except Exception as error:
raise AuthenticationError(f"Cannot generate JWT token: {error}") from error


def resolve_check_done_github_app_installation_id(session: Session, organization_name: str) -> str:
def resolve_github_app_installation_id(session: Session, organization_name: str) -> str:
"""Fetches the installation ID for the organization."""
response = session.get(f"https://api.github.com/orgs/{organization_name}/installation")

Expand All @@ -65,7 +59,7 @@ def resolve_check_done_github_app_installation_id(session: Session, organization
)


def resolve_access_token_from_check_done_github_app_installation_id(session: Session, installation_id: str) -> str:
def resolve_access_token_from_github_app_installation_id(session: Session, installation_id: str) -> str:
"""Retrieves the access token using the installation ID."""
response = session.post(f"https://api.github.com/app/installations/{installation_id}/access_tokens")
if response.status_code == 201 and response.json().get("token") is not None:
Expand Down
4 changes: 2 additions & 2 deletions tests/data/test_configuration.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
project_url: ${CHECK_DONE_GITHUB_PROJECT_URL}
project_status_name_to_check: ${CHECK_DONE_GITHUB_PROJECT_STATUS_NAME_TO_CHECK}
personal_access_token: ${CHECK_DONE_PERSONAL_ACCESS_TOKEN}
check_done_github_app_id: ${CHECK_DONE_GITHUB_APP_ID}
check_done_github_app_private_key: ${CHECK_DONE_GITHUB_APP_PRIVATE_KEY}
github_app_id: ${CHECK_DONE_GITHUB_APP_ID}
github_app_private_key: ${CHECK_DONE_GITHUB_APP_PRIVATE_KEY}
4 changes: 2 additions & 2 deletions tests/test_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ def test_can_set_config_argument():
config_path = (current_folder / CONFIG_BASE_NAME).with_suffix(".yaml")
config_path.write_text(
"project_url: ${CHECK_DONE_GITHUB_PROJECT_URL}\n"
"check_done_github_app_id: ${CHECK_DONE_GITHUB_APP_ID}\n"
"check_done_github_app_private_key: ${CHECK_DONE_GITHUB_APP_PRIVATE_KEY}\n"
"github_app_id: ${CHECK_DONE_GITHUB_APP_ID}\n"
"github_app_private_key: ${CHECK_DONE_GITHUB_APP_PRIVATE_KEY}\n"
)
exit_code = check_done_command(["--config", str(config_path)])
assert exit_code == 0
Expand Down
16 changes: 8 additions & 8 deletions tests/test_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,12 @@ def test_can_validate_at_least_one_type_of_authentication_is_properly_configured
fake_organization_project_url = "https://github.com/orgs/fake-organization/projects/1"
fake_configuration_info_with_organization_project = ConfigurationInfo(
project_url="https://github.com/orgs/fake-organization/projects/1",
check_done_github_app_id="fake_app_id",
check_done_github_app_private_key="fake_private_key",
github_app_id="fake_app_id",
github_app_private_key="fake_private_key",
)
assert fake_configuration_info_with_organization_project.project_url == fake_organization_project_url
assert fake_configuration_info_with_organization_project.check_done_github_app_id == "fake_app_id"
assert fake_configuration_info_with_organization_project.check_done_github_app_private_key == "fake_private_key"
assert fake_configuration_info_with_organization_project.github_app_id == "fake_app_id"
assert fake_configuration_info_with_organization_project.github_app_private_key == "fake_private_key"


def test_fails_on_no_authentication_method_configured():
Expand All @@ -130,15 +130,15 @@ def test_fails_on_organization_authentication_method_missing_private_key():
with pytest.raises(ValueError, match="A user or an organization authentication method must be configured."):
ConfigurationInfo(
project_url="https://github.com/orgs/fake-organization/projects/1",
check_done_github_app_id="fake_check_done_github_app_id",
github_app_id="fake_github_app_id",
)


def test_fails_on_organization_authentication_method_missing_app_id():
with pytest.raises(ValueError, match="A user or an organization authentication method must be configured."):
ConfigurationInfo(
project_url="https://github.com/orgs/fake-organization/projects/1",
check_done_github_app_private_key="fake_check_done_github_app_private_key",
github_app_private_key="fake_github_app_private_key",
)


Expand Down Expand Up @@ -166,8 +166,8 @@ def test_can_resolve_project_details_from_user_project_url():
def test_can_resolve_project_details_from_organization_project_url():
configuration_info = ConfigurationInfo(
project_url="https://github.com/orgs/fake-organization-name/projects/1/views/2",
check_done_github_app_id="fake_check_done_github_app_id",
check_done_github_app_private_key="fake_check_done_github_app_private_key",
github_app_id="fake_github_app_id",
github_app_private_key="fake_github_app_private_key",
)
assert configuration_info.is_project_owner_of_type_organization
assert configuration_info.project_number == 1
Expand Down
4 changes: 2 additions & 2 deletions tests/test_done_project_items_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
def test_can_resolve_done_project_items_info():
fake_configuration_info = ConfigurationInfo(
project_url=DEMO_CHECK_DONE_GITHUB_PROJECT_URL,
check_done_github_app_id=DEMO_CHECK_DONE_GITHUB_APP_ID,
check_done_github_app_private_key=DEMO_CHECK_DONE_GITHUB_APP_PRIVATE_KEY,
github_app_id=DEMO_CHECK_DONE_GITHUB_APP_ID,
github_app_private_key=DEMO_CHECK_DONE_GITHUB_APP_PRIVATE_KEY,
)
assert len(done_project_items_info(fake_configuration_info)) >= 1

Expand Down
14 changes: 7 additions & 7 deletions tests/test_organization_authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
from check_done.organization_authentication import (
AuthenticationError,
generate_jwt_token,
resolve_check_done_github_app_installation_id,
resolve_github_app_installation_id,
resolve_organization_access_token,
)
from tests._common import (
Expand Down Expand Up @@ -73,30 +73,30 @@ def test_can_generate_jwt_token():
not HAS_DEMO_CHECK_DONE_ORGANIZATION_PROJECT_CONFIGURED,
reason=REASON_SHOULD_HAVE_DEMO_CHECK_DONE_ORGANIZATION_PROJECT_CONFIGURED,
)
def test_can_resolve_check_done_github_app_installation_id():
def test_can_resolve_github_app_installation_id():
session = _session()
fake_installation_id = resolve_check_done_github_app_installation_id(session, DEMO_CHECK_DONE_PROJECT_OWNER_NAME)
fake_installation_id = resolve_github_app_installation_id(session, DEMO_CHECK_DONE_PROJECT_OWNER_NAME)
assert isinstance(fake_installation_id, int)


@pytest.mark.skipif(
not HAS_DEMO_CHECK_DONE_ORGANIZATION_PROJECT_CONFIGURED,
reason=REASON_SHOULD_HAVE_DEMO_CHECK_DONE_ORGANIZATION_PROJECT_CONFIGURED,
)
def test_fails_to_resolve_check_done_github_app_installation_id():
def test_fails_to_resolve_github_app_installation_id():
session = _session()
with pytest.raises(AuthenticationError, match="Could not retrieve installation ID: status=404 "):
resolve_check_done_github_app_installation_id(session, _DUMMY_ORGANIZATION_NAME)
resolve_github_app_installation_id(session, _DUMMY_ORGANIZATION_NAME)


def test_fails_to_resolve_check_done_github_app_installation_id_from_bad_request():
def test_fails_to_resolve_github_app_installation_id_from_bad_request():
with requests_mock.Mocker() as mock:
mock.get(f"https://api.github.com/orgs/{_DUMMY_ORGANIZATION_NAME}/installation", status_code=400)
with pytest.raises(AuthenticationError, match="Could not retrieve installation ID: status=400 "):
resolve_organization_access_token(_DUMMY_ORGANIZATION_NAME, _DUMMY_GITHUB_APP_ID, _FAKE_PEM_PRIVATE_KEY)


def test_fails_to_resolve_access_token_from_check_done_github_app_installation_id():
def test_fails_to_resolve_access_token_from_github_app_installation_id():
with requests_mock.Mocker() as mock:
mock.get(
f"https://api.github.com/orgs/{_DUMMY_ORGANIZATION_NAME}/installation",
Expand Down

0 comments on commit 344f2de

Please sign in to comment.