Skip to content
Closed
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
2 changes: 1 addition & 1 deletion DataProvider/Nimblesite.DataProvider.Core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ The core source generator library. Parses SQL files and generates strongly-typed
## Documentation

- Parent README: [DataProvider/README.md](../README.md)
- Migration CLI spec: [docs/specs/migration-cli-spec.md](../../docs/specs/migration-cli-spec.md)
- Migration spec: [docs/specs/migration-spec.md](../../docs/specs/migration-spec.md#74-dataprovidermigrate-cli-mig-cli)
2 changes: 1 addition & 1 deletion DataProvider/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,4 @@ SqliteCodeGenerator.GenerateCodeWithMetadata(config: config, /* … */);

- [LQL](../Lql/README.md) — cross-database query language that transpiles to SQL
- [Migrations](../Migration/README.md) — YAML schema definitions consumed by `DataProviderMigrate`
- Migration CLI spec: [docs/specs/migration-cli-spec.md](../docs/specs/migration-cli-spec.md)
- Migration spec: [docs/specs/migration-spec.md](../docs/specs/migration-spec.md#74-dataprovidermigrate-cli-mig-cli)
15 changes: 15 additions & 0 deletions Migration/DataProviderMigrate/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,14 @@ private static int ExecuteMigration(MigrateParseResult.Success args)
return 1;
}

if (IsSqlServerProvider(args.Provider) && SchemaContainsRls(schema))
{
// Implements [RLS-MSSQL]. The SQL Server migration package does
// not exist yet, so RLS targeting SQL Server must fail closed.
Console.WriteLine(MigrationError.RlsMssqlUnsupported().Message);
return 1;
}

return args.Provider.ToLowerInvariant() switch
{
"sqlite" => MigrateSqliteDatabase(
Expand All @@ -112,6 +120,13 @@ private static int ExecuteMigration(MigrateParseResult.Success args)
};
}

private static bool IsSqlServerProvider(string provider) =>
provider.Equals("sqlserver", StringComparison.OrdinalIgnoreCase)
|| provider.Equals("mssql", StringComparison.OrdinalIgnoreCase);

private static bool SchemaContainsRls(SchemaDefinition schema) =>
schema.Tables.Any(table => table.RowLevelSecurity is not null);

private static int MigrateSqliteDatabase(
SchemaDefinition schema,
string outputPath,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
using System.Globalization;

namespace Nimblesite.DataProvider.Migration.Tests;

// Tests [RLS-MSSQL] SQL Server package absence guard from docs/specs/rls-spec.md.

/// <summary>
/// CLI tests for unsupported SQL Server RLS migration attempts.
/// </summary>
public sealed class DataProviderMigrateRlsUnsupportedTests
{
[Fact]
public void Migrate_SqlServerProviderWithRlsSchema_ReturnsCanonicalUnsupportedError()
{
var schemaPath = WriteTempSchemaFile(contents: RlsSchemaYaml());

try
{
var result = RunMigrate(schemaPath: schemaPath);

Assert.Equal(expected: 1, actual: result.ExitCode);
Assert.Contains(
expectedSubstring: "MIG-E-RLS-MSSQL-UNSUPPORTED",
actualString: result.Output,
comparisonType: StringComparison.Ordinal
);
Assert.Contains(
expectedSubstring: "Nimblesite.DataProvider.Migration.SqlServer package does not exist",
actualString: result.Output,
comparisonType: StringComparison.Ordinal
);
}
finally
{
File.Delete(path: schemaPath);
}
}

private static (int ExitCode, string Output) RunMigrate(string schemaPath)
{
var originalOut = Console.Out;
using var output = new StringWriter(CultureInfo.InvariantCulture);
Console.SetOut(output);
try
{
var exitCode = DataProviderMigrate.Program.Main(
args:
[
"migrate",
"--schema",
schemaPath,
"--provider",
"sqlserver",
"--output",
"unused",
]
);
return (exitCode, output.ToString());
}
finally
{
Console.SetOut(originalOut);
}
}

private static string WriteTempSchemaFile(string contents)
{
var schemaPath = Path.Combine(
Path.GetTempPath(),
string.Create(
CultureInfo.InvariantCulture,
$"dataprovider-rls-unsupported-{Guid.NewGuid():N}.yaml"
)
);
File.WriteAllText(path: schemaPath, contents: contents);
return schemaPath;
}

private static string RlsSchemaYaml() =>
"""
name: sqlserver_rls_guard
tables:
- name: documents
schema: public
columns:
- name: id
type: Uuid
isNullable: false
- name: owner_id
type: Uuid
isNullable: false
primaryKey:
columns:
- id
rowLevelSecurity:
policies:
- name: owner_isolation
operations:
- Select
using: owner_id = current_user_id()
""";
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="../DataProviderMigrate/DataProviderMigrate.csproj" />
<ProjectReference Include="../Nimblesite.DataProvider.Migration.Core/Nimblesite.DataProvider.Migration.Core.csproj" />
<ProjectReference Include="../Nimblesite.DataProvider.Migration.SQLite/Nimblesite.DataProvider.Migration.SQLite.csproj" />
<ProjectReference Include="../Nimblesite.DataProvider.Migration.Postgres/Nimblesite.DataProvider.Migration.Postgres.csproj" />
Expand Down
2 changes: 1 addition & 1 deletion Migration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -202,4 +202,4 @@ Regenerate the database on every build so developers never run migrations manual

- [DataProvider](../DataProvider/README.md) — generated extension methods for the tables defined here
- [LQL](../Lql/README.md) — write portable queries against the migrated schema
- Migration CLI spec: [docs/specs/migration-cli-spec.md](../docs/specs/migration-cli-spec.md)
- Migration spec: [docs/specs/migration-spec.md](../docs/specs/migration-spec.md#74-dataprovidermigrate-cli-mig-cli)
4 changes: 2 additions & 2 deletions Reporting/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,12 +259,12 @@ The renderer is a standalone JS bundle. Embed in any page:

## Database Schema

**All database schemas MUST be created using the Migration library with YAML definitions.** Raw SQL for creating database schemas is strictly prohibited. Use `Migration.Cli` with YAML schema files as the single source of truth.
**All database schemas MUST be created using the Migration library with YAML definitions.** Raw SQL for creating database schemas is strictly prohibited. Use `DataProviderMigrate` with YAML schema files as the single source of truth.

If the reporting platform requires its own persistence (e.g., for saved reports, scheduled executions), the schema MUST be defined in a `reporting-schema.yaml` file and created via:

```bash
dotnet run --project Migration/Migration.Cli -- --schema reporting-schema.yaml --output reporting.db --provider sqlite
dotnet run --project Migration/DataProviderMigrate/DataProviderMigrate.csproj -- migrate --schema reporting-schema.yaml --output reporting.db --provider sqlite
```

For the MVP, report definitions are loaded from JSON files on disk (no database persistence needed). Future phases will add YAML-migrated schema for saved reports.
Expand Down
4 changes: 2 additions & 2 deletions coverage-thresholds.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,10 @@
"include": "[Nimblesite.Reporting.Engine]*,[Nimblesite.Reporting.Api]*"
},
"Lql/lql-lsp-rust": {
"threshold": 83
"threshold": 88
},
"Lql/LqlExtension": {
"threshold": 38
"threshold": 39
}
}
}
10 changes: 5 additions & 5 deletions docs/plans/RLS-PLAN.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,14 +85,14 @@ Predicates that query other tables (e.g. group membership) MUST use LQL, transpi
- [x] Write failing `RlsPredicateTranspiler` unit tests in new `RlsPredicateTranspilerTests.cs`
- [x] Make `RlsPredicateTranspiler` tests pass
- [x] Implement RLS operation handling in `PostgresDdlGenerator.cs` (Enable, Create, Drop, Disable)
- [ ] Write failing Postgres RLS E2E tests in `PostgresMigrationTests.cs`
- [x] Write failing Postgres RLS E2E tests in `PostgresRlsE2ETests.cs`
- [x] Extend `PostgresSchemaInspector.cs` to read `pg_policies` into `RlsPolicySetDefinition`
- [ ] Make Postgres E2E tests pass
- [x] Make Postgres E2E tests pass
- [x] Extend `SchemaDiff.Calculate` in `SchemaDiff.cs` with RLS diff logic
- [x] Write failing SQLite RLS E2E tests in `SqliteRlsMigrationTests.cs`
- [x] Implement `__rls_context` table, trigger generation, and `_secure` view generation in `SqliteDdlGenerator.cs`
- [x] Extend `SqliteSchemaInspector.cs` to reverse-map `rls_*` triggers
- [x] Make SQLite E2E tests pass
- [ ] Add `MIG-E-RLS-MSSQL-UNSUPPORTED` error guard for SQL Server
- [ ] Run `make ci` -- all tests pass, coverage thresholds maintained
- [ ] Update `Migration/README.md` with RLS usage examples
- [x] Add `MIG-E-RLS-MSSQL-UNSUPPORTED` error guard for SQL Server
- [x] Run `make ci` -- all tests pass, coverage thresholds maintained
- [x] Update `Migration/README.md` with RLS usage examples
119 changes: 0 additions & 119 deletions docs/specs/migration-cli-spec.md

This file was deleted.

Loading
Loading