diff --git a/.github/README.md b/.github/README.md index 2d58e45e39..320018a73c 100644 --- a/.github/README.md +++ b/.github/README.md @@ -33,7 +33,6 @@ Typical adblockers run as an extension in popular web browsers. As we browse the | ------------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Website | A React & TypeScript UI built with Ant Design. | [![Website](https://img.shields.io/website-up-down-green-red/http/shields.io.svg?label=Website)](https://filterlists.com/) [![Website Azure DevOps builds](https://dev.azure.com/collinbarrett/FilterLists/_apis/build/status/Web?branchName=main)](https://dev.azure.com/collinbarrett/FilterLists/_build/latest?definitionId=18) [![Website Azure DevOps releases](https://vsrm.dev.azure.com/collinbarrett/_apis/public/Release/badge/b06a3d5c-459e-4789-9735-0f5969006fe8/4/5)](https://dev.azure.com/collinbarrett/FilterLists/_release?definitionId=4) [![Website Docker Image](https://img.shields.io/badge/docker%20image-web-blue?label=Docker%20Image)](https://github.com/users/collinbarrett/packages/container/package/filterlists-web) [![Website Security Headers](https://img.shields.io/security-headers?url=https%3A%2F%2Ffilterlists.com)](https://securityheaders.com/?q=https%3A%2F%2Ffilterlists.com) | | Directory API | An ASP.NET Core API serving the core FilterList information. | [![Directory API Swagger UI](https://img.shields.io/website-up-down-green-red/http/shields.io.svg?label=API%20Docs)](https://filterlists.com/api/?urls.primaryName=Directory) [![Directory API OpenAPI Specification](https://img.shields.io/swagger/valid/3.0?specUrl=https%3A%2F%2Ffilterlists.com%2Fapi%2Fdirectory%2Fv1%2Fswagger.json)](https://filterlists.com/api/directory/v1/swagger.json) [![Directory API Azure DevOps builds](https://dev.azure.com/collinbarrett/FilterLists/_apis/build/status/Directory%20API?branchName=main)](https://dev.azure.com/collinbarrett/FilterLists/_build/latest?definitionId=27) [![Directory API Azure DevOps releases](https://vsrm.dev.azure.com/collinbarrett/_apis/public/Release/badge/b06a3d5c-459e-4789-9735-0f5969006fe8/3/4)](https://dev.azure.com/collinbarrett/FilterLists/_release?definitionId=3) [![Directory API Docker Image](https://img.shields.io/badge/docker%20image-directory--api-blue?label=Docker%20Image)](https://github.com/users/collinbarrett/packages/container/package/filterlists-directory-api) [![Directory API Security Headers](https://img.shields.io/security-headers?url=https%3A%2F%2Ffilterlists.com%2Fapi%2Fdirectory%2Fv1%2Fswagger.json)](https://securityheaders.com/?q=https%3A%2F%2Ffilterlists.com%2Fapi%2Fdirectory%2Fv1%2Fswagger.json) | -| Reverse Proxy | An NGINX instance forwarding requests to the respective services above. | [![Reverse Proxy Azure DevOps builds](https://dev.azure.com/collinbarrett/FilterLists/_apis/build/status/Reverse%20Proxy?branchName=main)](https://dev.azure.com/collinbarrett/FilterLists/_build/latest?definitionId=21) [![Reverse Proxy Azure DevOps releases](https://vsrm.dev.azure.com/collinbarrett/_apis/public/Release/badge/b06a3d5c-459e-4789-9735-0f5969006fe8/5/6)](https://dev.azure.com/collinbarrett/FilterLists/_release?definitionId=5) [![Reverse Proxy Mozilla HTTP Observatory Grade](https://img.shields.io/mozilla-observatory/grade/filterlists.com?publish)](https://observatory.mozilla.org/analyze/filterlists.com) [![Reverse Proxy Chromium HSTS preload](https://img.shields.io/hsts/preload/filterlists.com)](https://hstspreload.org/?domain=filterlists.com) | # Contributing @@ -53,18 +52,79 @@ FilterLists does not maintain any of these lists. It serves only as a discovery ## Building and Running Locally -We have containerized FilterLists to make it as easy as possible for contributers to get the project up and running locally. - -1. Install Docker CE. [Docs](https://docs.docker.com/install/) -2. Install the current version of Node.js. [Docs](https://nodejs.org/en/download/current/) -3. Clone the FilterLists git repository to your computer. [Docs](https://help.github.com/en/articles/cloning-a-repository) -4. Navigate to the root directory of your locally cloned FilterLists git repository in a command-line interface. -5. Start the APIs:
- `docker-compose -f docker-compose/docker-compose.yml -f docker-compose/docker-compose.override.yml up -d`
- You can then view the API docs and execute API calls here: http://localhost:8080/api/ -6. Start the Web app:
- `npm i --cwd web && npm start --prefix web`
- You can then view the Web app calling your local instance of the Directory API here: http://localhost:3000 +FilterLists is build on the .NET Aspire stack. Install the [.NET Aspire prerequisites](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/setup-tooling) before proceeding. + +### Directory API + +#### Configure Azure Resources + +Local debugging depends on an Azure Application Insights resource. Either [configure a connection to your Azure subscription](https://learn.microsoft.com/en-us/dotnet/aspire/deployment/azure/local-provisioning#configuration) or comment out the `appInsights` resource in `services/FilterLists.AppHost/Program.cs`. + +#### Prepare Database Volume + +So that the database does not need to be re-seeded on every startup, the SQL Server container is configured with a volume mount. Create a persistent password in order for this to be accessed by executing the command below in `services/FilterLists.AppHost` replacing `` with a custom password: + +```bash +dotnet user-secrets set Parameters:directorysqlserver-password +``` + +Alternatively, remove the `.WithDataVolume()` configuration on the `directoryDb` resource in `services/FilterLists.AppHost/Program.cs` to re-seed the database on every startup. + +[MS Learn](https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/persist-data-volumes) + +#### Adding EF Core Migrations + +Modify the database schema or seed data by adding an EF Core migration. + +1. Install the [EF Core tools](https://learn.microsoft.com/en-us/ef/core/cli/dotnet#installing-the-tools). +2. Modify the `QueryDbContext` EF Core model or the seed data. +3. Execute the command below in the `services/Directory` directory replacing `` with a meaningful name. + +```bash +dotnet ef migrations add --project FilterLists.Directory.Infrastructure.Migrations/FilterLists.Directory.Infrastructure.Migrations.csproj --startup-project FilterLists.Directory.Infrastructure.MigrationService/FilterLists.Directory.Infrastructure.MigrationService.csproj +``` + +## Deploying to Production + +### Directory API + +#### Create and Prepare SQL Server Database + +Create an instance of SQL Server containing the users below. + +##### DirectoryMigrations user for applying EF Core migrations + +```sql +USE [master]; +GO + +CREATE LOGIN [DirectoryMigrations] WITH PASSWORD = 'my_password'; +GO + +USE [directorydb]; +GO + +CREATE USER [DirectoryMigrations] FOR LOGIN [DirectoryMigrations]; +ALTER ROLE [db_ddladmin] ADD MEMBER [DirectoryMigrations]; -- to apply migrations +ALTER ROLE [db_datareader] ADD MEMBER [DirectoryMigrations]; -- to read from __EFMigrationsHistory +ALTER ROLE [db_datawriter] ADD MEMBER [DirectoryMigrations]; -- to insert to __EFMigrationsHistory +``` + +##### DirectoryApiReadonly for API runtime reads + +```sql +USE [master]; +GO + +CREATE LOGIN [DirectoryApiReadonly] WITH PASSWORD = 'my_password'; +GO + +USE [directorydb]; +GO + +CREATE USER [DirectoryApiReadonly] FOR LOGIN [DirectoryApiReadonly]; +ALTER ROLE [db_datareader] ADD MEMBER [DirectoryApiReadonly]; +``` # Acknowledgements diff --git a/services/Directory/AddMigration.md b/services/Directory/AddMigration.md deleted file mode 100644 index aa3f7604f3..0000000000 --- a/services/Directory/AddMigration.md +++ /dev/null @@ -1 +0,0 @@ -dotnet ef migrations add InitialCreate --project FilterLists.Directory.Infrastructure.Migrations/FilterLists.Directory.Infrastructure.Migrations.csproj --startup-project FilterLists.Directory.Infrastructure.MigrationService/FilterLists.Directory.Infrastructure.MigrationService.csproj \ No newline at end of file diff --git a/services/Directory/CreateSqlUsers.md b/services/Directory/CreateSqlUsers.md deleted file mode 100644 index 508a3112a4..0000000000 --- a/services/Directory/CreateSqlUsers.md +++ /dev/null @@ -1,33 +0,0 @@ -# DirectoryMigrations user for applying EF Core migrations - -```sql -USE [master]; -GO - -CREATE LOGIN DirectoryMigrations WITH PASSWORD = 'my_password'; -GO - -USE [directorydb]; -GO - -CREATE USER DirectoryMigrations FOR LOGIN DirectoryMigrations; -ALTER ROLE db_ddladmin ADD MEMBER DirectoryMigrations; -- to apply migrations -ALTER ROLE db_datareader ADD MEMBER DirectoryMigrations; -- to read from __EFMigrationsHistory -ALTER ROLE db_datawriter ADD MEMBER DirectoryMigrations; -- to insert to __EFMigrationsHistory -``` - -# DirectoryApiReadonly for API runtime reads - -```sql -USE [master]; -GO - -CREATE LOGIN DirectoryApiReadonly WITH PASSWORD = 'my_password'; -GO - -USE [directorydb]; -GO - -CREATE USER DirectoryApiReadonly FOR LOGIN DirectoryApiReadonly; -ALTER ROLE db_datareader ADD MEMBER DirectoryApiReadonly; -- to read from __EFMigrationsHistory -``` \ No newline at end of file diff --git a/services/FilterLists.AppHost/Program.cs b/services/FilterLists.AppHost/Program.cs index 5d0fc5c55a..aba16b0d66 100644 --- a/services/FilterLists.AppHost/Program.cs +++ b/services/FilterLists.AppHost/Program.cs @@ -6,7 +6,8 @@ // TODO: use separate users (db_ddladmin only for migrations) https://stackoverflow.com/q/78564037/2343739 var directoryDb = builder.AddSqlServer("directorysqlserver") - .PublishAsConnectionString() // customized for free tier, don't trust Aspire to provision db + .PublishAsConnectionString() // customized Azure resource for free tier, don't yet trust Aspire to provision db + .WithDataVolume() // don't re-seed db on every startup locally, requires https://learn.microsoft.com/en-us/dotnet/aspire/fundamentals/persist-data-volumes#create-a-persistent-password .AddDatabase("directorydb"); // TODO: migrate published db from run-once instance (Container Apps 'App" type restarts)