Защита рецептов: SQL DEPO/SPECTRE/QUIK вынесен в пакет fsql под garble

Реализация варианта B из аудита защиты знаний. Прямой garble всего bj-server
ломает html/template (он обращается к полям структур по имени, garble их
переименовывает). Решение — селективная обфускация: GOGARBLE обфусцирует ТОЛЬКО
пакет с секретами, шаблоны и обработчики не затрагиваются.

95 SQL-запросов к DEPO/SPECTRE/QUIK и трансферным таблицам FTV_M2M вынесены из
lkgateway в отдельный пакет internal/lkgateway/fsql как переменные (именно var,
не const: const компилятор вставил бы обратно в необфусцируемый пакет, и
шифрование бы не сработало — проверено). Сами обработчики, типы и параметры
sql.Named остались на месте; пакет держит только строки запросов.

build-release.sh собирает bj-server с `GOGARBLE=.../fsql garble -literals`
(нужен отдельный SDK go1.26 — модуль-кэшный тулчейн garble не подходит); если
garble/go1.26 не найдены — обычная сборка с предупреждением.

Проверено на реальном garble-бинаре (запускается, /admin и страницы на
структурах работают): рецепт чтения чужих систем из бинаря исчез —
OD_RESTS 13→0, OD_WIRING 5→0, OD_TURNS 1→0, OD_BALANCES 3→0, D_B_CONTRACTS 1→0,
OD_CLIENTS_PORTS 10→0, DepoLimits/MoneyLimits →0. Остаток FTV_M2M — упоминания
имён таблиц в операторских embed-шаблонах и логах, не сам рецепт.

Стенд собран обычной сборкой (без garble) — трассировки остаются читаемыми.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q4YVo4UMopqT5DzicqpPjL
This commit is contained in:
zuevav
2026-09-18 20:29:47 +03:00
parent 47f5015c3f
commit 7ce4c2c79f
49 changed files with 605 additions and 332 deletions
+6 -13
View File
@@ -9,6 +9,7 @@ import (
"context"
"database/sql"
"fmt"
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/lkgateway/fsql"
"log"
"regexp"
"strings"
@@ -55,13 +56,7 @@ func (f depoJobFailure) TableRu() string {
// depoJobFailures — записи с ошибкой обработки за days дней, новые первыми.
func depoJobFailures(ctx context.Context, db *sql.DB, days, limit int) ([]depoJobFailure, error) {
rows, err := db.QueryContext(ctx, `SELECT TOP (@n) * FROM (
SELECT 'FTV_M2M' AS T, ID, CAST(GUID AS varchar(36)) AS G, '' AS R, ISNULL(DIRECTION,'') AS K, ISNULL(TimeEnd, TimeNew) AS A, ISNULL(COMMENT,'') AS C
FROM dbo.FTV_M2M WHERE STATE='ERROR' AND ISNULL(TimeEnd, TimeNew) > DATEADD(day, -@d, GETDATE())
UNION ALL
SELECT 'FTV_M2M_EVENTS', ID, CAST(GUID AS varchar(36)), ISNULL(REFERENCE,''), EVENT_TYPE, ISNULL(TimeEnd, TimeNew), ISNULL(COMMENT,'')
FROM dbo.FTV_M2M_EVENTS WHERE STATE='ERROR' AND EVENT_TYPE LIKE 'BJ[_]%' AND ISNULL(TimeEnd, TimeNew) > DATEADD(day, -@d, GETDATE())
) x ORDER BY A DESC`, sql.Named("n", limit), sql.Named("d", days))
rows, err := db.QueryContext(ctx, fsql.Hlth01, sql.Named("n", limit), sql.Named("d", days))
if err != nil {
return nil, err
}
@@ -95,9 +90,9 @@ func depoRequeueFailures(ctx context.Context, db *sql.DB, days int) (orders, eve
}
for _, f := range fails {
comment := "повторная обработка из bj"
q := "UPDATE dbo.FTV_M2M SET STATE='TODO', TimeBeg=NULL, TimeEnd=NULL, COMMENT=@c WHERE ID=@id AND STATE='ERROR'"
q := fsql.QHl01
if f.Table == "FTV_M2M_EVENTS" {
q = "UPDATE dbo.FTV_M2M_EVENTS SET STATE='TODO', TimeBeg=NULL, TimeEnd=NULL, COMMENT=@c WHERE ID=@id AND STATE='ERROR'"
q = fsql.QHl02
if lf := globalLKFlows.Get(f.GUID); f.Type == "BJ_GATEWAY_REJECT" && lf != nil && lf.Reason != "" {
comment = lf.Reason
}
@@ -111,7 +106,7 @@ func depoRequeueFailures(ctx context.Context, db *sql.DB, days int) (orders, eve
if f.Table == "FTV_M2M" {
orders += n
// строки поручения, помеченные ошибкой, тоже возвращаем
if _, e := tx.ExecContext(ctx, "UPDATE dbo.FTV_M2M_LINES SET STATE='TODO', TimeBeg=NULL, TimeEnd=NULL WHERE GUID=@g AND STATE='ERROR'", sql.Named("g", f.GUID)); e != nil {
if _, e := tx.ExecContext(ctx, fsql.QHl03, sql.Named("g", f.GUID)); e != nil {
tx.Rollback()
return 0, 0, e
}
@@ -133,9 +128,7 @@ func depoAlertEventFailures(ctx context.Context, db *sql.DB, rc *RuntimeConfig)
var id sql.NullInt64
var typ, guid, comment string
var n int
err := db.QueryRowContext(ctx, `SELECT COUNT(*) OVER (), ID, EVENT_TYPE, CAST(GUID AS varchar(36)), ISNULL(COMMENT,'')
FROM dbo.FTV_M2M_EVENTS WHERE STATE='ERROR' AND EVENT_TYPE LIKE 'BJ[_]%' AND ID > @last AND ISNULL(TimeEnd, TimeNew) > DATEADD(day, -1, GETDATE())
ORDER BY ID DESC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY`, sql.Named("last", depoFailAlertedID)).Scan(&n, &id, &typ, &guid, &comment)
err := db.QueryRowContext(ctx, fsql.Hlth02, sql.Named("last", depoFailAlertedID)).Scan(&n, &id, &typ, &guid, &comment)
if err != nil || !id.Valid {
return
}