FEAT: Security & Azure deployment for CoPyRIT GUI#1554
FEAT: Security & Azure deployment for CoPyRIT GUI#1554adrian-gavrila wants to merge 161 commits intomicrosoft:mainfrom
Conversation
- Add run_initializers_async to pyrit.setup for programmatic initialization - Switch AIRTInitializer to Entra (Azure AD) auth, removing API key requirements - Add --config-file flag to pyrit_backend CLI - Use PyRIT configuration loader in FrontendCore and pyrit_backend - Update AIRTTargetInitializer with new target types Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add conversation_stats model and attack_result extensions - Add get_attack_results with filtering by harm categories, labels, attack type, and converter types to memory interface - Implement SQLite-specific JSON filtering for attack results - Add memory_models field for targeted_harm_categories - Add prompt_metadata support to openai image/video/response targets - Fix missing return statements in SQLite harm_category and label filters Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add attack CRUD routes with conversation management - Add message sending with target dispatch and response handling - Add attack mappers for domain-to-DTO conversion with signed blob URLs - Add attack service with video remix support and piece persistence - Expand target service and routes with registry-based target management - Add version endpoint with database info Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add attack-centric chat UI with multi-conversation support - Add conversation panel with branching and message actions - Add attack history view with filtering - Add labels bar for attack metadata - Add target configuration with create dialog - Add message mapper utilities for backend/frontend translation - Add video playback support with signed blob URLs - Add InputBox with attachment support and auto-expand - Update dev.py with --detach, logs, and process management - Add e2e tests for chat, config, and flow scenarios Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ssibility Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… into romanlutz/backend-attack-api
- Rename supports_multiturn_chat to supports_multi_turn to align with TargetCapabilities field - Use target_obj.capabilities.supports_multi_turn instead of isinstance check - Update tests to set capabilities on mock targets Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…_async Reverts the separate run_initializers_async function and restores the original pattern where run_scenario_async calls initialize_pyrit_async a second time with initializers. This avoids a larger refactor. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Catch ValueError in get_conversation_messages route, return 400 - Fix target_registry_name field description - Simplify redundant except (ValueError, Exception) to except Exception - Fix docstring: converter_classes -> converter_types - Fix test assertions: converter_types -> converter_classes (matches memory API) - Remove dead tests for deleted helper methods - Restore azure_openai_video target config to match main Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Move _inject_video_id_from_history and _strip_video_pieces methods from AttackService to OpenAIVideoTarget where they belong - Update _validate_request to accept video_path pieces and check for video_path+image_path conflicts - Add ValueError when video_path is present but no video_id can be resolved - Add 7 unit tests for the inject/strip logic - Remove video-specific logic from attack_service._send_and_store_message Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adds test_remix_with_text_and_video_path_pieces which covers the full send_prompt_async flow when the frontend sends both a text piece and a video_path piece with matching video_id metadata (the UI remix flow). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep Python and uv installed so seeded tests can be re-enabled once CI secrets are configured. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
These tests call real backend endpoints (/api/health, /api/targets, /api/attacks) and timeout in CI where only Vite runs. Tagging them @seeded excludes them from the mock project. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… service principal auth - start.sh: Use pyrit_backend CLI instead of raw uvicorn so config file, initializers, operator/operation labels are loaded - run_pyrit_docker.py: Mount ~/.pyrit/.pyrit_conf if it exists - docker-compose.yaml: Add .pyrit_conf volume mount for gui service - QUICKSTART.md: Document service principal auth for Docker (AZURE_TENANT_ID/CLIENT_ID/CLIENT_SECRET in .env) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…pal locally - start.sh: Clean startup, no interactive az login attempts - QUICKSTART.md: Document managed identity (Azure infra) and service principal (local Docker) as the two auth paths - run_pyrit_docker.py: Mount ~/.azure/ for cases where it helps - docker-compose.yaml: Mount ~/.azure/ volume Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add missing __init__ docstring (ruff D107) - Simplify conditional return (ruff SIM103) - Use ASGIApp type instead of object for middleware app param (mypy) - Add type parameters to bare dict types (mypy type-arg) - Annotate group_ids to avoid returning Any (mypy no-any-return) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add enablePrivateEndpoint toggle to main.bicep (default true) - Conditionalize PE/DNS/VNet resources on the toggle - Toggle publicNetworkAccess based on PE setting - Remove hardcoded second IP restriction rule - Fix MSAL scope from .default to /access for custom API scope - Update README: ApplicationGroup auth, CGNAT caveat, production hardening - Document groups overage workaround and group assignment steps Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add SecurityHeadersMiddleware (CSP, HSTS, X-Frame-Options, etc.) - Gate Swagger/OpenAPI behind PYRIT_DEV_MODE - Tighten CORS to explicit method/header lists - Remove docs paths from public auth bypass - Add gui-deploy.yml ADO pipeline (variable group-based, no secrets in YAML) - Rewrite infra/README.md for clarity (combined diagram, TOC, restructured sections) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Prevents ADO from validating copyrit-gui-prod variable group when deployToProd is false. Template expressions are evaluated at parse time and exclude the entire stage block from the YAML. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
azureSubscription is validated at YAML parse time, before variable groups are loaded. Move the service connection name to a top-level pipeline variable so ADO can resolve it during compilation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Role assignments (AcrPull, Key Vault Secrets User) require Microsoft.Authorization/roleAssignments/write which is blocked by ABAC conditions in this tenant. These are one-time manual steps documented in infra/README.md Post-Deployment. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add frontend/.npmrc pinning npm registry (resolves CFS0001) - Remove default value from BASE_IMAGE ARG in docker/Dockerfile (resolves CSSC unapproved image warning — all callers already pass --build-arg explicitly) - Await handleRedirectPromise() before selecting active account in AuthProvider to fix first-visit auth failure Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Switch frontend/.npmrc from npmjs.org to the copyrit-npm Azure Artifacts feed to satisfy CSSC CFS0003 policy. Add NPM_CONFIG_REGISTRY env var in Dockerfile to override for Docker builds (no ADO auth context inside containers). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Expand Security > Data & Supply Chain section with npm feed and Docker base image details. Add npm registry override note to Technical Notes. Trim inline comments to brief pointers to the README. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Simplifies local dev and Docker builds — no ADO auth needed for npm install. Accepts CFS0003 warning as tradeoff. Removes NPM_CONFIG_REGISTRY override from Dockerfile and Artifacts feed references from README. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- ENTRA_ALLOWED_GROUP_ID -> ENTRA_ALLOWED_GROUP_IDS (comma-separated) - Backend checks set intersection for group membership - Remove OID-based authorization (all access via security groups) - Rename bicep param allowedGroupObjectId -> allowedGroupObjectIds - Update README, pipeline YAML, and ARM template Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
img-src and media-src now permit https://*.blob.core.windows.net so inline images and video/audio from Azure Blob render correctly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Add Development Workflow section (local dev, auth options, promotion flow) - Fix pipeline: allowedGroupObjectId -> allowedGroupObjectIds (matches ADO var) - Quote comma-separated group IDs in bash to prevent shell splitting - Document nested group limitation, app roles, AADSTS50105 troubleshooting - Document appRoleAssignmentRequired as built-in hardening - Update CSP description for blob storage allowance Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
….com - Rewrite legacy graph.windows.net endpoint to graph.microsoft.com/v1.0 - Add @odata.nextLink pagination for large group lists - Azure AD Graph was retired in 2023; this ensures overage resolution continues working for users in >200 groups Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Replace internal resource names, CIDRs, policy IDs with placeholders - Remove SFI-SM, CFS0001, team-specific tag values - Fix SQL output message to include -identity suffix - Add KV troubleshooting, quick-start, environments table to README Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| @@ -0,0 +1,229 @@ | |||
| # CI/CD pipeline for CoPyRIT GUI deployment. | |||
There was a problem hiding this comment.
We should put all the ADO pipelines in a dedicated folder at some point...
@azure/msal-react@5.0.7 requires react@^19.2.1 but the project uses react@^18.3.1, causing ERESOLVE failures in CI. Adding legacy-peer-deps=true to .npmrc resolves the conflict. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Tests for msalConfig.ts (9 tests): - getApiScopes: default vs client-specific scopes - buildLoginRequest: wraps scopes for MSAL loginRedirect - buildMsalConfig: assembles MSAL Configuration from AuthConfig - fetchAuthConfig: success, caching, non-OK response, network error Tests for AuthProvider.tsx (10 tests): - Loading state, auth disabled (empty config), OR branch - Error handling (Error vs non-Error) - Full MSAL init, redirect account, cached account fallback - LoginRedirect rendering and failure handling Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| if "graph.windows.net" in endpoint: | ||
| # Legacy format: https://graph.windows.net/{tenant}/users/{oid}/getMemberObjects | ||
| # Graph format: https://graph.microsoft.com/v1.0/me/getMemberObjects | ||
| endpoint = "https://graph.microsoft.com/v1.0/me/getMemberObjects" |
There was a problem hiding this comment.
I'm wondering if we have a way to test if this path gets hit (i.e. too many groups -> call graph to get group memberships) to validate this logic is working as expected (group overage)
I believe in order to call this endpoint, we'd need a token issued for calling graph, (i.e scope must be something like https://graph.microsoft.com/<scope> but the token we send to this backed server is the one we fetch on the front end, and the audience for it is <copyrit-client-id>/access ... so calling graph with with throws a 401.
I think the reason we never see this in tests env is the group claim is always populated with the group that warranted our access to the app. (maybe this happened after we "require assignment" on the app? I remember at some point we did have the _claim_sources somewhere)
There was a problem hiding this comment.
thinking more about this, I'm wondering if we need to even have a token whose audience is the copyRIT app, if all we're doing is checking group memberships of a user?
and instead, simply get a graph token from the beginning (ie. in the front end, set "loginScope ="https://graph.microsoft.com/User.Read"
and not even expose the access scope on our app and try to get a token with that scope. that scope itself is not used after all. it looks like all we're using it for is, in conjunction with this fact:
Access tokens include the
groupsclaim when the app manifest hasgroupMembershipClaims: "SecurityGroup"configured.
to get a token that has group memberships included in it
(this could be a follow-up optimization, and will probably make our token usable against graph.microsoft.com if we want to handle group overage)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
| */ | ||
| export function getApiScopes(clientId: string): string[] { | ||
| if (!clientId) return ['openid', 'profile', 'email'] | ||
| return [`${clientId}/access`] |
There was a problem hiding this comment.
from our chat, I think this might be more optimal and cleaner, and also address my other comment:
- add back Microsoft Graph's User.Read delegated API permission to the app registration
- in getApiScopes in the frontend, request a token with this scope
["https://graph.microsoft.com/User.Read"] - then group resolution will work okay (because the token that's sent to our backend will have graph as its audience)
- now you can remove
accessfrom "exposed APIs" of the app because it's not used anyways - we can also remove the "App Roles" (Copyrit.Dev.All) , and instead assign those 2 groups to the ServicePrincipal (Enterprise Application) with the default role (we can do that even right now, because we don't check this role value in user claims)
Description
Adds authentication, security middleware, Azure infrastructure-as-code, and a CI/CD pipeline for deploying the CoPyRIT GUI as an
Azure Container App.
Authentication
@azure/msal-browser— no client secrets needed. NewAuthProviderandmsalConfigcomponents;Axios interceptor attaches Bearer tokens automatically.
pyrit/backend/middleware/auth.py) validates tokens against Entra ID JWKS. Supports multi-groupauthorization via
allowedGroupObjectIds. Auth gracefully disables when env vars are unset (local dev)./api/auth/me) for the frontend to display the signed-in user.Security middleware
SecurityHeadersMiddleware: CSP, HSTS (prod only), X-Frame-Options, X-Content-Type-Options, Referrer-Policy, Permissions-Policy,Cache-Control (
no-storeon API routes). Swagger disabled in production.Infrastructure (Bicep)
infra/main.bicep+ ARM template: provisions Container App Environment, ACR (optional), Log Analytics, Application Insights(opt-in OTel), User-Assigned Managed Identity, and VNet/Private Endpoint (opt-in).
.envinjection — no secrets baked into the container.infra/README.md: full deployment guide covering prerequisites, Entra setup, RBAC grants, and post-deployment steps.CI/CD
gui-deploy.yml: ADO pipeline — build → push to ACR → deploy to test → opt-in prod promotion.Docker
Dockerfile,start.sh, anddocker-compose.yamlfor managed identity auth on Azure and service principal auth locally..pyrit_conf_examplewith operator/operation label examples.Tests and Documentation
frontend/src/App.test.tsxandfrontend/src/services/api.test.tsupdated to cover auth integration.infra/README.mdserves as the deployment guide with full prerequisites, step-by-step setup, post-deployment checklist, andteardown instructions.
docker/QUICKSTART.mdupdated with auth configuration and local dev workflow.