Каталог разрезов и измеренный род агрегации

- род метрики выводится сверкой минутного слоя с часовым: часовое значение
  сходится с суммой минутных — накопительная, со средним — мгновенная, иначе
  `unknown` и свёртка не предлагается вовсе. На живом архиве (123 доставки,
  31 метрика) 7 накопительных, 9 мгновенных, противоречащих часов ноль
- `GET /api/v1/metrics` под токеном чтения отдаёт единицы, слои с границами и
  род вместе с основанием измерения; род нигде не хранится — он функция витрины,
  а витрина функция журнала, устаревать в нём нечему
- миграция 00009: покрывающий индекс, чтобы каталог отвечал по учётным колонкам,
  не разжимая содержимое объектов
This commit is contained in:
av
2026-08-02 19:23:59 +03:00
parent 98e0772ec5
commit 03edf1087d
39 changed files with 4744 additions and 58 deletions
+11 -1
View File
@@ -103,11 +103,21 @@ var secretHeaders = map[string]bool{
// redacted подменяет значение, которое оказалось секретом.
const redacted = "[redacted]"
// isSecretValue — совпало ли значение заголовка с каким-нибудь настроенным
// токеном, всё равно какого контура.
func (a *api) isSecretValue(v string) bool {
return tokenAllowed(v, a.writeTokens) || tokenAllowed(v, a.readTokens)
}
// safeHeaders собирает заголовки запроса для хранения, вычищая секреты.
//
// Двойная защита: имя из чёрного списка вырезается всегда, а любое значение,
// совпавшее с настроенным токеном, подменяется — токен можно положить в
// заголовок с произвольным именем, и угадать его мы не можем.
//
// Сверяется с токенами ОБОИХ контуров. Токен чтения так же секрет, как токен
// приёма, и посланный на этот маршрут произвольным заголовком осел бы в базе
// доставок навсегда.
func (a *api) safeHeaders(r *http.Request) map[string][]string {
out := make(map[string][]string, len(r.Header)+1)
for name, values := range r.Header {
@@ -117,7 +127,7 @@ func (a *api) safeHeaders(r *http.Request) map[string][]string {
}
safe := make([]string, len(values))
for i, v := range values {
if tokenAllowed(v, a.writeTokens) || tokenAllowed(strings.TrimPrefix(v, "Bearer "), a.writeTokens) {
if a.isSecretValue(v) || a.isSecretValue(strings.TrimPrefix(v, "Bearer ")) {
safe[i] = redacted
continue
}