Skip to content

Review: server ingest/query correctness + API consistency #46

Description

@awksedgreep

Summary

Correctness and API-consistency bugs in the servers that are individually small but collectively erode trust in ingest/query results.

Locations

  1. Jaeger prefix-integer parsing truncates garbage: traces query.rs:801-811 parse_integer_prefix("17junk")→17 (pinned by test at :866); overflow on start/end degrades to unbounded (None) instead of 400 — fail-open to a wider scan. Dashboard since/until correctly use exact parse (:787-795).
  2. Logs ingest fabricates data: logs api.rs:1670-1699 unparseable time falls back to now(); unknown level canonicalizes to "info" (:1657-1668). A typo'd column silently shifts rows instead of counting an error. parse_query_time (:1702-1712) is correctly strict-ish on the query side.
  3. authctl parse_ttl overflow: timeless-authctl/src/lib.rs:313-330 quantity * 86_400 on i64 wraps (release) / panics (debug). Use checked_mul.
  4. authctl policy init audience drift: lib.rs:143 emits timeless-{signal} while verifier fixtures use timeless-data-plane (auth.rs:1437-1438). Works (mint copies from policy) but cross-implementation tokens and docs disagree — pin one.
  5. kid comment lies: authctl lib.rs:44-61 says "first 16 hex of SHA-256", code takes first 8 raw pubkey bytes. Fix comment or hash.
  6. policy add-subject overwrites silently + accepts arbitrary scopes (lib.rs:171-189); verifier rejects at use time (fail-closed) but CLI gives no feedback.
  7. Clock-skew asymmetry: auth.rs:677-681 gives +30 s leeway to nbf/iat but none to exp — 1 s-skewed clients see spurious expired_token.
  8. enforce_query_limit heuristic (auth.rs:567-572): non-UTF8 skips; form-field scan false-positives on ingest bodies while {"limit":…} JSON bodies aren't caught. Verify every JSON query path sets RESULT_ROWS_HEADER so the post-check (:456-467) fires.
  9. Tail ordering differs: traces publishes after durable accept (traces api.rs:461-469, deliberate); logs publishes before writer send (logs storage.rs:1211-1214) — a logs subscriber can see entries a search never returns.
  10. Backup blocks the single writer: logs storage.rs:1690-1704 (flush + up to 1M optimize steps + checkpoint with 5 s retry) runs synchronously; repeated POST /api/v1/backup (open by default) is a throughput DoS. Same shape in metrics/traces.
  11. No shutdown deadline: storage.rs:1579-1613 sequencing vs hung checkpoint_wal (lib.rs:58-79) can stall past orchestrator kill grace.
  12. API inconsistency: flush GET vs POST varies per signal; error envelopes vary ({"error"} vs {"status":"error"} vs Prometheus shape); RESULT_ROWS_HEADER stripped on authed routes but emitted on open ones (auth.rs:456-467); no Retry-After/RateLimit-* on 429/503; logs field_values limit dance (api.rs:352-359) is obscure.

Also: unbounded regex compile per request (metrics query.rs:149-166, logs LogPredicate::Regex) with no pattern-length cap; PromQL parse input bounded only by the 10 MiB body cap with no depth cap; OTLP/log ingest admission bounded by batch count not spans/bytes (traces storage.rs:590-645, logs storage.rs:1193-1217).

Suggested fix

Exact integer parsing + bounded limits; strict ingest time/level handling; checked_mul TTL; one audience value; symmetric clock leeway; one tail contract; backup off the writer or rate-limited; shutdown deadline; one error envelope ({"error","reason"} + Prometheus shape on Prometheus routes); POST-only flush.

Source

Full code review @ bacdf6f, servers track.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions