Azure IPAM v4.0.0 Release #377
Open
DCMattyG wants to merge 200 commits into
Open
Conversation
…tion for Azure IPAM
…that were not being accounted for properly
…ue to improper handling of missing vNETs and vHUBs
…DataGrid component
Switch the lodash dependency to lodash-es and update all named imports across 19 source files. The ES module build allows Vite/Rollup to tree-shake unused lodash methods, reducing the production bundle size. Also collapse two duplicate lodash-es imports in visualize.jsx into a single statement. No functional changes; import names and call sites are unchanged.
Moment.js is in maintenance mode and ships a large, non-tree-shakeable
bundle. Replace it with dayjs (a ~2KB drop-in) in reservations.jsx, the
only file using moment.
Add the localizedFormat plugin to preserve the 'lll' token used in the
reservation grid date columns. Output was verified identical to moment
for all call patterns (localized format, unix parsing, startOf('day')).
The browserslist field was inert: Vite uses esbuild/build.target for browser targeting and there is no autoprefixer, postcss-preset-env, or Babel config consuming it. Removing it eliminates misleading config with no functional effect.
Add an engines field to package.json mirroring the minimum versions already enforced in tools/build.ps1 (node >=22.12.0, npm >=10.9.2). This documents the toolchain contract in the standard location for Node-native tooling and contributors. Advisory only; not enforced at install time.
Add a "preview" script (vite preview) to smoke-test the production build locally, and a "lint:fix" script (eslint src/ --fix) for auto-fixable lint issues. Existing start, build, and lint scripts are unchanged.
Correct stale UBI8 container-image overrides in the deploy, update, and migrate scripts so private-registry RHEL builds use UBI9, matching the Dockerfile.rhel defaults. Raise the build-time Node.js floor to 22.22.0. - deploy/deploy.ps1: ubi8/nodejs-22 and ubi8/python-311 -> ubi9 equivalents - deploy/update.ps1: ubi8/nodejs-22 and ubi8/python-311 -> ubi9 equivalents - migrate/migrate.ps1: ubi8/nodejs-22 and ubi8/python-311 -> ubi9 equivalents - tools/build.ps1: bump MIN_NODE_VERSION 22.12.0 -> 22.22.0
Bump react-router 7.18.0 -> 8.0.1 (major). The UI uses declarative-mode routing (BrowserRouter / Routes / Route) with all imports already sourced from "react-router", so no application code changes were required. React Router v8 requires Node.js 22.22.0+, so the UI package "engines" floor is raised from 22.12.0 to 22.22.0 to match.
Migrate the publicly hosted Azure IPAM container registry from azureipam.azurecr.io to the new registry.azureipam.com FQDN across the deployment, migration, and update tooling. - deploy and migrate Bicep modules now default the public ACR URI to registry.azureipam.com (appService.bicep, functionApp.bicep) - update.ps1 now recognizes both the new and legacy public registries and auto-migrates existing App Service / Function deployments by rewriting the baked-in LinuxFxVersion to the new registry before restarting - testing workflow replace-string updated to match the new Bicep default - docs (update README) and the v4.0.0 release notes updated to reference both the new and legacy registries The legacy Docker Compose migration path (migrate.ps1) intentionally continues to reference azureipam.azurecr.io, since it only ever processes pre-existing legacy Docker Compose deployments. BREAKING CHANGE: public Azure IPAM images are now served from registry.azureipam.com instead of azureipam.azurecr.io. New and existing deployments continue to work (running update.ps1 auto-migrates existing ones), but any custom automation or pipelines that hardcoded azureipam.azurecr.io should be updated to registry.azureipam.com.
Replace the legacy AZURE_CREDENTIALS service-principal secret with workload identity federation (OIDC) in the Azure IPAM testing workflow, aligning it with the auth model already used by the build workflow. - Add top-level `permissions` block (id-token: write, contents: read) so GitHub can issue the OIDC token - Convert all three Azure Login steps (deploy, test, cleanup) to the client-id/tenant-id/subscription-id form using the new AZURE_TEST_CLIENT_ID, AZURE_TEST_TENANT_ID, and AZURE_TEST_SUBSCRIPTION_ID secrets - Preserve enable-AzPSSession so deploy.ps1's Get-AzContext / Get-AzAccessToken -> Connect-MgGraph chain continues to work Removes the last long-lived Azure credential secret from CI.
…delete The federated client assertion (GitHub OIDC token) is valid only a few minutes. The synchronous resource-group deletion could exceed that window, so the later Microsoft Graph (identity) and ACR data-plane (container) deletions failed with AADSTS700024 when acquiring tokens for their audiences. Run the identity and container cleanup first, while the assertion is still valid, and delete the resource group last (it reuses the ARM token cached at login). Mark all cleanup steps `if: always()` so resource, identity, and container teardown are best-effort and run independently of each other.
Bump ag-grid-community and ag-grid-react from ^35.3.1 to ^36.0.0. No app code changes required; verified build and grids in light/dark mode.
Stamp the org.opencontainers.image.version label (plus title and source) onto all production images so the version behind the `latest` tag can be queried from the registry without pulling or running the container. - Add ARG IPAM_VERSION and OCI LABEL block to all production Dockerfiles (deb, rhel, and func variants for root, engine, ui, and lb) - Pass --build-arg IPAM_VERSION to every az acr build in the build workflow - Anchor the release-tag `v` strip to the start (^v) so version suffixes like -preview are preserved
…pdate Provision a dormant `staging` deployment slot alongside production for both native and container App Service and Function App deployments, laying the groundwork for safer slot-based upgrades. Slots are created disabled, share the production App Service Plan and managed identity, and mirror production configuration. Add an additive, auto-detected infrastructure update to the update workflow that retrofits the staging slot onto existing deployments that predate slots. The step is best-effort and never modifies the production site: it verifies plan tier, managed identity, and baseline settings before deploying, preserves all existing app-setting values (only backfilling missing baseline keys), and gracefully falls back to a slot without vNet integration when regional vNet replication cannot be applied automatically. Relocate the update tooling from `deploy/update.ps1` to a dedicated `update/` folder with its own subscription-scoped Bicep templates, and refresh the console output for clearer, consistent status reporting. * deploy/modules/appService.bicep: shared site config + dormant staging slot * deploy/modules/functionApp.bicep: dormant staging slot + sticky slot settings * migrate/modules/appService.bicep: dormant container staging slot * update/main.bicep, update/modules/*: additive per-deployment slot templates * update/update.ps1: moved from deploy/ and rewritten with the infra update * docs/update/README.md, README.md: document slots, prerequisites, and layout BREAKING CHANGE: the update script has moved from deploy/update.ps1 to update/update.ps1; update any automation that references the old path.
The v2.0.0 release renamed the client class ManagementGroupsAPI to ManagementGroupsMgmtClient, breaking the import in helper.py. Update the import and instantiation to the new client name and unpin the dependency so the latest version is used.
Drop the >=0.103.0 and >=2.3.0 minimum version constraints from fastapi[all] and pydantic[email] so they match the unpinned style of the rest of requirements.txt. The extras are preserved and exact versions remain governed by requirements.lock.txt, so resolution behavior is unchanged.
Reimagine the startup database upgrade to be safe for App Service
deployment slots. Instead of eagerly migrating on every boot, the engine
now converges data only on the production slot and leaves staging slots
inert, so the previous version keeps running unharmed until the swap —
and swap preview / rollback stay possible.
- Replace the eager startup upgrade_db() with app/schema: production-only
convergence plus a compatibility gate; the v4 baseline step folds in all
prior data fixups so upgrades from any older version still land correctly
- Record schema state in a Cosmos "schema" control doc as a compatibility
floor { current, minReadable }; additive convergence never raises the
floor, preserving swap-back / rollback
- Detect the slot via WEBSITE_SLOT_NAME (globals.IS_PRODUCTION_SLOT);
unset / non-Azure hosts are treated as production
- Introduce production/staging/incompatible service modes with a gate that
disables all /api routes except /api/status and /api/health when not in
production
- Run convergence and the find_reservations scheduler only on the
production slot; gate reservation reconciliation and the heartbeat to
production across both the App Service and Functions entry points
- Add GET /api/health: an authenticated, live dependency checklist
(config, cosmos, arm, schema) that stays reachable in staging for
pre-swap verification
- Trim /api/status to a portable "mode"; drop Azure-specific slot detail
- Add Status/Health models and a Pester integration test for /api/health
BREAKING CHANGE: The engine now refuses to serve (503 on all API routes)
when the running build is older than the database's minimum readable
schema, and staging-slot instances return 503 on every route except
/api/status and /api/health until swapped to production.
…uction-accurate Improve the update workflow's handling of container deployments and the auto-provisioned staging slot so updates are safer, idempotent, and consistent. - Tag built images with both the app version and `latest`, and pass IPAM_VERSION as a build arg, matching the CI build convention - Skip the image build when the running version already matches the repository (unless -Force), using the bare version from /api/status - Mirror production's actual ACR authentication method onto the staging slot (AcrUseManagedIdentityCreds) instead of inferring it from the registry name, so admin/anonymous and non-ACR registries are no longer forced to use a managed identity - Treat a private registry outside the app's resource group as a clean, non-fatal manual-handoff instead of a hard failure - Correct the staging slot for container function apps: match production's kind (functionapp,linux,container) and skip the content-share sticky settings that are not permitted as slot settings - Normalize per-branch console output: consistent manual-handoff sections and async-completion guidance across the container and native paths
Bring the update guide in line with the current update.ps1 behavior. - Note that private ACR container deployments now compare the running version and skip the image build when already up to date - Document version+latest image tagging (ipam:<version> + ipam:latest, ipamfunc:<version> + ipamfunc:latest) - Explain the same-resource-group requirement for automated builds and the manual image-update handoff when the registry is elsewhere - Refresh the Docker Compose detection example to match the new output - Split the multi-part Additional Requirements and Version Comparison items into child bullets for readability
Harden the SPA's MSAL redirect handling so a service restart no longer triggers a cascading interaction_in_progress loop: - Poll the public /api/status endpoint without a bearer token so the restart gate's recovery poll never triggers MSAL token acquisition. - Reload the page only when no MSAL interaction is in progress, so an in-flight redirect is never interrupted mid-handshake. - Replace the hand-rolled Login component with MSAL's native MsalAuthenticationTemplate for initial sign-in, removing the second interactive-redirect owner that raced with AuthHandler. - Simplify AuthHandler to a single loginRedirect re-auth path and drop a dead acquireTokenRedirect branch (ACQUIRE_TOKEN_FAILURE events carry a null payload, so it never executed).
MsalAuthenticationTemplate internally calls acquireTokenSilent with the default (iframe-capable) cache policy and throws on error, which crashed the UI in privacy browsers that block third-party cookies. Restore the AuthenticatedTemplate/UnauthenticatedTemplate + Login sign-in, which only uses loginRedirect (no iframe). Keeps the unauthenticated /api/status poll and the AuthHandler cleanup.
…d update detectors
Adds a self-describing notification framework (GET /api/notifications,
POST /api/notifications/{id}/resolve) with admin-gated, resolve-by-reference
remediation. Includes detectors for legacy/dev container-registry migration
(with a server-owned "switch to official registry" remediation) and for
available GitHub releases. Replaces the previous service router/models.
…art gate Adds the AppBar notification center (bell, badge, list, manual refresh), the detail dialog with server-driven resolve actions, and the full-screen service restart gate that polls /api/status for recovery. Registers the notifications/restart reducers and pauses background polling during restarts.
control.py was never staged in the slot-safe convergence commit (fcb3379), even though app/schema/convergence.py, app/schema/steps.py, and app/routers/health.py all import from it. Runtime deployments worked only because they were built from the working tree; a clean checkout would fail to import app.schema.control on startup. Commit the file to complete the feature.
Order the app.schema.control import after app.routers.common.helper in health.py and steps.py. Import ordering only; no functional change.
Adds a Notifications context to the Pester integration suite (ordered to match
the FastAPI router mount order). Covers GET /api/notifications (200 + response
shape validation) and the safe, non-mutating POST /api/notifications/{id}/resolve
guard paths: 404 for an unknown id, 404 for a link-only notification with no
remediation, and 409 for a remediable notification that isn't currently active.
The destructive resolve happy path is intentionally left to engine unit tests.
Mounts the notifications router before health so the route order in FastAPI (and the generated Swagger docs) reads consistently.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Azure IPAM v4.0.0
This is a major release that delivers significant framework upgrades, a data grid migration, authentication modernization, comprehensive documentation overhaul, revamped examples, and numerous bug fixes.
Major Framework & Dependency Upgrades
forwardRefwrappers (ref-as-prop), removal ofPropTypes, explicitnullforuseRef()calls, and migration ofLoadingButtontoButton@azure/msal-browser4.x → 5.x,@azure/msal-react3.x → 5.x): Removed obsolete config, consolidated event types, fixed silent token timeout recovery (timed_outerror code), and prevented iframe fallback timeout loopsag-grid-community/ag-grid-react36.x): Complete migration to AG Grid including centralizedDataGridcomponent, custom styling, column state persistence, unified data loading overlays, and custom cell renderers (drill-down, info, progress)vite7.x → 8.x,@vitejs/plugin-react5.x → 6.x): Migrated to Vite 8 which replaces Rollup with Rolldown and esbuild with Oxc for bundling, transforms, and minification. Removedvite-plugin-eslint2(redundant with editor-based linting and incompatible with Vite 8)@eslint-react/eslint-pluginv5,eslint-plugin-react-hooksv7 — which now consolidates the React Compiler lint rules per the React Compiler 1.0 release), replacingeslint-plugin-react. Addeddist/ignore, fixedno-useless-assignmentviolations, and removed unusedeslint-plugin-jest. Resolved all remaining lint warnings as part of the React 19 modernization —useContext→use,<Context.Provider>→<Context>, ref naming conventions, stable list keys, hoisted static styled components, migration ofSnackbarUtilsto notistack's standaloneenqueueSnackbar, and moved "ref assigned during render" patterns intouseEffect@mui/material7.3.x → 9.0.x,@mui/icons-material7.3.x → 9.0.x): Major two-version jump. Migrated deprecated component props to the unifiedslots/slotPropsAPI (largely via@mui/codemod), moved deprecated system props intosx, replaced the removedUnstable_Grid2with the new defaultGrid(usingsize={{ xs: N }}), renamed removedOutline(no "d") icon exports to theirOutlinedcounterparts, and removed@mui/lab(no longer needed —LoadingButton'sloadingprop is now native toButton)react-router7.x → 8.x): Major version upgrade. The UI uses declarative-mode routing (BrowserRouter/Routes/Route) with all imports already sourced fromreact-router, so no application code changes were required. v8 raises the minimum runtime to Node.js 22.22.0 (and React 19.2.7+)Engine & Backend
msal,azure-common,azure-keyvault-secrets, andsix; addedazure-mgmt-resource-subscriptionsto address Azure SDK module separationpyproject.tomlwith Ruff linter configuration (pycodestyle, pyflakes, isort). Resolved all lint violations across 18 engine files — bare except clauses, wildcard imports replaced with explicit names, unused imports/variables, invalid escape sequences, import sorting and groupingUI & UX Improvements
AuthHandlerfor MSAL error handling, centralized token acquisition viatokenServiceDraggablePapercomponent: Replacedreact-draggablepackage with a purpose-built componentDataGridandConfigureGridcomponents with shared filter utilities, consistent loading overlays, and AG Grid custom styling (brightnessfilter for row hover)Notifications & Service Management
GET /api/notifications,POST /api/notifications/{id}/resolve): A self-describing, API-first advisory system. Server-side detectors emit notifications that the UI — or any API / IaC consumer — can read, while remediation is resolve-by-reference: the client asks the backend to resolve a notification by id and the backend owns all the logic (admin-gated, with an active-notification guard). Adding a new advisory is a single detector module registered in one listazureipam.azurecr.io, critical) or the development registry (azureipamdev.azurecr.io, warning) and offers a one-click remediation that repoints the App Service / FunctionLinuxFxVersiontoregistry.azureipam.com. The target image is validated as anonymously pullable before any change is applied, then the app restarts to pull it — complementing theupdatescript's auto-migration with an in-app pathIPAM_VERSIONagainst the latest published GitHub release and surfaces an informational notice linking to the update guide. Fails safe (no notification, no error) on network or rate-limit failures/api/status, and confirms recovery via a changed service start time before reloading — with calm, time-keyed messaging and a deliberate manual-reload escape hatch if recovery runs long. Background polling is paused while the gate is upDeployment, Build & Infrastructure
azureipam.azurecr.ioto the newregistry.azureipam.comendpoint. The deployment and migration Bicep templates now reference the new registry by default, while theupdatescript continues to recognize the legacyazureipam.azurecr.ioendpoint so existing deployments keep working. The Docker Compose migration tooling intentionally still targets the legacy endpoint, as it only ever processes pre-existing legacy deploymentsmigratescript now halts on a non-standard or unresolvable container registry with guidance to re-run using the-JsonFileoverride, instead of silently falling back to the public registry. A new-ContainerType(Debian|RHEL) override handles cases where the source app is stopped/unreachable and its distro can't be auto-detecteddeploy,update, andmigratePowerShell scriptsbuild.ps1version gate and the UIpackage.jsonenginesfieldADD→COPY, JSON notation forCMD/ENTRYPOINT,pipefailfor pipedRUNcommands). Added centralized.hadolint.yamlfor rule suppressionscheckout@v6,setup-node@v6,setup-python@v6,github-script@v9,create-github-app-token@v3,azure/login@v3,hadolint-action@v3.3.0) to address the Node.js 20 runner deprecationGet-AzAccessTokenbreaking changes (fixes Breaking changes to Get-AzAccessToken #343); updated deploy & migrate scriptsorg.opencontainers.image.version,.title,.source), stamped at build time via a newIPAM_VERSIONbuild arg. This lets you determine the exact version behind a floating tag likelatestby inspecting the registry — no pull or run required (e.g.docker buildx imagetools inspectoraz acr manifest show). Covers alldeb,rhel, andfuncvariants across the root, engine, ui, and lb images, with the build workflow passing--build-arg IPAM_VERSIONto everyaz acr build. Labels begin with the v4.0.0 release imagesv(^v) from the release tag, preserving suffixes such as-previewDocumentation Overhaul
.markdownlint.jsonconfigurationExamples
examples/scripts/folder with new helper scripts and READMETesting
Bug Fixes
Get-AzAccessTokenbreaking changes not accounted for[major]