Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,8 @@ jobs:
Hosting.Flyway.Tests,
Hosting.GoFeatureFlag.Tests,
Hosting.Golang.Tests,
Hosting.JavaScript.Extensions.Tests,
Hosting.Java.Tests,
Hosting.k6.Tests,
Hosting.JavaScript.Extensions.Tests,
Hosting.Keycloak.Extensions.Tests,
Hosting.KurrentDB.Tests,
Hosting.LavinMQ.Tests,
Expand All @@ -51,6 +50,7 @@ jobs:
Hosting.Ollama.Tests,
Hosting.OpenTelemetryCollector.Tests,
Hosting.PapercutSmtp.Tests,
Hosting.Permify.Tests,
Hosting.PostgreSQL.Extensions.Tests,
Hosting.PowerShell.Tests,
Hosting.Python.Extensions.Tests,
Expand All @@ -60,12 +60,13 @@ jobs:
Hosting.Sftp.Tests,
Hosting.Solr.Tests,
Hosting.SqlDatabaseProjects.Tests,
Hosting.Sqlite.Tests,
Hosting.SqlServer.Extensions.Tests,
Hosting.Sqlite.Tests,
Hosting.Stripe.Tests,
Hosting.SurrealDb.Tests,
Hosting.Umami.Tests,

Hosting.k6.Tests,

# Client integration tests
GoFeatureFlag.Tests,
KurrentDB.Tests,
Expand Down
5 changes: 5 additions & 0 deletions CommunityToolkit.Aspire.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@
<Project Path="examples/papercut/CommunityToolkit.Aspire.Hosting.PapercutSmtp.SendMailApi/CommunityToolkit.Aspire.Hosting.PapercutSmtp.SendMailApi.csproj" />
<Project Path="examples/papercut/CommunityToolkit.Aspire.Hosting.PapercutSmtp.ServiceDefaults/CommunityToolkit.Aspire.Hosting.PapercutSmtp.ServiceDefaults.csproj" />
</Folder>
<Folder Name="/examples/permify/">
<Project Path="examples/permify/CommunityToolkit.Aspire.Hosting.Permify.AppHost/CommunityToolkit.Aspire.Hosting.Permify.AppHost.csproj" />
</Folder>
<Folder Name="/examples/postgres-ext/">
<Project Path="examples/postgres-ext/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.AppHost.csproj" />
</Folder>
Expand Down Expand Up @@ -214,6 +217,7 @@
<Project Path="src/CommunityToolkit.Aspire.Hosting.Ollama/CommunityToolkit.Aspire.Hosting.Ollama.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.PapercutSmtp/CommunityToolkit.Aspire.Hosting.PapercutSmtp.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.Permify/CommunityToolkit.Aspire.Hosting.Permify.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.PowerShell/CommunityToolkit.Aspire.Hosting.PowerShell.csproj" />
<Project Path="src/CommunityToolkit.Aspire.Hosting.Python.Extensions/CommunityToolkit.Aspire.Hosting.Python.Extensions.csproj" />
Expand Down Expand Up @@ -275,6 +279,7 @@
<Project Path="tests/CommunityToolkit.Aspire.Hosting.Ollama.Tests/CommunityToolkit.Aspire.Hosting.Ollama.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.Tests/CommunityToolkit.Aspire.Hosting.OpenTelemetryCollector.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.PapercutSmtp.Tests/CommunityToolkit.Aspire.Hosting.PapercutSmtp.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.Permify.Tests/CommunityToolkit.Aspire.Hosting.Permify.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.Tests/CommunityToolkit.Aspire.Hosting.PostgreSQL.Extensions.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests/CommunityToolkit.Aspire.Hosting.PowerShell.Tests.csproj" />
<Project Path="tests/CommunityToolkit.Aspire.Hosting.RavenDB.Tests/CommunityToolkit.Aspire.Hosting.RavenDB.Tests.csproj" />
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ This repository contains the source code for the Aspire Community Toolkit, a col
| - **Learn More**: [`Hosting.Elasticsearch.Extensions`][elasticsearch-ext-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions][elasticsearch-ext-shields]][elasticsearch-ext-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.Elasticsearch.Extensions][elasticsearch-ext-shields-preview]][elasticsearch-ext-nuget-preview] | An integration that contains some additional extensions for hosting Elasticsearch container. |
| - **Learn More**: [`Hosting.Umami`][umami-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Hosting.Umami][umami-shields]][umami-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.Umami][umami-shields-preview]][umami-nuget-preview] | An Aspire hosting integration leveraging the [Umami](https://umami.is/) container. |
| - **Learn More**: [`Hosting.Azure.Extensions`][azure-ext-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Azure.Extensions][azure-ext-shields]][azure-ext-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.Azure.Extensions][azure-ext-shields-preview]][azure-ext-nuget-preview] | An integration that contains some additional extensions for hosting Azure container. |
| - **Learn More**: [`Hosting.Permify`][permify-integration-docs] <br /> - Stable 📦: [![CommunityToolkit.Aspire.Hosting.Permify][permify-shields]][permify-nuget] <br /> - Preview 📦: [![CommunityToolkit.Aspire.Hosting.Permify][permify-shields-preview]][permify-nuget-preview] | An Aspire hosting integration for [Permify](https://permify.co/). |

## 🙌 Getting Started

Expand Down Expand Up @@ -292,3 +293,5 @@ This project is supported by the [.NET Foundation](https://dotnetfoundation.org)
[azure-ext-nuget]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Azure.Extensions/
[azure-ext-shields-preview]: https://img.shields.io/nuget/vpre/CommunityToolkit.Aspire.Hosting.Azure.Extensions?label=nuget%20(preview)
[azure-ext-nuget-preview]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Azure.Extensions/absoluteLatest
[permify-shields]: https://img.shields.io/nuget/v/CommunityToolkit.Aspire.Hosting.Permify
[permify-nuget]: https://nuget.org/packages/CommunityToolkit.Aspire.Hosting.Permify/
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
var builder = DistributedApplication.CreateBuilder(args);

var database = builder.AddPostgres("permify-postgres")
.AddDatabase("permify-db");

builder.AddPermify("permify")
.WithWatchSupport(database);

builder.Build().Run();
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<Project Sdk="Aspire.AppHost.Sdk/13.1.0">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<UserSecretsId>246f588a-9d7e-4cea-9959-c81ec1fa7900</UserSecretsId>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\..\src\CommunityToolkit.Aspire.Hosting.Permify\CommunityToolkit.Aspire.Hosting.Permify.csproj" IsAspireProjectResource="false" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"$schema": "https://json.schemastore.org/launchsettings.json",
"profiles": {
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "https://localhost:17093;http://localhost:15041",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "https://localhost:21069",
"ASPIRE_DASHBOARD_MCP_ENDPOINT_URL": "https://localhost:23152",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "https://localhost:22049"
}
},
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"applicationUrl": "http://localhost:15041",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"DOTNET_ENVIRONMENT": "Development",
"ASPIRE_DASHBOARD_OTLP_ENDPOINT_URL": "http://localhost:19262",
"ASPIRE_DASHBOARD_MCP_ENDPOINT_URL": "http://localhost:18202",
"ASPIRE_RESOURCE_SERVICE_ENDPOINT_URL": "http://localhost:20117"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Aspire.Hosting.Dcp": "Warning"
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<Description>A .NET Aspire host integration for Permify.</Description>
<AdditionalPackageTags>permify zanzibar rbac abac access-control least-privilege rebac</AdditionalPackageTags>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aspire.Hosting" />
<PackageReference Include="Aspire.Hosting.PostgreSQL" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace CommunityToolkit.Aspire.Hosting.Permify;

/// <summary>
/// Contains the (default) container tags for Permify.
/// </summary>
internal static class PermifyContainerImageTags
{
/// <remarks>Github Container Registry</remarks>
public const string Registry = "ghcr.io";

/// <remarks>permify/permify</remarks>
public const string Image = "permify/permify";

/// <remarks>v1.6.0</remarks>
public const string Tag = "v1.6.0";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
using Aspire.Hosting.ApplicationModel;
using CommunityToolkit.Aspire.Hosting.Permify;

namespace Aspire.Hosting;

/// <summary>
/// Provides extension methods for adding Permify to an <see cref="IDistributedApplicationBuilder" />.
/// </summary>
public static class PermifyHostingExtensions
{
/// <summary>
/// Adds a Permify resource to the application.
/// </summary>
/// <param name="builder">The distributed application builder.</param>
/// <param name="name">The name of the Permify resource.</param>
/// <param name="httpPort">The HTTP port for Permify.</param>
/// <param name="grpcPort">The gRPC port for Permify.</param>
public static IResourceBuilder<PermifyResource> AddPermify(
this IDistributedApplicationBuilder builder,
[ResourceName] string name,
int? httpPort = null,
int? grpcPort = null
)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(name);

var resource = new PermifyResource(name);
var permifyBuilder = builder.AddResource(resource)
.WithImage(PermifyContainerImageTags.Image)
.WithImageTag(PermifyContainerImageTags.Tag)
.WithImageRegistry(PermifyContainerImageTags.Registry)
// Configure endpoints
.WithHttpsEndpoint(
targetPort: 8080,
port: httpPort,
name: PermifyResource.HttpsEndpointName
)
.WithEnvironment("PERMIFY_HTTP_ENABLED", "true")
.WithEnvironment("PERMIFY_HTTP_PORT", "8080")
.WithHttpHealthCheck("/healthz")
// Configure OTLP
.WithOtlpExporter()
.WithEnvironment("PERMIFY_TRACER_ENABLED", "true")
.WithEnvironment("PERMIFY_TRACER_EXPORTER", "otlp")
.WithEnvironment("PERMIFY_METER_ENABLED", "true")
.WithEnvironment("PERMIFY_METER_EXPORTER", "otlp")
.WithEnvironment(ctx =>
{
// TODO: Permify requires the endpoint to *just* be the host + port
// it cannot contain a scheme, which makes it difficult to use HostUrl
ctx.EnvironmentVariables["PERMIFY_TRACER_ENDPOINT"] = string.Empty;
ctx.EnvironmentVariables["PERMIFY_METER_ENDPOINT"] = string.Empty;
});

#pragma warning disable ASPIRECERTIFICATES001
permifyBuilder.WithHttpsCertificateConfiguration(ctx =>
{
// Configure HTTPS
ctx.EnvironmentVariables["PERMIFY_HTTP_TLS_ENABLED"] = true;
ctx.EnvironmentVariables["PERMIFY_HTTP_TLS_CERT_PATH"] = ctx.CertificatePath;
ctx.EnvironmentVariables["PERMIFY_HTTP_TLS_KEY_PATH"] = ctx.KeyPath;

// Configure gRPC
ctx.EnvironmentVariables["PERMIFY_GRPC_TLS_ENABLED"] = true;
ctx.EnvironmentVariables["PERMIFY_GRPC_TLS_CERT_PATH"] = ctx.CertificatePath;
ctx.EnvironmentVariables["PERMIFY_GRPC_TLS_KEY_PATH"] = ctx.KeyPath;

return Task.CompletedTask;
});
#pragma warning restore ASPIRECERTIFICATES001

return permifyBuilder;
}

/// <summary>
/// Enables gRPC support for Permify.
/// </summary>
/// <param name="builder">The resource to enable gRPC support for</param>
/// <param name="grpcPort">An optional port on which to enable gRPC</param>
public static IResourceBuilder<PermifyResource> WithGrpc(
this IResourceBuilder<PermifyResource> builder,
int? grpcPort = null
)
{
return builder
.WithHttpsEndpoint(
targetPort: 8081,
port: grpcPort,
name: PermifyResource.GrpcEndpointName
)
.WithEnvironment("PERMIFY_GRPC_ENABLED", "true")
.WithEnvironment("PERMIFY_GRPC_PORT", "8081");
}

/// <summary>
/// Adds <paramref name="database"/> as the database for Permify to persist data.
/// </summary>
public static IResourceBuilder<PermifyResource> WithDatabase(
this IResourceBuilder<PermifyResource> builder,
IResourceBuilder<PostgresDatabaseResource> database
)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(database);

builder
.WithEnvironment("PERMIFY_DATABASE_ENGINE", "postgres")
.WithEnvironment("PERMIFY_DATABASE_URI", database.Resource.UriExpression)
.WaitFor(database);

return builder;
}

/// <summary>
/// Configures Permify to enable watch support.
/// </summary>
/// <remarks>
/// Permify's watch support relies on Postgres' <c>track_commit_timestamp</c> feature.
/// Refer to https://docs.permify.co/api-reference/watch/watch-changes#enabling-track-commit-timestamp-on-postgresql
/// for information on how to configure this, or call <see cref="WithWatchSupport(IResourceBuilder{PermifyResource}, IResourceBuilder{PostgresServerResource}, IResourceBuilder{PostgresDatabaseResource})"/>
/// to automatically configure the flag for you.
/// </remarks>
public static IResourceBuilder<PermifyResource> WithWatchSupport(
this IResourceBuilder<PermifyResource> builder,
IResourceBuilder<PostgresDatabaseResource> database
)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(database);

return WithDatabase(builder, database)
.WithEnvironment("PERMIFY_SERVICE_WATCH_ENABLED", "true");
}

/// <summary>
/// Configures permify to enable watch support.
/// The passed <paramref name="server"/> resource will be modified to enable <c>track_commit_timestamp</c>.
/// If you don't want this, use <see cref="WithWatchSupport(IResourceBuilder{PermifyResource}, IResourceBuilder{PostgresDatabaseResource})"/> instead.
/// </summary>
public static IResourceBuilder<PermifyResource> WithWatchSupport(
this IResourceBuilder<PermifyResource> builder,
IResourceBuilder<PostgresServerResource> server,
IResourceBuilder<PostgresDatabaseResource> database
)
{
ArgumentNullException.ThrowIfNull(builder);
ArgumentNullException.ThrowIfNull(server);
ArgumentNullException.ThrowIfNull(database);

server.WithArgs("-c", "track_commit_timestamp=on");
return builder.WithWatchSupport(database);
}
}
19 changes: 19 additions & 0 deletions src/CommunityToolkit.Aspire.Hosting.Permify/PermifyResource.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
using Aspire.Hosting.ApplicationModel;

namespace CommunityToolkit.Aspire.Hosting.Permify;

/// <summary>
/// Resource for the Permify API server.
/// </summary>
public sealed class PermifyResource(string name) : ContainerResource(name)
{
/// <summary>
/// The name of the HTTP API endpoint.
/// </summary>
public const string HttpsEndpointName = "https";

/// <summary>
/// The name of the gRPC API endpoint.
/// </summary>
public const string GrpcEndpointName = "grpc";
}
42 changes: 42 additions & 0 deletions src/CommunityToolkit.Aspire.Hosting.Permify/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# CommunityToolkit.Aspire.Hosting.Permify library

Provides extension methods and resource definitions for the .NET Aspire AppHost to support running [Permify](https://permify.co/) containers
with optional watch support.

## Getting Started

### Install the package

In your AppHost project, install the package using the following command:

```dotnetcli
dotnet add package CommunityToolkit.Aspire.Hosting.Permify
```

### Example usage

Then, in the _Program.cs_ file of `AppHost`, define a Permify resource, then call `AddPermify`:

```csharp
var permify = builder.AddPermify("permify");
```

If you want to enable watch support you'll need a Postgres database:

```csharp
var postgres = builder.AddPostgres("postgres")
.WithArgs("-c", "track_commit_timestamp=on")
.AddDatabase("permify-db");

var permify = builder.AddPermify("permify")
.WithWatchSupport(postgres);
```

## Additional Information

https://learn.microsoft.com/dotnet/aspire/community-toolkit/ollama

## Feedback & contributing

https://github.com/CommunityToolkit/Aspire

Loading
Loading