Skip to content
Merged
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
33 changes: 33 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Keep ACR build context small and prevent local secrets/artifacts from being uploaded.
**

!application/
!application/single_app/
!application/single_app/**
!docker-customization/
!docker-customization/**

.git/
.github/
.vscode/
.azure/
artifacts/
deployers/
docs/
functional_tests/
ui_tests/
scripts/

**/.env
**/.env.*
**/.venv/
**/venv/
**/__pycache__/
**/.pytest_cache/
**/*.pyc
**/*.pyo
**/*.pyd

application/single_app/flask_session/
application/single_app/uploaded_openapi_files/
application/single_app/instance/
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ applyTo: '**'

## 📍 **Location**
All functional tests are stored in: `.\simplechat\functional_tests\`
Check local.instructions.md for any additional instructions on test creation, execution, and maintenance.

## 📂 **Directory Structure**
The functional tests directory contains:
- **Python test files** (`test_*.py`) - Executable test scripts
- **JavaScript test files** (`test_*.js`) - Client-side/browser test scripts
- **Documentation files** (`*.md`) - Test documentation and fix summaries
- **route_tests/** - Route registration, Blueprint policy, and unauthenticated access contract tests
- **flask_session/** - Session data for tests requiring authenticated state

## 🎯 **When to Create Functional Tests**
Expand All @@ -25,6 +27,12 @@ The functional tests directory contains:
✅ **UI/UX Changes** - Test display logic, user interactions, data flow
✅ **Authentication/Security** - Verify access controls and data isolation

### **Always Update Route Tests For:**
✅ **New Flask Routes** - Add the route to `functional_tests/route_tests/` policy coverage
✅ **Route Moves or Renames** - Update Blueprint policy and endpoint-name expectations
✅ **Auth Policy Changes** - Update unauthenticated access expectations and role-policy checks
✅ **Public or External Routes** - Add explicit public/bearer-token policy entries and justify them in the tests

### **Test Categories:**
- **Integration Tests** - End-to-end functionality across multiple components
- **Regression Tests** - Prevent previously fixed bugs from returning
Expand Down Expand Up @@ -184,6 +192,7 @@ test_config = {
- **Plugin Integration Tests** → `functional_tests/` (follow `test_openapi_*.py` patterns)
- **Migration Tests** → `functional_tests/` (follow `test_migration.py` pattern)
- **UI/Display Tests** → `functional_tests/` (follow `test_*_display.py` patterns)
- **Route Policy Tests** → `functional_tests/route_tests/` for Blueprint registration, route security policy inventory, and unauthenticated access contracts

### **Documentation Requirements:**
- **For Bug Fixes**: Create accompanying `.md` file describing the issue and solution
Expand All @@ -205,6 +214,11 @@ for test in test_*.py; do python $test; done

# Run specific test pattern
python test_openapi_*.py

# Run route policy coverage tests
python route_tests/test_route_blueprint_policy_inventory.py
python route_tests/test_route_unauthenticated_policy_contract.py
python route_tests/test_route_policy_test_coverage.py
```

### **Integration with Development Workflow:**
Expand All @@ -230,4 +244,4 @@ python test_openapi_*.py
### **Maintenance:**
✅ **Regular Review** - Periodically review and update tests for relevance
✅ **Refactoring** - Extract common patterns into reusable utilities
✅ **Documentation Updates** - Keep test documentation current with code changes
✅ **Documentation Updates** - Keep test documentation current with code changes
10 changes: 8 additions & 2 deletions .github/instructions/python-lang.instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,16 @@ applyTo: '**/*.py'

- Files with routes MUST import `from swagger_wrapper import swagger_route, get_auth_security` and use the `@swagger_route(security=get_auth_security())` decorator for all route functions.

- New Flask routes MUST be registered on a `Blueprint`, not directly on `app`. Use `Blueprint(...).route(...)` or pass a `Blueprint` into the route module registrar. Do not add new `@app.route(...)` routes except for a reviewed framework/bootstrap exception.

- Each route-owning Blueprint MUST have an explicit `before_request` security policy using the shared helpers in `functions_authentication.py`, such as `login_required_blueprint()`, `user_required_blueprint()`, `admin_required_blueprint()`, or `external_api_required_blueprint()`. Mixed-policy Blueprints may use a login-only Blueprint guard and keep stricter route-specific decorators such as `@user_required`, `@admin_required`, `@control_center_required(...)`, `@feedback_admin_required`, or `@safety_violation_admin_required` on individual routes.

- Every route change MUST update or verify the route coverage tests in `functional_tests/route_tests/`. At minimum, run `python functional_tests/route_tests/test_route_blueprint_policy_inventory.py`, `python functional_tests/route_tests/test_route_unauthenticated_policy_contract.py`, and `python functional_tests/route_tests/test_route_policy_test_coverage.py` after adding, moving, or changing routes.

- When editing group workspace content, always use the `assert_group_role(user_id, group_id, allowed_roles=("Owner", "Admin", "DocumentManager", "User"))` function to verify the user's current membership and role in the group before allowing access to group-scoped resources or operations. This ensures that users cannot access or modify group content based solely on a potentially stale or tampered `activeGroupOid` reference. Roles should vary based on the level of access required for the operation, but should always include "Owner" and "Admin" as allowed roles.

- Unless otherwise indicated, all routes MUST include `@login_required` decorator.
- Unless otherwise indicated, all protected routes MUST be covered by a Blueprint-level login policy and/or an explicit route-level `@login_required` decorator. Public and external bearer-token routes must be listed in the route policy tests with their expected unauthenticated behavior.

- Always use f-strings for string interpolation. Ex: `f"User ID: {user_id}"` instead of `"User ID: {}".format(user_id)"`

- Never use `except:` without specifying the exception type. Always catch specific exceptions or use `except Exception as ex:` to capture the exception details. This also avoids accidentally catching system-exiting exceptions like `KeyboardInterrupt` or `SystemExit`.
- Never use `except:` without specifying the exception type. Always catch specific exceptions or use `except Exception as ex:` to capture the exception details. This also avoids accidentally catching system-exiting exceptions like `KeyboardInterrupt` or `SystemExit`.
9 changes: 7 additions & 2 deletions .github/prompts/prepare-for-pull-request.prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ Always run:
When Python route files changed:

- Run `python scripts/check_swagger_routes.py <changed-python-files>`.
- Verify every Flask route has `@swagger_route(security=get_auth_security())` immediately after `@app.route(...)`.
- Verify every Flask route is registered on a Blueprint, every route-owning Blueprint has an explicit `before_request` auth policy, and every route has `@swagger_route(security=get_auth_security())` immediately after the route decorator.
- Run the route policy coverage tests:
`python functional_tests/route_tests/test_route_blueprint_policy_inventory.py`
`python functional_tests/route_tests/test_route_unauthenticated_policy_contract.py`
`python functional_tests/route_tests/test_route_policy_test_coverage.py`

When JavaScript, HTML, or Python browser-rendering surfaces changed:

Expand All @@ -110,6 +114,7 @@ When HTML, CSS, or JavaScript changes affect UI behavior:
When bug fixes, new features, route changes, API changes, security changes, or UI workflow changes are present:

- Check for matching functional tests under `functional_tests/`.
- For route changes, check for matching route policy coverage under `functional_tests/route_tests/`.
- Run relevant functional tests with pytest or directly with Python, matching existing test style.
- If no relevant test exists, call this out and recommend the missing coverage.

Expand Down Expand Up @@ -158,4 +163,4 @@ If the user confirms PR creation:
- Include a PR body with summary, validation, tests, release notes status, and known risks.
- Return the PR URL.

If GitHub CLI is unavailable or unauthenticated, report the exact blocker and provide the PR title/body text for manual creation.
If GitHub CLI is unavailable or unauthenticated, report the exact blocker and provide the PR title/body text for manual creation.
31 changes: 17 additions & 14 deletions .github/prompts/route-authentication-audit.prompt.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,30 @@ argument-hint: "Target route files, endpoint prefixes, changed files, or route n
agent: "agent"
---

Audit the requested SimpleChat Flask routes for runtime authentication and role authorization decorator coverage. Treat `@swagger_route(security=get_auth_security())` as OpenAPI metadata only; it does not enforce authentication at runtime.
Audit the requested SimpleChat Flask routes for Blueprint-level runtime authentication, route-specific role authorization, and Swagger metadata coverage. Treat `@swagger_route(security=get_auth_security())` as OpenAPI metadata only; it does not enforce authentication at runtime.

Use the repository route and access-control guardrails in [.github/copilot-instructions.md](../copilot-instructions.md), [.github/instructions/python-lang.instructions.md](../instructions/python-lang.instructions.md), and [.github/instructions/broken-access-control-prevention.instructions.md](../instructions/broken-access-control-prevention.instructions.md). Use [scripts/check_swagger_routes.py](../../scripts/check_swagger_routes.py) and [scripts/check_broken_access_control.py](../../scripts/check_broken_access_control.py) where useful, but do not stop at deterministic checker output.

## Expected Route Patterns

- Every Flask route must be registered on a `Blueprint`. New `@app.route(...)` routes are not allowed except for a reviewed framework/bootstrap exception.
- Every route-owning Blueprint must have an explicit `before_request` policy using helpers such as `login_required_blueprint()`, `user_required_blueprint()`, `admin_required_blueprint()`, or `external_api_required_blueprint()`.
- Every Flask route must include `@swagger_route(security=get_auth_security())` immediately after the route decorator unless the route has a reviewed exception.
- Most non-admin application API routes should use `@login_required` followed by `@user_required` before the view function runs.
- Admin-namespaced or admin-only routes should use `@login_required` followed by `@admin_required`, or a more specific admin decorator such as `@feedback_admin_required` or `@safety_violation_admin_required` when the codebase already uses that role boundary.
- Most non-admin application API routes should be covered by `user_required_blueprint()` or by a login-only Blueprint guard plus route-level `@user_required` before the view function runs.
- Admin-namespaced or admin-only routes should be covered by `admin_required_blueprint()` or by a login-only Blueprint guard plus `@admin_required`, `@control_center_required(...)`, `@feedback_admin_required`, or `@safety_violation_admin_required` where the codebase already uses that role boundary.
- Group, public workspace, conversation, document, user profile, and plugin/action routes still need object-level authorization at the sensitive read or mutation boundary. Role decorators are not enough for object access.
- Feature flags such as `@enabled_required(...)`, Swagger metadata, frontend-only visibility, and route names are not substitutes for runtime auth decorators.
- Public routes should be rare and explicit. Validate likely public exceptions against nearby files and app behavior, such as health probes, static assets, login/auth callbacks, external API bearer-token routes, and documentation endpoints.
- Public routes should be rare and explicit. Validate likely public exceptions against nearby files and app behavior, such as health probes, static assets, login/auth callbacks, and external API bearer-token routes. Public, login-only, admin, and external bearer routes must be represented in `functional_tests/route_tests/`.

## Audit Workflow

1. Identify all Flask route functions in the target files, including routes registered on blueprints and routes inside `register_route_backend_*` functions.
2. Record each route path, HTTP method, endpoint function, and decorator stack in source order.
3. Classify each route as public, authenticated user, admin, specialized admin, external API, or unclear.
4. Compare the decorator stack against nearby routes in the same file and similar feature areas. Prefer local conventions over generic assumptions.
5. Flag routes that are missing runtime authentication, have only `@login_required` where the surrounding user-facing API pattern expects `@user_required`, or expose admin functionality without an admin decorator.
6. For each protected route, check that `@login_required` appears before role decorators in the source so unauthenticated API callers receive the login boundary before role checks.
7. For routes using object IDs from path, query, body, session settings, or plugin arguments, call out any missing ownership, membership, or relationship validation separately from decorator coverage.
1. Identify all Flask route functions in the target files, including routes registered on Blueprints and routes inside route registrar functions.
2. Record each route path, HTTP method, endpoint function, Blueprint name, Blueprint `before_request` policy, and route decorator stack in source order.
3. Classify each route as public, authenticated user, login-only, admin, specialized admin, external API, or unclear.
4. Compare the Blueprint policy and route decorator stack against nearby routes in the same file and similar feature areas. Prefer local conventions over generic assumptions.
5. Flag routes that are not on a Blueprint, Blueprints without a `before_request` auth policy, protected routes missing a login boundary, routes with only `login_required` where the surrounding user-facing API pattern expects `user_required`, or admin functionality without an admin/specialized admin boundary.
6. For routes using object IDs from path, query, body, session settings, or plugin arguments, call out any missing ownership, membership, or relationship validation separately from Blueprint/decorator coverage.
7. Update or verify `functional_tests/route_tests/test_route_blueprint_policy_inventory.py`, `functional_tests/route_tests/test_route_unauthenticated_policy_contract.py`, and `functional_tests/route_tests/test_route_policy_test_coverage.py` for any new, removed, moved, or policy-changed route.
8. Recommend the smallest remediation and the minimum regression test that would fail before the fix and pass after.

## Output Format
Expand All @@ -36,10 +38,11 @@ Return findings first, ordered by severity. For each finding include:
- `Severity`: Critical, Important, Moderate, or Low.
- `Route`: HTTP method and path.
- `Function`: file path and function name.
- `Blueprint Policy`: Blueprint name and `before_request` auth policy, or missing.
- `Current Decorators`: runtime auth decorators currently present.
- `Expected Decorators`: the route pattern that should be used.
- `Expected Policy`: the Blueprint/route pattern that should be used.
- `Impact`: what anonymous, non-user, or non-admin callers could do or learn.
- `Remediation`: exact decorator or object-level check to add.
- `Regression Test`: focused test coverage to prevent recurrence.
- `Regression Test`: focused test coverage to prevent recurrence, including route policy tests under `functional_tests/route_tests/` when route coverage changes.

If no issues are found, say that clearly and list any routes intentionally left public or login-only with the reason they are acceptable.
If no issues are found, say that clearly and list any routes intentionally left public or login-only with the reason they are acceptable.
22 changes: 21 additions & 1 deletion .github/workflows/swagger-route-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ on:
paths:
- 'application/single_app/**/*.py'
- 'scripts/check_swagger_routes.py'
- 'functional_tests/route_tests/**/*.py'
- '.github/instructions/python-lang.instructions.md'
- '.github/instructions/location_of_functional_tests.instructions.md'
- '.github/prompts/route-authentication-audit.prompt.md'
- '.github/prompts/prepare-for-pull-request.prompt.md'
- '.github/workflows/swagger-route-check.yml'

jobs:
Expand All @@ -34,6 +39,14 @@ jobs:
route_python:
- 'application/single_app/**/*.py'
- 'scripts/check_swagger_routes.py'
route_policy:
- 'application/single_app/**/*.py'
- 'functional_tests/route_tests/**/*.py'
- '.github/instructions/python-lang.instructions.md'
- '.github/instructions/location_of_functional_tests.instructions.md'
- '.github/prompts/route-authentication-audit.prompt.md'
- '.github/prompts/prepare-for-pull-request.prompt.md'
- '.github/workflows/swagger-route-check.yml'

- name: Run swagger route validation
env:
Expand All @@ -47,4 +60,11 @@ jobs:
echo "Changed Python files:"
printf '%s\n' "$CHANGED_ROUTE_FILES" | tr ' ' '\n'

python scripts/check_swagger_routes.py $CHANGED_ROUTE_FILES
python scripts/check_swagger_routes.py $CHANGED_ROUTE_FILES

- name: Run route policy validation
if: steps.changed-files.outputs.route_policy_any_changed == 'true'
run: |
python functional_tests/route_tests/test_route_blueprint_policy_inventory.py
python functional_tests/route_tests/test_route_unauthenticated_policy_contract.py
python functional_tests/route_tests/test_route_policy_test_coverage.py
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ scripts/me.json


deploy.zip
.azure/deployment-plan.md
application/teams_app/manifest.json
application/teams_app/*.zip

local_storage_state.json
local_storage_state.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Use list_resource_groups() for resource groups under a given subscription.
Retrieve current and historical charges.
Generate cost forecasts for future periods.
Display budgets and cost alerts.
Produce Matplotlib (pyplot) visualizations for actual, forecast, or combined datasets, using only the dedicated graphing functions.
Produce SimpleChat dynamic inline charts for actual, forecast, or combined datasets, using only the dedicated graphing functions.
Use run_data_query(...) exclusively for data retrieval.
When a visualization is requested, in the same turn:
Execute run_data_query(...) with the appropriate parameters.
Expand Down Expand Up @@ -47,14 +47,15 @@ Output Rules
Do not truncate data unless the user explicitly requests it.
When displaying tables, render full Markdown tables with all rows/columns.
When producing CSV output, return the full CSV without truncation.
Do not embed binary data or raw images. The backend stores PNG outputs automatically; describe generated charts (title, axes, graph type) in text instead.
Do not embed binary data or raw images. Use the `chart_markdown` returned by plot_chart so the chat UI renders a dynamic chart.
For every visualization request:
Call run_data_query(...) to obtain rows, csv, and plot_hints.
Immediately call plot_chart(...) (or plot_custom_chart(...)) with:
conversation_id
data = the returned rows or csv
x_keys/y_keys chosen from plot_hints
An appropriate graph_type from the recommended options
Return or include the `chart_markdown` value from the plot result in the response.
Do not ask the user to restate parameters already inferred or used.
Error Handling and Recovery
Classify errors using: MissingParameter, BadDateFormat, UnknownEnum, NotFound, Authz, Throttle, ServiceError.
Expand Down
Loading
Loading