security: hard-disable all KIS trading paths (AEG-X-016)
Blocks submit, status, cancel, and settlement before HTTP or database writes and removes the KIS polling recurring job. Evidence: concrete adapter test 1/1 passed with zero HTTP calls. WBS remains IN_PROGRESS pending endpoint/startup override evidence.
This commit is contained in:
@@ -398,8 +398,8 @@ try { RecurringJob.AddOrUpdate<OpenDartDailyBatchJob>("opendart-daily-batch", jo
|
||||
try { RecurringJob.AddOrUpdate<GenerateDailyRecommendationJob>("daily-recommendation", job => job.ExecuteAsync(CancellationToken.None), "0 9 * * *", new RecurringJobOptions { TimeZone = kstTimeZone }); logger.LogInformation("✅ daily-recommendation registered"); } catch (Exception ex) { logger.LogWarning(ex, "⚠️ daily-recommendation error"); }
|
||||
try { RecurringJob.AddOrUpdate<GenerateWeeklyRecommendationJob>("weekly-recommendation", job => job.ExecuteAsync(CancellationToken.None), "0 9 * * 6", new RecurringJobOptions { TimeZone = kstTimeZone }); logger.LogInformation("✅ weekly-recommendation registered"); } catch (Exception ex) { logger.LogWarning(ex, "⚠️ weekly-recommendation error"); }
|
||||
try { RecurringJob.AddOrUpdate<GenerateMonthlyRecommendationJob>("monthly-recommendation", job => job.ExecuteAsync(CancellationToken.None), "0 9 1 * *", new RecurringJobOptions { TimeZone = kstTimeZone }); logger.LogInformation("✅ monthly-recommendation registered"); } catch (Exception ex) { logger.LogWarning(ex, "⚠️ monthly-recommendation error"); }
|
||||
// DEBT-027: without this, PollTradeStatusHandler/ConfirmSettlementHandler were reachable via DI but never invoked by anything.
|
||||
try { RecurringJob.AddOrUpdate<KArtSell.Host.Jobs.TradeStatusPollingJob>("trade-status-polling", job => job.ExecuteAsync(CancellationToken.None), "*/2 * * * *", new RecurringJobOptions { TimeZone = TimeZoneInfo.Utc }); logger.LogInformation("✅ trade-status-polling registered"); } catch (Exception ex) { logger.LogWarning(ex, "⚠️ trade-status-polling error"); }
|
||||
RecurringJob.RemoveIfExists("trade-status-polling");
|
||||
logger.LogWarning("KIS trade-status-polling removed: KIS trading is hard-disabled.");
|
||||
|
||||
logger.LogInformation("🎯 Hangfire background jobs initialization complete");
|
||||
|
||||
|
||||
@@ -25,6 +25,17 @@ public class KisTradeExecutionException : Exception
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class KisTradingDisabledException : InvalidOperationException
|
||||
{
|
||||
public KisTradingDisabledException()
|
||||
: base("KIS trading is hard-disabled. No buy, sell, cancel, status, or settlement call is permitted.") { }
|
||||
}
|
||||
|
||||
public static class KisTradingHardOff
|
||||
{
|
||||
public static void EnsureDisabled() => throw new KisTradingDisabledException();
|
||||
}
|
||||
|
||||
public interface IKisTradeExecutionService
|
||||
{
|
||||
Task<(string OrderId, JsonElement Response)> ExecuteTradeAsync(Guid tradeId, int quantity, decimal limitPrice, Guid correlationId, CancellationToken ct = default);
|
||||
@@ -56,6 +67,7 @@ public class KisTradeExecutionService : IKisTradeExecutionService
|
||||
Guid correlationId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
KisTradingHardOff.EnsureDisabled();
|
||||
var requestBody = new
|
||||
{
|
||||
symbol = "US0100",
|
||||
@@ -120,6 +132,7 @@ public class KisTradeExecutionService : IKisTradeExecutionService
|
||||
Guid correlationId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
KisTradingHardOff.EnsureDisabled();
|
||||
var request = new HttpRequestMessage(HttpMethod.Get, $"{KisApiBase}/orders/{kisOrderId}");
|
||||
request.Headers.Add("X-Correlation-ID", correlationId.ToString());
|
||||
|
||||
@@ -159,6 +172,7 @@ public class KisTradeExecutionService : IKisTradeExecutionService
|
||||
Guid correlationId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
KisTradingHardOff.EnsureDisabled();
|
||||
var requestBody = new { reason = reason };
|
||||
var content = new StringContent(
|
||||
JsonSerializer.Serialize(requestBody),
|
||||
@@ -195,6 +209,7 @@ public class KisTradeExecutionService : IKisTradeExecutionService
|
||||
Guid correlationId,
|
||||
CancellationToken ct = default)
|
||||
{
|
||||
KisTradingHardOff.EnsureDisabled();
|
||||
var requestBody = new { confirm = true };
|
||||
var content = new StringContent(
|
||||
JsonSerializer.Serialize(requestBody),
|
||||
|
||||
@@ -42,6 +42,7 @@ public class SubmitTradeHandler
|
||||
|
||||
public async Task<Guid> HandleAsync(SubmitTradeCommand command, CancellationToken ct = default)
|
||||
{
|
||||
KisTradingHardOff.EnsureDisabled();
|
||||
var trade = Trade.Create(command.SellDecisionId, command.Quantity, command.CorrelationId, _clock.UtcNow.UtcDateTime);
|
||||
await _sql.InsertTradeAsync(trade, ct);
|
||||
_logger.LogInformation("Created trade: {TradeId}", trade.Id);
|
||||
@@ -127,6 +128,7 @@ public class PollTradeStatusHandler
|
||||
|
||||
public async Task HandleAsync(PollTradeStatusCommand command, CancellationToken ct = default)
|
||||
{
|
||||
KisTradingHardOff.EnsureDisabled();
|
||||
var trade = await _sql.GetTradeByIdAsync(command.TradeId, command.CorrelationId, ct);
|
||||
if (trade == null)
|
||||
{
|
||||
@@ -222,6 +224,7 @@ public class ConfirmSettlementHandler
|
||||
|
||||
public async Task HandleAsync(ConfirmSettlementCommand command, CancellationToken ct = default)
|
||||
{
|
||||
KisTradingHardOff.EnsureDisabled();
|
||||
var trade = await _sql.GetTradeByIdAsync(command.TradeId, command.CorrelationId, ct);
|
||||
if (trade == null)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user