Skip to content

feat: New Finding Types Endpoint for Findings Table - BED-8673 - #3058

Merged
kpowderly merged 20 commits into
mainfrom
BED-8673
Jul 30, 2026
Merged

feat: New Finding Types Endpoint for Findings Table - BED-8673#3058
kpowderly merged 20 commits into
mainfrom
BED-8673

Conversation

@kpowderly

@kpowderly kpowderly commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Description

This PR adds a new GET /api/v2/attack-paths/finding-types endpoint to support the attack path type filter in the findings table UI.

The endpoint returns only attack path types that currently have findings associated with them, rather than all attack path types. It also respects environment scoping, ETAC access, asset group tag filtering, and the OpenGraph findings feature flag.

  • added GET /api/v2/attack-paths/finding-types
  • added handler, service, and appdb support for fetching distinct finding types
  • scoped results to finding types with non-archived findings
  • added ETAC-aware environment filtering
  • added predicate-based asset_group_tag_id filtering
  • excluded OpenGraph finding types when the feature flag is disabled
  • added tests for route registration, handler behavior, service behavior, and ETAC filtering
  • OpenAPI Spec

Motivation and Context

Resolves BED-8673

How Has This Been Tested?

Unit, Integration, Manual Testing

Screenshots (optional):

Screenshot 2026-07-28 at 10 26 59 AM Screenshot 2026-07-28 at 10 27 07 AM Screenshot 2026-07-28 at 10 27 23 AM Screenshot 2026-07-28 at 10 28 19 AM

Types of changes

  • New feature (non-breaking change which adds functionality)

Checklist:

Summary by CodeRabbit

  • New Features
    • Added a new Enterprise endpoint: GET /api/v2/attack-paths/finding-types to list distinct attack path finding types with environment and asset group tag filtering.
    • Introduced access-aware environment filtering that returns only environments a user can access, while preserving existing behavior when filtering is disabled.
  • Bug Fixes
    • Improved handling of empty/no-access outcomes and propagated database errors correctly.
  • Tests
    • Expanded and parallelized test coverage for the filtering behavior, including intersection, passthrough when disabled, empty results, and error propagation.

@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds FilterEnvironmentsByAccess to the ETAC service, filtering requested environment IDs against database-backed user access. Tests and mocks are updated, a new attack-path finding-types API contract is documented, and two indirect Go dependencies change.

Changes

ETAC filtering and attack-path API

Layer / File(s) Summary
Filtering contract and implementation
server/etac/etac.go, server/etac/internal/services/service.go
Adds the service API and returns unfiltered IDs, accessible intersections, sentinel results, or database errors according to ETAC state.
ETAC validation and mock support
server/etac/internal/services/service_test.go, server/etac/mocks/service.go
Refactors existing tests, adds filtering cases, enables parallel execution, and updates the generated service mock.
Attack-path finding-types API contract
packages/go/openapi/src/openapi.yaml, packages/go/openapi/src/paths/..., packages/go/openapi/doc/openapi.json
Adds GET /api/v2/attack-paths/finding-types with environment and asset-group filters, typed finding/title results, examples, and shared error responses.

Go module updates

Layer / File(s) Summary
Indirect module requirements
go.mod
Adds the OpenTelemetry metric SDK and updates the Google RPC module revision.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ServiceTests
  participant ETACService
  participant AppDatabase
  ServiceTests->>ETACService: FilterEnvironmentsByAccess(user, requestedIDs)
  ETACService->>AppDatabase: Fetch allowed environment access
  AppDatabase-->>ETACService: Allowed IDs or database error
  ETACService-->>ServiceTests: Filtered IDs or error
Loading

Possibly related PRs

Suggested labels: enhancement, api, go

Suggested reviewers: cweidenkeller, lawsonwillard, mistahj67, sirisjo

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and clearly identifies the new finding types endpoint and related ticket.
Description check ✅ Passed The description includes the required sections, a clear summary, motivation, testing, and checklist items.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch BED-8673

Comment @coderabbitai help to get the list of available commands.

@kpowderly kpowderly self-assigned this Jul 27, 2026
@kpowderly
kpowderly marked this pull request as ready for review July 28, 2026 15:30
@coderabbitai coderabbitai Bot added api A pull request containing changes affecting the API code. enhancement New feature or request go Pull requests that update go code labels Jul 28, 2026
@bsheth711
bsheth711 self-requested a review July 28, 2026 17:08
Comment thread cmd/api/src/model/auth.go Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
server/etac/internal/services/service.go (2)

86-89: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Doc comment omits the sentinel "deny all" return behavior.

The comment only describes the nil "no filtering" case. It doesn't mention that the function returns []string{""} when the user has no allowed environments or none of the requested IDs are permitted — a subtle contract that callers building SQL filters need to know about.

📝 Proposed doc update
 // FilterEnvironmentsByAccess returns the environment IDs the user is allowed to query.
 // It returns nil when ETAC filtering does not apply, such as when the user has
 // access to all environments.
+// When ETAC filtering applies and the user has no accessible environments, or none
+// of the requested IDs are accessible, it returns the sentinel []string{""} so that
+// callers can build a filter that matches no results.
 func (s *Service) FilterEnvironmentsByAccess(ctx context.Context, user users.User, requestedIDs []string) ([]string, error) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/etac/internal/services/service.go` around lines 86 - 89, Update the
doc comment for Service.FilterEnvironmentsByAccess to document both sentinel
outcomes: nil when ETAC filtering does not apply, and []string{""} when the user
has no allowed environments or none of the requested IDs are permitted. Preserve
the existing description of returning permitted environment IDs.

86-132: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate allow-list construction with CheckUserAccessToEnvironments.

Both FilterEnvironmentsByAccess (lines 97-118) and CheckUserAccessToEnvironments (lines 142-150, shown as context) call GetEnvironmentTargetedAccessControlForUser and then build a set/map of allowed environment IDs from the result. Consider extracting a small private helper (e.g., allowedEnvironmentSet(ctx, userID) (map[string]struct{}, error)) that both methods can share, to avoid the two implementations drifting apart over time.

♻️ Proposed refactor sketch
+func (s *Service) allowedEnvironmentSet(ctx context.Context, userID uuid.UUID) (map[string]struct{}, error) {
+	allowedList, err := s.appdb.GetEnvironmentTargetedAccessControlForUser(ctx, userID)
+	if err != nil {
+		return nil, err
+	}
+
+	allowedSet := make(map[string]struct{}, len(allowedList))
+	for _, envAccess := range allowedList {
+		allowedSet[envAccess.EnvironmentID] = struct{}{}
+	}
+	return allowedSet, nil
+}
+
 func (s *Service) FilterEnvironmentsByAccess(ctx context.Context, user users.User, requestedIDs []string) ([]string, error) {
 	if !s.ShouldFilterForETAC(user) {
 		if len(requestedIDs) == 0 {
 			return nil, nil
 		}
 		return requestedIDs, nil
 	}

-	allowedList, err := s.appdb.GetEnvironmentTargetedAccessControlForUser(ctx, user.GetID())
+	allowedSet, err := s.allowedEnvironmentSet(ctx, user.GetID())
 	if err != nil {
 		return nil, err
 	}

-	var allowlist []string
-	for _, envAccess := range allowedList {
-		allowlist = append(allowlist, envAccess.EnvironmentID)
-	}
-
-	if len(allowlist) == 0 {
+	if len(allowedSet) == 0 {
 		return []string{""}, nil
 	}
 
 	if len(requestedIDs) == 0 {
-		return allowlist, nil
-	}
-
-	allowedSet := make(map[string]struct{}, len(allowlist))
-	for _, environmentID := range allowlist {
-		allowedSet[environmentID] = struct{}{}
+		allowlist := make([]string, 0, len(allowedSet))
+		for environmentID := range allowedSet {
+			allowlist = append(allowlist, environmentID)
+		}
+		return allowlist, nil
 	}
 	...

Note: switching to a map-first approach changes iteration order for the "no requestedIDs" full-allowlist case (map iteration is unordered), which would break the existing TestService_FilterEnvironmentsByAccess assertion expecting []string{"env-1", "env-2"} in order. If you adopt this refactor, either keep a parallel ordered slice or update that test to use ElementsMatch.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/etac/internal/services/service.go` around lines 86 - 132, Extract the
shared allow-list retrieval and environment-ID set construction from
FilterEnvironmentsByAccess and CheckUserAccessToEnvironments into a private
helper such as allowedEnvironmentSet, then use it in both methods. Preserve the
existing ordered allowlist slice in FilterEnvironmentsByAccess for the
no-requestedIDs case so its output order remains unchanged, while retaining
current empty-access and intersection behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@server/etac/internal/services/service.go`:
- Around line 86-89: Update the doc comment for
Service.FilterEnvironmentsByAccess to document both sentinel outcomes: nil when
ETAC filtering does not apply, and []string{""} when the user has no allowed
environments or none of the requested IDs are permitted. Preserve the existing
description of returning permitted environment IDs.
- Around line 86-132: Extract the shared allow-list retrieval and environment-ID
set construction from FilterEnvironmentsByAccess and
CheckUserAccessToEnvironments into a private helper such as
allowedEnvironmentSet, then use it in both methods. Preserve the existing
ordered allowlist slice in FilterEnvironmentsByAccess for the no-requestedIDs
case so its output order remains unchanged, while retaining current empty-access
and intersection behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 1150e6d8-4425-4358-be07-95238e936d09

📥 Commits

Reviewing files that changed from the base of the PR and between 89c78d3 and 0b948b9.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (4)
  • server/etac/etac.go
  • server/etac/internal/services/service.go
  • server/etac/internal/services/service_test.go
  • server/etac/mocks/service.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/go/openapi/src/paths/attack-paths.attack-paths-finding-types.yaml`:
- Around line 39-44: Align the asset_group_tag_id filter description and
referenced predicate schema in
packages/go/openapi/src/paths/attack-paths.attack-paths-finding-types.yaml:39-44
by either documenting ~eq among the supported predicates or constraining the
schema to eq and neq, then regenerate
packages/go/openapi/doc/openapi.json:18667-18674 so the generated artifact
matches the corrected source.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 6e7ac8df-5457-43bd-8e8a-ea924477d200

📥 Commits

Reviewing files that changed from the base of the PR and between b944888 and 04c1c6a.

📒 Files selected for processing (3)
  • packages/go/openapi/doc/openapi.json
  • packages/go/openapi/src/openapi.yaml
  • packages/go/openapi/src/paths/attack-paths.attack-paths-finding-types.yaml

Comment thread packages/go/openapi/src/paths/attack-paths.attack-paths-finding-types.yaml Outdated
@kpowderly
kpowderly merged commit e1e556a into main Jul 30, 2026
13 checks passed
@kpowderly
kpowderly deleted the BED-8673 branch July 30, 2026 16:39
@github-actions github-actions Bot locked and limited conversation to collaborators Jul 30, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

api A pull request containing changes affecting the API code. enhancement New feature or request go Pull requests that update go code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants