What changed, and why it matters
This commit removes database-provider checks from two old database migration files and adds developer instructions for creating future migrations. It does not change application behavior for users, fix a vulnerability, or introduce new functionality. The SQL inside the migrations is unchanged; it now simply runs unconditionally rather than only when PostgreSQL is detected.
No security action required. Review as normal code cleanup / developer-documentation update.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The diff removes if (migrationBuilder.IsNpgsql()) guards in two EF Core migration classes (20231219031609_translationsmigration.cs and 20260610081428_TranslationsFallbackRestrict.cs) and re-indents the raw SQL blocks. It also updates AGENTS.md with guidance for creating migrations, including not using migrationBuilder.IsNpgsql() and assuming PostgreSQL. The SQL statements themselves are identical in content. No runtime code, API surface, authentication, authorization, or data handling logic is modified.
Changed components
BTCPayServer.Data/Migrations/20231219031609_translationsmigration.csBTCPayServer.Data/Migrations/20260610081428_TranslationsFallbackRestrict.csAGENTS.mdInspect captured patch +45 / −49
diff --git a/AGENTS.md b/AGENTS.md
index ed7cc85..55f7432 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -1,5 +1,14 @@
# Agent Instructions
+## Creating Migrations
+
+* Run `dotnet ef migrations add <migration-name>` to generate the migration.
+* Copy the attributes from the generated `.Designer.cs` file to the `.cs` migration file.
+* Remove the generated `.Designer.cs` file.
+* Remove the `Down()` method.
+* Do not use `migrationBuilder.IsNpgsql()`; assume PostgreSQL is used.
+* If a migration cannot be generated through `dotnet ef migrations`, add a migration file prefixed by date in the `Migrations` folder, for example `20260525115757_passkey.cs`, and use `migrationBuilder.Sql` to run raw SQL.
+
## Updating `Changelog.md`
When asked to update or review the changelog, focus on user-visible changes and keep entries concise.
diff --git a/BTCPayServer.Data/Migrations/20231219031609_translationsmigration.cs b/BTCPayServer.Data/Migrations/20231219031609_translationsmigration.cs
index f8f752f..9d8f3e4 100644
--- a/BTCPayServer.Data/Migrations/20231219031609_translationsmigration.cs
+++ b/BTCPayServer.Data/Migrations/20231219031609_translationsmigration.cs
@@ -13,45 +13,42 @@ namespace BTCPayServer.Migrations
{
protected override void Up(MigrationBuilder migrationBuilder)
{
- if (migrationBuilder.IsNpgsql())
- {
- migrationBuilder.Sql("""
-CREATE TABLE lang_dictionaries (
- dict_id TEXT PRIMARY KEY,
- fallback TEXT DEFAULT NULL,
- source TEXT DEFAULT NULL,
- metadata JSONB DEFAULT NULL,
- FOREIGN KEY (fallback) REFERENCES lang_dictionaries(dict_id) ON UPDATE CASCADE ON DELETE SET NULL
-);
-INSERT INTO lang_dictionaries(dict_id, source) VALUES ('English', 'Default');
+ migrationBuilder.Sql("""
+ CREATE TABLE lang_dictionaries (
+ dict_id TEXT PRIMARY KEY,
+ fallback TEXT DEFAULT NULL,
+ source TEXT DEFAULT NULL,
+ metadata JSONB DEFAULT NULL,
+ FOREIGN KEY (fallback) REFERENCES lang_dictionaries(dict_id) ON UPDATE CASCADE ON DELETE SET NULL
+ );
+ INSERT INTO lang_dictionaries(dict_id, source) VALUES ('English', 'Default');
-CREATE TABLE lang_translations (
- dict_id TEXT NOT NULL,
- sentence TEXT NOT NULL,
- translation TEXT NOT NULL,
- PRIMARY KEY (dict_id, sentence),
- FOREIGN KEY (dict_id) REFERENCES lang_dictionaries(dict_id) ON UPDATE CASCADE ON DELETE CASCADE
-);
+ CREATE TABLE lang_translations (
+ dict_id TEXT NOT NULL,
+ sentence TEXT NOT NULL,
+ translation TEXT NOT NULL,
+ PRIMARY KEY (dict_id, sentence),
+ FOREIGN KEY (dict_id) REFERENCES lang_dictionaries(dict_id) ON UPDATE CASCADE ON DELETE CASCADE
+ );
-CREATE VIEW translations AS
-WITH RECURSIVE translations_with_paths AS (
- SELECT d.dict_id, t.sentence, t.translation, ARRAY[d.dict_id] AS path FROM lang_translations t
- INNER JOIN lang_dictionaries d USING (dict_id)
+ CREATE VIEW translations AS
+ WITH RECURSIVE translations_with_paths AS (
+ SELECT d.dict_id, t.sentence, t.translation, ARRAY[d.dict_id] AS path FROM lang_translations t
+ INNER JOIN lang_dictionaries d USING (dict_id)
- UNION ALL
+ UNION ALL
- SELECT d.dict_id, t.sentence, t.translation, d.dict_id || t.path FROM translations_with_paths t
- INNER JOIN lang_dictionaries d ON d.fallback=t.dict_id
-),
-ranked_translations AS (
- SELECT *,
- ROW_NUMBER() OVER (PARTITION BY dict_id, sentence ORDER BY array_length(path, 1)) AS rn
- FROM translations_with_paths
-)
-SELECT dict_id, sentence, translation, path FROM ranked_translations WHERE rn=1;
-COMMENT ON VIEW translations IS 'Compute the translation for all sentences for all dictionaries, taking into account fallbacks';
-""");
- }
+ SELECT d.dict_id, t.sentence, t.translation, d.dict_id || t.path FROM translations_with_paths t
+ INNER JOIN lang_dictionaries d ON d.fallback=t.dict_id
+ ),
+ ranked_translations AS (
+ SELECT *,
+ ROW_NUMBER() OVER (PARTITION BY dict_id, sentence ORDER BY array_length(path, 1)) AS rn
+ FROM translations_with_paths
+ )
+ SELECT dict_id, sentence, translation, path FROM ranked_translations WHERE rn=1;
+ COMMENT ON VIEW translations IS 'Compute the translation for all sentences for all dictionaries, taking into account fallbacks';
+ """);
}
protected override void Down(MigrationBuilder migrationBuilder)
diff --git a/BTCPayServer.Data/Migrations/20260610081428_TranslationsFallbackRestrict.cs b/BTCPayServer.Data/Migrations/20260610081428_TranslationsFallbackRestrict.cs
index b0005f5..b16233d 100644
--- a/BTCPayServer.Data/Migrations/20260610081428_TranslationsFallbackRestrict.cs
+++ b/BTCPayServer.Data/Migrations/20260610081428_TranslationsFallbackRestrict.cs
@@ -15,25 +15,15 @@ namespace BTCPayServer.Migrations
/// <inheritdoc />
protected override void Up(MigrationBuilder migrationBuilder)
{
- if (migrationBuilder.IsNpgsql())
- {
- migrationBuilder.Sql(
- "ALTER TABLE lang_dictionaries DROP CONSTRAINT lang_dictionaries_fallback_fkey;");
- migrationBuilder.Sql(
- "ALTER TABLE lang_dictionaries ADD CONSTRAINT lang_dictionaries_fallback_fkey FOREIGN KEY (fallback) REFERENCES lang_dictionaries(dict_id) ON UPDATE CASCADE ON DELETE RESTRICT;");
- }
+ migrationBuilder.Sql(
+ "ALTER TABLE lang_dictionaries DROP CONSTRAINT lang_dictionaries_fallback_fkey;");
+ migrationBuilder.Sql(
+ "ALTER TABLE lang_dictionaries ADD CONSTRAINT lang_dictionaries_fallback_fkey FOREIGN KEY (fallback) REFERENCES lang_dictionaries(dict_id) ON UPDATE CASCADE ON DELETE RESTRICT;");
}
/// <inheritdoc />
protected override void Down(MigrationBuilder migrationBuilder)
{
- if (migrationBuilder.IsNpgsql())
- {
- migrationBuilder.Sql(
- "ALTER TABLE lang_dictionaries DROP CONSTRAINT lang_dictionaries_fallback_fkey;");
- migrationBuilder.Sql(
- "ALTER TABLE lang_dictionaries ADD CONSTRAINT lang_dictionaries_fallback_fkey FOREIGN KEY (fallback) REFERENCES lang_dictionaries(dict_id) ON UPDATE CASCADE ON DELETE SET NULL;");
- }
}
}
}
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.