Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
9ea2b05
Update to dotnet 10, fix namespaces and code consistency
RWL-Dittrich Mar 24, 2026
3f6bde8
Merge pull request #1 from Niverplast/feat/dotnet-10-cleanup
RWL-Dittrich Mar 25, 2026
bf302e1
Feature/plat 672 add entra auth (#2)
RWL-Dittrich Apr 8, 2026
ad3a4c3
Feature/plat 671 add multifeed support (#3)
RWL-Dittrich Apr 22, 2026
e341573
Merge remote-tracking branch 'upstream/main' into merge/upstream-main
RWL-Dittrich Apr 22, 2026
e95e6a7
Fix empty CachedFrom on mirrored packages
RWL-Dittrich Apr 22, 2026
68db449
Merge pull request #4 from Niverplast/merge/upstream-main
RWL-Dittrich Apr 22, 2026
fa5728b
Fix missing CachedFrom in migration designer snapshots
RWL-Dittrich Apr 23, 2026
52da311
Merge pull request #5 from Niverplast/fix/migration-issues
RWL-Dittrich Apr 23, 2026
1ec0afc
Add support for DefaultAzureCredential in Azure Blob Storage options
RWL-Dittrich May 13, 2026
ae0e3dd
update Azure.Identity
RWL-Dittrich May 13, 2026
927fa22
update docs
RWL-Dittrich May 13, 2026
fb311f0
Fix delete behavior for CreatedByUser foreign key relationships
RWL-Dittrich May 13, 2026
953552c
also small verification hotfix. Validate connectionstring is not empt…
RWL-Dittrich May 13, 2026
072c5ae
Merge pull request #8 from Niverplast/hotfix/fix-sqlserver-migrations
RWL-Dittrich May 13, 2026
ee9a56b
add /ping healthcheck
RWL-Dittrich May 21, 2026
d576a6c
Merge pull request #9 from Niverplast/patch/ping-healthcheck
RWL-Dittrich May 21, 2026
69d72a4
Update liveness probe endpoint to /livez and clarify comment on middl…
RWL-Dittrich Jun 4, 2026
fe0ee7e
Merge pull request #12 from Niverplast/feat/liveness-probe-update
RWL-Dittrich Jun 4, 2026
6f8236f
Fix token page F5 resubmit (PLAT-757) and enforce unique token names …
RWL-Dittrich Jun 4, 2026
c23fe23
Merge pull request #15 from Niverplast/feat/token-page-UX-improvements
RWL-Dittrich Jun 4, 2026
28d62b8
Only show package info links when present (PLAT-760) and fix Source c…
RWL-Dittrich Jun 4, 2026
e17b400
Add CanPushToCurrentFeedAsync method and UI gating for upload tab
RWL-Dittrich Jun 4, 2026
2b35864
Sort feeds with default feed first and add unit test for GetAllFeedsA…
RWL-Dittrich Jun 4, 2026
238b7b9
Implement Connect page with service index URL and authentication inst…
RWL-Dittrich Jun 4, 2026
3353bd5
Refactor group permissions management to support bulk saving; introdu…
RWL-Dittrich Jun 4, 2026
7ab124a
Address PR review comments
RWL-Dittrich Jun 4, 2026
5b13b1c
Feat/ux improvements and bugfixes (#16)
RWL-Dittrich Jun 4, 2026
8f39bcb
Add per-feed delete permission with unlist/relist/delete UI
RWL-Dittrich Jun 4, 2026
8dc9ba2
Enhance FeedService and FeedsModel with logging and package deletion …
RWL-Dittrich Jun 4, 2026
1add83a
Merge pull request #18 from Niverplast/feat/ux-improvements-and-bugfixes
RWL-Dittrich Jun 4, 2026
fbdd876
Merge pull request #19 from Niverplast/develop
RWL-Dittrich Jun 4, 2026
a92a146
Add feed title display to Index page and style adjustments
RWL-Dittrich Jun 4, 2026
e6f33e5
Merge pull request #20 from Niverplast/feat/ux-improvements-and-bugfixes
RWL-Dittrich Jun 4, 2026
090e583
Merge pull request #21 from Niverplast/develop
RWL-Dittrich Jun 4, 2026
ec0f8a4
Merge pull request #22 from Niverplast/feat/delete-unlist-packages
RWL-Dittrich Jun 8, 2026
7bc5a9e
Reorder nav and fix Connect code-block styling
RWL-Dittrich Jun 8, 2026
708cd44
Merge pull request #23 from Niverplast/feat/ux-improvements-and-bugfixes
RWL-Dittrich Jun 8, 2026
8307203
Merge pull request #24 from Niverplast/develop
RWL-Dittrich Jun 8, 2026
55b6c6c
Add PackageDependencies and TargetFrameworks to IContext and NullCont…
RWL-Dittrich Jun 8, 2026
2da971b
Merge pull request #25 from Niverplast/feat/ux-improvements-and-bugfixes
RWL-Dittrich Jun 8, 2026
0c682d6
Merge pull request #26 from Niverplast/develop
RWL-Dittrich Jun 8, 2026
cae6a58
Make search filters feed-specific and add tag filter
RWL-Dittrich Jun 9, 2026
97b590f
disable statistics page if the user doesn't have perms
RWL-Dittrich Jun 9, 2026
fb24cd3
Merge pull request #27 from Niverplast/feat/ux-improvements-and-bugfixes
RWL-Dittrich Jun 9, 2026
3f715ea
Merge pull request #28 from Niverplast/develop
RWL-Dittrich Jun 9, 2026
89654b8
Enhance tag filtering in dropdown and optimize resource loading
RWL-Dittrich Jun 9, 2026
35207b9
Merge pull request #29 from Niverplast/feat/ux-improvements-and-bugfixes
RWL-Dittrich Jun 9, 2026
265a763
Merge pull request #30 from Niverplast/develop
RWL-Dittrich Jun 9, 2026
c1ef9ed
Improve tag dropdown styling by adjusting padding and adding border r…
RWL-Dittrich Jun 9, 2026
8353133
Merge pull request #31 from Niverplast/feat/ux-improvements-and-bugfixes
RWL-Dittrich Jun 9, 2026
9e2a375
Merge pull request #32 from Niverplast/main
RWL-Dittrich Jun 9, 2026
46defc6
Add support for including unlisted packages in search results and UI
RWL-Dittrich Jun 9, 2026
9a29299
Merge pull request #33 from Niverplast/feat/ux-improvements-and-bugfixes
RWL-Dittrich Jun 9, 2026
65d6912
Implement data protection key storage with XML repository
RWL-Dittrich Jun 9, 2026
f292708
Merge pull request #35 from Niverplast/feat/ux-improvements-and-bugfixes
RWL-Dittrich Jun 9, 2026
334456c
Refactor data protection key storage methods for improved clarity and…
RWL-Dittrich Jun 9, 2026
71934c6
Merge pull request #36 from Niverplast/feat/ux-improvements-and-bugfixes
RWL-Dittrich Jun 9, 2026
eddbccf
Add email notification support for personal access token expiry
RWL-Dittrich Jul 9, 2026
b369914
Fix email handling in PAT expiry notifications and improve test coverage
RWL-Dittrich Jul 9, 2026
c6ca7ad
update documentation
RWL-Dittrich Jul 9, 2026
eccb4ae
Split email sender tests into one file per test class
RWL-Dittrich Jul 10, 2026
a90c235
Apply suggestions from code review
RWL-Dittrich Jul 10, 2026
11ff50f
Merge pull request #38 from Niverplast/feature/email-notifications
RWL-Dittrich Jul 14, 2026
faa2c1f
Add support for raw email claim in token validation process
RWL-Dittrich Jul 14, 2026
584220d
update comment
RWL-Dittrich Jul 14, 2026
ee54e2e
Merge pull request #43 from Niverplast/feature/email-notifications
RWL-Dittrich Jul 14, 2026
4f22f01
Update application URLs and adjust claim mapping in token validation
RWL-Dittrich Jul 14, 2026
ac42396
Merge pull request #45 from Niverplast/feature/email-notifications
RWL-Dittrich Jul 14, 2026
78f141b
fix email message
RWL-Dittrich Jul 14, 2026
4a42b39
Merge pull request #47 from Niverplast/feature/email-notifications
RWL-Dittrich Jul 14, 2026
dbf876f
Add admin-controlled feed sort order
RWL-Dittrich Jul 17, 2026
2fef349
Merge pull request #53 from Niverplast/feature/default-branch-option
RWL-Dittrich Jul 22, 2026
bee0bcf
Add numbered pagination to the feed page
RWL-Dittrich Aug 4, 2026
94f711b
center on page
RWL-Dittrich Aug 4, 2026
7ba20c6
Merge pull request #58 from Niverplast/feature/page-numbering
RWL-Dittrich Aug 4, 2026
449fb60
Implement in-memory caching for password verification and add tests f…
RWL-Dittrich Oct 5, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -277,4 +277,9 @@ __pycache__/

# Chart dependencies
charts/
Chart.lock
Chart.lock

.claude

# keyring
DataProtection
221 changes: 221 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
# AGENTS.md

This file provides guidance to AI agents when working with code in this repository.

## Guidelines for AI Agents
### 1. Think Before Coding

**Don't assume. Don't hide confusion. Surface tradeoffs.**

Before implementing:
- State your assumptions explicitly. If uncertain, ask.
- If multiple interpretations exist, present them - don't pick silently.
- If a simpler approach exists, say so. Push back when warranted.
- If something is unclear, stop. Name what's confusing. Ask.

### 2. Simplicity First

**Minimum code that solves the problem. Nothing speculative.**

- No features beyond what was asked.
- No abstractions for single-use code.
- No "flexibility" or "configurability" that wasn't requested.
- No error handling for impossible scenarios.
- If you write 200 lines and it could be 50, rewrite it.

Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.

### 3. Surgical Changes

**Touch only what you must. Clean up only your own mess.**

When editing existing code:
- Don't "improve" adjacent code, comments, or formatting.
- Don't refactor things that aren't broken.
- Match existing style, even if you'd do it differently.
- If you notice unrelated dead code, mention it - don't delete it.

When your changes create orphans:
- Remove imports/variables/functions that YOUR changes made unused.
- Don't remove pre-existing dead code unless asked.

The test: Every changed line should trace directly to the user's request.

### 4. Goal-Driven Execution

**Define success criteria. Loop until verified.**

Transform tasks into verifiable goals:
- "Add validation" → "Write tests for invalid inputs, then make them pass"
- "Fix the bug" → "Write a test that reproduces it, then make it pass"
- "Refactor X" → "Ensure tests pass before and after"

For multi-step tasks, state a brief plan:
```
1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]
```

Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.

---

**These guidelines are working if:** fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.

---

## About this project: What is BaGetter

BaGetter is a lightweight, open-source NuGet and symbol server (ASP.NET Core, .NET 10). Community fork of BaGet. Implements NuGet v3 protocol with pluggable database, storage, and search backends.

### Repo Layout (top level)

- **`src/`** — application projects (see Project Layout below).
- **`tests/`** — xUnit test projects mirroring `src/`.
- **`samples/`** — `BaGetterWebApplication` (embed BaGetter in a host app) and `BaGetter.Protocol.Samples.Tests` (protocol client examples).
- **`docs/`** — Docusaurus documentation site (Node/Yarn, `yarn.lock`); published separately from the server.
- **`deployment templates/`** — ready-to-use deployment manifests (e.g., Docker Compose, cloud).
- **`Directory.Packages.props`**, **`global.json`**, **`nuget.config`** — central package versions, pinned SDK, restore sources.
- **`Dockerfile`** — multi-stage Alpine build; publishes to `/app` and defaults `/data` for packages/symbols/db.

## Build & Test Commands

```bash
dotnet restore
dotnet build --no-restore
dotnet test --no-build --verbosity normal
dotnet run --project src/BaGetter # runs on http://localhost:5000
```

Run a single test class or method:
```bash
dotnet test --filter "FullyQualifiedName~UserServiceTests"
dotnet test --filter "FullyQualifiedName~UserServiceTests+CreateEntraUserAsync"
```

EF Core migrations (example for SQLite):
```bash
dotnet ef migrations add MigrationName --project src/BaGetter.Database.Sqlite --startup-project src/BaGetter
```

Requires .NET SDK 10.0.104 (pinned in `global.json`).

## Architecture

### Provider Pattern

Storage, database, and search services use a configuration-driven provider pattern (`IProvider<T>`). Multiple implementations coexist in DI (registered via `TryAddTransient`); the active one is selected by `appsettings.json` config at runtime. This is the core extensibility mechanism.

### Project Layout

- **`src/BaGetter/`** — ASP.NET Core host. Entry point (`Program.cs`), DI/middleware setup (`Startup.cs`), config, `ValidateBaGetterOptions`, `ConfigureBaGetterServer`, `wwwroot/` static assets.
- **`src/BaGetter.Core/`** — Business logic, EF Core entities, authentication services, configuration options, storage/search interfaces. Database-agnostic. Notable subfolders: `Indexing/`, `Metadata/`, `Search/`, `Storage/`, `Upstream/` (read-through mirror/cache), `Statistics/`, `ServiceIndex/`, `Content/`, `Validation/`, `Feeds/` (multi-feed WIP).
- **`src/BaGetter.Web/`** — HTTP controllers (`FeedController`, `PackageContentController`, `PackageMetadataController`, `PackagePublishController`, `SearchController`, `ServiceIndexController`, `SymbolController`), Razor Pages UI (`Pages/`), endpoint routing (`BaGetterEndpointBuilder.cs`), URL generation (`BaGetterUrlGenerator.cs`), `OperationCancelledMiddleware`, `libman.json` for client-side libs.
- **`src/BaGetter.Protocol/`** — NuGet v3 protocol client and models for upstream feed communication.
- **`src/BaGetter.Database.{Sqlite,SqlServer,PostgreSql,MySql}/`** — EF Core context + migrations per database provider.
- **`src/BaGetter.{Aws,Azure,Gcp,Aliyun,Tencent}/`** — Cloud storage provider implementations.

### Key Interfaces

| Interface | Purpose |
|-----------|---------|
| `IPackageDatabase` | Package CRUD operations |
| `IStorageService` | Raw blob storage |
| `IPackageStorageService` | Package-specific storage (nupkg, nuspec, readme, icon) |
| `ISearchService` / `ISearchIndexer` | Package search and indexing |
| `IContext` | EF Core DbContext abstraction |

### Authentication

Supports multiple simultaneous auth modes controlled by `AuthenticationMode` enum (`Config`, `Local`, `Entra`, `Hybrid`). `Config` is the backward-compatible mode. Auth services live in `src/BaGetter.Core/Authentication/`.

- **NuGetBasicAuth** is the default scheme; it forwards to the cookie scheme when a session cookie is present without an `Authorization` header (browser vs. client tool detection).
- **Entra ID** uses `AddMicrosoftIdentityWebApp()` (authorization code flow). `EntraRoleSyncService` syncs Entra app roles to local groups on token validation. Cookie name is `BaGetter.Auth`, 60-minute sliding session.
- **`IFeedAuthenticationService`** provides two auth paths: `AuthenticateByTokenAsync()` (PAT) and `AuthenticateByCredentialsAsync()` (username/password).
- **`FeedPermissionHandler`** (AuthorizationHandler) enforces feed-level permissions using the default feed ID `"default"`.
- Passwords use bcrypt; tokens store prefix + hash.

Authentication config structure:
```json
"Authentication": {
"Mode": "Hybrid",
"Entra": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "",
"ClientId": "",
"ClientSecret": "",
"CallbackPath": "/signin-oidc"
},
"MaxTokenExpiryDays": 365,
"MaxFailedAttempts": 5,
"LockoutMinutes": 15
}
```

### Data Model

Defined in `src/BaGetter.Core/Entities/AbstractContext.cs`. Core entities: Package, PackageDependency, PackageType, TargetFramework, User, PersonalAccessToken, Group, UserGroup, FeedPermission.

### API Endpoints

Routes defined in `BaGetterEndpointBuilder.cs`:
- Service index: `GET /v3/index.json`
- Search/autocomplete: `GET /v3/search`, `GET /v3/autocomplete`
- Package metadata: `GET /v3/registration/{id}/index.json`
- Package content: `GET /v3/package/{id}/{version}/{id}.nupkg`
- Publish: `PUT /api/v2/package`
- Symbols: `PUT /api/v2/symbol`, `GET /api/download/symbols/...`

### Middleware

- **`OperationCancelledMiddleware`** converts `OperationCanceledException` to HTTP 409 Conflict.
- **`ConfigureBaGetterServer`** (implements multiple `IConfigureOptions<T>`) configures CORS, `FormOptions` (multipart upload limits via `MaxPackageSizeGiB`), forwarded headers, and IIS options.

## Configuration

Options class: `BaGetterOptions` in `src/BaGetter.Core/Configuration/`. Config sources (in order): `appsettings.json`, env vars, user secrets, Docker secrets (`/run/secrets/`), optional `BAGET_CONFIG_ROOT` env var.

`ValidateBaGetterOptions` validates all config at startup — database/storage/search types against whitelists, Entra config completeness when required, and numeric minimums (token expiry, failed attempts, lockout).

Top-level `BaGetterOptions` keys (see `src/BaGetter/appsettings.json`):

- `ApiKey`, `PackageDeletionBehavior` (`Unlist`/`HardDelete`), `AllowPackageOverwrites`, `MaxPackageSizeGiB` (default 8).
- `Database` — `Type` + `ConnectionString`.
- `Storage` — `Type` + provider-specific settings (`Path` for FileSystem).
- `Search` — `Type` (`Database` default; Azure Search alternative).
- `Mirror` — upstream read-through cache; `Enabled`, `PackageSource`, optional `Legacy` flag for NuGet v2.
- `Authentication` — see Authentication section. Legacy `Credentials[]` and `ApiKeys[]` arrays are supported for backward-compat alongside the new Local/Entra/Hybrid modes.
- `HealthCheck.Path` (default `/health`).
- `Statistics.EnableStatisticsPage`, `Statistics.ListConfiguredServices`.
- Standard ASP.NET `Kestrel` and `Logging` sections.

Docker defaults (`Dockerfile`): `Storage__Path=/data`, `Search__Type=Database`, `Database__Type=Sqlite`, `Database__ConnectionString=Data Source=/data/db/bagetter.db`. Volume-mount `/data` to persist packages, symbols, and the SQLite DB.

## Code Style

Enforced via `.editorconfig`: 4-space indent (2-space for JSON), PascalCase for public APIs/constants, `_camelCase` for private fields, `var` preferred, System usings first, all usings outside namespace.

Additional enforced rules (warning severity):
- File-scoped namespaces (`namespace Foo;`)
- Accessibility modifiers always required
- Readonly fields where possible
- No `this.` qualification
- Predefined types (`int`, `string`) over framework types (`Int32`, `String`)
- No primary constructors (`csharp_style_prefer_primary_constructors = false`)
- No expression-bodied methods or constructors (properties/accessors OK)
- One top-level type per file — with a narrow exception. Never bundle unrelated types together just to save tool calls. Co-locating a small helper type with its primary owner is OK when the helper is only meaningful in that owner's context: a result enum for an interface (e.g. `enum PackageAddResult` beside `interface IPackageDatabase`), a response item beside its response wrapper (e.g. `PackageDependent` beside `DependentsResponse`), or tightly-coupled serialization models. Rule of thumb: if a reader would look for the helper anywhere other than next to the primary type, split it out.

Suppress CS1591 for non-public XML doc comments.

## Testing

xUnit + Moq. Test projects mirror source: `tests/BaGetter.Core.Tests/`, `tests/BaGetter.Web.Tests/`, `tests/BaGetter.Protocol.Tests/`. Integration tests use in-memory SQLite.

Naming convention: the outer test class is named after the type under test — `<Type>Tests` in `BaGetter.Core.Tests`, `<Type>Facts` in `BaGetter.Web.Tests`. Tests for one method are grouped in a nested class named exactly after that method, with a shared-setup `FactsBase` (e.g. `PermissionServiceTests` → `public class CanPushAsync : FactsBase`). Some older `BaGetter.Web.Tests` classes are flat (no nested per-method classes); prefer the nested style for new tests. Do not use the older `The<Method>Method` idiom.

**`BaGetterApplication`** (WebApplicationFactory) is the integration test host — it mocks `SystemTime` to 2020-01-01, creates temp-dir SQLite databases, and wires up `XunitLoggerProvider`. Use `BaGetWebApplicationFactoryExtensions` helpers (`AddPackageAsync`, `AddSymbolPackageAsync`) to seed test data. Override config via in-memory dictionary config sources in test setup.

## Centralized Package Versions

All NuGet package versions managed in `Directory.Packages.props` at repo root. Do not specify versions in individual `.csproj` files.
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
@AGENTS.md
7 changes: 6 additions & 1 deletion Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Azure.Identity" Version="1.21.0" />
<PackageVersion Include="Azure.Data.Tables" Version="12.10.0" />
<PackageVersion Include="Azure.Search.Documents" Version="11.6.0" />
<PackageVersion Include="Azure.Storage.Blobs" Version="12.24.0" />
<PackageVersion Include="Azure.Storage.Common" Version="12.23.0" />
<PackageVersion Include="BCrypt.Net-Next" Version="4.1.0" />
<PackageVersion Include="MailKit" Version="4.17.0" />
<PackageVersion Include="Microsoft.Graph" Version="6.2.0" />
<PackageVersion Include="McMaster.Extensions.CommandLineUtils" Version="4.1.1" />
<PackageVersion Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="9.0.10" />
<PackageVersion Include="Microsoft.Azure.Cosmos" Version="3.38.1" />
Expand All @@ -19,6 +23,7 @@
<PackageVersion Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.10" />
<PackageVersion Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="9.0.10" />
<PackageVersion Include="Microsoft.Identity.Web" Version="4.6.0" />
<PackageVersion Include="NuGet.Frameworks" Version="6.13.2" />
<PackageVersion Include="NuGet.Protocol" Version="6.13.2" />
<PackageVersion Include="NuGet.Versioning" Version="6.13.2" />
Expand Down Expand Up @@ -47,4 +52,4 @@
<PackageVersion Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.10" />
<PackageVersion Include="Tencent.QCloud.Cos.Sdk" Version="5.4.44" />
</ItemGroup>
</Project>
</Project>
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
ARG Version=1.0.0

FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:9.0-alpine AS build
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:10.0-alpine AS build
ARG Version
ARG TARGETARCH
WORKDIR /src
Expand Down Expand Up @@ -37,7 +37,7 @@ RUN mkdir -p "/data/packages" \
mkdir -p "/data/db"

## Create final image
FROM mcr.microsoft.com/dotnet/aspnet:9.0-alpine AS base
FROM mcr.microsoft.com/dotnet/aspnet:10.0-alpine AS base
# install cultures (same approach as Alpine SDK image)
RUN apk add --no-cache icu-libs icu-data-full tzdata
# disable the invariant mode (set in base image)
Expand Down
47 changes: 47 additions & 0 deletions docs/docs/Installation/azure.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,30 @@ To use a SQL database, set the database type to the SQL provider of your choice
}
```

To authenticate using managed identity instead of a username/password, add `Authentication=Active Directory Default` to the connection string:

```json
{
...

"Database": {
"Type": "SqlServer",
"ConnectionString": "Server=tcp:<server>.database.windows.net,1433;Initial Catalog=<database>;Authentication=Active Directory Default;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;"
},

...
}
```

The managed identity must be added as a user in the database before BaGetter can connect:

```sql
CREATE USER [<identity-name>] FROM EXTERNAL PROVIDER;
ALTER ROLE db_datareader ADD MEMBER [<identity-name>];
ALTER ROLE db_datawriter ADD MEMBER [<identity-name>];
ALTER ROLE db_ddladmin ADD MEMBER [<identity-name>];
```

</TabItem>

<TabItem value="table" label="Table Storage">
Expand Down Expand Up @@ -109,6 +133,29 @@ To use a connection string, add it like this:
}
```

</TabItem>

<TabItem value="managedIdentity" label="Managed identity">

To authenticate using managed identity, set `ConnectionString` to the blob service endpoint and enable `UseAzureDefaultCredential`:

```json
{
...

"Storage": {
"Type": "AzureBlobStorage",
"Container": "my-container",
"ConnectionString": "https://<account>.blob.core.windows.net",
"UseAzureDefaultCredential": true
},

...
}
```

The managed identity must be granted the **Storage Blob Data Contributor** role on the storage account before BaGetter can read or write packages.

</TabItem>
</Tabs>

Expand Down
Loading