Защита рецептов: 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 -16
View File
@@ -11,18 +11,13 @@ package lkgateway
import (
"context"
"git.zetit.ru/zuevav/Bridge-and-Join-s/internal/lkgateway/fsql"
"log"
"strings"
"time"
)
const lkSnapshotSchema = `
CREATE TABLE IF NOT EXISTS lk.portfolio_daily (
day DATE NOT NULL, contract VARCHAR(64) NOT NULL,
value DOUBLE PRECISION NOT NULL DEFAULT 0, cash DOUBLE PRECISION NOT NULL DEFAULT 0,
positions INT NOT NULL DEFAULT 0, priced INT NOT NULL DEFAULT 0,
source VARCHAR(16) NOT NULL DEFAULT 'quik', created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
PRIMARY KEY (day, contract))`
var lkSnapshotSchema = fsql.Sn01
// lkSnapshotEnabled — ведём ли историю стоимости. По умолчанию (режим не выбран)
// ведём, если настроен экспорт QUIK: история накапливается только вперёд, и
@@ -76,8 +71,7 @@ func lkSnapshotHistory(ctx context.Context, rc *RuntimeConfig, contract string,
}
cctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
rows, err := db.QueryContext(cctx, `SELECT day, value, cash, positions FROM lk.portfolio_daily
WHERE contract = $1 AND day >= current_date - $2::int ORDER BY day`, num, days)
rows, err := db.QueryContext(cctx, fsql.Sn02, num, days)
if err != nil {
return nil, err
}
@@ -104,10 +98,7 @@ func lkSnapshotSave(ctx context.Context, rc *RuntimeConfig, day time.Time, contr
}
cctx, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
_, err = db.ExecContext(cctx, `INSERT INTO lk.portfolio_daily(day, contract, value, cash, positions, priced, source)
VALUES ($1,$2,$3,$4,$5,$6,$7)
ON CONFLICT (day, contract) DO UPDATE SET value = EXCLUDED.value, cash = EXCLUDED.cash,
positions = EXCLUDED.positions, priced = EXCLUDED.priced, source = EXCLUDED.source, created_at = now()`,
_, err = db.ExecContext(cctx, fsql.Sn03,
day.Format("2006-01-02"), lkContractNumber(contract), p.Securities, p.CashRUB,
len(p.Positions), p.Priced, p.Source)
return err
@@ -123,8 +114,7 @@ func lkSnapshotContracts(ctx context.Context, rc *RuntimeConfig) []string {
}
cctx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
rows, err := p.Query(cctx, `SELECT DISTINCT "ClientCode" FROM "DepoLimits"
WHERE "LimitKind" = 'T2' AND "CurrentBal" <> 0 AND "ClientCode" <> ''`)
rows, err := p.Query(cctx, fsql.Sn04)
if err != nil {
return nil
}
@@ -218,7 +208,7 @@ func lkSnapshotDone(ctx context.Context, rc *RuntimeConfig, day time.Time) bool
cctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
var n int
if db.QueryRowContext(cctx, `SELECT count(*) FROM lk.portfolio_daily WHERE day = $1`,
if db.QueryRowContext(cctx, fsql.Sn05,
day.Format("2006-01-02")).Scan(&n) != nil {
return true
}