Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,15 @@

## 🔍 **Test Discovery & Reuse**

### Import Lifecycle and Assertion Safety

- Execute setup, mutations, database/cache operations, callbacks, and any getter that can initialize or refresh state **before** an assertion. Assert on the captured result. Python removes `assert` expressions under `-O`; pytest rewriting does not justify side effects in them.
- For example, use `saved = update_settings(changes)` followed by `assert saved`, not `assert update_settings(changes)`.
- Import-cycle regressions need fresh-process tests of real modules, with network calls blocked. Include both import orders, early bootstrap, web/scheduler wiring, and failure paths; a fake `config` module or an AST-only function test can conceal the exact cycle being tested.
- Test normal and optimized Python when verifying that required test operations cannot disappear. An optimized run is not proof of assertion coverage; use explicit checks in its subprocess probe.

Check warning on line 129 in .github/instructions/location_of_functional_tests.instructions.md

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains dynamic execution, persistence, or system access marker. Recommendation%3A Do not execute changed lifecycle scripts or installers while this finding is unresolved.
- Restore every injected module, callback, environment variable, and monkeypatch after a test. Prefer scoped fixtures/context managers over persistent `sys.modules` replacements.
- Read each CodeQL alert's exact rule and path. Cover the full affected pattern, not just the one flagged line, and rerun the relevant integration tests.

### **Before Creating New Tests:**
1. **Search existing tests**: `grep -r "test_.*{feature}" functional_tests/`
2. **Check for similar patterns**: Look for tests in the same feature area
Expand Down
13 changes: 12 additions & 1 deletion .github/instructions/python-lang.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,18 @@

## Rule: Imports Must Be Organized and at the Top of the File !IMPORTANT

- IMPORTANT: `from` and `import` statements MUST be grouped at the top of the document after the module docstring, unless otherwise indicated by the code writer or for performance reasons in which case the import should be as close as possible to the usage with a comment explaining why the import is not at the top of the file. CodeQL hammers us on this in the findings. If you find imports that are not at the top of the file, move them to the top and add a comment if there is a reason they cannot be moved. This also helps prevent multuple imports of the same module in different places which can lead to confusion and maintenance issues.
- Group imports after the module docstring by default. Before moving or adding any import, trace the dependency chain and initialization timing. Do not mechanically hoist a local import: that can turn a deferred dependency into a startup failure. Local imports require a concrete lifecycle or performance justification.

## Rule: Preserve Settings and Bootstrap Dependency Boundaries

- A local import delays execution; it does **not** remove a cycle in the dependency graph. Never claim a cycle is fixed merely because the import moved inside a function, or hide it with `try/except ImportError`, `getattr`, or a success-shaped fallback.

Check warning on line 19 in .github/instructions/python-lang.instructions.md

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains secret or sensitive data source marker. Recommendation%3A Pair this source with any nearby network, logging, serialization, or process execution sink before approving.
- `config.py` constructs Azure clients and imports logging. Treat `config`, `functions_settings`, logging, cache modules, and Redis/Key Vault helpers as a startup dependency chain, not interchangeable utility modules.
- Configure cache/client behavior from the **settings object already supplied by the caller**. Do not import `config`, `cosmos_settings_container`, or another settings owner back into a lower-level cache helper to rediscover that configuration.

Check warning on line 21 in .github/instructions/python-lang.instructions.md

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains secret or sensitive data source marker. Recommendation%3A Pair this source with any nearby network, logging, serialization, or process execution sink before approving.
- Pass storage handles, factories, and logging callbacks explicitly from the owning settings/bootstrap layer. Keep those runtime objects separate from the settings dictionary: never persist them, copy them into Redis settings payloads, or pass them to the browser.

Check warning on line 22 in .github/instructions/python-lang.instructions.md

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.

Check warning on line 22 in .github/instructions/python-lang.instructions.md

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains secret or sensitive data source marker. Recommendation%3A Pair this source with any nearby network, logging, serialization, or process execution sink before approving.
- Keep `app_settings_cache.py` and `app_settings_store.py` below their owners in the dependency graph. Neither may directly or transitively import `config`, `functions_settings`, `functions_appinsights`, or the configuration-dependent Redis factory. The web app and scheduler supply the factory; the settings owner supplies initialized storage dependencies.

Check warning on line 23 in .github/instructions/python-lang.instructions.md

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains secret or sensitive data source marker. Recommendation%3A Pair this source with any nearby network, logging, serialization, or process execution sink before approving.
- Use `import app_settings_cache` and module-qualified access for dynamically configured accessors. Importing an accessor by value can retain the pre-initialization `None` or an obsolete implementation.
- On bootstrap changes, inspect both normal web startup and the scheduler, Redis-enabled/disabled/error paths, and calls that occur before initialization. An uninitialized accessor must not silently import its owner or initialize cloud resources.

Check warning on line 25 in .github/instructions/python-lang.instructions.md

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.
- Validate with real-module cold imports in fresh processes and blocked network access, plus static dependency checks that include function-local imports. Stub external I/O, not the module boundary under test. Compilation and AST-extracted function tests alone do not prove import safety.

Check warning on line 26 in .github/instructions/python-lang.instructions.md

View workflow job for this annotation

GitHub Actions / malicious-pr-security-review

Important - Changed line contains security control, sanitization, or audit marker. Recommendation%3A Confirm the change does not weaken auth, CSRF, CSP, XSS defenses, settings sanitization, redaction, audit logging, or tests.

## Rule: Indentation, Logging, and Decorators
- Use 4 spaces per indentation level. No tabs.
Expand Down
8 changes: 8 additions & 0 deletions .github/prompts/prepare-for-pull-request.prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,14 @@ Always run:
- A Python syntax compile check for changed Python files, and at minimum the Python files under `application/single_app` that GitHub compiles.
- Any new or changed test files directly.

When imports, settings/cache initialization, or logging bootstrap changed:

- Trace the complete dependency chain, including function-local imports and both web and scheduler startup. A local import is not proof that a cycle was removed.
- Verify lower-level cache helpers use the caller's settings object and explicitly supplied runtime dependencies; do not let them import `config` or the settings owner back into the cache.
- Run `functional_tests/test_app_settings_import_boundaries.py` and the relevant real-module bootstrap tests with network access blocked. Do not rely only on syntax compilation, AST-extracted functions, or stubs for modules at the boundary under test.
- Inspect test assertions for side effects, including getters that populate caches. Execute those operations before assertions and assert only on their results.
- Review CodeQL alert annotations and review threads, not only the workflow job conclusion. A successful analysis job can still publish blocking findings. Do not mark those findings resolved based on compilation alone.

When Python route files changed:

- Run `python scripts/check_swagger_routes.py <changed-python-files>`.
Expand Down
6 changes: 3 additions & 3 deletions application/single_app/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,11 +285,11 @@ def initialize_application(force=False):
print("Initializing application...")
settings = get_settings(use_cosmos=True)
redis_hostname = settings.get('redis_url', '').strip().split('.')[0]
app_settings_cache.configure_app_cache(
configure_application_cache(
settings,
get_redis_cache_infrastructure_endpoint(redis_hostname)
get_redis_cache_infrastructure_endpoint(redis_hostname),
redis_client_factory=functions_redis_client.create_redis_client,
)
app_settings_cache.update_settings_cache(settings)
sanitized_settings = sanitize_settings_for_logging(settings)
debug_print(f"DEBUG:Application settings: {sanitized_settings}")
sanitized_settings_cache = sanitize_settings_for_logging(app_settings_cache.get_settings_cache())
Expand Down
Loading
Loading