From 98ffc2b4f135e763e30e37c8aeef1469f614abe7 Mon Sep 17 00:00:00 2001 From: General Kroll Date: Wed, 4 Nov 2026 13:07:05 +1100 Subject: [PATCH] doc-auth-token-url-variables Summary: - Stop presenting document-registered auth as a runtime `token_url` override; omnisdk now overlays the document token URL and resolves `config.auth.variables` when no `--auth` is supplied. - Preserve explicit `token_url` overrides from `--auth` and provider aliases. - Declare client credential environment variables in the endpoint selector test document and allow selector scenarios to run without `--auth`. - Added `robot` test `Document Auth Applies Token URL Variables`. Fixes #890 --- internal/stackql/handler/handler.go | 5 ++++- test/robot/functional/EndpointSelectorLibrary.py | 15 ++++++++++++--- .../functional/stackql_endpoint_selectors.robot | 3 +++ 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/internal/stackql/handler/handler.go b/internal/stackql/handler/handler.go index 364f1a81..a1416da6 100644 --- a/internal/stackql/handler/handler.go +++ b/internal/stackql/handler/handler.go @@ -806,7 +806,10 @@ func transformOpenapiStackqlAuthToLocal(auth *omnisdk.ProviderAuth) *dto.AuthCtx if auth == nil { return nil } - return &dto.AuthCtx{AuthConfig: auth.AuthConfig, Successor: transformOpenapiStackqlAuthToLocal(auth.Successor)} + cfg := auth.AuthConfig + // A runtime token URL bypasses the document's token URL variables; omnisdk overlays the document's own. + cfg.TokenURL = "" + return &dto.AuthCtx{AuthConfig: cfg, Successor: transformOpenapiStackqlAuthToLocal(auth.Successor)} } func (hc *standardHandlerContext) GetExecutionContext() context.Context { diff --git a/test/robot/functional/EndpointSelectorLibrary.py b/test/robot/functional/EndpointSelectorLibrary.py index d7018778..ed313c35 100644 --- a/test/robot/functional/EndpointSelectorLibrary.py +++ b/test/robot/functional/EndpointSelectorLibrary.py @@ -57,6 +57,7 @@ def reply(self, data): version = self.root / "registry/src/widgets/v00.00.00000" provider = json.loads((version / "provider.yaml").read_text()) provider["config"]["auth"] = {"type": "oauth2", "grant_type": "client_credentials", "token_url": "http://{account_host}/token", + "client_id_env_var": "STACKQL_SELECTOR_CLIENT_ID", "client_secret_env_var": "STACKQL_SELECTOR_CLIENT_SECRET", "variables": {"account_host": self.selector_variable}} doc = json.loads((version / "services/things.yaml").read_text()) doc["servers"] = [{"url": "http://{account_host}", "variables": {"account_host": self.selector_variable}}] @@ -73,13 +74,16 @@ def reply(self, data): self.selector_auth = {"widgets": {"type": "client_credentials", "client_id": "dummy-client", "client_secret": "dummy-secret"}} def execute_selector_sql(self, sql, cloud="", direct="", auth=None, expected=()): - env = dict(self.env, STACKQL_SELECTOR_CLOUD=cloud, STACKQL_SELECTOR_DIRECT=direct) + client = {"STACKQL_SELECTOR_CLIENT_ID": "dummy-client", "STACKQL_SELECTOR_CLIENT_SECRET": "dummy-secret"} + env = dict(self.env, STACKQL_SELECTOR_CLOUD=cloud, STACKQL_SELECTOR_DIRECT=direct, **client) prefix = list(self.prefix) if self.execution_platform == "docker": position = prefix.index("--entrypoint") - prefix[position:position] = ["-e", "STACKQL_SELECTOR_CLOUD=" + cloud, "-e", "STACKQL_SELECTOR_DIRECT=" + direct] + prefix[position:position] = ["-e", "STACKQL_SELECTOR_CLOUD=" + cloud, "-e", "STACKQL_SELECTOR_DIRECT=" + direct, + *[arg for name, value in client.items() for arg in ("-e", name + "=" + value)]] + auth_flags = [] if auth is False else ["--auth", json.dumps(auth or self.selector_auth)] before = len(self.selector_calls) - result = subprocess.run(prefix + ["exec", sql] + self.flags + ["--auth", json.dumps(auth or self.selector_auth)], + result = subprocess.run(prefix + ["exec", sql] + self.flags + auth_flags, text=True, capture_output=True, env=env, timeout=30) assert result.returncode == 0 and all(line == "The operation was despatched successfully" for line in result.stderr.splitlines()), (result.stdout, result.stderr) assert self.selector_calls[before:] == list(expected), (self.selector_calls[before:], result.stdout, result.stderr) @@ -93,6 +97,11 @@ def default_selector_matches_query_show_and_exec(self): self.execute_selector_sql("SELECT id FROM widgets.things.widgets;", expected=[("aws", "POST", "/token"), ("aws", "GET", "/widgets")]) self.execute_selector_sql("EXEC widgets.things.widgets.fetch;", expected=[("aws", "POST", "/token"), ("aws", "GET", "/widgets")]) + def document_auth_applies_token_url_variables(self): + self.execute_selector_sql("SELECT id FROM widgets.things.widgets;", auth=False, expected=[("aws", "POST", "/token"), ("aws", "GET", "/widgets")]) + self.execute_selector_sql("SELECT id FROM widgets.things.widgets;", "azure", auth=False, + expected=[("azure", "POST", "/token"), ("azure", "GET", "/widgets")]) + def selector_and_direct_override_apply_to_exec(self): for cloud, direct in [(" azure ", ""), ("invalid", " " + self.selector_hosts["azure"] + "/// ")]: self.execute_selector_sql("EXEC widgets.things.widgets.fetch;", cloud, direct, diff --git a/test/robot/functional/stackql_endpoint_selectors.robot b/test/robot/functional/stackql_endpoint_selectors.robot index 57783763..12a4f1d9 100644 --- a/test/robot/functional/stackql_endpoint_selectors.robot +++ b/test/robot/functional/stackql_endpoint_selectors.robot @@ -9,6 +9,9 @@ Suite Teardown Stop Endpoint Selectors Default Selector Matches Query Show And Exec Default Selector Matches Query Show And Exec +Document Auth Applies Token URL Variables + Document Auth Applies Token URL Variables + Selector And Direct Override Apply To Exec Selector And Direct Override Apply To Exec