Skip to content

refactor: opt-in app-scoped registry isolation (#381) - #388

Merged
yeongseon merged 1 commit into
mainfrom
refactor/381-isolate-scanned-registry
Aug 10, 2026
Merged

refactor: opt-in app-scoped registry isolation (#381)#388
yeongseon merged 1 commit into
mainfrom
refactor/381-isolate-scanned-registry

Conversation

@yeongseon

Copy link
Copy Markdown
Owner

Summary

  • Add an opt-in --isolate-app CLI flag that scans the --app module:variable FunctionApp into a fresh, app-scoped OpenAPIRegistry instead 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).
  • Thread a registry parameter through scan_endpoint_metadata, register_openapi_metadata, generate_openapi_spec, and collect_spec_warnings.
  • In isolated mode, each discovered handler's canonical @openapi entry is seeded (deep-copied) from the global registry before reconciliation, so plain @openapi handlers are not dropped. Programmatic register_openapi_metadata entries (_function_id="programmatic.*") are never seeded.
  • Default behaviour (shared global registry) is fully unchanged — the flag is off by default.

Acceptance

  • --isolate-app requires module:variable; a bare module warns and falls back to the global registry.
  • Isolated scan documents only the selected app's routes; other apps' global @openapi entries do not leak.
  • Discovery warnings are recorded on the selected registry only.
  • Programmatic entries excluded from isolated specs.
  • Global default flow unchanged; regression tests added.
  • make check-all green, coverage ≥95%.

Closes #381

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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-app and 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 @openapi entries 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-app is used without module: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.

Comment thread src/azure_functions_openapi/decorator.py Outdated
Comment thread src/azure_functions_openapi/bridge.py Outdated
Comment on lines +469 to +476
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
@yeongseon

Copy link
Copy Markdown
Owner Author

Rebased onto main (resolved conflicts in bridge.py/test_spec_warnings.py: empty-discovery skipped guard from #380 and app-scoped isolation from #381 now coexist). Addressed both Copilot review comments: (1) removed the duplicated security_scheme line under the registry: param docstring in decorator.py; (2) _seed_canonical_entry no longer holds both registry locks simultaneously — it snapshots matching global entries (deep-copied) under the global lock, releases it, then writes into the target registry under its own lock, eliminating the deadlock/contention risk. make check-all green.

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.

refactor(registry): isolate scanned metadata to the selected application

3 participants