Changelog
Entries in this file are generated by semantic-release from Conventional Commit messages — do not edit it by hand; your commit message is the changelog entry. Historic sections at the bottom were maintained by hand in the Keep a Changelog format.
0.12.0 (2026-09-01)
Bug Fixes
- blob: default unusable blob content types to application/octet-stream (#210) (4fdbb7a)
- blob: honor user delegation SAS signing layouts by version (#202) (8ca73e8)
- blob: preserve ADLS list directory identity (#201) (2a3635b)
- cosmos: enable .NET SDK queries (#220) (8bde4d5), closes #216
- cosmos: support .NET transactional batch (#222) (5efd630), closes #217
- eventhub: make the AMQP data plane usable from the Azure SDKs (CBS + library patches) (#237) (5c8806e), closes #128
- eventhub: route sends addressed the way the Azure SDKs address them (#241) (0d04662)
- functions: support Python v2 app-root packages (#200) (09d6a7c)
- honor Cosmos patch filter predicates (#230) (10dd22c), closes #217
- honor X-Forwarded-Proto in /metadata/endpoints so URLs are https behind a TLS proxy (#253) (37aa829), closes #252
- return ARM errors for failed SQL operations (#229) (7519c7d), closes #138
- servicebus: reap orphaned sidecars (#219) (c9f3915), closes #218
- servicebus: report runtime counts (#225) (e869661), closes #214
- servicebus: route .NET admin requests (#221) (c0e003f), closes #215
- servicebus: support session DLQ access (#223) (5036cad)
- servicebus: unpack AMQP batches (#224) (bc01cee)
- table: wrap error responses in the OData error envelope (#182) (96a0f6a), closes #181
Features
- aci: add Azure Container Instances emulation (mocked ARM CRUD) (#208) (1377f74), closes #59
- add ADLS list paths support (#198) (7c47687)
- blob: blob lease support for the Azure Functions storage backplane (#183) (e82139f), closes #182 #136
- compatibility-tests: add Azure SDK for C++ compatibility suite (#186) (3c69159), closes #184
- servicebus: add duplicate detection (#171) (413a65a)
- servicebus: add entity message expiration (#172) (0648e1a)
- servicebus: honor per-entity MaxDeliveryCount and LockDuration (#207) (4d39b93)
- servicebus: start the default namespace on boot for a deterministic AMQP endpoint (#250) (69d3600)
- servicebus: support non-destructive message peeking (#203) (93f3b6d), closes #137 #137
- sql: add data-plane providers (#204) (d789831), closes #138
- sql: provision managed servers async (#205) (aff2aca), closes #138
0.11.0 (2026-08-18)
Bug Fixes
- blob: persist upload HTTP properties (#166) (28cd215), closes #163
- core: omit Content-Type on bodyless error responses (#185) (51b545a)
- cosmos: enforce item ETag conditions (#167) (dd5ae45), closes #160 #161
- cosmos: evaluate correlated EXISTS queries (#168) (fbaa6bf), closes #162
- dns,tls: converge dns and tls clusters on floci-aws baseline 0142dc4 (#177) (90736bc)
- docker: converge docker cluster on floci-aws baseline 0142dc4 (#178) (eb0bf42), closes #157 #95
- entra: make EntraStore participate in /_admin/reset (#195) (a370440)
- functions: accept deployment packages larger than 20 MB (#196) (c247f32), closes #192
- postgres: answer 202 with Location so azurerm 3.x and 4.x both apply (#135) (3a11776)
- sql: replace retired Azure SQL Edge image (#139) (11fc293), closes #138
- storage: converge storage cluster on floci-aws baseline 0142dc4 (#180) (7b375a7)
- storage: serve service-properties XML for table, queue, and blob (#134) (1848a4d), closes #132 #131
Features
- cosmos: container DefaultTimeToLive (TTL) with per-document overrides (#141) (d4f1d70), closes #126
- enforce scoped ADLS SAS authorization (#158) (3f951ae)
- Entra ID phase 2 — auth-code+PKCE grant + Microsoft Graph slice (#143) (913954b), closes #120
- release: release parity, one-button release cut, and the -compat image (#188) (6fe9958)
- servicebus: support message sessions (#190) (dccc3dd), closes #159
Performance Improvements
0.10.0 - 2026-07-31
Added
- blob (ADLS): user delegation key vending —
POST /?restype=service&comp=userdelegationkeybehind bearer auth returns the spec-exactUserDelegationKeyXML with a deterministic per-account signing key, and ARM storage accounts expose thedfsprimary endpoint, soazure-storage-file-datalakeclients can mint and use user-delegation SAS end to end (#122) - mysql / mariadb: Azure Database for MySQL (Flexible Server,
Microsoft.DBforMySQL/flexibleServers) and Azure Database for MariaDB (Single Server,Microsoft.DBforMariaDB/servers) emulation — server CRUD, databases, firewall rules, configurations, checkNameAvailability, and a/connectconvenience endpoint, backed by realmysql:8.0/mariadb:10.11sidecar containers with protocol-handshake readiness, admin grants matching a real Azure admin, in-placeALTER USERpassword rotation, and container rehydration after emulator restarts; plus a cross-resource Monitor diagnostic settings extension ({resourceUri}/providers/microsoft.insights/diagnosticSettings). Continues #104 with original authorship preserved - cosmos: custom container indexing policies with Azure-parity composite-index enforcement. A client-supplied
indexingPolicy(included/excluded paths, composite indexes) on container create is normalized the way Azure does (defaults filled, composite pathorderdefaulting toascending), persisted, and returned on container read; container replace (PUT /dbs/{db}/colls/{coll}) is now supported for updating the policy, withidandpartitionKeyimmutable as in Azure. Queries with anORDER BYover two or more properties (or mixed sort directions) now fail with400 BadRequest("The order by query does not have a corresponding composite index that it can be served from", codeSC2104) unless the container has a composite index matching the clause exactly — same paths, same sequence, same length, directions matching exactly or all-inverted — so queries that would be rejected in production fail locally too (#127) - Network: realistic property synthesis for
Microsoft.Networkload balancers (top-levelskuround-trip, frontend/rule/pool ARM IDs), network security groups (rule IDs, the six real-AzuredefaultSecurityRules, standalonesecurityRuleschild endpoint), and application gateways (child sub-resource IDs,operationalState), plus thebackendAddressPoolschild endpoint — enablingazurerm_lb*,azurerm_network_security_*, andazurerm_application_gatewayTerraform/OpenTofu flows. - servicebus: subscription rules and topic filters — the
/{topic}/subscriptions/{sub}/rules[/{rule}]management-plane endpoints (create/get/list/delete, ATOMRuleDescriptionwire format withCorrelationFilter/SqlFilter/TrueFilter/FalseFilterandSqlRuleActionbodies), Azure's implicit$DefaultTrueFilter rule (auto-created per subscription, replaceable via the delete-then-add SDK flow or aDefaultRuleDescriptionin the subscription create body), and broker-side filter evaluation: rules compile to Artemis SQL92 queue selectors (CorrelationId→JMSCorrelationID,Label/Subject→JMSType,SessionId→JMSXGroupID, application properties by name, with typed int/long/double/boolean correlation values), multiple rules OR-combine into a single delivery, no rules delivers nothing, and rule changes update the queue filter in place (updateQueue) without dropping routed messages or kicking receivers. Filters onMessageId/To/ReplyTo/ReplyToSessionId/ContentTypeare rejected with 400 (no broker-side AMQP mapping);SqlRuleActionis stored/echoed but not applied to delivered messages (#124) - docker: every emulator-created container and volume is now labelled
floci=true(umbrella across the Floci emulators) andfloci_emulator=floci-az(per-emulator discriminator), applied centrally in the container lifecycle layer — sodocker ps --filter label=floci_emulator=floci-azanddocker volume prune --filter label=floci_emulator=floci-aztarget this emulator alone, whilelabel=floci=truestill matches all Floci emulators. Thefloci-az-name prefix is now owned by a single naming helper instead of being spelled at each call site (container names are unchanged), the Functions runtime container is created through the shared container layer (it previously bypassed it and carried no labels), and the AKS k3s volume is created explicitly so it is labelled too. New optionalfloci-az.docker.resource-namespace(FLOCI_AZ_DOCKER_RESOURCE_NAMESPACE) inserts a namespace into child container/volume names (floci-az-<ns>-...) and afloci_namespacelabel, for running multiple emulator processes against one Docker daemon. Docker volume labels are immutable, so volumes created by earlier versions keep no labels until recreated (the AKS k3s volume is deleted on shutdown by default, so this resolves itself); such volumes can be listed withdocker volume ls --filter name=floci-az-and removed manually if needed. Note: with a namespace set, the Event Hubs broker certificate SAN (floci-az-artemis) does not cover the namespaced container name for in-network TLS clients — connect vialocalhostin that setup.
Fixed
- storage: blob, queue, and table service-properties requests now return proper
StorageServicePropertiesXML with spec-correct statuses (Get 200 / Set 202) instead of a JavatoStringbody (#131, #132) - blob: unimplemented
compoperations onPUT /{container}/{blob}(lease, snapshot, properties, tier, tags, page, appendblock) and header-discriminated CopyBlob / Data Lake rename no longer fall through to PutBlob — previously they replaced the blob content with the (usually empty) request body and answered 201; they now return501 NotImplementedin the Azure error shape (#155) - servicebus: the CBS responder no longer exhausts file descriptors when the broker is
unreachable — the reconnect backoff sat in a catch block that Proton's normally-returning
reactor.run()never reached, so the loop re-created reactors (and their selectors/pipes) at CPU speed (#154) - email: the ACS Email send operation now matches the real operation contract so the Azure SDKs can poll a send to completion (#148)
- core: unified ARM provider dispatch with strict ARM body parsing (#118);
bare Key Vault deleted-* collection routes resolve and disabled services report
503(#114) - servicebus: ATOM feed responses (queues/topics/subscriptions list) no longer embed an XML prolog inside every
<entry>, which made the feed malformed XML for strict parsers - tls: the emulator now starts with
FLOCI_AZ_TLS_ENABLED=trueon Windows hosts.TlsConfigSourcefed native backslash paths intoquarkus.http.ssl.certificate.*, and SmallRye Config treats backslashes in property values as escape characters, so startup died withNoSuchFileException: D:Devfloci-az.datatls.... Certificate and key paths (generated and user-provided) are now emitted with forward slashes on Windows, which the Windows file APIs accept; on other platforms paths are passed through untouched since a backslash is a legal filename character there - blob:
Get Blob/Get Blob Propertiesnow return thex-ms-creation-time,x-ms-lease-status,x-ms-lease-state, andx-ms-server-encryptedresponse headers that Azure always sends, andGet Container Propertiesnow returnsx-ms-lease-state/x-ms-lease-status. The Azure SDK for C++ (azure-storage-blobs12.18.0) reads these unconditionally (std::map::at()) when deserialising Download, GetProperties, and GetContainerProperties responses, so their absence threwstd::out_of_rangeand crashed the client process; the Java, Python, and Node SDKs map them to nullable fields and were unaffected, which is why the existing compatibility suites stayed green. Creation time is now recorded when a blob is written and preserved across metadata updates and overwrites, so it no longer tracks last-modified. Leases remain unmodelled: the lease headers report the fixed values of an unleased blob or container.Content-Rangeis also no longer sent on full (200 OK) downloads, matching the Azure spec, which scopes it to range requests (#145)
0.9.0 - 2026-07-09
Added
- managedidentity: Managed Identity emulation (
Microsoft.ManagedIdentity/userAssignedIdentities+ IMDS token endpoint) — HTTP-only with no Docker sidecar. ARM CRUD for user-assigned identities (server-generatedprincipalId/clientId/tenantIdGUIDs that stay stable across updates),federatedIdentityCredentialschildren (issuer/subject/audiences, as used byazurerm_federated_identity_credential), and the system-assigned readGET /{scope}/providers/Microsoft.ManagedIdentity/identities/defaultwith deterministic per-scope GUIDs. Implements the IMDS token endpoint (GET /metadata/identity/oauth2/token, imds spec 2023-07-01): requires theMetadata: trueheader, resolves an identity byclient_id/object_id/msi_res_id(or synthesizes the system-assigned identity when no selector is given), and returns the all-string IMDS response shape with a v1.0 JWT (appid,oid,idtyp=app) signed by the Entra key — verifiable against the emulator JWKS. Compatible with theazure-identityManagedIdentityCredential(Java, Python, Node.js) by pointingAZURE_POD_IDENTITY_AUTHORITY_HOSTat the emulator. The system-assigned IMDS identity's scope is configurable viaservices.managed-identity.system-assigned-scopeso tokenoidclaims can matchidentities/defaultreads, and identities appear in the resource group's/resourceslisting for azurerm's pre-delete emptiness check. Enabled by default; Java + Python + Node.js compatibility suites wired intocompat-dockerand CI (#61) - network: Azure Private Endpoint and Private DNS emulation (
Microsoft.Network/privateEndpoints,privateDnsZones,privateLinkServices) so Terraform/SDK clients that declare Private Link + private DNS plumbing apply cleanly. Private DNS zones support CreateOrUpdate/Get/Delete/List with a default SOA record set seeded on creation, record sets (A/AAAA/CNAME/MX/PTR/SOA/SRV/TXT) with ETag (If-Match/If-None-Match) concurrency, andvirtualNetworkLinks(reportingvirtualNetworkLinkState: "Completed"); record-set and link counts are tracked on the zone. Private endpoints auto-approve theirprivateLinkServiceConnections, synthesize a backing network interface with a10.0.0.4private IP, and support nestedprivateDnsZoneGroups; deleting an endpoint cascades the synthesized NIC and zone groups. Private link services echo their config with a synthesizedalias. All resource types are ARM-state only (no real private-link traffic or DNS resolution), gated by the existingnetwork.enabledflag with no routing changes. Compatibility:@QuarkusTestlifecycle coverage inNetworkHandlerTest, aPrivateLinkCompatibilityTestJava SDK suite, andazurerm_private_dns_zone/azurerm_private_dns_zone_virtual_network_link/azurerm_private_endpointresources in the Terraform and OpenTofu suites (#60)
Fixed
- core (reset):
POST /_admin/resetnow clears every state-holding service via CDI self-registration (a newResettableinterface). Previously the reset dispatched to a hand-maintained handler list that silently omitted API Management and Communication Email, so their state survived a reset used for test isolation (#107) - acr: the shared container registry sidecar is now restarted if it dies or is removed after its first start, and the readiness poller recovers a registry stuck in
provisioningState: Creating. Previously a dead sidecar left every subsequent registry pending forever, timing out azurerm/OpenTofu applies (#108)
0.8.0 - 2026-06-25
Added
- eventgrid: Azure Event Grid emulation (
Microsoft.EventGrid/topics+eventSubscriptions) — the Azure counterpart of EventBridge/SNS, HTTP-only with no Docker sidecar. Custom Topic lifecycle (CreateOrUpdate, Get, Delete, List by resource group and subscription) returning a data-planeproperties.endpoint, pluslistKeys/regenerateKey({key1,key2}). Classic scoped webhookeventSubscriptionswith aWebHookdestination andfilter(subjectBeginsWith/subjectEndsWith/includedEventTypes/isSubjectCaseSensitive); creating one runs theMicrosoft.EventGrid.SubscriptionValidationEventhandshake (or the CloudEventsOPTIONSabuse-protection probe). The data plane acceptsPOST /{topic}-eventgrid/api/eventsin both the Event Grid and CloudEvents 1.0 schemas and fans matching events out to subscriber webhooks asynchronously, retried per the subscription'sretryPolicywith exponential backoff; delivered events carrytopicset to the topic resource id and theaeg-event-type: Notificationheader. Enabled by default. Compatibility: a@QuarkusTestcovering ARM + publish + filtered delivery + validation, and a Java SDK suite (azure-messaging-eventgrid) wired intomake test-eventgrid. WebHook destinations only; dead-lettering is best-effort (logged, not written to blob) (#58)
Fixed
- blob (Data Lake / DFS): route
{account}.dfs.core.windows.netrequests to the Blob handler so ADLS Gen2 /azure-storage-file-datalakeclients resolve against the emulator (#88) - blob:
listBlobsnow honours thedelimiterparameter, returning<BlobPrefix>elements for virtual directories (hierarchical listing) instead of a flat blob list (#84) - blob: invalid range requests now include the
Content-Range: bytes */{size}header alongside the416 InvalidRangeresponse, matching Azure (#82) - servicebus: resolve an index error and add host-based routing (
{account}.servicebus.windows.net) plus root-level AtomPub /$namespaceinfo/$Resourcesrequest routing so Service Bus SDK management operations resolve (#79) - banner: list the Monitor and Email services in the startup banner's enabled-services output (#92)
0.7.0 - 2026-06-18
Added
- monitor: Azure Monitor / Log Analytics emulation (
Microsoft.OperationalInsights/workspaces+Microsoft.Insights/dataCollectionEndpoints+dataCollectionRules) — HTTP-only with no Docker sidecar. ARM CRUD for workspaces (generating acustomerIdGUID), Data Collection Endpoints, and Data Collection Rules (generating animmutableId). Implements the Logs Ingestion API (POST /dataCollectionRules/{immutableId}/streams/{stream}) which resolves the DCR's Log Analytics destination and stores each posted record against the destination workspace, and the Log Analytics query API (POST /v1/workspaces/{workspaceId}/query) which runs a KQL subset (wherewith==/!=/>/</>=/<=,project,take/limit, plus request-leveltimespanfiltering onTimeGenerated) and returns the standard{tables:[{name,columns,rows}]}shape with inferred column types. Compatible with theazure-monitor-ingestion/azure-monitor-querySDKs. Enabled by default (#68) - email: Azure Communication Services Email emulation (
Microsoft.CommunicationARM plane + ACS Email data plane) — HTTP-only with no Docker sidecar.POST /emails:sendaccepts the full ACS payload and returns202with anOperation-Locationheader;GET /emails/operations/{id}reports the operation asSucceeded. Every message is captured in-memory (Mailpit-style) for test inspection viaGET /emailMessages,GET /emailMessages/{operationId}, andDELETE /emailMessages; no real email is delivered. ARM CRUD forcommunicationServices,emailServices, andemailServices/{name}/domains/{domain}. Routed via the ACS host form*.communication.azure.com, the/{account}-email/suffix, and the ARM base URL. Compatible with theazure-communication-emailSDK. Enabled by default (#70) - vm: Container-backed virtual machines (
floci-az.services.vm.mocked=false). Each VM is backed by a long-lived Linux container (image resolved fromstorageProfile.imageReferenceviaVmImageResolver, falling back toubuntu:22.04) kept alive withtail -f /dev/null. Azure power actions map onto the container:start→ docker start,powerOff/deallocate→ docker stop (container retained),restart/redeploy/reapply→ docker restart, delete → stop + remove. VMs provision asynchronously (Creating→Succeededonce the container is running, surfaced via a readiness poller) so SDK/Terraform LRO pollers complete. Docker failures degrade gracefully to mocked-style state and are never fatal. Mocked mode remains the default, so unit tests stay Docker-free. - entra: Microsoft Entra ID (Azure AD) emulation — phase 1: a local OpenID Connect provider that replaces the previous static, unsigned-token stub. Issues real RS256-signed JWTs from a stable signing key persisted across restarts, serves an OpenID discovery document (
/.well-known/openid-configuration) and JWKS (/discovery/v2.0/keys) derived from the request base URL, and handles the non-interactive grants client credentials and resource-owner password (ROPC) in both v1.0 and v2.0 token shapes. For closer Entra parity, app-only tokens carry theidtyp=appclaim and every token carries a uniqueuti, the JWKS publishes the signing key's self-signed cert chain (x5c/x5t) alongsiden/e, and token-endpoint errors use Azure's shape (error_codes,trace_id,correlation_id,timestamp,error_uri, and theAADSTScode inerror_description). Seeds a default tenant (00000000-0000-0000-0000-000000000002) and a well-known dev app registration soClientSecretCredentialworks with zero setup. Tenant-rooted at the base URL (/{tenant}/oauth2/v2.0/token, where{tenant}may be a tenant id orcommon/organizations/consumers); the token response shape (token_type/expires_in/ext_expires_in/access_token) is preserved so existing Terraform/OpenTofu compatibility is unaffected. Enabled by default; incoming-token enforcement (validate-tokens) stays opt-in/off so existing services keep accepting any Bearer token in dev. App-registration management, Microsoft Graph CRUD, and interactive flows (device code, auth code + PKCE) follow in later phases (#23) - compat (az cli): new Azure CLI compatibility suite (
compatibility-tests/compat-azcli, BATS) that registers a customaz cloudpointing at floci-az and runsaz login --service-principalagainst the Entra token endpoint, then exercises resource group, storage account (+ blob data-plane), Key Vault (+ secret data-plane), virtual network/NIC, ACR, and Redis through the realazCLI. Wired intomake test-azcli,make compat-docker, and thecompatibility.ymlCI matrix - arm: management-plane endpoints used by the
azCLI during sign-in and resource creation —GET /subscriptionsandGET /tenants(list), andMicrosoft.*/checkNameAvailability(returns available) - arm, network:
enabledtrue/false flags so every service can be toggled (closing the last config gaps).FLOCI_AZ_SERVICES_NETWORK_ENABLED=falsegates all of Microsoft.Network (VNet, subnets, NIC, public IP, NSG, and DNS zones) —/providers/Microsoft.Network/...then returns404while the rest of ARM keeps working.FLOCI_AZ_SERVICES_ARM_ENABLED=falseturns off the entire ARM management plane (and therefore every ARM-based service). Both default totrue; the cosmeticcosmos-engineservice type is now gated oncosmos.enabledas well - sql, functions, cosmos: uniform
mockedtrue/false flag so every Docker-backed service has the same explicit on/off switch (matching vm/acr/redis/aks/servicebus/eventhub). Defaultfalse.FLOCI_AZ_SERVICES_SQL_MOCKED=truecreates servers in state withstate=Ready, noazure-sql-edgecontainer and no EULA required (data plane unavailable).FLOCI_AZ_SERVICES_FUNCTIONS_MOCKED=truekeeps the management plane (deploy/list/get/delete) working with no runtime container; invocations return a synthetic200stub.FLOCI_AZ_SERVICES_COSMOS_MOCKED=trueis a master switch that forces all engine containers off (equivalent toengines.startup=disabled); the in-process NoSQL/Table paths are unaffected
Changed
- identity: the OAuth2 token endpoints (
/{tenant}/oauth2/v2.0/token,common/...) now return a genuine signed JWT served by the Entra service instead of a fixed unsigned stub token;metadata/endpointsARM environment discovery is unchanged
0.6.0 - 2026-06-09
Added
- acr: Azure Container Registry emulation (
Microsoft.ContainerRegistry/registries) — registry lifecycle (CreateOrUpdate, Get, Patch, List by subscription and resource group, Delete),listCredentials/regenerateCredential,listUsages, andcheckNameAvailability. Non-mocked mode backs all registries with a single sharedregistry:2sidecar exposing the Docker Registry HTTP API V2; registries are isolated by an internal repository prefix, sologinServeris path-style (localhost:{port}/{name}, not{name}.azurecr.io) and standarddocker push/pullwork against it. The shared registry runs anonymous (admin credentials are issued but not enforced at the data plane). Registries provision asynchronously (Creating→SucceededonceGET /v2/answers); mocked mode (default in tests) is management-plane only. Compatibility: Terraform/OpenTofuazurerm_container_registrysuites and a Python data-plane push/pull test - redis: Azure Cache for Redis emulation (
Microsoft.Cache/redis) — cache lifecycle (CreateOrUpdate, Get, Patch, List by subscription and resource group, Delete) pluslistKeysandregenerateKey. Non-mocked mode backs each cache with a realvalkey/valkey:8-alpinesidecar container (a drop-in, RESP-compatible Redis fork) that standard Redis clients connect to; the primary access key is the Redis password (--requirepass) and both keys authenticate via adefault-user ACL. Caches provision asynchronously (Creating→Succeededonce the container answersPING); mocked mode (default in tests) is management-plane only. Compatibility: Terraform/OpenTofuazurerm_redis_cachesuites and a Python redis-py data-plane test - appconfig: 2024-09-01 data-plane parity for the behaviors SDK clients exercise — server-side pagination (
@nextLink/Linkheader with opaqueaftercontinuation, 100 items per page),$selectfield projection,tagsfiltering (repeatable, AND semantics) on key-value and revision lists,Accept-Datetimetime-travel resolved from revision history, aSync-Tokenconsistency header on every response, and true async snapshot provisioning (PUTreturnsprovisioning+Operation-Location;GET /operationsreportsSucceededand flips the snapshot toready) plus conditionalIf-Match/If-None-MatchonGetSnapshot. Adds aqueryParamsMultiaccessor toAzureRequestso repeated query params (tags) survive routing. Compatibility: extended Java and Pythonazure-appconfigurationsuites and a new Node@azure/app-configurationsuite - vm: Azure Virtual Machines emulation (
Microsoft.Compute/virtualMachines) — VM lifecycle (CreateOrUpdate, Get, List by subscription and resource group, UpdateTags, Delete), power actions (start,powerOff,deallocate,restart,redeploy,reapply),instanceViewreportingProvisioningState/*andPowerState/*, and?$expand=instanceView. Power actions return202with anAzure-AsyncOperationheader and a terminal operation-status endpoint for SDK LRO polling. Mocked mode (default) requires no Docker; container-backed VMs are planned (#19) - arm:
Microsoft.Networkdependency stubs — virtual networks, subnets, network interfaces (synthesized private IP), public IP addresses, and network security groups, so Terraform'sazurerm_linux_virtual_machineand its dependencies apply end-to-end - arm: Terraform/OpenTofu compatibility suite extended with a Linux virtual machine and its network dependencies
Changed
- acr, redis: Docker backing is now on by default (
mocked: false) — creating a registry or cache starts a real container (a sharedregistry:2for ACR, avalkey/valkey:8-alpinecontainer per cache for Redis). SetFLOCI_AZ_SERVICES_ACR_MOCKED=true/FLOCI_AZ_SERVICES_REDIS_MOCKED=trueto restore management-plane-only mode. Unit tests pinmocked=truevia test profiles and remain Docker-free.
0.5.0 - 2026-05-28
Added
- arm: Azure Resource Manager management-plane emulation — ARM routing on
management.azure.com-style paths; resource group CRUD (Microsoft.Resources); storage account + blob/queue/table endpoint resolution (Microsoft.Storage); Key Vault CRUD with vault URI (Microsoft.KeyVault); subscription and resource-group list endpoints; OAuth token endpoint (/oauth2/token) returning a synthetic bearer token accepted by the ARM routing layer (#40) - arm: Terraform compatibility —
azurermprovider~> 4.0;make compat-terraformtarget; BATS test suite covering resource group, storage account, storage container, storage queue, Key Vault, and Key Vault secret via Terraform apply/destroy (#40) - arm: OpenTofu compatibility — identical BATS suite against OpenTofu
tofuCLI;make compat-opentofutarget (#40)
Fixed
- blob: Large blob uploads beyond 20 MB now work correctly — raised Quarkus HTTP body limit to
2G(quarkus.http.limits.max-body-size) and Jackson string-length limit to 512 MB; implemented block blob protocol (PUT ?comp=block/PUT ?comp=blocklist) so the Azure SDK's chunked multi-part upload path is fully supported (#41) - functions: All functions in a Function App now share a single container — pool keyed on
appKey(account/appName) instead of per-function;ContainerLauncher.launch()injects every function's code atwwwroot/{funcName}/and writes a sharedhost.jsonbefore the container starts; previously N functions started N containers (#42)
0.4.0 - 2026-05-25
Added
- tls: Dynamic self-signed certificate generation at runtime via BouncyCastle — no static cert bundled in the image; certs persist under
data/tls/and regenerate automatically when hostname config changes (FLOCI_AZ_HOSTNAMEorFLOCI_AZ_BASE_URL) - tls: Protocol-sniffing
TlsProxyServer— both HTTP and HTTPS served on the same public port4577; first byte0x16routes to the HTTPS backend, anything else to HTTP - tls:
GET /_floci/tls-certendpoint — returns the active TLS certificate PEM so SDK clients and compat tests can dynamically install it into their truststores - tls:
CertificateGenerator— dedicated class (matching aws-local structure) responsible for X.509 self-signed cert generation with configurable SANs (hostname, IP, wildcard) - tls:
BouncyCastleInitializer— CDI@Startupbean that registers the BouncyCastle JCA provider at application startup - event-hubs: Mocked namespace mode — management API returns
"mocked":truewhen no Artemis broker is running; compat tests skip AMQP data-plane assertions gracefully viaAssumptions.assumeTrue - compat (java):
CosmosCompatibilityTestnow works in Docker compat runs —EmulatorConfig.installEmulatorTlsCert()fetches the emulator cert at test setup and installs it into a temp PKCS12 truststore; Netty forced to JDK SSL via-Dio.netty.handler.ssl.noOpenSsl=true
Changed
- tls: Replaced static bundled certificates (
src/main/resources/certs/) with runtime generation — removedfloci-az.crt,floci-az.key,floci-az.p12from the image - tls:
TlsConfigSourcedelegates cert generation toCertificateGeneratorinstead of inlining BouncyCastle calls - build: Added GraalVM
--initialize-at-run-timeflags for BouncyCastle classes (DRBG,SP800SecureRandom,KeyPairGeneratorSpi,CertificateFactory) andCertificateGeneratorto support native image builds - ci: Compatibility workflow now starts the emulator with
FLOCI_AZ_TLS_ENABLED=trueandFLOCI_AZ_HOSTNAME=floci-az— required for Cosmos Java SDK which enforces HTTPS in gateway mode - compat (java): Removed static
floci-az.p12truststore from test resources — truststore is now built dynamically from the live emulator cert
0.3.0 - 2026-05-23
Added
- aks: Azure Kubernetes Service emulation — CreateOrUpdate, Get, Delete, List (by subscription and by resource group), UpdateTags, agent pool CRUD,
listClusterAdminCredential/listClusterUserCredential; ARM path routing onMicrosoft.ContainerService - aks: Real k3s mode — each cluster starts a privileged
rancher/k3scontainer; background readiness poller transitionsprovisioningStatefromCreating→Succeeded; kubeconfig with real CA extracted from the container - aks: Mocked mode (
FLOCI_AZ_SERVICES_AKS_MOCKED=true) — clusters immediately reachSucceededwith a synthetic kubeconfig; no Docker required; suitable for unit tests and CI without Docker - aks:
instanceId-based container naming (floci-az-aks-{instanceId}) — 8-char UUID prefix per cluster prevents naming collisions when the same cluster name exists across resource groups -
aks: 10 unit tests (
AksHandlerTest) covering full CRUD in mocked mode; 5 Docker integration tests (AksDockerTest) with@TestProfile(mocked=false)exercising real k3s start, readiness poll, kubeconfig extraction, and deletion -
cosmos: Azure Cosmos DB SQL API emulator — always-on at
/{account}-cosmos/; databases, containers, and document CRUD; full SQL dialect (SELECT,WHERE,ORDER BY,GROUP BY,OFFSET LIMIT,SELECT TOP,SELECT DISTINCT); aggregates (COUNT,SUM,AVG,MIN,MAX); string, math, array, and type-check functions; named parameters;PATCHdocument operations; transactional batch; server-side pagination with continuation tokens; system properties (_rid,_self,_etag,_ts) auto-generated on every write (#16) - cosmos: Modular multi-API engine support — opt-in per API via environment variable; Docker-backed: MongoDB (
mongo:7), PostgreSQL/Citus (citusdata/citus), Cassandra (scylladb/scylla:6.2), Gremlin (tinkerpop/gremlin-server); embedded (no Docker): NoSQL in-process SQL engine, Table in-memory OData; each engine exposes a/connectendpoint returning its connection string (#16) - cosmos: HTTPS proxy on port
4578with bundled self-signed certificate (CN=localhost, valid 100 years) — required for the Azure Cosmos DB Java SDK which enforces TLS in gateway mode; no certificate import needed (#16) - cosmos: Java compatibility tests —
CosmosCompatibilityTest(SQL API CRUD + queries),CosmosNoSqlEngineCompatibilityTest(embedded NoSQL engine),CosmosMongoEngineCompatibilityTest,CosmosPostgresEngineCompatibilityTest,CosmosCassandraEngineCompatibilityTest,CosmosGremlinEngineCompatibilityTest,CosmosTableEngineCompatibilityTest(#16) - table: OData
$filter/$select/$topquery support — operatorseq,ne,gt,ge,lt,le,and,or,not; functionsstartswith,endswith,substringof; typed property annotations (Edm.Int64,Edm.DateTime,Edm.Guid, etc.) - table: ETag optimistic concurrency —
If-Match: *andIf-Match: "<etag>"honoured onPUT,MERGE,PATCH, andDELETE;412 Precondition Failedon mismatch - table: Entity Group Transactions (
$batch) — atomic execution of multiple operations against a single partition key; full rollback on any failure; standard Azuremultipart/mixedwire format - table: Server-side pagination with
NextPartitionKey/NextRowKeycontinuation tokens - event-hubs: Multi-namespace support — each Event Hubs namespace gets its own isolated Artemis container with dynamically allocated ports; default namespace starts on-demand via
PUT /{account}-eventhub/namespaces/{ns} - event-hubs: Namespace management REST API —
GET/PUT/DELETE /{account}-eventhub/namespaces[/{ns}];GET /{account}-eventhub/namespaces/{ns}/connectionreturns AMQP/AMQPS ports and Kafka bootstrap when running;GET /{account}-eventhub/namespaces/{ns}/tls-certreturns TLS PEM - event-hubs: ANYCAST + exclusive divert topology embedded in
broker.xml— durable queues per consumer group ensure messages persist before a receiver connects; Jolokia setup runs asynchronously after broker start - event-hubs:
ArtemisConfigGeneratorgeneratesbroker.xmlper namespace;ArtemisTlsGeneratorgenerates self-signed RSA-2048 cert + PKCS12 keystore per namespace for TLS AMQP - event-hubs: Java AMQP compatibility tests (
EventHubCompatibilityTest,EventHubNamespaceManagementTest) replacing previous Python uamqp suite - event-hubs: Kafka (
EventHubsKafkaManager) starts on-demand when a namespace is created withkafkaEnabled: true; idempotent, synchronized, resolves broker address correctly inside and outside Docker - docker:
ContainerSpec,ContainerBuilder,ContainerLifecycleManager,ImageCacheService,PortAllocatorported from floci — shared container infrastructure for sidecar-based services
Changed
- docs: README restructured to match floci (aws-local) format — nav links, "What is?", Features section, SDK examples collapsed per language, Migrating from Azurite, Star History, Contributors
- docs:
mkdocs.yml— added Cosmos DB service page; movedapplication.yml ReferenceunderAdvancedsubsection - docker: Added OCI image labels (
org.opencontainers.image.*,io.k8s.*,io.openshift.*) toDockerfile.jvm-packageandDockerfile.native-package - build: Removed stale
test-appconfigMakefile target andAPPCONFIG_DIRvariable — AppConfig tests are covered bytest-pythonandtest-java-compat
0.2.0 - 2026-05-15
Added
- key-vault: Azure Key Vault Secrets service — CRUD, versioning (immutable versions with latest pointer), soft-delete lifecycle (delete → recover or purge), properties update (
content_type,tags,enabled,nbf,exp), list secrets/versions/deleted, backup (#16) - key-vault: 24 Python (
azure-keyvault-secrets 4.11.0) compatibility tests covering secrets CRUD, versioning, soft-delete, enabled attribute, and backup (#16) - app-config: Azure App Configuration service — key-values, labels, feature flags, snapshots (frozen KV sets), revisions, ETags, and optimistic-concurrency locks (#15)
- app-config: Snapshot lifecycle —
PUT /snapshots/{name}captures a frozen set of key-values;GET /operations?snapshot={name}returns the LRO result;GET /kv?snapshot={name}reads from the frozen set; supportskeyandkey_labelcomposition modes (#15) - app-config: 36 Python (
azure-appconfiguration 1.7.1) and 36 Java compatibility tests covering KV, labels, feature flags, ETags, locks, and snapshots (#15) - docker:
CurrentContainerNetworkResolver— detects which Docker network floci-az itself is on when running inside a container, improving function container IP resolution (#14) - docker:
DockerClientProducergainsnormalizeDockerHost()(prependstcp://when scheme is missing) andresolveEffectiveDockerHost()(prefersDOCKER_HOSTenv over config default) — fixes connectivity in Bitbucket Pipelines and similar CI environments (#14) - functions:
FLOCI_AZ_SERVICES_FUNCTIONS_DOCKER_HOST_OVERRIDEenv var — explicitly override the hostname function containers use to reach floci-az (#14)
Fixed
- docker:
ContainerDetector.hasMountInfoMarkers()now only checks lines where the filesystem is mounted at root (/), preventing false positives in some cgroup configurations (#14) - functions:
WarmPoolfield renamed tomaxPoolSizePerFunction; eviction scheduler renamed toevictionScheduler; idle timeout config key renamed fromidle-timeout-mstocontainer-idle-timeout-seconds(value now in seconds, default300) (#14) - storage:
HybridStorage,PersistentStorage, andWalStorage— replaced.toList()withCollectors.toCollection(ArrayList::new)for GraalVM native-image compatibility (#14)
Dependencies
- Bump
actions/setup-pythonfrom 5 to 6 - Bump
actions/setup-javafrom 4 to 5 - Bump
docker/login-actionfrom 3 to 4 - Bump Maven minor/patch group
0.1.4 - 2026-04-26
Fixed
- Release pipeline fix (version bump only; no functional changes)
0.1.3 - 2026-04-25
Added
- docker:
docker/entrypoint.sh— gosu-based Docker socket GID fix-up; theflociuser (uid 1001) is granted access to the Docker socket at runtime, handling both Docker Desktop (macOS/Windows) and native Linux Docker without manual group configuration
Changed
- ci: Release workflow restructured with SHA-pinned actions and a single multi-arch native build (replaces separate per-arch builds)
- docker: Dockerfile aligned with floci structure — dedicated
flociuser, correct/app/datapermissions, ENTRYPOINT wired throughdocker/entrypoint.sh
0.1.2 - 2026-04-23
Fixed
- functions: Stability improvements — container lifecycle edge cases, improved error handling on function invocation failures (#9)
- core: Log output improvements — cleaner startup banner, structured service-status lines (#9)
- docs: Corrected broken links in documentation
Changed
- Expanded compatibility test coverage across Blob, Queue, Table, and Functions suites (#9)
0.1.1 - 2026-04-22
Fixed
- Docker image deployment issue in release workflow (multi-arch manifest push)
0.1.0 - 2026-04-22
Fixed
- GitHub Actions Java version configuration in release workflow
0.0.1 - 2026-04-22
Added
- blob: Azure Blob Storage — create/delete containers; upload, download, delete, and list blobs; ETag support
- queue: Azure Queue Storage — create/delete queues; send, receive, peek, and delete messages; visibility timeout
- table: Azure Table Storage — create/delete tables; insert, get, update, upsert, delete, and list entities; OData filter support
- functions: Azure Functions emulation — deploy HTTP-triggered functions via ZIP upload; warm-container pool (LIFO, one container per function); supports
node,python,java, anddotnetruntimes; Docker-in-Docker via mounted Docker socket - storage: Four pluggable storage backends —
memory(default),persistent,hybrid, andwal; configurable globally or per service - auth:
devmode (accept any credentials) andstrictmode (validate HMAC-SHA256 shared-key signatures) - azfloci: Companion Python CLI that proxies
azcommands to the local emulator, injecting connection strings automatically - compat: Python (
azure-storage-blob,azure-storage-queue,azure-data-tables), Java (Azure SDK BOM 1.2.28), and Node.js (@azure/storage-blob,@azure/storage-queue,@azure/data-tables) compatibility test suites - Multi-arch Docker image (
linux/amd64,linux/arm64) — native binary (latest) and JVM (latest-jvm) tags - Single unified port
4577for all services