Skip to content

feat(reports): scope the executive report by group + framework (A1)#631

Merged
remyluslosius merged 2 commits into
mainfrom
feat/reports-a1-scope
Jun 21, 2026
Merged

feat(reports): scope the executive report by group + framework (A1)#631
remyluslosius merged 2 commits into
mainfrom
feat/reports-a1-scope

Conversation

@remyluslosius

Copy link
Copy Markdown
Contributor

First implementation slice of the Reports build-out (docs/engineering/reports_design.md §11, Phase A1). Makes the executive report scopable instead of all-hosts-only.

What

POST /api/v1/reports:generate now accepts an optional scope {group_id?, framework?}. An empty body keeps the exact v1.0.0 all-hosts behavior.

  • group_id scopes the posture to a group's member hosts via a new group.Service.ScopeGroup (reuses memberCTE: manual → group_members, auto → hosts.os_family == match_family). host_count and every rule count reflect only those hosts. Unknown group → group.ErrNotFound400 reports.invalid_scope; an empty group reads as zero hosts (distinct from unscoped).
  • framework applies the fleet-rollup lens (framework_refs ? key), counting only rules in that framework.
  • The resolved scope (group_id, group name frozen at generation time, framework) is stored on a new reports.scope JSONB (migration 0041) and echoed on the wire. scope_label is derived: Production · CIS, All hosts · STIG, Production, All hosts.

Frontend

A group scope picker beside Generate (a <select> sourced from GET /api/v1/groups, default "All hosts"), host:write-gated. scope_label already flows to the Library + detail rows, so the chosen scope shows up automatically.

Deliberate cut: the framework-lens picker UI is deferred until a fleet framework catalog endpoint exists (there's only a per-host one today). The backend, API contract, spec, and tests already fully support framework — so it's forward-compatible, just not yet exposed in the UI. Noted for a fast-follow.

SDD

  • api-reports v1.1.0 — C-07 + AC-07 (label derivation, unit), AC-08 (group scope, DB), AC-09 (framework scope, DB).
  • frontend-reports v1.1.0 — C-04 + AC-05 (scope picker source inspection).

Validation

  • gofmt/go vet/go build clean.
  • specter check 111/111 structural; api-reports 9/9, frontend-reports 5/5, 100%; specter check --test 0 errors.
  • report + group Go suites green (isolated PG); reports vitest 5/5; full frontend suite 323/323.

Net: no new data collection — reports still derive from host_rule_state + groups, so the numbers stay consistent with the Groups page.

Reports Phase A1 (docs/engineering/reports_design.md §11). POST
/api/v1/reports:generate now accepts an optional scope {group_id?,
framework?}; an empty body keeps the v1.0.0 all-hosts behavior.

- group_id scopes the posture to a group's member hosts via a new
  group.Service.ScopeGroup (reuses memberCTE: manual -> group_members,
  auto -> hosts.os_family == match_family). An unknown group_id ->
  group.ErrNotFound -> 400 reports.invalid_scope; an empty group reads
  as zero hosts (distinct from unscoped).
- framework applies the fleet-rollup lens (framework_refs ? key),
  counting only rules in that framework.
- The resolved scope (group_id, group name frozen at gen time,
  framework) is stored on a new reports.scope JSONB (migration 0041)
  and echoed on the wire; scope_label is derived
  ("Production · CIS", "All hosts · STIG", ...).
- Frontend: a group scope picker beside Generate (select sourced from
  GET /api/v1/groups, "All hosts" default), host:write-gated. The
  framework-lens UI is deferred until a fleet framework catalog exists
  (backend/API/contract already support it).

SDD: api-reports v1.1.0 (C-07, AC-07/08/09), frontend-reports v1.1.0
(C-04, AC-05). New service/DB tests for group + framework scoping and
the label derivation. gofmt/vet/build clean; specter 111 (api-reports
9/9, frontend-reports 5/5, 100% structural); report+group Go suites and
the reports vitest green.
@remyluslosius remyluslosius merged commit 4f8aa28 into main Jun 21, 2026
13 checks passed
@remyluslosius remyluslosius deleted the feat/reports-a1-scope branch June 21, 2026 14:55
remyluslosius added a commit that referenced this pull request Jun 21, 2026
Reconciles the docs with the merged reports build-out.

- BACKLOG.md: the Reports entry flips Planned -> Phase A shipped (P1->P2),
  summarizing A1-A4b and the production signing-key op note; remaining
  work scoped to Phases B-D (OSCAL/CSV, async+scheduling, other kinds).
- reports_design.md: a STATUS banner on §11 records Phase A as shipped
  and the two in-flight plan adjustments (coverage shipped before the
  structural migration; A3/A4 split backend/frontend).
- SESSION_LOG.md: a Phase A handoff entry (per-PR summary, the live
  verification result, Phases B-D next, and the dev-serve / ephemeral-key
  gotchas).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant