Cohesive.Adapters.Pulumi.Azure
0.1.0-alpha.100
dotnet add package Cohesive.Adapters.Pulumi.Azure --version 0.1.0-alpha.100
NuGet\Install-Package Cohesive.Adapters.Pulumi.Azure -Version 0.1.0-alpha.100
<PackageReference Include="Cohesive.Adapters.Pulumi.Azure" Version="0.1.0-alpha.100" />
<PackageVersion Include="Cohesive.Adapters.Pulumi.Azure" Version="0.1.0-alpha.100" />
<PackageReference Include="Cohesive.Adapters.Pulumi.Azure" />
paket add Cohesive.Adapters.Pulumi.Azure --version 0.1.0-alpha.100
#r "nuget: Cohesive.Adapters.Pulumi.Azure, 0.1.0-alpha.100"
#:package Cohesive.Adapters.Pulumi.Azure@0.1.0-alpha.100
#addin nuget:?package=Cohesive.Adapters.Pulumi.Azure&version=0.1.0-alpha.100&prerelease
#tool nuget:?package=Cohesive.Adapters.Pulumi.Azure&version=0.1.0-alpha.100&prerelease
Cohesive.Adapters.Pulumi.Azure
Connect exact Cohesive Infra declarations to native Pulumi resources and their existing lifecycle.
Tailor at the seams: canonical identity, relationships, ownership and validated projections belong to Cohesive; ordinary provider configuration and resource options belong to native Pulumi APIs. Add construction helpers only where they enforce a meaningful cross-resource invariant or remove repeated integration friction. A parallel wrapper for every provider option is not an adoption requirement.
- Machine Learning binding seam: workspace supporting identities and explicit disabled, managed or externally owned registry selection.
- App Service hosting seam: canonical shared/dedicated plans, workload activation, classified native settings and explicit identity observations.
- Entra binding seam: external tenant versus managed registrations, explicit permission actions and classified credentials.
- Telemetry binding seam: canonical Application Insights/Log Analytics association and secret consumer outputs.
- Key Vault binding seam: associate a native Pulumi vault with canonical identity and explicit consumer decisions.
- Shared Blob Storage construction: one account owner, exact containers and explicit/coalesced blob grants.
- Cosmos SQL construction: account/database/container policy and explicit data-plane grant scopes.
- Durable Task construction is described below.
Durable Task
Construct one Azure Durable Task Consumption scheduler and task hub from an exact
InfrastructureTargetDeploymentPlan inside an existing Pulumi program. The adapter returns
managed-identity connection outputs and canonical worker binding access-grant inputs.
Ownership and flow
Cohesive.Infra remains the authority for topology, canonical bindings, capability/readiness proof,
physical identity, and lifecycle ownership. Validate reads that compiled plan; Register repeats
validation before creating any provider resource. The selected resource must use facility
azure/durable-task, target pulumi-azure-native/3.16.0, and the expected single Pulumi lifecycle
authority. Its physical identity is:
azure/durable-task/schedulers/<scheduler-name>/task-hubs/<hub-name>
The manifest identity supplies both Azure names. AzureDurableTaskPolicy supplies the explicit
subscription, resource group, location, Pulumi logical names, worker contract, and attributed network
rules. The caller must provide the same subscription it uses for its other Azure resources; the
generated provider never falls back to an ambient subscription. This physical identity convention is
relative to that explicit deployment scope; it does not itself assert subscription ownership.
The generated provider creates scheduler → hub dependencies through Pulumi outputs. Active canonical
worker bindings produce AccessGrant inputs scoped to the hub's actual ID, with the built-in
Durable Task Data Contributor role. The caller supplies the source workload's managed-identity
principal and preserves its role-assignment GUID, logical name, parent, and Azure Native provider.
An explicitly non-participating worker has no grant. Endpoint and managed-identity connection strings
contain no credentials; Pulumi output secret propagation is preserved, including secret principal inputs.
Pulumi owns state, reconciliation, retries, update atomicity, and operation cancellation. The adapter adds no lifecycle execution or store. Cancellation is checked before registration; after registration starts, cancellation belongs to the existing Pulumi executor. A failed provider operation may leave partial Pulumi-managed progress and must be recovered through the same backend, not a second engine.
Existing-plan integration and migration
Within the existing Pulumi program, first call the Aspire handoff's RequireExactPlan(plan). The
Cohesive.Adapters.Aspire.Pulumi executor and handoff
remain unchanged. This provider adapter deliberately has no Aspire dependency.
The following fragment assumes the program already has plan, handoff, subscriptionId,
resourceGroupName, resourceGroup, location, existingSchedulerTags, workerPrincipalId,
existingAssignmentId, and azureProvider:
handoff.RequireExactPlan(plan);
var durable = AzureDurableTaskConstruction.Register(plan, new AzureDurableTaskPolicy
{
Resource = new("resources/process-scheduler"),
WorkerContract = new("contracts/durable-worker"), // use the existing canonical contract ID
LifecycleAuthority = handoff.LifecycleAuthority,
SubscriptionId = subscriptionId,
ResourceGroupName = resourceGroupName,
Location = location,
ProviderName = "existing-durable-provider",
SchedulerName = "existing-scheduler",
TaskHubName = "existing-hub",
IpAllowlist = ["192.0.2.0/24"], // replace with explicit environment policy
Tags = existingSchedulerTags, // immutable sorted dictionary of the existing non-secret tags
SourceReferences = [SourceReference.Create("environment-policy", "production/durable-task/v1")]
}, subscriptionId, resourceGroupDependency: resourceGroup);
var workerBinding = durable.WorkerBindings.Single(b => b.Source == new InfrastructureNodeId("workloads/worker"));
var grant = new RoleAssignment("existing-worker-grant",
durable.AccessGrant(workerBinding.Id, subscriptionId, workerPrincipalId, existingAssignmentId),
new CustomResourceOptions { Provider = azureProvider });
var connectionString = durable.ConnectionString;
Replace the handwritten provider/scheduler/hub declarations in place. Preserve their logical names,
physical names, subscription, resource group, region, common parent (null for root resources), and
role identities and tags. Pass resourceGroupDependency when the group is created by the same program;
otherwise null means the group already exists. Scheduler creation waits for that dependency, and hub
creation waits for scheduler outputs. No component parent is introduced. Preserve the role provider and any existing
resource options when registering the returned role arguments. Programs requiring distinct parents,
imports, aliases, or other scheduler/hub options need an explicit adapter extension before adoption.
Do not construct both the old and new slice in one program.
Remove the consumer's generated Durable Task SDK project reference when adopting this package; the package contains that assembly. Compare previews using the same exact plan and Pulumi backend. Any unexpected replacement or unrelated drift must be resolved before an apply. Ari adoption and environment-specific identity/network decisions are tracked separately in ARI-535.
Supported boundary and diagnostics
This initial slice supports Consumption, one scheduler/hub pair, managed resources, same-subscription ServicePrincipal grants, explicit IPv4 address/CIDR rules, and managed-identity connections. Empty network lists are emitted as empty; there is no automatic public-access fallback. Dedicated capacity, private networking, IPv6, retention policy, cross-subscription grants, physical aliases, other binding contracts/directions, and referenced/external lifecycle ownership are outside this slice. Unsupported options are absent from the policy rather than silently ignored; use strict document JSON when restoring policy so unknown properties are rejected.
Validate returns structured DocumentValidationDiagnostic values with stable azure.durable-task.*
codes, canonical resource location, manifest fingerprint, and policy source references. Register
throws AzureDurableTaskValidationException containing those diagnostics before any registration.
The original plan's compilation errors are retained. Policies can be serialized with
StrictDocumentJson.CreateOptions; they are target configuration, not another topology or binding IR.
Principal-to-workload association remains an explicit caller responsibility: the adapter cannot infer
the Azure principal belonging to a canonical workload or verify an arbitrary external provider's settings.
SDK provenance and packaging
The generated sources under Generated/dotnet come from Pulumi Azure Native 3.19.0, module
durabletask v20251101, generated by Pulumi CLI 3.260.0. The schema is pinned to
Azure API 2025-11-01
and its task-hub schema.
The generated resource token namespace is preserved for migration. Regenerate from the repository root:
pulumi package gen-sdk azure-native --version 3.19.0 --language dotnet --local \
--out src/adapters/Cohesive.Adapters.Pulumi.Azure/Generated -- durabletask v20251101
Do not hand-edit generated files. The adjacent host Directory.Build.props/targets disable Cohesive
global usings, pin the generated project's Pulumi runtime to 3.113.1, and disable independent packing.
The Cohesive NuGet package bundles the generated assembly; it does not publish a package under Pulumi's
namespace. Azure Native 3.16.0 is the existing general Azure role-assignment SDK. No SDK dependency is
introduced into Cohesive.Infra.
The design evaluated the existing exact target deployment plan, Aspire/Pulumi handoff and executor, Infra configuration bindings, and Durable Task runtime adapter. Reuse the first three unchanged; runtime orchestration is not infrastructure construction. A separate provider adapter keeps generated Azure dependencies outside core Infra and the provider-neutral Aspire bridge. A general graph lowering framework or parallel connection-binding catalog would duplicate existing semantic authority and is unnecessary for this bounded facility.
Verification
dotnet test src/Cohesive.Adapters.Pulumi.Azure.Tests -c Release
dotnet test src/Cohesive.Adapters.Aspire.Pulumi.Tests -c Release
dotnet pack src/adapters/Cohesive.Adapters.Pulumi.Azure -c Release -o artifacts/nuget
After eng/pack-local.sh <version>, run bash eng/test-pulumi-azure-package-consumer.sh <version>.
This repeats the semantic tests against NuGet packages only and verifies that the bundled provider
assembly loads without a consumer-side generated project. CI runs the same package-only check.
Offline Pulumi mocks verify stable construction under reordered network rules, provider subscription, schema namespace, physical names, preserved parent options, credential classification, exact hub-scoped grants, absent-worker exclusion, early cancellation, policy roundtrips, and fail-before-registration diagnostics. These checks do not prove live Azure availability, RBAC permission, or migration preview equivalence; the consumer validates those against its existing backend before applying.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Cohesive.Infra (>= 0.1.0-alpha.100)
- Pulumi (>= 3.113.1)
- Pulumi.AzureAD (>= 6.9.0)
- Pulumi.AzureNative (>= 3.16.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.1.0-alpha.100 | 0 | 9/20/2026 |
| 0.1.0-alpha.99 | 48 | 9/20/2026 |
| 0.1.0-alpha.98 | 32 | 9/19/2026 |
| 0.1.0-alpha.97 | 37 | 9/19/2026 |
| 0.1.0-alpha.96 | 62 | 9/19/2026 |
| 0.1.0-alpha.95 | 48 | 9/18/2026 |
| 0.1.0-alpha.94 | 38 | 9/18/2026 |
| 0.1.0-alpha.93 | 37 | 9/18/2026 |
| 0.1.0-alpha.92 | 44 | 9/18/2026 |
| 0.1.0-alpha.91 | 38 | 9/18/2026 |
| 0.1.0-alpha.90 | 42 | 9/18/2026 |
| 0.1.0-alpha.89 | 42 | 9/18/2026 |
| 0.1.0-alpha.88 | 46 | 9/18/2026 |
| 0.1.0-alpha.87 | 40 | 9/17/2026 |
| 0.1.0-alpha.86 | 48 | 9/17/2026 |
| 0.1.0-alpha.85 | 45 | 9/17/2026 |
| 0.1.0-alpha.84 | 42 | 9/17/2026 |
| 0.1.0-alpha.83 | 39 | 9/16/2026 |
| 0.1.0-alpha.82 | 50 | 9/16/2026 |
| 0.1.0-alpha.81 | 38 | 9/16/2026 |