Skip to content
Merged
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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -281,6 +281,7 @@ jobs:

push_layer "Layer 0 (core)" \
"SharpCoreDB.[0-9]*.nupkg" \
"SharpCoreDB.Aspire.Hosting.*.nupkg" \
"SharpCoreDB.Client.Protocol.*.nupkg" \
"SharpCoreDB.Server.Protocol.*.nupkg"

Expand Down
66 changes: 66 additions & 0 deletions .github/workflows/docker-publish.yml
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
name: Docker

on:
push:
tags: [ 'v*' ]
workflow_dispatch:

env:
REGISTRY: ghcr.io
IMAGE_NAME: ghcr.io/mpcoredeveloper/sharpcoredb-server

jobs:
build-and-push:
name: Build & push SharpCoreDB server image
runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7

- name: Compute image tags
id: meta
shell: pwsh
run: |
$version = if ("${{ github.ref_type }}" -eq 'tag') { "${{ github.ref_name }}".TrimStart('v') } else { "${{ github.sha }}".Substring(0, 7) }
$tags = @("${{ env.IMAGE_NAME }}:$version")
if ("${{ github.ref_type }}" -eq 'tag') {
$tags += "${{ env.IMAGE_NAME }}:latest"
}
Write-Host "Version: $version"
Write-Host "Tags: $($tags -join ', ')"
"version=$version" >> $env:GITHUB_OUTPUT
"tags=$($tags -join ',')" >> $env:GITHUB_OUTPUT

- name: Set up QEMU
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3

- name: Log in to GHCR
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: Build and push
uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6
with:
context: .
file: src/SharpCoreDB.Server/Dockerfile
push: true
platforms: linux/amd64, linux/arm64
tags: ${{ steps.meta.outputs.tags }}
build-args: |
VERSION=${{ steps.meta.outputs.version }}
labels: |
org.opencontainers.image.title=SharpCoreDB Server
org.opencontainers.image.description=SharpCoreDB network database server (gRPC + HTTPS)
org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
org.opencontainers.image.version=${{ steps.meta.outputs.version }}
org.opencontainers.image.revision=${{ github.sha }}
1 change: 1 addition & 0 deletions .github/workflows/publish-manual.yml
Original file line numberDiff line numberDiff line change
Expand Up@@ -95,6 +95,7 @@ jobs:

push_layer "Layer 0 (core)" \
"SharpCoreDB.[0-9]*.nupkg" \
"SharpCoreDB.Aspire.Hosting.*.nupkg" \
"SharpCoreDB.Client.Protocol.*.nupkg" \
"SharpCoreDB.Server.Protocol.*.nupkg"

Expand Down
2 changes: 2 additions & 0 deletions Directory.Packages.props
Original file line numberDiff line numberDiff line change
Expand Up@@ -7,6 +7,7 @@
<ItemGroup>
<PackageVersion Include="SharpCoreDB" Version="$(SharpCoreDBVersion)" />
<PackageVersion Include="SharpCoreDB.Analytics" Version="$(SharpCoreDBVersion)" />
<PackageVersion Include="SharpCoreDB.Aspire.Hosting" Version="$(SharpCoreDBVersion)" />
<PackageVersion Include="SharpCoreDB.Client" Version="$(SharpCoreDBVersion)" />
<PackageVersion Include="SharpCoreDB.Client.Protocol" Version="$(SharpCoreDBVersion)" />
<PackageVersion Include="SharpCoreDB.CQRS" Version="$(SharpCoreDBVersion)" />
Expand All@@ -30,6 +31,7 @@
<PackageVersion Include="SharpCoreDB.Server.Core" Version="$(SharpCoreDBVersion)" />
<PackageVersion Include="SharpCoreDB.Server.Protocol" Version="$(SharpCoreDBVersion)" />
<PackageVersion Include="SharpCoreDB.VectorSearch" Version="$(SharpCoreDBVersion)" />
<PackageVersion Include="Aspire.Hosting" Version="13.5.3" />
<PackageVersion Include="Aspire.Hosting.AppHost" Version="13.5.3" />
<PackageVersion Include="AngleSharp" Version="1.7.2" />
<PackageVersion Include="AWSSDK.Core" Version="4.0.102.1" />
Expand Down
17 changes: 16 additions & 1 deletion SharpCoreDB.sln
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 18
VisualStudioVersion = 18.1.11312.151
Expand DownExpand Up@@ -185,6 +185,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OrderManagement.CqrsDemo",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCoreDB.AppHost", "src\SharpCoreDB.AppHost\SharpCoreDB.AppHost.csproj", "{532DCF54-42EE-41C6-AC93-4DB59425C017}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCoreDB.Aspire.Hosting", "src\SharpCoreDB.Aspire.Hosting\SharpCoreDB.Aspire.Hosting.csproj", "{5D4E3C2B-1A09-4E8F-B6C7-D8E9F0A1B2C3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCoreDB.Functional", "src\SharpCoreDB.Functional\SharpCoreDB.Functional.csproj", "{B7C3FE06-9C25-46F1-BDE4-C37A51192CDD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SharpCoreDB.Functional.Dapper", "src\SharpCoreDB.Functional.Dapper\SharpCoreDB.Functional.Dapper.csproj", "{4D7E752E-F1E9-4580-A60F-6F3F31CBD8A8}"
Expand DownExpand Up@@ -731,6 +733,18 @@ Global
{532DCF54-42EE-41C6-AC93-4DB59425C017}.Release|x64.Build.0 = Release|Any CPU
{532DCF54-42EE-41C6-AC93-4DB59425C017}.Release|x86.ActiveCfg = Release|Any CPU
{532DCF54-42EE-41C6-AC93-4DB59425C017}.Release|x86.Build.0 = Release|Any CPU
{5D4E3C2B-1A09-4E8F-B6C7-D8E9F0A1B2C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5D4E3C2B-1A09-4E8F-B6C7-D8E9F0A1B2C3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5D4E3C2B-1A09-4E8F-B6C7-D8E9F0A1B2C3}.Debug|x64.ActiveCfg = Debug|Any CPU
{5D4E3C2B-1A09-4E8F-B6C7-D8E9F0A1B2C3}.Debug|x64.Build.0 = Debug|Any CPU
{5D4E3C2B-1A09-4E8F-B6C7-D8E9F0A1B2C3}.Debug|x86.ActiveCfg = Debug|Any CPU
{5D4E3C2B-1A09-4E8F-B6C7-D8E9F0A1B2C3}.Debug|x86.Build.0 = Debug|Any CPU
{5D4E3C2B-1A09-4E8F-B6C7-D8E9F0A1B2C3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5D4E3C2B-1A09-4E8F-B6C7-D8E9F0A1B2C3}.Release|Any CPU.Build.0 = Release|Any CPU
{5D4E3C2B-1A09-4E8F-B6C7-D8E9F0A1B2C3}.Release|x64.ActiveCfg = Release|Any CPU
{5D4E3C2B-1A09-4E8F-B6C7-D8E9F0A1B2C3}.Release|x64.Build.0 = Release|Any CPU
{5D4E3C2B-1A09-4E8F-B6C7-D8E9F0A1B2C3}.Release|x86.ActiveCfg = Release|Any CPU
{5D4E3C2B-1A09-4E8F-B6C7-D8E9F0A1B2C3}.Release|x86.Build.0 = Release|Any CPU
{B7C3FE06-9C25-46F1-BDE4-C37A51192CDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B7C3FE06-9C25-46F1-BDE4-C37A51192CDD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B7C3FE06-9C25-46F1-BDE4-C37A51192CDD}.Debug|x64.ActiveCfg = Debug|Any CPU
Expand DownExpand Up@@ -969,6 +983,7 @@ Global
{16246662-205B-4B38-9C72-5386FD85A4B4} = {2F8A8533-DAA8-4CF9-A6C0-2F663AF7FD2E}
{7BBCA0B4-D868-C04E-8748-21DE9A02486F} = {16246662-205B-4B38-9C72-5386FD85A4B4}
{532DCF54-42EE-41C6-AC93-4DB59425C017} = {F8B5E3A4-1C2D-4E5F-8B9A-1D2E3F4A5B6C}
{5D4E3C2B-1A09-4E8F-B6C7-D8E9F0A1B2C3} = {F8B5E3A4-1C2D-4E5F-8B9A-1D2E3F4A5B6C}
{B7C3FE06-9C25-46F1-BDE4-C37A51192CDD} = {F8B5E3A4-1C2D-4E5F-8B9A-1D2E3F4A5B6C}
{4D7E752E-F1E9-4580-A60F-6F3F31CBD8A8} = {F8B5E3A4-1C2D-4E5F-8B9A-1D2E3F4A5B6C}
{67976C63-C341-4D9D-A805-812B565E7CC9} = {F8B5E3A4-1C2D-4E5F-8B9A-1D2E3F4A5B6C}
Expand Down
2 changes: 2 additions & 0 deletions SharpCoreDB.slnx
Original file line numberDiff line numberDiff line change
Expand Up@@ -32,6 +32,7 @@
<File Path="docs/server/QUICKSTART.md" />
<File Path="docs/server/REST_API.md" />
<File Path="docs/server/SECURITY.md" />
<File Path="docs/server/ASPIRE_INTEGRATION.md" />
</Folder>
<Folder Name="/Examples/">
<Project Path="Examples/SharpCoreDB.GraphRAG.AIAssistant/SharpCoreDB.GraphRAG.AIAssistant.csproj" />
Expand DownExpand Up@@ -92,6 +93,7 @@
<Folder Name="/src/">
<Project Path="src/SharpCoreDB.Analytics/SharpCoreDB.Analytics.csproj" />
<Project Path="src/SharpCoreDB.AppHost/SharpCoreDB.AppHost.csproj" />
<Project Path="src/SharpCoreDB.Aspire.Hosting/SharpCoreDB.Aspire.Hosting.csproj" />
<Project Path="src/SharpCoreDB.Client.Protocol/SharpCoreDB.Client.Protocol.csproj" />
<Project Path="src/SharpCoreDB.Client/SharpCoreDB.Client.csproj" />
<Project Path="src/SharpCoreDB.CQRS/SharpCoreDB.CQRS.csproj" />
Expand Down
108 changes: 108 additions & 0 deletions docs/server/ASPIRE_INTEGRATION.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
# SharpCoreDB Server × .NET Aspire Integration

> **Status:** SharpCoreDB-side prerequisites implemented · **Date:** 2026-09-05
>
> This repository delivers the two SharpCoreDB prerequisites defined by the SCDMS design doc
> [`docs/aspire.md`](https://github.com/MPCoreDeveloper/SCDMS/blob/main/docs/aspire.md)
> (SCDMS issue #10). Once the `SCDMS.Aspire.Hosting` package is built in the SCDMS repository,
> SharpCoreDB server + SCDMS can run as one Aspire application with all SCDMS ⇄ SharpCoreDB
> traffic over **gRPC**.

## Goal (from the SCDMS design doc)

Run SharpCoreDB server + SCDMS as a single Aspire app, like pgAdmin next to PostgreSQL:

```csharp
var builder = DistributedApplication.CreateBuilder(args);

var sharpCoreDb = builder.AddSharpCoreDB("db")
.WithServerContainer(); // SharpCoreDB server container

builder.AddSCDMS("admin")
.WithGrpcReference(sharpCoreDb) // SCDMS container linked via gRPC
.WithHttpEndpoint(port: 8080, name: "http");

builder.Build().Run();
```

## What this repository now provides

### 1. Server container image → `ghcr.io/mpcoredeveloper/sharpcoredb-server`

- `.github/workflows/docker-publish.yml` builds and pushes the server image on every `v*` tag
and via `workflow_dispatch`.
- Multi-architecture: `linux/amd64` + `linux/arm64` (Docker Buildx + QEMU).
- Tags: `<version>` (tag without the leading `v`) and `latest`.
- Build context is the repository root; the Dockerfile lives at
`src/SharpCoreDB.Server/Dockerfile`.

### 2. `SharpCoreDB.Aspire.Hosting` NuGet package

The package (project `src/SharpCoreDB.Aspire.Hosting/`) registers the server container in an
Aspire application:

```csharp
using SharpCoreDB.Aspire.Hosting;

var builder = DistributedApplication.CreateBuilder(args);

var db = builder.AddSharpCoreDB("db") // ghcr.io/mpcoredeveloper/sharpcoredb-server:latest
.WithServerContainer()
.WithImageTag("2.0.0.2") // optional pinned tag
.WithJwtSecret("a-secret-of-at-least-32-characters");

builder.Build().Run();
```

The resource (`SharpCoreDbServerResource`) implements `IResourceWithConnectionString` and always
exposes **two** HTTPS endpoints:

| Endpoint | Container port | Purpose |
|---|---|---|
| `grpc` | 5001 | Primary gRPC protocol (HTTP/2), matching `Server.GrpcPort` |
| `https` | 8443 | HTTPS REST API + `/health`, matching `Server.HttpsApiPort` |

The connection string of the resource points at the gRPC endpoint:
`Host=<host>;Port=<port>;SSL=True`.

## TLS in development (important)

SharpCoreDB server **enforces TLS 1.2+** and refuses to start on plain HTTP
(`Server.Security.TlsEnabled` must stay `true` and a certificate path is required). Both
endpoints are therefore modeled with `WithHttpsEndpoint` in the hosting package.

- **Production / behind a reverse proxy:** terminate TLS at a publicly trusted proxy (see the
SCDMS `samples/docker/` pattern) and mount the real certificate into `/app/certs`.
- **Local Aspire development:** the container still needs a certificate. Use the Aspire
development certificate (trust it in the consuming client) or mount a development PFX and
point `Server__Security__TlsCertificatePath` at it. gRPC clients in development may need
certificate validation disabled for the local `grpc` endpoint.

## Environment configuration

| Setting | Container env var | Notes |
|---|---|---|
| JWT secret | `Server__Security__JwtSecretKey` | Min. 32 chars; use `WithJwtSecret(...)` |
| TLS cert | `Server__Security__TlsCertificatePath` | Default `./certs/server.pfx`; mount into `/app/certs` |
| HTTPS API | `Server__EnableHttpsApi` / `Server__HttpsApiPort` | Defaults `true` / `8443` |
| gRPC | `Server__EnableGrpc` / `Server__GrpcPort` | Defaults `true` / `5001` |

## Consuming the resource from another hosting package

`WithGrpcReference` (to be added by `SCDMS.Aspire.Hosting`) can resolve the gRPC endpoint and
forward `SCDMS__DefaultServer*` settings:

```csharp
var grpcEndpoint = sharpCoreDb.GetEndpoint("grpc");
scdms.WithEnvironment("SCDMS__DefaultServerHost", grpcEndpoint)
.WithEnvironment("SCDMS__DefaultServerPort", grpcEndpoint.Property(EndpointProperty.Port))
.WithEnvironment("SCDMS__DefaultServerUseSsl", "true");
```

## Related

- Server quick start: [`QUICKSTART.md`](QUICKSTART.md)
- Server configuration reference: [`CONFIGURATION_SCHEMA.md`](CONFIGURATION_SCHEMA.md)
- Server Docker Compose: `src/SharpCoreDB.Server/docker-compose.yml`
- SCDMS Aspire design doc (the plan this implements):
https://github.com/MPCoreDeveloper/SCDMS/blob/main/docs/aspire.md
1 change: 1 addition & 0 deletions docs/server/README.md
Original file line numberDiff line numberDiff line change
Expand Up@@ -33,6 +33,7 @@ In server mode, SharpCoreDB runs as a network service instead of an in-process e
- **Linux systemd:** `installers/linux/install.sh`
- **macOS launchd:** `installers/macos/install.sh`
- **Docker:** `src/SharpCoreDB.Server/docker-compose.yml`
- **.NET Aspire:** `ASPIRE_INTEGRATION.md` — `SharpCoreDB.Aspire.Hosting` package + server container image

For complete production installation instructions, see `INSTALLATION.md`.

Expand Down
47 changes: 47 additions & 0 deletions src/SharpCoreDB.Aspire.Hosting/NuGet.README.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
# SharpCoreDB.Aspire.Hosting

.NET Aspire hosting integration for the **SharpCoreDB network server** container image
(`ghcr.io/mpcoredeveloper/sharpcoredb-server`).

## Quick start

```csharp
var builder = DistributedApplication.CreateBuilder(args);

var db = builder.AddSharpCoreDB("db")
.WithServerContainer()
.WithImageTag("2.0.0.2")
.WithJwtSecret("replace-with-a-secret-of-at-least-32-characters");

builder.Build().Run();
```

The server container exposes two HTTPS endpoints (TLS 1.2+ is enforced, plain HTTP is not supported):

| Endpoint name | Container port | Purpose |
|---|---|---|
| `grpc` | 5001 | Primary gRPC protocol (HTTP/2) |
| `https` | 8443 | HTTPS REST API + `/health` |

The resource implements `IResourceWithConnectionString`; the connection string points at the
`grpc` endpoint (`Host=…;Port=…;SSL=True`).

## Extension methods

- `AddSharpCoreDB(name)` — adds the container resource.
- `WithServerContainer()` — documentation alias for the container-based hosting intent.
- `WithJwtSecret(secret)` — forwards `Server__Security__JwtSecretKey` (min. 32 chars).
- `WithImageTag(tag)` — pick a published image tag instead of `latest`.

## Prerequisites

- The image is published to `ghcr.io/mpcoredeveloper/sharpcoredb-server` by the repository
Docker workflow on every `v*` tag (`linux/amd64` + `linux/arm64`).

## Development notes (TLS)

In local Aspire development the container keeps enforcing TLS. Trust the Aspire development
certificate in the consuming app, or connect over the Aspire network with certificate
validation disabled for the `grpc` endpoint. See
[docs/server/ASPIRE_INTEGRATION.md](https://github.com/MPCoreDeveloper/SharpCoreDB/blob/master/docs/server/ASPIRE_INTEGRATION.md)
for the full guide.
56 changes: 56 additions & 0 deletions src/SharpCoreDB.Aspire.Hosting/SharpCoreDB.Aspire.Hosting.csproj
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<!-- Aspire.Hosting resolves a large transitive graph that does not participate in the
repo-wide central package version pinning. Central package management is disabled
for this project only (same approach as src/SharpCoreDB.AppHost). -->
<ManagePackageVersionsCentrally>false</ManagePackageVersionsCentrally>
</PropertyGroup>

<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<LangVersion>14.0</LangVersion>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>true</GenerateDocumentationFile>

<!-- Assembly info -->
<AssemblyName>SharpCoreDB.Aspire.Hosting</AssemblyName>
<Version>2.0.0.2</Version>
<Description>.NET Aspire hosting integration for the SharpCoreDB network server</Description>

<!-- NuGet Package Properties -->
<PackageId>SharpCoreDB.Aspire.Hosting</PackageId>
<Authors>MPCoreDeveloper</Authors>
<Company>SharpCoreDB</Company>
<Product>SharpCoreDB.Aspire.Hosting</Product>
<PackageTags>database;aspire;hosting;grpc;container;sharpcoredb;net10</PackageTags>
<PackageLicenseExpression>MIT</PackageLicenseExpression>
<PackageProjectUrl>https://github.com/MPCoreDeveloper/SharpCoreDB</PackageProjectUrl>
<RepositoryUrl>https://github.com/MPCoreDeveloper/SharpCoreDB</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<PackageReadmeFile>NuGet.README.md</PackageReadmeFile>
<PackageIcon>SharpCoreDB.jpg</PackageIcon>
<IncludeSymbols>true</IncludeSymbols>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<PackageReleaseNotes>v2.0.0.2 (2026-09-05): first .NET Aspire hosting package for SharpCoreDB.Server - container image ghcr.io/mpcoredeveloper/sharpcoredb-server with HTTPS gRPC (5001) and HTTPS REST API (8443) endpoints. Full details: https://github.com/MPCoreDeveloper/SharpCoreDB/blob/master/docs/server/ASPIRE_INTEGRATION.md</PackageReleaseNotes>
</PropertyGroup>

<ItemGroup>
<!-- Aspire hosting (matches SharpCoreDB.AppHost / Aspire.Hosting.AppHost 13.5.3). -->
<PackageReference Include="Aspire.Hosting" Version="13.5.3" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="10.0.400">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<None Include="NuGet.README.md" Pack="true" PackagePath="/" />
<None Include="..\SharpCoreDB\SharpCoreDB.jpg" Link="SharpCoreDB.jpg" Pack="true" PackagePath="/" />
</ItemGroup>

</Project>
Loading
Loading