From 41713095bc7b4683c63e11cefee3c4d081514424 Mon Sep 17 00:00:00 2001 From: SUY Date: Wed, 17 Jun 2026 02:02:26 -0500 Subject: [PATCH 1/2] Add EnvVar.inject_into_auth_data to route secrets into auth_data Adds a single additive, backward-compatible field to the EnvVar contract (default False reproduces today's behavior). When True, the runtime must guarantee the value reaches a credential's auth_data at action-execution time; the source is derived from only_for_custom (server-level secret vs per-credential user input) rather than declared, so no integration-specific branching is needed. Wires the two integrations that currently fail with "missing from auth_data": - google_ads GOOGLE_ADS_DEVELOPER_TOKEN: only_for_custom=True + inject_into_auth_data=True (managed app resolves from server env). - google_merchant_center GOOGLE_MERCHANT_CENTER_MERCHANT_ID: inject_into_auth_data=True (per-credential user input). tools.py is unchanged (both already read these keys from auth_data). The actual injection behavior lands in the modulex runtime; see the external brief. Verification baseline unchanged: 1890 passed, ruff clean, mypy clean for touched files. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/modulex_integrations/schema.py | 15 +++++++++++++++ .../tools/google_ads/manifest.py | 6 ++++++ .../tools/google_merchant_center/manifest.py | 5 +++++ 3 files changed, 26 insertions(+) diff --git a/src/modulex_integrations/schema.py b/src/modulex_integrations/schema.py index 763d80a..b64da0c 100644 --- a/src/modulex_integrations/schema.py +++ b/src/modulex_integrations/schema.py @@ -98,6 +98,21 @@ class EnvVar(BaseModel): required: bool = True sensitive: bool = False only_for_custom: bool = False + # When True, the runtime must guarantee this value is present in the + # credential's ``auth_data`` at action-execution time, so a ``tools.py`` + # function can read it. The source is *derived*, not declared: + # - ``only_for_custom=False`` -> per-credential user input; the runtime + # persists the user-entered value into ``auth_data`` at credential + # creation (e.g. Google Merchant Center ``merchant_id``). + # - ``only_for_custom=True`` -> server-level secret; for the managed + # app the runtime resolves it from the server environment and injects + # it at credential-resolution time, while a bring-your-own-app user + # supplies their own (e.g. Google Ads ``developer_token``). + # Tools read the value via the normalized (prefix-stripped, lowercased) + # key. Default False preserves today's behavior: the EnvVar is used only + # for OAuth provider config and the credential test endpoint, never for + # action calls. + inject_into_auth_data: bool = False sample_format: str | None = None about_url: str | None = None diff --git a/src/modulex_integrations/tools/google_ads/manifest.py b/src/modulex_integrations/tools/google_ads/manifest.py index d313835..2b76397 100644 --- a/src/modulex_integrations/tools/google_ads/manifest.py +++ b/src/modulex_integrations/tools/google_ads/manifest.py @@ -567,6 +567,12 @@ ), required=True, sensitive=True, + # Server-level secret for the managed app (one token for all + # users; per-user access is via OAuth). The runtime resolves + # it from the server environment and injects it into + # auth_data; a bring-your-own-app user supplies their own. + only_for_custom=True, + inject_into_auth_data=True, sample_format="xxxxxxxxxxxxxxxxxxxxxx", about_url="https://developers.google.com/google-ads/api/docs/get-started/dev-token", ), diff --git a/src/modulex_integrations/tools/google_merchant_center/manifest.py b/src/modulex_integrations/tools/google_merchant_center/manifest.py index a0f37a6..c4e5518 100644 --- a/src/modulex_integrations/tools/google_merchant_center/manifest.py +++ b/src/modulex_integrations/tools/google_merchant_center/manifest.py @@ -113,7 +113,12 @@ description="Your Google Merchant Center account ID (numeric)", required=True, sensitive=False, + # Per-credential user input (every merchant has their own + # ID, so it can't be a server global). The runtime persists + # the user-entered value into auth_data at credential + # creation; tools.py reads it as auth_data["merchant_id"]. only_for_custom=False, + inject_into_auth_data=True, sample_format="123456789", about_url="https://merchants.google.com/mc/overview", ), From 57b633ad5dacc965abf3c1f6560efea16e0c0278 Mon Sep 17 00:00:00 2001 From: SUY Date: Wed, 17 Jun 2026 02:34:15 -0500 Subject: [PATCH 2/2] Add CHANGELOG entry for inject_into_auth_data + Google credential fix Co-Authored-By: Claude Opus 4.8 (1M context) --- CHANGELOG.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c7faf53..e0c46fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,27 @@ The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and ## [Unreleased] +### Changed (schema) + +- `EnvVar.inject_into_auth_data: bool = False` added — additive, + defaults to `False` (today's behavior preserved). When `True`, the + modulex runtime surfaces the value in `auth_data` at action time: + per-credential user input (`only_for_custom=False`) is persisted at + OAuth2 creation; server-level secrets (`only_for_custom=True`) are + injected from the server environment at tool execution. Fully + backward-compatible — every other integration dumps it as `False` + and the runtime injection is a no-op for them. + +### Fixed + +- `google_ads` / `google_merchant_center` — flagged + `GOOGLE_ADS_DEVELOPER_TOKEN` (`only_for_custom=True`) and + `GOOGLE_MERCHANT_CENTER_MERCHANT_ID` (`only_for_custom=False`) with + `inject_into_auth_data=True` so the developer token and merchant ID + reach `auth_data` at action time, fixing the "missing from auth_data" + errors on `list_account_id_options` / `create_product`. Requires the + matching modulex runtime change (external brief #021). + ### Added - `revolt` integration — 3 actions, auth: bearer_token. Revolt open-source