Commit 495c8ea
feat: add custom blueprint permissions configuration and management (#298)
* feat: add custom blueprint permissions with auto-lookup and code quality fixes
- Add support for custom API permissions in agent blueprints
- Auto-resolve resource display names from Azure (eliminates manual "Resource Name" prompt)
- New `a365 setup permissions custom` command
- New `a365 config init --custom-blueprint-permissions` management commands
- Comprehensive validation with GUID format checks and duplicate scope detection
- Integration with `a365 setup all` workflow
- Fix "Agent Blueprints are not supported on the API version used" error
- Change addToRequiredResourceAccess from true to false (matches CopilotStudio/MCP pattern)
- Inheritable permissions now configure correctly without Graph API errors
Security & Reliability:
- Add HttpResponseMessage disposal with using statements
- Add GUID validation to prevent OData injection in service principal lookups
- Add safe substring operations with null/length checks in fallback name generation
- Fix duplicate error logging when re-throwing exceptions
Maintainability:
- Add WithCustomBlueprintPermissions() helper to eliminate config reconstruction anti-pattern
- Add --force flag for non-interactive permission updates
- Add early validation for empty/whitespace scope inputs
- Fix inconsistent null handling in Scopes property with setter null protection
- Extract magic strings to constants in fallback resource names
Documentation:
- Add complete XML documentation with 10 parameter descriptions
- Remove redundant test comments
- Add trailing commas for consistency
- 7 new/modified documentation files
- 12 source files (commands, models, services)
- 4 test files with 6 new unit tests
- ✅ 992 tests passing (6 new tests for custom permissions)
- ✅ Build: 0 warnings, 0 errors
- ✅ All critical/high priority issues resolved
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
* Expose scopes as public property with null protection
Changed the _scopes field in CustomResourcePermission to a public Scopes property with getter and setter. The setter ensures null values are replaced with an empty list, allowing safe external access and modification of scopes.
* Update custom permissions: resource name now auto-resolved
Docs clarify that resource name is not prompted or required during `a365 config init --custom-blueprint-permissions`; it is now set to null and auto-resolved during setup. Updated sample config and validation requirements to reflect this. Minor code refactor in ConfigCommand.cs to adjust validation order.
* Refactor custom permissions: new 'config permissions' cmd
Major overhaul of custom blueprint permissions management:
- Adds `a365 config permissions` subcommand for add/update/list/reset
- Removes old permission flags from `config init`
- Integrates improved permission step into interactive wizard
- Updates all docs and tests to use new command/flags
- Improves validation, error messages, and config file discovery
- Refactors logic into PermissionsSubcommand.cs and adds helper methods
- Adds comprehensive unit tests for CLI and wizard flows
- Enhances UX: wizard re-prompts only for invalid scopes
- CLI suggests next steps after permission changes
This modernizes and simplifies custom API permission management for agent blueprints.
* Update docs for new 'a365 config permissions' command
Replaced deprecated 'init --custom-blueprint-permissions' usage with 'config permissions' in Readme-Usage.md, including Copilot Studio setup instructions. Added [Collection("ConfigTests")] to ConfigurationWizardServicePermissionsTests.cs for improved test grouping.
* chore: ignore diagnostics/, .codereviews/, and nul artifacts
Prevents accidental commit of local diagnostic files, code review
artifacts, and the Windows NUL device pseudo-file.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: auto-apply custom blueprint permissions in 'setup blueprint'
When customBlueprintPermissions are configured in a365.config.json,
'setup blueprint' now automatically calls ConfigureCustomPermissionsAsync
instead of showing a hint to run a separate command.
This matches the behavior of 'setup all' (Step 5) and ensures developers
who run config init → add custom permissions → setup blueprint get a
complete setup without extra manual steps.
Note: guarded by !isSetupAll to avoid double-applying when called from
'setup all' (which handles custom permissions at its own Step 5).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* Reconcile custom blueprint permissions in setup command
Implements full reconciliation for custom blueprint permissions in the CLI. When running `a365 setup permissions custom` (or as part of `setup all`), the CLI now removes any custom permissions from Azure AD that are no longer present in the config file, including both inheritable permissions and OAuth2 grants (excluding standard/required permissions). Reconciliation runs even if the config is empty, ensuring stale permissions are cleaned up.
Documentation and CLI output are updated to clarify that resource display names are resolved in-memory for logging only and not persisted. Adds new methods to list and remove inheritable permissions. Switches test mocking to NSubstitute and improves test resource cleanup. Also normalizes scope strings and enhances summary/error reporting.
---------
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>1 parent 422b513 commit 495c8ea
File tree
25 files changed
+3399
-19
lines changed- docs
- ai-workflows
- commands
- src
- Microsoft.Agents.A365.DevTools.Cli
- Commands
- ConfigSubcommands
- SetupSubcommands
- Models
- Services
- Tests/Microsoft.Agents.A365.DevTools.Cli.Tests
- Commands
- Models
- Services
- Helpers
25 files changed
+3399
-19
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
92 | 92 | | |
93 | 93 | | |
94 | 94 | | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
53 | 53 | | |
54 | 54 | | |
55 | 55 | | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
56 | 69 | | |
57 | 70 | | |
58 | 71 | | |
| |||
122 | 135 | | |
123 | 136 | | |
124 | 137 | | |
| 138 | + | |
125 | 139 | | |
126 | 140 | | |
127 | 141 | | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
128 | 159 | | |
129 | 160 | | |
130 | 161 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
154 | 154 | | |
155 | 155 | | |
156 | 156 | | |
157 | | - | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
158 | 186 | | |
159 | 187 | | |
160 | 188 | | |
| |||
284 | 312 | | |
285 | 313 | | |
286 | 314 | | |
287 | | - | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
| 327 | + | |
| 328 | + | |
| 329 | + | |
| 330 | + | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
| 335 | + | |
| 336 | + | |
| 337 | + | |
| 338 | + | |
| 339 | + | |
| 340 | + | |
| 341 | + | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
| 346 | + | |
| 347 | + | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
288 | 393 | | |
289 | 394 | | |
290 | 395 | | |
| |||
306 | 411 | | |
307 | 412 | | |
308 | 413 | | |
309 | | - | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
310 | 418 | | |
311 | 419 | | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
312 | 424 | | |
| 425 | + | |
313 | 426 | | |
314 | 427 | | |
315 | 428 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
190 | 190 | | |
191 | 191 | | |
192 | 192 | | |
193 | | - | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
| 208 | + | |
| 209 | + | |
| 210 | + | |
| 211 | + | |
| 212 | + | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
| 217 | + | |
194 | 218 | | |
195 | 219 | | |
196 | 220 | | |
| |||
212 | 236 | | |
213 | 237 | | |
214 | 238 | | |
| 239 | + | |
215 | 240 | | |
216 | 241 | | |
217 | 242 | | |
218 | 243 | | |
219 | | - | |
| 244 | + | |
220 | 245 | | |
221 | 246 | | |
222 | 247 | | |
| |||
230 | 255 | | |
231 | 256 | | |
232 | 257 | | |
233 | | - | |
| 258 | + | |
234 | 259 | | |
235 | 260 | | |
236 | 261 | | |
| |||
0 commit comments