@@ -198,6 +198,53 @@ def add_undocumented_account_status_fields(spec):
198198 props .setdefault (name , schema )
199199
200200
201+ def add_undocumented_project_resource_fields (spec ):
202+ """Expose project resources and app→project linkage the API returns.
203+
204+ The live ``GET /projects/{project_id}/resources`` returns far more
205+ collections than the spec documents (verified against production):
206+ ``apps``, ``agents``, ``domains``, ``knowledgebases``, ``mailboxes``,
207+ ``registries``, ``cdn``, ``monitorings`` and ``routers`` alongside the six
208+ documented ones. Only ``apps`` is added here — its element shape was
209+ verified to match the documented ``app`` schema exactly; the other
210+ collections stay untouched until their shapes can be checked against live
211+ data.
212+
213+ Live ``app`` objects also carry a ``project_id`` the spec omits — the only
214+ way to attribute an app to a project from the apps list.
215+
216+ Both additions are defensive (optional, nullable) so a missing field never
217+ breaks deserialization. Run on every regeneration, so they survive
218+ upstream spec syncs automatically.
219+ """
220+ app = spec .get ("components" , {}).get ("schemas" , {}).get ("app" )
221+ if isinstance (app , dict ):
222+ app .setdefault ("properties" , {}).setdefault (
223+ "project_id" , {"type" : "integer" , "nullable" : True }
224+ )
225+
226+ path = spec .get ("paths" , {}).get ("/api/v1/projects/{project_id}/resources" , {})
227+ schema = (
228+ path .get ("get" , {})
229+ .get ("responses" , {})
230+ .get ("200" , {})
231+ .get ("content" , {})
232+ .get ("application/json" , {})
233+ .get ("schema" , {})
234+ )
235+ for part in schema .get ("allOf" , []):
236+ props = part .get ("properties" )
237+ if isinstance (props , dict ) and "servers" in props :
238+ props .setdefault (
239+ "apps" ,
240+ {
241+ "type" : "array" ,
242+ "items" : {"$ref" : "#/components/schemas/app" },
243+ "nullable" : True ,
244+ },
245+ )
246+
247+
201248_RENAMED_PROPERTIES = {
202249 "ssh-keys" : "ssh_keys" ,
203250 "knowledgebases" : "knowledge_bases" ,
@@ -409,6 +456,7 @@ def normalize(spec):
409456 localize_tags (spec )
410457 nullable_response_id (spec )
411458 add_undocumented_account_status_fields (spec )
459+ add_undocumented_project_resource_fields (spec )
412460 rename_mismatched_properties (spec )
413461 relax_overstrict_required (spec )
414462 relax_apps_preset_required (spec )
0 commit comments