Community.Pulumi.Osano 0.2.1

dotnet add package Community.Pulumi.Osano --version 0.2.1
                    
NuGet\Install-Package Community.Pulumi.Osano -Version 0.2.1
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Community.Pulumi.Osano" Version="0.2.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Community.Pulumi.Osano" Version="0.2.1" />
                    
Directory.Packages.props
<PackageReference Include="Community.Pulumi.Osano" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Community.Pulumi.Osano --version 0.2.1
                    
#r "nuget: Community.Pulumi.Osano, 0.2.1"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Community.Pulumi.Osano@0.2.1
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Community.Pulumi.Osano&version=0.2.1
                    
Install as a Cake Addin
#tool nuget:?package=Community.Pulumi.Osano&version=0.2.1
                    
Install as a Cake Tool

Osano Pulumi Provider for .NET

Build Status License: MIT NuGet version

⚠️ Unofficial community provider

This package is not affiliated with Osano or Pulumi. It is maintained by the community and provided "as is" under the MIT license. Use GitHub Issues for support.

Community.Pulumi.Osano is the .NET SDK for the Osano Pulumi provider. It lets you manage Osano Cookie Consent and Unified Consent workflows from C# and other .NET languages alongside the rest of your infrastructure-as-code. You can:

  • Create Cookie Consent configurations and rules, publish them after all dependencies settle, and export the hosted CMP script URL and exact HTML tag, so the same pipeline that provisions a website can put the consent script first in its <head>.
  • Look up the script, publish status, rules, discoveries, and audit log of any Cookie Consent configuration with GetCookieConsentConfig, GetCookieConsentConfigs, GetCookieConsentRules, GetCookieConsentDiscoveries, and GetCookieConsentAuditLog, for example to consume a centrally managed configuration from a website stack or to gate a switch to production mode.
  • Submit consent decisions programmatically from Pulumi deployments, including Global Privacy Control consents.
  • Query unified consent state for a subject with GetUnifiedConsent, and resolve verified, anonymous, and session references with GetSubject, GetSubjectProfile, and GetSession.
  • Inspect UC configuration and privacy protocol collections with GetConfig, GetCollections, and GetCollection, and check for existing consent state and hashed consent profiles with CheckConsent and GetConsentProfile.
  • Start and verify subject-profile challenges with SendSubjectCode and VerifySubjectCode. Pulumi runs functions on every preview, update, and refresh, so call these two from automation rather than declaring them in a long-lived stack; otherwise each run sends a new code.

Every function has an Invoke method that accepts and returns Pulumi outputs and an InvokeAsync method that returns a Task. The types live in the Community.Pulumi.Osano namespace, with argument types in Community.Pulumi.Osano.Inputs. SDKs for Node.js, Python, Go, and Java are also available; see the project README.

Prerequisites

  • Pulumi CLI v3+
  • .NET 8+
  • API access to an Osano tenant: a Customer REST API key for Cookie Consent, a Unified Consent API key for Unified Consent, or both for mixed workloads

Installation

dotnet add package Community.Pulumi.Osano

The package declares its provider plugin, and Pulumi downloads the matching pulumi-resource-osano release from GitHub the first time you run pulumi preview or pulumi up. To install it manually, pin the version and point Pulumi at the GitHub releases:

pulumi plugin install resource osano 0.2.1 --server github://api.github.com/jflavan/pulumi-osano

Package publishing describes how each release is built and how to verify its provenance.

This program creates a Cookie Consent configuration with one rule, publishes it, and hands the script tag to the rest of the program. It assumes a project created with pulumi new csharp:

dotnet add package Community.Pulumi.Osano
pulumi config set osano:osanoApiKey --secret   # Customer REST API key
pulumi up

Program.cs:

using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using Community.Pulumi.Osano;
using Pulumi;

return await Deployment.RunAsync(() =>
{
    var desired = new
    {
        Name = "www-example-com",
        Domains = new[] { "www.example.com" },
        Mode = "permissive",
        Configuration = new Dictionary<string, object> { ["storagePolicyHref"] = "https://www.example.com/privacy" },
        Rules = new[]
        {
            new { StoreType = "cookies", Classification = "ANALYTICS", Rule = "_ga", RuleType = "EXACT_MATCH" },
        },
    };

    var config = new CookieConsentConfig("consent", new()
    {
        Name = desired.Name,
        Domains = desired.Domains,
        Mode = desired.Mode,
        Configuration = desired.Configuration,
    });
    var rules = desired.Rules.Select((rule, i) => new CookieConsentRule($"rule-{i}", new()
    {
        ConfigId = config.ConfigId,
        StoreType = rule.StoreType,
        Classification = rule.Classification,
        Rule = rule.Rule,
        RuleType = rule.RuleType,
    })).ToArray();

    // Publish exactly once per change: derive the token from everything that is published.
    var changeToken = Convert.ToHexString(
        SHA256.HashData(Encoding.UTF8.GetBytes(JsonSerializer.Serialize(desired)))).ToLowerInvariant();
    var publication = new CookieConsentPublication("publication", new()
    {
        ConfigId = config.ConfigId,
        ChangeToken = changeToken,
    }, new CustomResourceOptions
    {
        DependsOn = rules.Prepend<Resource>(config).ToArray(),
        CustomTimeouts = new CustomTimeouts { Create = TimeSpan.FromMinutes(20), Update = TimeSpan.FromMinutes(20) },
    });

    // Hand the tag to whatever renders or configures the site's <head>; it must come first.
    return new Dictionary<string, object?>
    {
        ["scriptTag"] = publication.ScriptTag,
        ["headHtml"] = publication.ScriptTag.Apply(tag => $"<head>\n  {tag}\n</head>"),
    };
});

pulumi preview never publishes. pulumi up creates the configuration and rule, publishes, waits for Osano to finish, and returns <script src="https://cmp.osano.com/{customerId}/{configId}/osano.js"></script>. Running it again without changes publishes nothing.

The publication exports ScriptSrc (https://cmp.osano.com/{customerId}/{configId}/osano.js) and ScriptTag (exactly <script src="{scriptSrc}"></script>). These installation values are deliberately non-secret. Put the tag first in the site <head> without async or defer, so the CMP loads before scripts it may control. The URL never changes between revisions, so a website only needs it once. Publication completion and CDN propagation are separate: Osano's CDN can take up to 15 minutes to serve a new revision, and browsers cache osano.js for up to 24 hours.

Read a configuration from another stack

To use the script in another stack, such as one per website, read it with GetCookieConsentConfig.Invoke instead of managing the configuration there:

var consent = GetCookieConsentConfig.Invoke(new() { ConfigId = "<config-id>" });

return new Dictionary<string, object?>
{
    ["headScript"] = consent.Apply(c => c.ScriptTag),     // the same value the publication exports
    ["published"] = consent.Apply(c => c.PublishStatus),  // the URL returns 403 until the first publish
};

Before switching a configuration to production mode, which blocks everything unclassified, GetCookieConsentDiscoveries lists what osano.js has discovered that no rule covers yet. The end-to-end workflow guide covers the whole pipeline, including Content Security Policy settings and per-environment configurations.

The Consent resource submits a consent decision, and the functions read consent state back. This program assumes a project created with pulumi new csharp:

dotnet add package Community.Pulumi.Osano
pulumi config set osano:unifiedConsentApiKey --secret
pulumi config set subjectRef <subject-id> --secret
pulumi config set configId <config-id>
pulumi config set privacyProtocolId <protocol-id>
pulumi up

Program.cs:

using Community.Pulumi.Osano;
using Community.Pulumi.Osano.Inputs;
using Pulumi;

return await Deployment.RunAsync(() =>
{
    var cfg = new Pulumi.Config();
    var subjectRef = cfg.RequireSecret("subjectRef");
    var configId = cfg.Require("configId");
    var privacyProtocolId = cfg.Require("privacyProtocolId");
    var subjectType = cfg.Get("subjectType") ?? "verified";

    var consent = new Consent("example", new()
    {
        Subject = subjectType == "anonymous"
            ? new ConsentSubjectArgs { AnonymousId = subjectRef }
            : new ConsentSubjectArgs { VerifiedId = subjectRef },
        Actions =
        {
            new ConsentActionArgs { Target = privacyProtocolId, Vendor = configId, Action = "ACCEPT" },
        },
        Attributes = { ["pulumiStack"] = Deployment.Instance.StackName },
        Origin = "api",
        Tags = { "demo" },
    });

    return new Dictionary<string, object?>
    {
        ["consentId"] = consent.ConsentId,
    };
});

Destroying the stack removes the logical Pulumi resource but does not delete historical events from Osano (they are immutable).

GetSubject and GetUnifiedConsent look anonymous and verified IDs up with the default ReferenceType (subject); session resolves a session ID. To submit a Global Privacy Control consent, set Origin = "gpc" and omit Actions: Osano derives the actions and the resource exports them as GpcActions. When a pipeline submits consents on a subject's behalf, set CountryCodeOverride (and RegionCodeOverride) so Osano does not geolocate the CI runner.

Authentication

Two API keys exist:

Key Header Usage
Unified Consent API key x-uc-api-key Required for consent submissions and read operations
Osano Customer REST API key x-osano-api-key Required for Cookie Consent resources and functions; SendSubjectCode and VerifySubjectCode send every configured key, so either this key or the Unified Consent API key is enough

Configure them with Pulumi config:

pulumi config set osano:unifiedConsentApiKey --secret
pulumi config set osano:osanoApiKey --secret

Or set the OSANO_UC_API_KEY and OSANO_API_KEY environment variables, for example in CI.

Configuration

Provider-level settings (all optional):

Key Description
osano:unifiedConsentApiKey Unified Consent API key (secret); OSANO_UC_API_KEY takes precedence when set
osano:osanoApiKey Customer REST API key for Cookie Consent and subject verification (secret); OSANO_API_KEY takes precedence when set
osano:apiBaseUrl Override the Unified Consent API base URL, including any path prefix; defaults to https://uc.api.osano.com; OSANO_API_BASE_URL takes precedence when set
osano:customerBaseUrl Override the Customer REST API base URL; defaults to https://api.osano.com
osano:requestTimeoutSeconds HTTP timeout for Customer REST and Unified Consent calls, default 60 seconds; OSANO_API_TIMEOUT_SECONDS takes precedence when valid

The deprecated osano:ucApiKey and osano:ucBaseUrl keys are still read as fallbacks for unifiedConsentApiKey and apiBaseUrl.

Learn more

Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net6.0

    • Pulumi (>= 3.76.1 && < 4.0.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.2.1 23 9/25/2026
0.2.0 35 9/25/2026
0.1.0 55 9/25/2026