Skip to content

fix: mutable reference headers #1095 #1096

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

Conversation

AsahiSoftWareEngineer
Copy link
Contributor

What kind of change does this PR introduce?

Bug fix Isses #1095

What is the current behavior?

Isses No. #1095

What is the new behavior?

Prevent unintended header changes when sharing the same ClientOptions.

@AsahiSoftWareEngineer AsahiSoftWareEngineer marked this pull request as draft April 2, 2025 17:15
@AsahiSoftWareEngineer AsahiSoftWareEngineer marked this pull request as ready for review April 2, 2025 17:18
@AsahiSoftWareEngineer
Copy link
Contributor Author

AsahiSoftWareEngineer commented Apr 2, 2025

@olirice Sorry, I can not set reviewer. That's why , I request a review here.
Please review my pull request.

@olirice olirice requested a review from grdsdev April 3, 2025 15:01
@coveralls
Copy link

coveralls commented Apr 3, 2025

Pull Request Test Coverage Report for Build 15212706024

Details

  • 9 of 9 (100.0%) changed or added relevant lines in 2 files are covered.
  • No unchanged relevant lines lost coverage.
  • Overall coverage increased (+0.4%) to 86.318%

Totals Coverage Status
Change from base Build 14719173473: 0.4%
Covered Lines: 347
Relevant Lines: 402

💛 - Coveralls

Copy link
Contributor

@grdsdev grdsdev 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 the fix @AsahiSoftWareEngineer just some clarifications before merging.

Comment on lines 293 to 298
header = copy.deepcopy(self._create_auth_header(access_token))
self.options.headers["Authorization"] = header
self.auth._headers["Authorization"] = header
self.postgrest.session.headers["Authorization"] = header
self.storage.session.headers["Authorization"] = header

Copy link
Contributor

Choose a reason for hiding this comment

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

not sure the issue this is solving, could you elaborate?

Copy link
Contributor Author

@AsahiSoftWareEngineer AsahiSoftWareEngineer Apr 3, 2025

Choose a reason for hiding this comment

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

Sorry, Below source code is not necessary.

  self.postgrest.session.headers["Authorization"] = header
  self.storage.session.headers["Authorization"] = header

Caused by using deep-copy, before source code was not working. (auth._headers is not refreshed).
That's why, I changed to reassign deep-copied self._create_auth_header(access_token)methods

@AsahiSoftWareEngineer
Copy link
Contributor Author

AsahiSoftWareEngineer commented Apr 3, 2025

@grdsdev Sorry, I fixed it. Please re-review pull request.

@silentworks
Copy link
Contributor

I think this would be better addressed by using the .replace method on the ClientOptions class. This should probably be added to the docs as the go to way of updating anything inside of the ClientOptions.

I wrote your test below using the .replace method and it all passes.

def test_mutable_headers_issue():
    url = os.environ.get("SUPABASE_TEST_URL")
    key = os.environ.get("SUPABASE_TEST_KEY")

    shared_options = ClientOptions(
        headers={"Authorization": "Bearer initial-token", "x-site": "supanew.site"}
    )

    client1 = create_client(url, key, shared_options)
    client2 = create_client(url, key, shared_options)
    client1.options.replace({"headers": {"Authorization": "Bearer modified-token"}})

    assert client2.options.headers["Authorization"] == "Bearer initial-token"
    assert client2.options.headers["x-site"] == "supanew.site"
    assert client1.options.headers["x-site"] == "supanew.site"

@AsahiSoftWareEngineer
Copy link
Contributor Author

AsahiSoftWareEngineer commented Apr 5, 2025

@silentworks Sure. I think of trying, but I do not know Can I rewrite docs.(Have I permissions??)

@AsahiSoftWareEngineer
Copy link
Contributor Author

All test passed

@AsahiSoftWareEngineer
Copy link
Contributor Author

@grdsdev Hi, Can you re-review pull request.

@grdsdev
Copy link
Contributor

grdsdev commented May 6, 2025

I think this would be better addressed by using the .replace method on the ClientOptions class. This should probably be added to the docs as the go to way of updating anything inside of the ClientOptions.

I wrote your test below using the .replace method and it all passes.

def test_mutable_headers_issue():
    url = os.environ.get("SUPABASE_TEST_URL")
    key = os.environ.get("SUPABASE_TEST_KEY")

    shared_options = ClientOptions(
        headers={"Authorization": "Bearer initial-token", "x-site": "supanew.site"}
    )

    client1 = create_client(url, key, shared_options)
    client2 = create_client(url, key, shared_options)
    client1.options.replace({"headers": {"Authorization": "Bearer modified-token"}})

    assert client2.options.headers["Authorization"] == "Bearer initial-token"
    assert client2.options.headers["x-site"] == "supanew.site"
    assert client1.options.headers["x-site"] == "supanew.site"

@silentworks I just think I prefer to internally deep copy the client options object, I think that just makes more sense then having to use a separate replace method for changing the options for the client.

@silentworks
Copy link
Contributor

@grdsdev this is fine. I do however think we are trying to fix a language (python being dynamic by design) issue here but I am OK with this PR being merged in.

@silentworks silentworks changed the title Fix mutable reference headers #1095 fix: mutable reference headers #1095 May 16, 2025
@grdsdev
Copy link
Contributor

grdsdev commented May 20, 2025

@grdsdev this is fine. I do however think we are trying to fix a language (python being dynamic by design) issue here but I am OK with this PR being merged in.

that makes sense, let's not fight the language.

@grdsdev
Copy link
Contributor

grdsdev commented May 20, 2025

@AsahiSoftWareEngineer thank you for this contributions, but as said by @silentworks there're other ways of achieving this by using the replace method.

@grdsdev grdsdev closed this May 20, 2025
@grdsdev grdsdev mentioned this pull request May 20, 2025
2 tasks
@silentworks
Copy link
Contributor

We're re-opening this PR as I've realised in my tests I didn't test it fully. .replace doesn't work as how I had initially thought as it returns a new object. In order to use .replace and get the same result as this PR the code would look more like the test below which I think might be too verbose for some.

def test_mutable_headers_issue():
    url = os.environ.get("SUPABASE_TEST_URL")
    key = os.environ.get("SUPABASE_TEST_KEY")

    shared_options = ClientOptions(
        headers={"Authorization": "Bearer initial-token", "x-site": "supanew.site"}
    )

    client1 = create_client(url, key, shared_options)
    client2 = create_client(url, key, shared_options)
    client1.options = client1.options.replace(headers={**client1.options.headers, "Authorization": "Bearer modified-token"})

    assert client1.options.headers["Authorization"] == "Bearer modified-token"
    assert client2.options.headers["Authorization"] == "Bearer initial-token"
    assert client2.options.headers["x-site"] == "supanew.site"
    assert client1.options.headers["x-site"] == "supanew.site"

@silentworks silentworks reopened this May 23, 2025
@silentworks silentworks merged commit 50d79c1 into supabase:main May 23, 2025
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants