Sylin.Koan.Secrets.Abstractions
0.17.0
dotnet add package Sylin.Koan.Secrets.Abstractions --version 0.17.0
NuGet\Install-Package Sylin.Koan.Secrets.Abstractions -Version 0.17.0
<PackageReference Include="Sylin.Koan.Secrets.Abstractions" Version="0.17.0" />
<PackageVersion Include="Sylin.Koan.Secrets.Abstractions" Version="0.17.0" />
<PackageReference Include="Sylin.Koan.Secrets.Abstractions" />
paket add Sylin.Koan.Secrets.Abstractions --version 0.17.0
#r "nuget: Sylin.Koan.Secrets.Abstractions, 0.17.0"
#:package Sylin.Koan.Secrets.Abstractions@0.17.0
#addin nuget:?package=Sylin.Koan.Secrets.Abstractions&version=0.17.0
#tool nuget:?package=Sylin.Koan.Secrets.Abstractions&version=0.17.0
Koan.Secrets.Abstractions
✅ Validated against
SecretIdparsing,SecretValueprojections, and resolver template paths on 2025-09-29. SeeTECHNICAL.mdfor full contract details and edge cases.
Shared primitives for expressing secret identifiers, payloads, and provider contracts. Concrete providers (Koan.Secrets.Core, Vault, environment-based resolvers) wire into these interfaces so apps can request secrets without binding to a specific backend.
Quick start
Implement a provider that fetches payloads and register a resolver that supports templated strings:
using System.Text.RegularExpressions;
using Koan.Secrets.Abstractions;
public sealed class EnvSecretProvider : ISecretProvider
{
public Task<SecretValue> GetAsync(SecretId id, CancellationToken ct)
{
var key = $"SECRETS__{id.Scope}__{id.Name}".ToUpperInvariant();
var value = Environment.GetEnvironmentVariable(key)
?? throw new SecretNotFoundException(id.ToString());
var secret = new SecretValue(
System.Text.Encoding.UTF8.GetBytes(value),
SecretContentType.Text,
new SecretMetadata { Provider = "env", Version = id.Version });
return Task.FromResult(secret);
}
}
public sealed class TemplateSecretResolver : ISecretResolver
{
private readonly ISecretProvider _provider;
private static readonly Regex TokenRegex = new(@"secret://[A-Za-z0-9\-_.~/]+(?:\?version=[^}\""\s]+)?", RegexOptions.Compiled | RegexOptions.CultureInvariant);
public TemplateSecretResolver(ISecretProvider provider) => _provider = provider;
public Task<SecretValue> GetAsync(SecretId id, CancellationToken ct = default)
=> _provider.GetAsync(id, ct);
public async Task<string> ResolveAsync(string template, CancellationToken ct = default)
{
if (!TokenRegex.IsMatch(template)) return template;
var result = template;
foreach (Match match in TokenRegex.Matches(template))
{
ct.ThrowIfCancellationRequested();
var parsed = SecretId.Parse(match.Value);
var secret = await _provider.GetAsync(parsed, ct);
result = result.Replace(match.Value, secret.AsString(), StringComparison.Ordinal);
}
return result;
}
}
SecretIdURIs (secret://scope/name) keep scopes and names canonical; optional provider hints (secret+vault://) steer routing when multiple providers coexist.SecretValuewraps the payload and ensures projections (AsString(),AsJson<T>()) match the declaredSecretContentType.
Contract highlights
ISecretProvider.GetAsyncis the single source of truth for fetching secrets. ThrowSecretNotFoundException,SecretUnauthorizedException, orSecretProviderUnavailableExceptionfor precise error semantics.ISecretResolver.ResolveAsyncperforms best-effort templating—strings without tokens short-circuit without provider calls.SecretMetadatacaptures provider hints, versions, and TTLs so rotation tooling can make informed decisions.SecretId.Parserejects malformed URIs early (missing scope/name, unsupported schemes) to avoid propagating invalid identifiers.
Edge cases
- Whitespace or relative URIs throw
ArgumentExceptionduringSecretId.Parse. - Binary payloads (
SecretContentType.Bytes) can only be accessed viaAsBytes(); attempting to callAsString()/AsJson<T>()raisesInvalidOperationException. - Provider-qualified URIs (
secret+vault://prod/payment-key) fill theProviderproperty so orchestrators can direct the call to a specific backend. - Hostless URIs (
secret:///prod/payment-key) remain valid; parsing normalizes host/path combinations to(Scope="prod", Name="payment-key").
Validation checklist
- Unit tests:
tests/Koan.Secrets.Core.Testscover resolver templating, ID parsing, and provider routing logic. Run them after provider changes. - DocFX:
pwsh -File scripts/build-docs.ps1 -ConfigPath docs/api/docfx.json -Strictensures this documentation stays linked and warning-free.
Related docs
TECHNICAL.md– complete contract narrative and architectural positioning./docs/architecture/principles.md– cross-cutting security principles referenced by secrets modules.src/Koan.Secrets.Core/README.md– runtime orchestrator that consumes these abstractions.
| 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
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.8)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.8)
- Newtonsoft.Json (>= 13.0.4)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Sylin.Koan.Secrets.Abstractions:
| Package | Downloads |
|---|---|
|
Sylin.Koan.Secrets.Connector.Vault
HashiCorp Vault provider for Koan secrets: HTTP client wiring, health checks, and scoped secret resolution. |
|
|
Sylin.Koan.Secrets.Core
Secrets runtime for Koan: provider orchestration, options binding, and secret materialization helpers. |
GitHub repositories
This package is not used by any popular GitHub repositories.
See release notes: https://github.com/sylin-labs/Koan-framework/releases