Skip to content

feat(apim): APIM Policy Management — list APIs, assign templates, app…#32

Open
seiggy wants to merge 6 commits into
Azure-Samples:mainfrom
seiggy:feature/apim-policy-management
Open

feat(apim): APIM Policy Management — list APIs, assign templates, app…#32
seiggy wants to merge 6 commits into
Azure-Samples:mainfrom
seiggy:feature/apim-policy-management

Conversation

@seiggy
Copy link
Copy Markdown
Collaborator

@seiggy seiggy commented May 21, 2026

…ly via SDK

Adds the policy engine's ability to manage APIM policies through a UI instead of hand-edited XML files. Implements McNulty's architecture (Tier B: template apply) end-to-end across infra, backend, frontend, and tests.

M1 — Read-only catalog

  • GET /api/apim/apis, /apis/{id}/operations, /apis/{id}/policy
  • GET /api/apim/apis/{id}/operations/{opId}/policy

M2 — Template library

  • 5 templates under policies/templates/ (entra-jwt-ai, entra-jwt-ai-dlp, subscription-key-ai, subscription-key-ai-dlp, entra-jwt-rest)
  • {{placeholder}} substitution + template.json manifests
  • GET /api/apim/templates

M3 — Apply flow

  • POST /api/apim/apis/{id}/policy (and operation-scoped variant) — async 202
  • DELETE /api/apim/apis/{id}/policy (and operation-scoped variant)
  • Cosmos policy-assignment doc store (existing configuration container)
  • SHA256 hash of generated XML; status transitions pending→applying→synced|failed
  • Azure.ResourceManager.ApiManagement SDK via DefaultAzureCredential

M4 — UI (src/aipolicyengine-ui)

  • New /apis page with tree view (APIs/operations), details panel, assign-template modal with dynamic parameter form, 2s status polling, clear-confirm flow, XML viewer

Infra (Terraform)

  • Custom least-privilege APIM role with only apis/operations read + policies read/write/delete (NOT Service Contributor)
  • Role assignment to Container App managed identity
  • APIM_RESOURCE_ID plumbed to Container App env via deterministic root local (avoids compute<->gateway module cycle)

Tests

  • 76 new tests (TemplateRendering, TemplateLibrary, PolicyAssignmentRepository, ApplyOrchestrator, ApimManagementEndpoints) — 295 passed / 0 failed / 4 skipped
  • Caught and fixed a strict-XML-parse bug in TemplateLibraryService that was rejecting valid APIM policy-expression templates

Non-AI API usage limits (separate feature) is paused per Zack's call; the draft XML lives at .squad/files/non-ai-paused/ until M2 templates are validated.

…ly via SDK

Adds the policy engine's ability to manage APIM policies through a UI instead
of hand-edited XML files. Implements McNulty's architecture (Tier B: template
apply) end-to-end across infra, backend, frontend, and tests.

M1 — Read-only catalog
  - GET /api/apim/apis, /apis/{id}/operations, /apis/{id}/policy
  - GET /api/apim/apis/{id}/operations/{opId}/policy

M2 — Template library
  - 5 templates under policies/templates/ (entra-jwt-ai, entra-jwt-ai-dlp,
    subscription-key-ai, subscription-key-ai-dlp, entra-jwt-rest)
  - {{placeholder}} substitution + template.json manifests
  - GET /api/apim/templates

M3 — Apply flow
  - POST /api/apim/apis/{id}/policy (and operation-scoped variant) — async 202
  - DELETE /api/apim/apis/{id}/policy (and operation-scoped variant)
  - Cosmos policy-assignment doc store (existing configuration container)
  - SHA256 hash of generated XML; status transitions pending→applying→synced|failed
  - Azure.ResourceManager.ApiManagement SDK via DefaultAzureCredential

M4 — UI (src/aipolicyengine-ui)
  - New /apis page with tree view (APIs/operations), details panel,
    assign-template modal with dynamic parameter form, 2s status polling,
    clear-confirm flow, XML viewer

Infra (Terraform)
  - Custom least-privilege APIM role with only apis/operations read + policies
    read/write/delete (NOT Service Contributor)
  - Role assignment to Container App managed identity
  - APIM_RESOURCE_ID plumbed to Container App env via deterministic root local
    (avoids compute<->gateway module cycle)

Tests
  - 76 new tests (TemplateRendering, TemplateLibrary, PolicyAssignmentRepository,
    ApplyOrchestrator, ApimManagementEndpoints) — 295 passed / 0 failed / 4 skipped
  - Caught and fixed a strict-XML-parse bug in TemplateLibraryService that was
    rejecting valid APIM policy-expression templates

Non-AI API usage limits (separate feature) is paused per Zack's call; the
draft XML lives at .squad/files/non-ai-paused/ until M2 templates are validated.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@seiggy seiggy requested a review from a team May 21, 2026 17:22
seiggy and others added 5 commits May 21, 2026 13:42
…e nested config

The Container App env var was named APIM_RESOURCE_ID (single underscore),
but ASP.NET Core's EnvironmentVariablesConfigurationProvider only maps
nested config keys (like Apim:ResourceId) from env vars with double
underscores (Apim__ResourceId). At runtime the binding silently failed,
leaving Apim:ResourceId empty and throwing InvalidOperationException
from ApimCatalogService when the first request hit /api/apim/apis.

Rename the Terraform env var to Apim__ResourceId so it binds correctly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Orchestration log: 2026-05-21T17-43-57Z-freamon.md (APIM_RESOURCE_ID → Apim__ResourceId hotfix)
- Session log: 2026-05-21T17-43-57Z-apim-config-binding-fix.md
- Merge decision into Active Decisions: ASP.NET Core nested config convention (double-underscore env vars)
- Delete inbox file: freamon-apim-config-binding-fix.md
- Cross-agent context: append to sydnor/history.md and kima/history.md

All 295 tests pass. Audit complete: no other single-underscore ASP.NET Core nested-config mismatches.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Root cause: the initial APIM bootstrap callback depended on operationsByApi while also resetting that state, which changed the callback identity and retriggered the mount effect.

Fix: keep the latest operations map in a ref so loadInitialData can reconcile the current selection without depending on the mutable operationsByApi object.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Orchestration log: 2026-05-21T18-35-00Z-kima.md documents the infinite render loop fix
- Session log: 2026-05-21T18-35-00Z-apis-render-loop-fix.md brief summary
- Merged decision inbox: kima-apis-render-loop.md into decisions.md as 2026-05-21T18:35:00Z entry
- Cross-agent update: appended render-loop skill note to bunk/history.md with test coverage suggestion
- Deleted inbox file after merge

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- ApiTree: Add min-w-0 flex-1 truncate to API name, flex-shrink-0 on badge
- ApiTree: Remove redundant serviceUrl display (path is sufficient)
- ApiTree: Simplify operation rows - show method badge + urlTemplate only (removes duplicate verb text)
- AssignTemplateForm: Add min-w-0 + truncate to param label, flex-shrink-0 on badges
- AssignTemplateForm: Change param grid to sm:grid-cols-2 for better modal fit
- Dialog: Add overflow-x-hidden to prevent horizontal scrollbar

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant