Skip to content

Conversation

@SWITCHin2
Copy link

fixes: #540

@github-actions github-actions bot added the kr8s label Dec 4, 2025
@SWITCHin2
Copy link
Author

Hi @jacobtomlinson , I’ve attempted to fix the issue mentioned in the PR description. Could you please take a look when you get a chance? Thank you

@codecov
Copy link

codecov bot commented Dec 5, 2025

Codecov Report

❌ Patch coverage is 22.22222% with 7 lines in your changes missing coverage. Please review.
✅ Project coverage is 94.50%. Comparing base (87063fc) to head (e3f26d7).
⚠️ Report is 286 commits behind head on main.

Files with missing lines Patch % Lines
kr8s/_portforward.py 22.22% 7 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #712      +/-   ##
==========================================
- Coverage   94.61%   94.50%   -0.12%     
==========================================
  Files          29       33       +4     
  Lines        3141     5095    +1954     
==========================================
+ Hits         2972     4815    +1843     
- Misses        169      280     +111     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Copy link
Member

@jacobtomlinson jacobtomlinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good thanks!

Could I ask you to add a test that verifies this behaviour. I would start by finding a test that creates a temporary copy of the kubeconfig copy that. Then change token in the kubeconfig to something invalid and then trying to open a port forward

Comment on lines 242 to 251
if (
isinstance(e, httpx_ws.WebSocketUpgradeError)
and hasattr(e, "response")
and e.response.status_code in (401, 403)
):
error_message = f"Permission denied: {e.response.status_code}"
with suppress(httpx.StreamClosed, httpx.ResponseNotRead):
await e.response.aread()
error_message = e.response.text
raise ServerError(error_message, response=e.response) from e
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This bypasses the connection attempts. There may be cases where auth tokens expire and open_websocket will rotate them, so we don't want to raise here prematurely. Can you move this block inside the if connection_attempts > 5: section. That way we raise a ServerError if we have one, but a more generic ConnectionClosedError if we don't.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ummm yes thats makes sense, sure will do that

@SWITCHin2
Copy link
Author

This looks good thanks!

Could I ask you to add a test that verifies this behaviour. I would start by finding a test that creates a temporary copy of the kubeconfig copy that. Then change token in the kubeconfig to something invalid and then trying to open a port forward

Sure, actually I had an testing script which does something like this will add the same in to /test dir

@github-actions github-actions bot added the tests label Dec 6, 2025
@SWITCHin2
Copy link
Author

SWITCHin2 commented Dec 6, 2025

hey @jacobtomlinson

  • have handled premature error throwing case as you mentioned
  • modified my test script as per you said , pushed them and also fixed some pre checks

Copy link
Member

@jacobtomlinson jacobtomlinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for pushing the test. I left a few comments but overall there is a lot of unnecessary code in there.

I think you just need to:

  • Create the temporary credentials with bad token
  • Create the api_invalid
  • Create the invalid Pod object (but not actually create the resource)
  • Try to call the port forward and assert that it raises the ServerError

Comment on lines 15 to 23
# Override the k8s_cluster fixture to avoid creating a Kind cluster
@pytest.fixture
def k8s_cluster():
class MockCluster:
@property
def kubeconfig_path(self):
return Path(os.environ.get("KUBECONFIG", "~/.kube/config")).expanduser()

return MockCluster()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume you did this for local development? In CI we need to this run against the kind cluster.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes I was using this for my local dev test,
sure have incorporated that

Comment on lines 60 to 65
# Delete if exists
if await pod.exists():
await pod.delete()
await pod.wait("condition=Deleted")

await pod.create()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does the Pod actually need to exist? It never gets used other than to create pod_invalid.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that makes sense

Comment on lines 153 to 160
if __name__ == "__main__":

class MockCluster:
@property
def kubeconfig_path(self):
return Path(os.environ.get("KUBECONFIG", "~/.kube/config")).expanduser()

asyncio.run(test_portforward_invalid_token(MockCluster()))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In future instead of this you could just run pytest -k test_portforward_invalid_token and pytest will find the test and run it

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noted

@SWITCHin2
Copy link
Author

Thanks for pushing the test. I left a few comments but overall there is a lot of unnecessary code in there.

I think you just need to:

  • Create the temporary credentials with bad token
  • Create the api_invalid
  • Create the invalid Pod object (but not actually create the resource)
  • Try to call the port forward and assert that it raises the ServerError

@jacobtomlinson i have tried to sanitise the test file and in-corporate your review comments, please verify and let me know if everything seems fine now.

Copy link
Member

@jacobtomlinson jacobtomlinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A couple more comments on the tests, but otherwise this looks good to go.

Could I also ask you to put these tests in the existing test_objects.py file next to the other port forward tests instead of creating a new one. AI code tools love to create new test files unnecessarily.

Comment on lines +13 to +16
if k8s_cluster.kubeconfig_path.exists():
kubeconfig_data = yaml.safe_load(k8s_cluster.kubeconfig_path.read_text())
else:
pytest.skip("Kubeconfig file not found.")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to do this. If the kubeconfig doesn't exist then the whole test suite will be broken. You're safe to assume that it will exist.

pass

# Initialize a new API with the invalid kubeconfig
from kr8s._api import Api
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we put all the imports at the top of the file?

Comment on lines +38 to +48
original_check_version = Api._check_version

async def mock_check_version(self):
return

Api._check_version = mock_check_version

try:
api_invalid = await kr8s.asyncio.api(kubeconfig=kubeconfig_data)
finally:
Api._check_version = original_check_version
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using the mock patch context manager would hugely simplify this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

portforward obfuscates permissions issues

3 participants