diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 0380a03..0cf1a71 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -41,7 +41,7 @@ jobs: steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 with: egress-policy: audit diff --git a/.github/workflows/contributors_report.yaml b/.github/workflows/contributors_report.yaml index d80fb8e..32ea4a2 100644 --- a/.github/workflows/contributors_report.yaml +++ b/.github/workflows/contributors_report.yaml @@ -16,7 +16,7 @@ jobs: issues: write steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 with: egress-policy: audit diff --git a/.github/workflows/copilot-setup-steps.yml b/.github/workflows/copilot-setup-steps.yml index fcb8d67..8663a0e 100644 --- a/.github/workflows/copilot-setup-steps.yml +++ b/.github/workflows/copilot-setup-steps.yml @@ -26,7 +26,7 @@ jobs: # If you do not check out your code, Copilot will do this for you. steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 with: egress-policy: audit diff --git a/.github/workflows/dependency-review.yml b/.github/workflows/dependency-review.yml index c40f824..4f200f0 100644 --- a/.github/workflows/dependency-review.yml +++ b/.github/workflows/dependency-review.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 with: egress-policy: audit diff --git a/.github/workflows/docker-ci.yml b/.github/workflows/docker-ci.yml index a022d16..313845e 100644 --- a/.github/workflows/docker-ci.yml +++ b/.github/workflows/docker-ci.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 with: egress-policy: audit diff --git a/.github/workflows/mark-ready-when-ready.yml b/.github/workflows/mark-ready-when-ready.yml index 5deb181..3bb7cdf 100644 --- a/.github/workflows/mark-ready-when-ready.yml +++ b/.github/workflows/mark-ready-when-ready.yml @@ -25,7 +25,7 @@ jobs: github.event.pull_request.draft == true steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 with: egress-policy: audit diff --git a/.github/workflows/python-ci.yml b/.github/workflows/python-ci.yml index 6ebb592..8a9c6c7 100644 --- a/.github/workflows/python-ci.yml +++ b/.github/workflows/python-ci.yml @@ -25,7 +25,7 @@ jobs: python-version: [3.11, 3.12, 3.13, 3.14] steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 with: egress-policy: audit diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index c554a6b..5165b56 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -27,7 +27,7 @@ jobs: steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 with: egress-policy: audit diff --git a/.github/workflows/stale.yaml b/.github/workflows/stale.yaml index 17c96be..41257d7 100644 --- a/.github/workflows/stale.yaml +++ b/.github/workflows/stale.yaml @@ -14,7 +14,7 @@ jobs: pull-requests: read steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 with: egress-policy: audit diff --git a/.github/workflows/super-linter.yaml b/.github/workflows/super-linter.yaml index 47d25cd..23cdbe3 100644 --- a/.github/workflows/super-linter.yaml +++ b/.github/workflows/super-linter.yaml @@ -23,7 +23,7 @@ jobs: steps: - name: Harden the runner (Audit all outbound calls) - uses: step-security/harden-runner@58077d3c7e43986b6b15fba718e8ea69e387dfcc # v2.15.1 + uses: step-security/harden-runner@fa2e9d605c4eeb9fcad4c99c224cee0c6c7f3594 # v2.16.0 with: egress-policy: audit diff --git a/auth.py b/auth.py index 840d4eb..b4584dc 100644 --- a/auth.py +++ b/auth.py @@ -32,7 +32,7 @@ def auth_to_github( else: gh = github3.github.GitHub() gh.login_as_app_installation( - gh_app_private_key_bytes, gh_app_id, gh_app_installation_id + gh_app_private_key_bytes, str(gh_app_id), gh_app_installation_id ) github_connection = gh elif ghe and token: @@ -51,9 +51,9 @@ def auth_to_github( def get_github_app_installation_token( ghe: str, - gh_app_id: str, + gh_app_id: int | None, gh_app_private_key_bytes: bytes, - gh_app_installation_id: str, + gh_app_installation_id: int | None, ) -> str | None: """ Get a GitHub App Installation token. @@ -61,14 +61,16 @@ def get_github_app_installation_token( Args: ghe (str): the GitHub Enterprise endpoint - gh_app_id (str): the GitHub App ID + gh_app_id (int | None): the GitHub App ID gh_app_private_key_bytes (bytes): the GitHub App Private Key - gh_app_installation_id (str): the GitHub App Installation ID + gh_app_installation_id (int | None): the GitHub App Installation ID Returns: str: the GitHub App token """ - jwt_headers = github3.apps.create_jwt_headers(gh_app_private_key_bytes, gh_app_id) + jwt_headers = github3.apps.create_jwt_headers( + gh_app_private_key_bytes, str(gh_app_id) + ) api_endpoint = f"{ghe}/api/v3" if ghe else "https://api.github.com" url = f"{api_endpoint}/app/installations/{gh_app_installation_id}/access_tokens" diff --git a/test_auth.py b/test_auth.py index 9337abc..967fadc 100644 --- a/test_auth.py +++ b/test_auth.py @@ -56,9 +56,9 @@ def test_auth_to_github_with_ghe_and_ghe_app(self, mock_ghe): mock = mock_ghe.return_value mock.login_as_app_installation = MagicMock(return_value=True) result = auth.auth_to_github( - "", "123", "123", b"123", "https://github.example.com", True + "", 123, 456, b"123", "https://github.example.com", True ) - mock.login_as_app_installation.assert_called_once() + mock.login_as_app_installation.assert_called_once_with(b"123", "123", 456) self.assertEqual(result, mock) @patch("github3.github.GitHub") @@ -69,9 +69,9 @@ def test_auth_to_github_with_app(self, mock_gh): mock = mock_gh.return_value mock.login_as_app_installation = MagicMock(return_value=True) result = auth.auth_to_github( - "", "123", "123", b"123", "https://github.example.com", False + "", 123, 456, b"123", "https://github.example.com", False ) - mock.login_as_app_installation.assert_called_once() + mock.login_as_app_installation.assert_called_once_with(b"123", "123", 456) self.assertEqual(result, mock) @patch("github3.apps.create_jwt_headers", MagicMock(return_value="gh_token")) @@ -92,6 +92,32 @@ def test_get_github_app_installation_token(self, mock_post): self.assertEqual(result, dummy_token) + @patch( + "github3.apps.create_jwt_headers", + return_value={"Authorization": "Bearer gh_token"}, + ) + @patch("requests.post") + def test_get_github_app_installation_token_casts_int_app_id_to_str( + self, mock_post, mock_create_jwt + ): + """ + Test that get_github_app_installation_token casts an int gh_app_id to str + before passing it to create_jwt_headers (PyJWT requires iss to be a string). + """ + mock_response = MagicMock() + mock_response.raise_for_status.return_value = None + mock_response.json.return_value = {"token": "dummytoken"} + mock_post.return_value = mock_response + + auth.get_github_app_installation_token( + ghe="", + gh_app_id=12345, + gh_app_private_key_bytes=b"private_key", + gh_app_installation_id=678910, + ) + + mock_create_jwt.assert_called_once_with(b"private_key", "12345") + @patch("github3.apps.create_jwt_headers", MagicMock(return_value="gh_token")) @patch("auth.requests.post") def test_get_github_app_installation_token_request_failure(self, mock_post):