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
<PackageReference Include="Community.Pulumi.Osano" Version="0.2.1" />
<PackageVersion Include="Community.Pulumi.Osano" Version="0.2.1" />
<PackageReference Include="Community.Pulumi.Osano" />
paket add Community.Pulumi.Osano --version 0.2.1
#r "nuget: Community.Pulumi.Osano, 0.2.1"
#:package Community.Pulumi.Osano@0.2.1
#addin nuget:?package=Community.Pulumi.Osano&version=0.2.1
#tool nuget:?package=Community.Pulumi.Osano&version=0.2.1
Osano Pulumi Provider for .NET
⚠️ 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, andGetCookieConsentAuditLog, 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 withGetSubject,GetSubjectProfile, andGetSession. - Inspect UC configuration and privacy protocol collections with
GetConfig,GetCollections, andGetCollection, and check for existing consent state and hashed consent profiles withCheckConsentandGetConsentProfile. - Start and verify subject-profile challenges with
SendSubjectCodeandVerifySubjectCode. 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.
Quick start: publish a consent script
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.
Unified Consent
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
- Examples, including the canonical C# Cookie Consent program
- End-to-end workflow guide: install, deploy, day-2 changes, import, and teardown
- Troubleshooting and upgrade notes
- Changelog
- Osano's Consent JavaScript API and Customer REST API
publishConfigoperation
| Product | Versions 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. |
-
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.