Skip to content

chore(api): stop injecting SessionId into merged spec - #152

Merged
hotdata-automation[bot] merged 2 commits into
mainfrom
openapi-update-30398810433
Jul 30, 2026
Merged

chore(api): stop injecting SessionId into merged spec#152
hotdata-automation[bot] merged 2 commits into
mainfrom
openapi-update-30398810433

Conversation

@hotdata-automation

Copy link
Copy Markdown
Contributor

Auto-generated from the updated HotData OpenAPI spec.
Source: https://github.com/hotdata-dev/www.hotdata.dev/pull/283

@hotdata-automation
hotdata-automation Bot requested a review from a team as a code owner July 28, 2026 21:01
@hotdata-automation
hotdata-automation Bot requested review from eddietejeda and removed request for a team July 28, 2026 21:01
@hotdata-automation
hotdata-automation Bot enabled auto-merge (squash) July 28, 2026 21:01
Comment thread hotdata/configuration.py
'SessionId',
),
}
return auth

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Removing the SessionId scheme here silently breaks the hand-written session_id surface that this SDK's custom templates add on top of the generated code.

After this change:

  • Configuration.__init__ still accepts session_id= and still does self.api_keys["SessionId"] = session_id (line 240-241)
  • the session_id property/setter still exist (lines 543-557) and still document "sent as X-Session-Id"
  • the class docstring still advertises it (line 145-147) as a workspace/sandbox scoping example

…but nothing consumes it anymore. auth_settings() no longer emits a SessionId entry, and _auth_settings in query_api.py / results_api.py no longer lists it, so update_params_for_auth (api_client.py:649-651) never finds a setting to apply. X-Session-Id is never sent.

That is a silent failure mode, not a loud one: existing callers doing

conf = hotdata.Configuration(api_key=..., workspace_id="ws_abc", session_id="sb_xyz")

get no error, no warning, and conf.session_id still reads back "sb_xyz" — but their queries and result reads now run unscoped against the workspace instead of isolated in the sandbox. Sandbox isolation quietly disappears.

This needs to be resolved one of two ways:

  1. If dropping SessionId is intended — remove the session_id kwarg, property, setter, and docstring references from .openapi-generator-templates/configuration.mustache (lines 166-170, 212, 284, 331-337, 663-676) so the regenerated configuration.py no longer exposes a dead parameter, and note the removal as a breaking change in the CHANGELOG rather than under ### Changed.
  2. If SessionId is still a real header — restore it in the upstream spec so the generator re-emits both the auth_settings() entry and the per-operation _auth_settings membership.

Separately worth confirming while you're here: the session_id docstring points users at SandboxesApi.create_sandbox, but there is no sandboxes_api.py in hotdata/api/. That predates this PR, but it suggests option 1 is the intent — in which case the template cleanup belongs in this change so the public API and the wire behavior stay in sync.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review

Blocking Issues

hotdata/configuration.py:601session_id becomes a silent no-op

This PR removes the SessionId security scheme from the generated code (auth_settings() in configuration.py, the AuthSettings TypedDict, and _auth_settings in query_api.py / results_api.py), but the session_id public surface added by this repo's custom templates is left in place:

  • hotdata/configuration.py:191session_id: Optional[str]=None kwarg
  • hotdata/configuration.py:240-241 — still writes self.api_keys["SessionId"]
  • hotdata/configuration.py:543-557session_id property + setter, documented as "sent as X-Session-Id"
  • hotdata/configuration.py:145-147 — class docstring advertises sandbox scoping via session_id

Nothing consumes that value now. update_params_for_auth (hotdata/api_client.py:649-651) looks each requested auth name up in configuration.auth_settings(); SessionId is absent from both the operation lists and the returned dict, so X-Session-Id is never sent.

Callers passing session_id="sb_xyz" get no error and can still read the value back off the config, but their /query and results requests silently run unscoped against the workspace instead of isolated in the sandbox. Silent loss of scoping is the problem here, not the removal itself.

Action Required

Pick one and make the code consistent:

  1. Removal is intended — strip the session_id kwarg, property, setter, and docstring references from .openapi-generator-templates/configuration.mustache (lines 166-170, 212, 284, 331-337, 663-676) so regeneration stops exposing a dead parameter, and record this as a breaking change in CHANGELOG.md rather than a plain ### Changed entry.
  2. X-Session-Id is still live — restore the scheme in the upstream spec so the generator re-emits the auth_settings() entry and the per-operation _auth_settings membership.

Option 1 looks likelier given the session_id docstring points at SandboxesApi.create_sandbox and no sandboxes_api.py exists in hotdata/api/. Either way, the template change belongs in this PR so the public API and the wire behavior do not diverge.

@zfarrell

Copy link
Copy Markdown
Contributor

Took option 1 — session_id is removed, not restored. Confirmed dead upstream: the merged spec no longer carries the SessionId scheme (www #283) and RuntimeDB stopped enforcing X-Session-Id in #988, so no caller loses scoping that was still working.

Removed the kwarg, property, setter, and docstrings from .openapi-generator-templates/configuration.mustache, then regenerated hotdata/configuration.py against the current spec with the pinned generator (7.20.0) — the regen diff is exactly the session removal and nothing else. CHANGELOG entry moved out of ### Changed into ### Removed as a Breaking note. Also closes #151, which flagged the SandboxesApi.create_sandbox docstrings.

tests/test_config_auth_surface.py is new and pins the general invariant: every hand-added typed apiKey kwarg on Configuration must appear in auth_settings(), so the next scheme removal fails there instead of shipping a silent no-op.

Heads up on downstream: sdk-python-framework (hotdata_framework/env.py) and hotdata-ibis (backend.py) both pass Configuration(session_id=...) and will now hit a TypeError. They need matching PRs before picking up this release.

Comment on lines +79 to +89
@pytest.mark.parametrize("kwarg", _typed_api_key_kwargs())
def test_typed_api_key_kwarg_reaches_auth_settings(kwarg: str) -> None:
"""A convenience kwarg that never shows up in auth_settings() is a no-op."""
config = _config(**{kwarg: "value-for-" + kwarg})

settings = config.auth_settings()
wire_values = {setting["value"] for setting in settings.values()}
assert "value-for-" + kwarg in wire_values, (
f"Configuration(...{kwarg}=...) is accepted but auth_settings() never emits it, "
"so the value is silently dropped instead of being sent."
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nit: this tripwire only covers half the failure mode (not blocking).

The module docstring says the goal is to pin the invariant generally "so the next scheme removal fails here instead of shipping a silent no-op", but this test only checks the config-level half: kwarg → auth_settings(). The per-operation half is only covered for SessionId specifically, by test_session_header_is_not_sent.

auth_settings() is generated from the spec's securitySchemes, while each operation's _auth_settings list comes from that operation's security. Those move independently. If a future spec keeps a scheme declared under securitySchemes but drops it from every operation's security, auth_settings() still emits it, this test still passes — and the kwarg is once again a silent no-op that never reaches the wire. That's exactly the shape of the bug this file exists to catch.

A general version would assert scheme membership in the operations too, e.g. alongside the existing test:

_SCHEME_FOR_KWARG = {"workspace_id": "WorkspaceId"}

@pytest.mark.parametrize("kwarg", _typed_api_key_kwargs())
def test_typed_api_key_kwarg_is_used_by_some_operation(kwarg: str) -> None:
    scheme = _SCHEME_FOR_KWARG[kwarg]
    sources = "\n".join(
        p.read_text() for p in (REPO_ROOT / "hotdata" / "api").glob("*.py")
    )
    assert f"'{scheme}'" in sources, (
        f"{scheme} is in auth_settings() but no operation lists it in _auth_settings, "
        "so the kwarg is never sent."
    )

Nothing wrong with what's here — it just leaves the door open on the side that isn't spec-declaration.

@claude claude Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Prior blocking issue resolved: the session_id kwarg, property, and docstring references are gone from .openapi-generator-templates/configuration.mustache as well as the generated hotdata/configuration.py, the CHANGELOG entry moved under ### Removed and is marked breaking, and tests/test_config_auth_surface.py pins the kwarg/wire invariant so the next scheme removal fails loudly. Verified no session_id / SessionId / X-Session-Id references remain outside the test and changelog, and that the new tests match the actual _query_serialize / _list_results_serialize signatures and param_serialize's 5-tuple return.

Note: I could not execute pytest in this environment, so the new test file was reviewed by reading rather than by running it.

One non-blocking nit left inline on the test coverage.

@hotdata-automation
hotdata-automation Bot merged commit bbd4c52 into main Jul 30, 2026
5 checks passed
@hotdata-automation
hotdata-automation Bot deleted the openapi-update-30398810433 branch July 30, 2026 01:52
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.

1 participant