feat(api): transaction query endpoint with DSL + cursor pagination (Q3 §6.1)#398
Merged
Merged
Conversation
Q3 §6.1 first slice — machine-friendly structured query endpoint for the
transaction log. Complements the existing GET /api/transactions (kept for
UI list views) with a DSL body, cursor pagination, and field projection
suited to Agent API use cases.
Features:
- POST body DSL with single + list filters (host_ids, rule_ids, status,
phase, severity, initiator_type). Multi-value filters use parameterized
IN clauses.
- fleet_id filter resolves via EXISTS subquery against
host_group_memberships (not a huge inline IN list).
- Cursor pagination: opaque base64(json({started_at, id})) with tuple
comparison in the WHERE clause for deterministic tie-break on equal
timestamps.
- Projection: fields list restricted to an allow-list; unknown fields
return HTTP 400. Default excludes heavy JSONB columns.
- Response includes next_cursor (null on last page) and total_count
(ignores cursor, only filters).
Scope intentionally limited to the foundation. Follow-up PR will add:
- Sort DSL (request-specified ORDER BY beyond default)
- Per-API-key rate limiting
- p95 <500ms benchmark enforcement in CI
Spec: specs/api/transactions/transaction-query.spec.yaml (draft, 10 ACs).
Tests: tests/backend/unit/api/test_transaction_query_spec.py (source-
inspection pattern, all 10 ACs covered). Spec coverage 823/823 at 100%.
| if f in ("evidence_envelope", "framework_refs") and isinstance(val, str): | ||
| try: | ||
| val = json.loads(val) | ||
| except (json.JSONDecodeError, ValueError): |
| assert not missing, f"TransactionQueryRequest missing: {missing}" | ||
|
|
||
| def test_route_uses_parameterized_in_clauses(self): | ||
| import app.routes.transactions.query as mod |
| assert ":phase_" in source | ||
|
|
||
| def test_fleet_id_uses_subquery(self): | ||
| import app.routes.transactions.query as mod |
| assert "SELECT host_id FROM host_group_memberships" in source | ||
|
|
||
| def test_framework_uses_jsonb_operator(self): | ||
| import app.routes.transactions.query as mod |
| assert fields == {"items", "total_count", "next_cursor"} | ||
|
|
||
| def test_route_applies_cursor_with_tuple_compare(self): | ||
| import app.routes.transactions.query as mod |
| """AC-5: Default ORDER BY started_at DESC, id DESC.""" | ||
|
|
||
| def test_query_uses_stable_ordering(self): | ||
| import app.routes.transactions.query as mod |
| """AC-6: Requires GUEST+; audit logger writes on each query.""" | ||
|
|
||
| def test_route_requires_role(self): | ||
| import app.routes.transactions.query as mod |
| assert "UserRole.GUEST" in source | ||
|
|
||
| def test_route_writes_audit_log(self): | ||
| import app.routes.transactions.query as mod |
| assert exc_info.value.status_code == 400 | ||
|
|
||
| def test_date_range_inversion_check_present(self): | ||
| import app.routes.transactions.query as mod |
| """AC-8: All queries parameterized; no string-concat user input.""" | ||
|
|
||
| def test_all_filter_values_use_named_params(self): | ||
| import app.routes.transactions.query as mod |
remyluslosius
added a commit
that referenced
this pull request
Apr 14, 2026
Q3 §6.1 endpoint merged in PR #398 has a stable HTTP surface but an interim implementation. Per the Kensa↔OpenWatch coordination (docs/KENSA_OPENWATCH_COORDINATION_2026-04-14.md and the Kensa team's response at kensa/docs/KENSA_OPENWATCH_RESPONSE_2026-04-14.md), the implementation migrates to delegate into Kensa's Go api/ surface at Kensa Week 22. Changes: - transaction-query.spec.yaml bumped to 1.1 with interim_implementation frontmatter naming the specific Kensa api/ methods it converges onto (LogQuery.Query, LogQuery.Get, LogQuery.Aggregate) - Route file docstring updated with a prominent INTERIM IMPLEMENTATION header pointing at the Kensa convergence target and the coordination docs No behavioral changes. No endpoint surface changes. This establishes the convergence-annotation pattern that Kensa counter-asked for in their response §6.1, so that future reviewers can grep for stale interim annotations past their convergence week.
remyluslosius
added a commit
that referenced
this pull request
Apr 14, 2026
Q3 §6.1 endpoint merged in PR #398 has a stable HTTP surface but an interim implementation. Per the Kensa↔OpenWatch coordination (docs/KENSA_OPENWATCH_COORDINATION_2026-04-14.md and the Kensa team's response at kensa/docs/KENSA_OPENWATCH_RESPONSE_2026-04-14.md), the implementation migrates to delegate into Kensa's Go api/ surface at Kensa Week 22. Changes: - transaction-query.spec.yaml bumped to 1.1 with interim_implementation frontmatter naming the specific Kensa api/ methods it converges onto (LogQuery.Query, LogQuery.Get, LogQuery.Aggregate) - Route file docstring updated with a prominent INTERIM IMPLEMENTATION header pointing at the Kensa convergence target and the coordination docs No behavioral changes. No endpoint surface changes. This establishes the convergence-annotation pattern that Kensa counter-asked for in their response §6.1, so that future reviewers can grep for stale interim annotations past their convergence week.
3 tasks
remyluslosius
added a commit
that referenced
this pull request
Apr 14, 2026
Third and final PR in the Kensa↔OpenWatch coordination batch (PRs #399, #400, this one). Updates the Q1-Q3 plan to reflect the architectural commitments made in the 2026-04-14 coordination. .gitignore: - Whitelist docs/OPENWATCH_Q1_PLAN.md, Q2_PLAN.md, Q1_Q3_PLAN.md, VISION.md, VISION_STATUS.md, and KENSA_OPENWATCH_COORDINATION_*.md so cross-team coordination docs can reference them and the Kensa convergence schedule is reviewable. docs/OPENWATCH_Q1_Q3_PLAN.md (rewrite): - Add top-level Kensa Convergence Addendum documenting: - The "GitHub over Kensa's git" posture - Section-by-section table of what changes under the addendum - What stays purely OpenWatch-layer (SSO, notifications, 6.3, 6.4, 6.5) - Kensa milestone convergence table (Week 1, 22, 24, 25, 26, 40) - The interim_implementation: frontmatter convention - Rewrite §6.1 (Transaction Log Query API): endpoint URL + schema stable; implementation swaps to kensa.api.Kensa.TransactionLog() at Kensa Week 22. First slice shipped as PR #398; annotated in PR #399. - Rewrite §6.2 (Proactive Remediation Workflow): original draft had OpenWatch generating the plan; revised architecture wraps Kensa.Plan / Kensa.Execute with an approval UI. Detailed flow diagram, ownership split, blocking dependency on Kensa Week 24. - Update §3.4 (Fleet health): PostgreSQL transactions table reframed as derived cache; Kensa.Subscribe feeds drift counts at Week 25. docs/KENSA_OPENWATCH_COORDINATION_2026-04-14.md (now tracked): - The outbound coordination memo becomes a first-class committed artifact. Already written 2026-04-14; this commit tracks it so the Kensa response (at kensa/docs/...) can reference it without cross-repo submodule complexity. docs/OPENWATCH_Q1_PLAN.md, Q2_PLAN.md, VISION.md, VISION_STATUS.md: - Newly tracked. Earlier session edits (FreeBSD removal markers) are already in these local copies and are committed as-is. No code changes. This is the plan-doc counterpart to PR #399 (query interim annotation) and PR #400 (signing scope narrow).
5 tasks
remyluslosius
added a commit
that referenced
this pull request
Apr 14, 2026
…#399) Q3 §6.1 endpoint merged in PR #398 has a stable HTTP surface but an interim implementation. Per the Kensa↔OpenWatch coordination (docs/KENSA_OPENWATCH_COORDINATION_2026-04-14.md and the Kensa team's response at kensa/docs/KENSA_OPENWATCH_RESPONSE_2026-04-14.md), the implementation migrates to delegate into Kensa's Go api/ surface at Kensa Week 22. Changes: - transaction-query.spec.yaml bumped to 1.1 with interim_implementation frontmatter naming the specific Kensa api/ methods it converges onto (LogQuery.Query, LogQuery.Get, LogQuery.Aggregate) - Route file docstring updated with a prominent INTERIM IMPLEMENTATION header pointing at the Kensa convergence target and the coordination docs No behavioral changes. No endpoint surface changes. This establishes the convergence-annotation pattern that Kensa counter-asked for in their response §6.1, so that future reviewers can grep for stale interim annotations past their convergence week.
remyluslosius
added a commit
that referenced
this pull request
Apr 14, 2026
…#401) Third and final PR in the Kensa↔OpenWatch coordination batch (PRs #399, #400, this one). Updates the Q1-Q3 plan to reflect the architectural commitments made in the 2026-04-14 coordination. .gitignore: - Whitelist docs/OPENWATCH_Q1_PLAN.md, Q2_PLAN.md, Q1_Q3_PLAN.md, VISION.md, VISION_STATUS.md, and KENSA_OPENWATCH_COORDINATION_*.md so cross-team coordination docs can reference them and the Kensa convergence schedule is reviewable. docs/OPENWATCH_Q1_Q3_PLAN.md (rewrite): - Add top-level Kensa Convergence Addendum documenting: - The "GitHub over Kensa's git" posture - Section-by-section table of what changes under the addendum - What stays purely OpenWatch-layer (SSO, notifications, 6.3, 6.4, 6.5) - Kensa milestone convergence table (Week 1, 22, 24, 25, 26, 40) - The interim_implementation: frontmatter convention - Rewrite §6.1 (Transaction Log Query API): endpoint URL + schema stable; implementation swaps to kensa.api.Kensa.TransactionLog() at Kensa Week 22. First slice shipped as PR #398; annotated in PR #399. - Rewrite §6.2 (Proactive Remediation Workflow): original draft had OpenWatch generating the plan; revised architecture wraps Kensa.Plan / Kensa.Execute with an approval UI. Detailed flow diagram, ownership split, blocking dependency on Kensa Week 24. - Update §3.4 (Fleet health): PostgreSQL transactions table reframed as derived cache; Kensa.Subscribe feeds drift counts at Week 25. docs/KENSA_OPENWATCH_COORDINATION_2026-04-14.md (now tracked): - The outbound coordination memo becomes a first-class committed artifact. Already written 2026-04-14; this commit tracks it so the Kensa response (at kensa/docs/...) can reference it without cross-repo submodule complexity. docs/OPENWATCH_Q1_PLAN.md, Q2_PLAN.md, VISION.md, VISION_STATUS.md: - Newly tracked. Earlier session edits (FreeBSD removal markers) are already in these local copies and are committed as-is. No code changes. This is the plan-doc counterpart to PR #399 (query interim annotation) and PR #400 (signing scope narrow).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First slice of Q3 §6.1 — Transaction Log Query API. Per `docs/OPENWATCH_Q1_Q3_PLAN.md`, this is the foundation for the future Agent API and the <500ms historical posture query KPI.
Summary
Adds `POST /api/transactions/query` — a machine-friendly structured query endpoint for the transaction log. Complements the existing `GET /api/transactions` (kept for UI list views) with features suited to programmatic use:
Out of scope (tracked for follow-up PR)
The scope above are explicitly listed in the spec's `out_of_scope` section.
Spec + tests
Security
Test plan