Skip to content

fix: relax over-strict Okta SDK models that reject valid API responses - #107

Open
jackvaughanjr wants to merge 1 commit into
okta:mainfrom
jackvaughanjr:fix/okta-sdk-model-compat
Open

fix: relax over-strict Okta SDK models that reject valid API responses#107
jackvaughanjr wants to merge 1 commit into
okta:mainfrom
jackvaughanjr:fix/okta-sdk-model-compat

Conversation

@jackvaughanjr

Copy link
Copy Markdown

Supersedes #102, which patched two of these four inline in policies.py. Closing that in favour of this.

Four generated Okta SDK models are stricter than the API they describe. Each one aborts an entire response, so a single non-conforming record makes a whole page unreadable. They are all in the pinned okta==3.4.4 dependency, so they cannot be fixed in this repo directly; they have to be relaxed at runtime.

Model Problem
A SamlApplicationSettingsSignOn Five required StrictBool fields the API omits on apps created from OIN catalog templates. Breaks list_applications, list_group_apps, and get_application.
B Policy.embedded Typed Dict[str, Dict[str, Any]], but Okta returns scalars inside _embedded, e.g. {"resourceType": "APP"}. Breaks list_policies(type="ACCESS_POLICY").
C AuthenticatorEnrollmentPolicyAuthenticatorSettings.key Closed enum missing smart_card_idp. Breaks list_policies(type="MFA_ENROLL") on any tenant using PIV/CAC.
D UserTypeCondition.exclude/.include Required lists where Okta sends null. Breaks list_policy_rules.

Approach

One module, okta_mcp_server/utils/okta_compat.py, applied at import time from server.py. This is the technique already used in this repo for LogSecurityContext.user_behaviors in system_logs.py; that patch is migrated into the new module so all SDK compatibility lives in one place.

Each patch is individually wrapped, so a future SDK version that removes a field logs a warning instead of breaking startup. Each carries the upstream issue that would make it removable.

Two deliberate choices worth review:

  • key is relaxed to Optional[str] rather than adding one enum member. Adding smart_card_idp alone would break again on the next authenticator Okta ships. This matches the approach in fix: relax two SDK model gaps blocking list_policies on Okta for Government tenants #102.
  • Only named fields are touched. Nothing sets extra="allow" and no model is blanket-relaxed. Request models keep their required-field validation, where a local error is more useful than an opaque API 400.

Pydantic v2 detail: each subclass builds its own model_fields at class-creation time, so patching Policy alone does not fix AccessPolicy. The patch names subclasses explicitly and rewrites __annotations__ so it works regardless of import order. There is a test that runs both orders in subprocesses.

Testing

26 tests, 10 synthetic fixtures (example.invalid hosts, fake IDs). Each defect has a test that fails before the fix with the exact upstream error signature and passes after. Control fixtures assert the happy path is unchanged: a populated assertionSigned: true stays True, an explicit {"exclude": [], "include": []} stays [] rather than becoming None, and SAML_2_0 still routes to SamlApplication.

Missing booleans deserialize to None, not False. For a security review, "not reported" and "not signed" must not be confusable.

Full suite: 555 passed, up from 529 on main.

Upstream

v3.4.4 is the latest release, so there is no version bump that resolves any of these.

Consolidates every SDK model compatibility patch into one module,
okta_mcp_server.utils.okta_compat, applied at import time.

Covers four defects where a generated Pydantic model is stricter than
the API it describes, each of which aborts an entire response:

  A  SamlApplicationSettingsSignOn: five required StrictBool fields the
     API omits on apps created from OIN catalog templates.
  B  Policy.embedded: typed Dict[str, Dict[str, Any]], but Okta returns
     scalars inside _embedded (e.g. {"resourceType": "APP"}).
  C  AuthenticatorEnrollmentPolicyAuthenticatorSettings.key: closed enum
     missing smart_card_idp, and brittle to any future authenticator.
  D  UserTypeCondition.exclude/include: required lists where Okta sends
     null. Also RiskDetectionTypesPolicyRuleCondition and
     UserIdentifierPolicyRuleCondition.

Also migrates the existing LogSecurityContext.user_behaviors patch out
of system_logs.py so all SDK compatibility lives in one place.

Supersedes the inline patches in PR okta#102 (issues okta#100, okta#101).
Upstream: okta/okta-sdk-python#546 (A), #572 (D); okta#100
(B), okta#101 (C), okta#48 (A).

Regression fixtures are synthetic: example.invalid hosts and fake IDs.
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