V13-FE-006: consolidate approved UI and contract hardening
deploy / deploy (push) Successful in 1m52s
deploy / notify (push) Successful in 1s

This commit is contained in:
2026-08-13 02:41:00 +09:00
parent d79edae546
commit 3f293d8aa8
1278 changed files with 14384 additions and 1664 deletions
@@ -8,7 +8,7 @@ public sealed class RepositoryRulesTests
public void Prohibited_source_patterns_are_not_introduced()
{
var repositoryRoot = FindRepositoryRoot();
var sourceFiles = Directory.EnumerateFiles(repositoryRoot, "*.cs", SearchOption.AllDirectories)
var sourceFiles = Directory.EnumerateFiles(Path.Combine(repositoryRoot, "src"), "*.cs", SearchOption.AllDirectories)
.Where(x => !IsGeneratedOrTestOutput(x))
.ToArray();
@@ -21,7 +21,7 @@ public sealed class RepositoryRulesTests
public void DateTime_now_must_use_iclock_abstraction()
{
var repositoryRoot = FindRepositoryRoot();
var sourceFiles = Directory.EnumerateFiles(repositoryRoot, "*.cs", SearchOption.AllDirectories)
var sourceFiles = Directory.EnumerateFiles(Path.Combine(repositoryRoot, "src"), "*.cs", SearchOption.AllDirectories)
.Where(x => !IsGeneratedOrTestOutput(x))
.ToArray();
@@ -114,6 +114,82 @@ public sealed class RepositoryRulesTests
"Every module endpoint must declare Roles or Policies: " + string.Join(", ", violations));
}
[Fact]
public void Role_declared_endpoints_must_not_allow_anonymous_access()
{
var root = FindRepositoryRoot();
var endpoints = Directory.EnumerateFiles(
Path.Combine(root, "src"),
"*.cs",
SearchOption.AllDirectories)
.Where(path => Path.GetFileName(path).Contains("Endpoint", StringComparison.Ordinal))
.ToArray();
var violations = endpoints.Where(path =>
{
var text = File.ReadAllText(path);
return text.Contains("Roles(", StringComparison.Ordinal)
&& text.Contains("AllowAnonymous()", StringComparison.Ordinal)
&& !text.Contains("/test/", StringComparison.Ordinal);
}).ToArray();
Assert.True(violations.Length == 0,
"Role-declared endpoints must not also allow anonymous access: " + string.Join(", ", violations));
}
[Fact]
public void Unapproved_reconciliation_endpoints_must_remain_unregistered()
{
var root = FindRepositoryRoot();
var endpointFile = Path.Combine(root, "src", "KArtSell.Modules.ModelOperations", "PortfolioReconciliation", "Endpoints.cs");
var text = File.ReadAllText(endpointFile);
Assert.Equal(4, CountOccurrences(text, "[DontRegister]"));
Assert.Equal(4, CountOccurrences(text, "AllowAnonymous()"));
}
[Fact]
public void KIS_trade_endpoints_must_remain_unregistered_while_capability_is_off()
{
var root = FindRepositoryRoot();
var endpointFile = Path.Combine(
root, "src", "KArtSell.Modules.ModelOperations", "TradeExecution", "TradeEndpoints.cs");
var text = File.ReadAllText(endpointFile);
Assert.Equal(2, CountOccurrences(text, "[DontRegister]"));
Assert.Equal(2, CountOccurrences(text, "AllowAnonymous()"));
}
[Fact]
public void Job_run_repository_columns_exist_in_authoritative_baseline_schema()
{
var root = FindRepositoryRoot();
var repository = File.ReadAllText(Path.Combine(
root, "src", "KArtSell.BuildingBlocks", "Reliability", "DapperJobRunRepository.cs"));
var schema = File.ReadAllText(Path.Combine(root, "db", "migrations", "0000_building_blocks.sql"));
var requiredColumns = new[]
{
"job_run_id", "job_type", "job_version", "scope_key", "idempotency_key",
"watermark", "app_version", "model_version", "config_version", "data_version",
"contract_version", "status", "input_hash", "output_hash", "started_at",
"heartbeat_at", "finished_at", "error_code", "trace_id"
};
var missingFromSchema = requiredColumns
.Where(column => !schema.Contains(column, StringComparison.OrdinalIgnoreCase))
.ToArray();
Assert.Empty(missingFromSchema);
var insertSection = repository[(repository.IndexOf("insert into", StringComparison.OrdinalIgnoreCase))..];
var referencedInRepository = requiredColumns
.Where(column => insertSection.Contains(column, StringComparison.OrdinalIgnoreCase))
.ToArray();
Assert.Equal(
requiredColumns.OrderBy(x => x),
referencedInRepository.OrderBy(x => x));
}
[Fact]
public void Accidental_placeholder_files_are_not_committed()
{
@@ -179,6 +255,9 @@ public sealed class RepositoryRulesTests
Assert.True(violations.Length == 0, message + " " + string.Join(", ", violations));
}
private static int CountOccurrences(string text, string value) =>
text.Split(value, StringSplitOptions.None).Length - 1;
private static bool IsGeneratedOrTestOutput(string path)
=> path.Contains($"{Path.DirectorySeparatorChar}obj{Path.DirectorySeparatorChar}", StringComparison.Ordinal)
|| path.Contains($"{Path.DirectorySeparatorChar}bin{Path.DirectorySeparatorChar}", StringComparison.Ordinal)