refactor: opt-in app-scoped registry isolation (#381) - #388
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds an opt-in CLI mode to generate OpenAPI specs scoped to a single selected FunctionApp (--app module:variable) by scanning into an app-local OpenAPIRegistry, preventing cross-app route leakage when multiple apps are imported into the same process.
Changes:
- Introduces
--isolate-appand threads an optional registry through the CLI flow so spec generation + warning collection use the selected registry. - Updates endpoint scanning to support an injected registry, including seeding canonical
@openapientries from the global registry into the isolated registry (excluding programmatic entries). - Adds regression tests covering isolated vs global behavior, warning isolation, and CLI behavior when
--isolate-appis used withoutmodule:variable.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| tests/test_spec_warnings.py | Adds tests for isolated registry behavior and CLI --isolate-app end-to-end behavior. |
| src/azure_functions_openapi/decorator.py | Extends register_openapi_metadata() to accept an optional target registry for programmatic entries. |
| src/azure_functions_openapi/cli.py | Adds --isolate-app flag and passes an app-scoped registry through scanning/spec/warnings when enabled. |
| src/azure_functions_openapi/bridge.py | Adds registry injection to scanning and seeds per-handler canonical decorator entries into isolated registries. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if function_id.startswith("programmatic."): | ||
| return | ||
| with _global_registry.lock, reg.lock: | ||
| for key, entry in _global_registry.entries.items(): | ||
| if entry.get("_function_id") != function_id: | ||
| continue | ||
| if reg.get(key) is None: | ||
| reg.set(key, copy.deepcopy(entry)) |
Add --isolate-app CLI flag and a registry parameter threaded through scan_endpoint_metadata, register_openapi_metadata, generate_openapi_spec, and collect_spec_warnings so multiple FunctionApps imported in one process can each generate a spec limited to their own routes. Isolated scans seed each discovered handler's canonical @openapi entry from the global registry (deep-copied); programmatic register_openapi_metadata entries are never seeded. Default global-registry behaviour is unchanged. Closes #381
|
Rebased onto |
bc5052d to
c2cd452
Compare
Summary
--isolate-appCLI flag that scans the--app module:variableFunctionApp into a fresh, app-scopedOpenAPIRegistryinstead of the shared global one, so several apps imported in one process each generate a spec limited to their own routes (no cross-app leakage).registryparameter throughscan_endpoint_metadata,register_openapi_metadata,generate_openapi_spec, andcollect_spec_warnings.@openapientry is seeded (deep-copied) from the global registry before reconciliation, so plain@openapihandlers are not dropped. Programmaticregister_openapi_metadataentries (_function_id="programmatic.*") are never seeded.Acceptance
--isolate-apprequiresmodule:variable; a bare module warns and falls back to the global registry.@openapientries do not leak.make check-allgreen, coverage ≥95%.Closes #381