Skip to content

Commit af94c90

Browse files
brandom-msftgithub-actions[bot]Copilot
authored
Reconcile public with private after sync outage (2026-06-02..06-03) (#749)
Reconcile public with private after 2026-06-02..06-03 sync outage The auto-sync pipeline has been blocked since 2026-06-02 due to a chain of events kicked off by an out-of-band direct merge on public (PR #745 - #745). That left public ahead of private on the autopilot/* rename and seed-marks recovery refused to synthesize marks because the trees diverged. PR microsoft-foundry/foundry-samples-pr#429 reconciled the rename semantically on private; PR microsoft-foundry/foundry-samples-pr#431 normalized the file bytes (LF vs CRLF) so the autopilot/* trees were byte-equal across both sides. But during the 24+ hour sync outage, multiple legitimate PRs landed on private and never propagated to public: - PR #382 voicelive: foreground-background-agents-responses-voicelive - PR #400 agent-framework: 14-browser-automation-agent updates - PR #407 bring-your-own: optimization samples - PR #415 voicelive: hotel-booking-invocations-voicelive - PR #416 hosted-agents: SUPPORTED_TOOLBOX_SCENARIOS update - PR #417 bicep: private-network-standard-agent-setup updates - PR #420 bring-your-own: browser-automation updates - PR #422 bring-your-own: invocations/github-copilot update This PR brings public's tree byte-equal with private's tree (origin/main SHA ae0d13b) over the sync include-set, so the next sync-to-public dispatch with seed_from_public_sha can rebuild the marks cache and resume automated forward sync. ADO: https://msdata.visualstudio.com/Vienna/_workitems/edit/5331347 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent ad7fe28 commit af94c90

42 files changed

Lines changed: 2265 additions & 77 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

infrastructure/infrastructure-setup-bicep/15-private-network-standard-agent-setup/README.md

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,19 @@ To use an existing Cosmos DB for NoSQL resource, set cosmosDBResourceId paramete
206206
To use an existing Azure AI Search resource, set aiSearchServiceResourceId parameter to the full Azure resource Id of the target Azure AI Search resource.
207207
- param aiSearchResourceId string = /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Search/searchServices/{searchServiceName}
208208

209+
> **AAD auth is required on the existing service.** Foundry connects to Search with
210+
> `authType=AAD`, so the service must accept Microsoft Entra (AAD) data-plane tokens
211+
> (local auth disabled, or `authOptions` includes an `aadOrApiKey` block). A new
212+
> Search service defaults to API-keys-only, which rejects AAD and makes agents fail
213+
> with HTTP 403. When you bring an existing service, the template checks its live
214+
> state and stops the deployment early with the exact fix command if it is
215+
> API-keys-only. To enable AAD before deploying:
216+
> ```bash
217+
> az search service update --name <search-name> --resource-group <search-rg> \
218+
> --subscription <search-sub> --auth-options aadOrApiKey \
219+
> --aad-auth-failure-mode http401WithBearerChallenge
220+
> ```
221+
209222
210223
4. **Use an existing Azure Storage account**
211224
@@ -707,8 +720,19 @@ description. Those stay exactly as they are.
707720
deployment). Network security is account-scoped, so once the account is
708721
injected, every project under it inherits agent-subnet security. You do not
709722
re-run the full template per project.
710-
4.**AI Search allows AAD auth** (`authOptions` is not set to API-keys-only), so
711-
the AAD connection can be used.
723+
4. ✅ **AI Search allows AAD auth.** Foundry connects to Search with `authType=AAD`,
724+
so the service must accept Microsoft Entra (AAD) data-plane tokens. A service is
725+
ready when local auth is disabled (RBAC-only) or its `authOptions` includes an
726+
`aadOrApiKey` block. The Azure default for a new Search service is API-keys-only,
727+
which rejects AAD and makes agents fail with HTTP 403. This template now checks
728+
the live state and stops the deployment early with the exact fix command if the
729+
service is API-keys-only, so you will not get a silent broken connection. To
730+
enable AAD up front:
731+
```bash
732+
az search service update --name <search-name> --resource-group <search-rg> \
733+
--subscription <search-sub> --auth-options aadOrApiKey \
734+
--aad-auth-failure-mode http401WithBearerChallenge
735+
```
712736
5. ✅ **Run the deployment in the account's resource group.** Like
713737
`add-project.bicep`, this template operates on the project and capability host
714738
at the deployment resource group, so deploy into the resource group that holds

infrastructure/infrastructure-setup-bicep/15-private-network-standard-agent-setup/add-existing-project.bicep

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,18 @@ resource cosmosDB 'Microsoft.DocumentDB/databaseAccounts@2024-11-15' existing =
9595
scope: resourceGroup(cosmosDBSubscriptionId, cosmosDBResourceGroupName)
9696
}
9797

98+
// Fail fast when the bring-your-own AI Search service rejects Microsoft Entra
99+
// (AAD) data-plane auth (apiKeyOnly). The project connection below uses
100+
// authType=AAD, so an unpatched service leaves agents failing with 403.
101+
module validateSearchAadAuth 'modules-network-secured/validate-search-aad-auth.bicep' = {
102+
name: 'validate-search-aad-auth-${projectNameLower}-deployment'
103+
params: {
104+
aiSearchName: existingAiSearchName
105+
aiSearchResourceGroupName: aiSearchResourceGroupName
106+
aiSearchSubscriptionId: aiSearchSubscriptionId
107+
}
108+
}
109+
98110
// Add the agent connections to the EXISTING project (no project is created)
99111
module aiProject 'modules-network-secured/ai-existing-project-connections.bicep' = {
100112
name: 'ai-existing-${projectNameLower}-deployment'
@@ -118,6 +130,9 @@ module aiProject 'modules-network-secured/ai-existing-project-connections.bicep'
118130
azureStorageConnectionName: azureStorageConnectionNameEffective
119131
aiSearchConnectionName: aiSearchConnectionNameEffective
120132
}
133+
dependsOn: [
134+
validateSearchAadAuth
135+
]
121136
}
122137

123138
module formatProjectWorkspaceId 'modules-network-secured/format-project-workspace-id.bicep' = {

infrastructure/infrastructure-setup-bicep/15-private-network-standard-agent-setup/azuredeploy.json

Lines changed: 72 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
"_generator": {
66
"name": "bicep",
77
"version": "0.43.8.12551",
8-
"templateHash": "4437106568758821389"
8+
"templateHash": "14993641389519398529"
99
}
1010
},
1111
"parameters": {
@@ -330,7 +330,7 @@
330330
"_generator": {
331331
"name": "bicep",
332332
"version": "0.43.8.12551",
333-
"templateHash": "1854398928287753773"
333+
"templateHash": "2638034982264747132"
334334
}
335335
},
336336
"parameters": {
@@ -627,7 +627,7 @@
627627
"_generator": {
628628
"name": "bicep",
629629
"version": "0.43.8.12551",
630-
"templateHash": "8011604849876491209"
630+
"templateHash": "11782697558662523210"
631631
}
632632
},
633633
"parameters": {
@@ -861,7 +861,10 @@
861861
}
862862
}
863863
}
864-
}
864+
},
865+
"dependsOn": [
866+
"[extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', subscription().subscriptionId, parameters('vnetResourceGroupName')), 'Microsoft.Resources/deployments', format('agent-subnet-{0}', uniqueString(deployment().name, parameters('agentSubnetName'))))]"
867+
]
865868
}
866869
],
867870
"outputs": {
@@ -1260,6 +1263,69 @@
12601263
}
12611264
}
12621265
},
1266+
{
1267+
"condition": "[variables('searchPassedIn')]",
1268+
"type": "Microsoft.Resources/deployments",
1269+
"apiVersion": "2025-04-01",
1270+
"name": "[format('validate-search-aad-auth-{0}-deployment', variables('uniqueSuffix'))]",
1271+
"properties": {
1272+
"expressionEvaluationOptions": {
1273+
"scope": "inner"
1274+
},
1275+
"mode": "Incremental",
1276+
"parameters": {
1277+
"aiSearchName": {
1278+
"value": "[last(variables('acsParts'))]"
1279+
},
1280+
"aiSearchResourceGroupName": {
1281+
"value": "[variables('aiSearchServiceResourceGroupName')]"
1282+
},
1283+
"aiSearchSubscriptionId": {
1284+
"value": "[variables('aiSearchServiceSubscriptionId')]"
1285+
}
1286+
},
1287+
"template": {
1288+
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
1289+
"contentVersion": "1.0.0.0",
1290+
"metadata": {
1291+
"_generator": {
1292+
"name": "bicep",
1293+
"version": "0.43.8.12551",
1294+
"templateHash": "5881130554558405559"
1295+
}
1296+
},
1297+
"parameters": {
1298+
"aiSearchName": {
1299+
"type": "string",
1300+
"metadata": {
1301+
"description": "Name of the existing AI Search service to validate."
1302+
}
1303+
},
1304+
"aiSearchResourceGroupName": {
1305+
"type": "string",
1306+
"defaultValue": "[resourceGroup().name]",
1307+
"metadata": {
1308+
"description": "Resource group containing the existing AI Search service."
1309+
}
1310+
},
1311+
"aiSearchSubscriptionId": {
1312+
"type": "string",
1313+
"defaultValue": "[subscription().subscriptionId]",
1314+
"metadata": {
1315+
"description": "Subscription ID containing the existing AI Search service."
1316+
}
1317+
}
1318+
},
1319+
"resources": [],
1320+
"outputs": {
1321+
"searchAadAuthStatus": {
1322+
"type": "string",
1323+
"value": "[if(and(not(coalesce(tryGet(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('aiSearchSubscriptionId'), parameters('aiSearchResourceGroupName')), 'Microsoft.Search/searchServices', parameters('aiSearchName')), '2024-06-01-preview'), 'disableLocalAuth'), false())), not(contains(coalesce(tryGet(reference(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('aiSearchSubscriptionId'), parameters('aiSearchResourceGroupName')), 'Microsoft.Search/searchServices', parameters('aiSearchName')), '2024-06-01-preview'), 'authOptions'), createObject()), 'aadOrApiKey'))), fail(format('Existing Azure AI Search service \"{0}\" rejects Microsoft Entra (AAD) data-plane authentication (apiKeyOnly). Foundry connects to Search with authType=AAD, so agents will fail with HTTP 403. Enable AAD on the service, then redeploy. Fix: az search service update --name {1} --resource-group {2} --subscription {3} --auth-options aadOrApiKey --aad-auth-failure-mode http401WithBearerChallenge', parameters('aiSearchName'), parameters('aiSearchName'), parameters('aiSearchResourceGroupName'), parameters('aiSearchSubscriptionId'))), 'ok')]"
1324+
}
1325+
}
1326+
}
1327+
}
1328+
},
12631329
{
12641330
"type": "Microsoft.Resources/deployments",
12651331
"apiVersion": "2025-04-01",
@@ -2277,7 +2343,8 @@
22772343
"dependsOn": [
22782344
"[resourceId('Microsoft.Resources/deployments', format('{0}-{1}-deployment', variables('accountName'), variables('uniqueSuffix')))]",
22792345
"[resourceId('Microsoft.Resources/deployments', format('dependencies-{0}-deployment', variables('uniqueSuffix')))]",
2280-
"[resourceId('Microsoft.Resources/deployments', format('{0}-private-endpoint', variables('uniqueSuffix')))]"
2346+
"[resourceId('Microsoft.Resources/deployments', format('{0}-private-endpoint', variables('uniqueSuffix')))]",
2347+
"[resourceId('Microsoft.Resources/deployments', format('validate-search-aad-auth-{0}-deployment', variables('uniqueSuffix')))]"
22812348
]
22822349
},
22832350
{

infrastructure/infrastructure-setup-bicep/15-private-network-standard-agent-setup/main.bicep

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,20 @@ module validateExistingResources 'modules-network-secured/validate-existing-reso
257257
}
258258
}
259259

260+
// Fail fast when a bring-your-own AI Search service rejects Microsoft Entra
261+
// (AAD) data-plane auth (apiKeyOnly). Foundry's CognitiveSearch connection uses
262+
// authType=AAD, so an unpatched existing service leaves agents failing with 403.
263+
// Only the existing-service path needs this; a service this template creates is
264+
// already configured for AAD.
265+
module validateSearchAadAuth 'modules-network-secured/validate-search-aad-auth.bicep' = if (searchPassedIn) {
266+
name: 'validate-search-aad-auth-${uniqueSuffix}-deployment'
267+
params: {
268+
aiSearchName: last(acsParts)
269+
aiSearchResourceGroupName: aiSearchServiceResourceGroupName
270+
aiSearchSubscriptionId: aiSearchServiceSubscriptionId
271+
}
272+
}
273+
260274
// This module will create new agent dependent resources
261275
// A Cosmos DB account, an AI Search Service, and a Storage Account are created if they do not already exist
262276
module aiDependencies 'modules-network-secured/standard-dependent-resources.bicep' = {
@@ -358,6 +372,7 @@ module aiProject 'modules-network-secured/ai-project-identity.bicep' = {
358372
accountName: aiAccount.outputs.accountName
359373
}
360374
dependsOn: [
375+
validateSearchAadAuth
361376
privateEndpointAndDNS
362377
cosmosDB
363378
aiSearch
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// Fail-fast guard for a bring-your-own Azure AI Search service.
2+
//
3+
// Foundry creates its CognitiveSearch connection with authType=AAD. A Search
4+
// service only accepts Microsoft Entra (AAD) data-plane tokens when local auth
5+
// is disabled OR when authOptions contains an aadOrApiKey block. The Azure
6+
// default for a new Search service is apiKeyOnly (local auth on, authOptions
7+
// null), which rejects AAD and surfaces as a misleading 403 "you do not have
8+
// permissions" on the agent. A newly created Search service in this sample sets
9+
// authOptions for you; an existing one you bring may not, so this module reads
10+
// the live state and stops the deployment with an actionable message instead of
11+
// letting it succeed with broken agents.
12+
13+
@description('Name of the existing AI Search service to validate.')
14+
param aiSearchName string
15+
16+
@description('Resource group containing the existing AI Search service.')
17+
param aiSearchResourceGroupName string = resourceGroup().name
18+
19+
@description('Subscription ID containing the existing AI Search service.')
20+
param aiSearchSubscriptionId string = subscription().subscriptionId
21+
22+
resource aiSearch 'Microsoft.Search/searchServices@2024-06-01-preview' existing = {
23+
name: aiSearchName
24+
scope: resourceGroup(aiSearchSubscriptionId, aiSearchResourceGroupName)
25+
}
26+
27+
// A missing disableLocalAuth defaults to false (local auth enabled), and a
28+
// missing authOptions means no AAD block is present.
29+
var localAuthDisabled = aiSearch.properties.?disableLocalAuth ?? false
30+
var aadOptionPresent = contains(aiSearch.properties.?authOptions ?? {}, 'aadOrApiKey')
31+
32+
// AAD is broken only in the apiKeyOnly state: local auth still enabled and no
33+
// aadOrApiKey block to fall back on.
34+
var aadAuthBroken = !localAuthDisabled && !aadOptionPresent
35+
36+
output searchAadAuthStatus string = aadAuthBroken
37+
? fail('Existing Azure AI Search service "${aiSearchName}" rejects Microsoft Entra (AAD) data-plane authentication (apiKeyOnly). Foundry connects to Search with authType=AAD, so agents will fail with HTTP 403. Enable AAD on the service, then redeploy. Fix: az search service update --name ${aiSearchName} --resource-group ${aiSearchResourceGroupName} --subscription ${aiSearchSubscriptionId} --auth-options aadOrApiKey --aad-auth-failure-mode http401WithBearerChallenge')
38+
: 'ok'

samples/python/hosted-agents/SUPPORTED_TOOLBOX_SCENARIOS.md

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -651,7 +651,7 @@ resources:
651651

652652
## 15. Browser Automation
653653

654-
Prompted parameters: `playwright_service_url`, `playwright_service_resource_id`. Requires an Azure Playwright workspace. After provisioning, grant the project-level Foundry Agent Identity **Playwright Workspace Contributor** on the Playwright workspace.
654+
Prompted parameters: `playwright_service_url`, `playwright_service_resource_id`, `playwright_service_access_token`. Requires an Azure Playwright workspace. The access token is used as a secret for the Playwright workspace connection.
655655

656656
**`agent.manifest.yaml`**
657657

@@ -661,8 +661,8 @@ name: toolbox-hosted-browser-automation
661661
displayName: "Browser Automation Toolbox Agent"
662662
description: >
663663
Hosted agent with a Browser Automation toolbox backed by an Azure Playwright
664-
workspace connection. Uses the project-level Foundry Agent Identity to
665-
authenticate to the Playwright workspace.
664+
workspace connection. Uses API key authentication to connect to the
665+
Playwright workspace.
666666
template:
667667
kind: hosted
668668
protocols:
@@ -676,16 +676,20 @@ parameters:
676676
- name: playwright_service_resource_id
677677
secret: false
678678
description: Azure resource ID of the Playwright workspace
679+
- name: playwright_service_access_token
680+
secret: true
681+
description: Access token for the Azure Playwright workspace
679682
resources:
680683
- kind: model
681684
id: gpt-4.1
682685
name: AZURE_AI_MODEL_DEPLOYMENT_NAME
683686
- kind: connection
684687
name: browserautomation
685688
category: PlaywrightWorkspace
686-
authType: AgenticIdentityToken
687-
audience: https://management.core.windows.net
689+
authType: ApiKey
688690
target: "{{ playwright_service_url }}"
691+
credentials:
692+
key: "{{ playwright_service_access_token }}"
689693
metadata:
690694
resourceId: "{{ playwright_service_resource_id }}"
691695
- kind: toolbox

samples/python/hosted-agents/agent-framework/responses/12-foundry-skills/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@
88
agent-framework-foundry
99
agent-framework-foundry-hosting
1010
azure-ai-projects
11+
mcp>=1.24.0
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
FOUNDRY_PROJECT_ENDPOINT=https://<account>.services.ai.azure.com/api/projects/<project>
22
AZURE_AI_MODEL_DEPLOYMENT_NAME=gpt-4.1
3+
TOOLBOX_NAME=browser-automation-tools
34
BROWSER_AGENT_PLAYWRIGHT_CLI_TIMEOUT_SECONDS=180
45
BROWSER_AGENT_MCP_TIMEOUT_SECONDS=120

0 commit comments

Comments
 (0)