Skip to content

BCH-1339: Responsibility-scoped filters, SSP resolution, and posture (Phase 3)#448

Merged
saltpy-cs merged 2 commits into
mainfrom
feat/BCH-1339
Jul 9, 2026
Merged

BCH-1339: Responsibility-scoped filters, SSP resolution, and posture (Phase 3)#448
saltpy-cs merged 2 commits into
mainfrom
feat/BCH-1339

Conversation

@saltpy-cs

@saltpy-cs saltpy-cs commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Phase 3 of Cross-SSP Control Export/Import: lets a downstream customer-responsibility be a first-class compliance target with its own filter → evidence → posture, without minting a synthetic catalog control. Depends on Phase 2 (#447, merged).

  • New filter_responsibilities join table (filter_id, responsibility_uuid, ssp_id) — a sibling of filter_controls, not an overload of it.
  • resolveSSPsViaFilters (risk evidence worker) gains a second resolution path: matched filter → filter_responsibilitiesssp_leverage_links → downstream SSP.
  • New ResponsibilityPosture function computes per-responsibility posture (satisfied / not-satisfied / unknown) from matched evidence, using the same status-count logic as control-keyed posture, and feeds it into the Inherited Capability projection (LeveragedControls's responsibilityPosture field).
  • Fixes a latent schema issue the new join exposed: ControlImplementationResponsibility.ProvidedUuid had no explicit uuid column type, causing a real uuid = text failure against Postgres. Fixed with the same tag + idempotent ALTER COLUMN pattern already used for filter_controls.control_catalog_id.

Test plan

  • Unit tests (sqlite): resolution-arm coverage in risk_evidence_worker_test.go, posture-default coverage in profile_compliance_unit_test.go, wiring coverage in ssp_leverage_unit_test.go.
  • Integration tests (real Postgres via testcontainers): TestRiskEvidenceWorkerResponsibilityIntegrationSuite (SSP resolution) and TestResponsibilityFilterFlipsPosture (posture flip against live evidence).
  • Regression: all pre-existing filter_controls/ComplianceProgress tests pass unmodified.
  • make reviewable (swag + lint + full integration suite) passes clean.

Out of scope

Risk generation (Phase 4).

Summary by CodeRabbit

  • New Features
    • Leveraged controls responses now include live responsibility posture for each responsibility UUID.
    • Responsibility status is computed from current evidence and can show satisfied, not-satisfied, or unknown.
  • Bug Fixes
    • Satisfaction is now recomputed from live data instead of relying on stored values.
    • Filters tied to responsibilities now resolve downstream SSPs correctly, even without control-based matches.
  • Tests
    • Added coverage for responsibility posture calculations and downstream SSP resolution behavior.

…(Phase 3)

Let a downstream customer-responsibility be a first-class compliance target
with its own filter -> evidence -> posture, without minting a synthetic
catalog control:

- New filter_responsibilities join table (filter_id, responsibility_uuid,
  ssp_id), a sibling of filter_controls.
- resolveSSPsViaFilters gains a second resolution path: matched filter ->
  filter_responsibilities -> ssp_leverage_links -> downstream SSP.
- ResponsibilityPosture computes per-responsibility posture (satisfied /
  not-satisfied / unknown) from matched evidence, using the same
  status-count logic as control-keyed posture, and feeds it into the
  Inherited Capability projection (LeveragedControls).

Also fixes a latent schema issue the new join exposed:
ControlImplementationResponsibility.ProvidedUuid had no explicit uuid
column type, causing a real uuid = text failure against Postgres.
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 567fccad-0571-432d-aa3c-828187cc71b6

📥 Commits

Reviewing files that changed from the base of the PR and between ee7e063 and 4255911.

📒 Files selected for processing (2)
  • internal/service/migrator.go
  • internal/service/relational/filters.go

📝 Walkthrough

Walkthrough

Adds a FilterResponsibility join model linking filters to upstream responsibility UUIDs per downstream SSP, computes live evidence-backed posture per responsibility via a new ResponsibilityPosture function, exposes it in the leveraged-controls response, and extends risk evidence worker SSP resolution to traverse filter_responsibilities. Migrations, docs, and tests updated accordingly.

Changes

Responsibility posture feature

Layer / File(s) Summary
FilterResponsibility model, migrations, and provided_uuid type fix
internal/service/relational/filters.go, internal/service/relational/system_security_plan.go, internal/service/migrator.go, internal/tests/migrate.go
New FilterResponsibility GORM model with composite primary key and cascade associations, AutoMigrate/DropTable wiring, Postgres DDL to align provided_uuid from text to uuid, and a new FK constraint on filter_responsibilities.ssp_id.
ResponsibilityPosture computation and shared status-count helper
internal/api/handler/oscal/profile_compliance.go, internal/api/handler/oscal/profile_compliance_unit_test.go
Extracts a shared getStatusCountsForFilters helper and adds exported ResponsibilityPosture computing per-responsibility satisfied/not-satisfied/unknown status, with unit tests.
LeveragedControls endpoint exposes responsibilityPosture
internal/api/handler/oscal/ssp_leverage.go, internal/api/handler/oscal/ssp_leverage_test.go, internal/api/handler/oscal/ssp_leverage_unit_test.go
Adds responsibilityPosture field to the response, batches ResponsibilityPosture calls across leverage links, and validates via unit/integration tests.
Risk evidence worker resolves SSPs via filter_responsibilities
internal/service/worker/risk_evidence_worker.go, internal/service/worker/risk_evidence_worker_test.go, internal/service/worker/risk_evidence_worker_responsibility_integration_test.go
Extends resolveSSPsViaFilters to add a responsibilities resolution arm joining control_implementation_responsibilities and ssp_leverage_links, removing the early-exit on empty control results, with new tests.
Swagger/docs description updates for responsibilityPosture
docs/docs.go, docs/swagger.json, docs/swagger.yaml
Updates endpoint descriptions, adds responsibilityPosture schema field, and clarifies provided-uuid typing/resolution documentation.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant SSPLeverageHandler
  participant ResponsibilityPosture
  participant DB as GormDB

  Client->>SSPLeverageHandler: GET /leveraged-controls
  SSPLeverageHandler->>SSPLeverageHandler: collect responsibility UUIDs across links
  SSPLeverageHandler->>ResponsibilityPosture: ResponsibilityPosture(db, downstreamSSPID, uuids)
  ResponsibilityPosture->>DB: query FilterResponsibility links
  DB-->>ResponsibilityPosture: link rows
  ResponsibilityPosture->>DB: getStatusCountsForFilters(filters)
  DB-->>ResponsibilityPosture: status counts
  ResponsibilityPosture-->>SSPLeverageHandler: map[UUID]posture
  SSPLeverageHandler->>Client: response with responsibilityPosture per link
Loading

Possibly related PRs

  • compliance-framework/api#447: Both PRs extend the same GET /oscal/system-security-plans/{id}/leveraged-controls projection in internal/api/handler/oscal/ssp_leverage.go.

Suggested reviewers: gusfcarvalho

Poem

A rabbit hops through filters deep,
Tracing UUIDs while others sleep,
"Satisfied? Unknown? Let's not guess—
Recompute live, no stale mess!"
With leverage links all joined just right,
This bunny thumps its tail in delight! 🐰✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change set: responsibility-scoped filters, SSP resolution, and posture updates for Phase 3.
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.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 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 `@internal/service/relational/filters.go`:
- Around line 30-32: The composite primary key on the filter model does not
match the lookup pattern used by ResponsibilityPosture. Keep the existing
primary key in place, but add a dedicated composite index on the fields used by
the query in profile_compliance.go so the WHERE ssp_id = ? AND
responsibility_uuid IN ? lookup can use an index; update the struct in
filters.go on the type that defines FilterID, ResponsibilityUUID, and SSPID to
include the new index annotation.
- Around line 29-35: The FilterResponsibility model currently has SSPID only as
a primary key field without a foreign-key constraint, so add the missing cascade
relationship for the ssp_id association. Update the schema/migration logic in
migrator.go to mirror the existing filters.ssp_id constraint and ensure
FilterResponsibility.SSPID is constrained with OnDelete:CASCADE, using the
FilterResponsibility struct and its SSPID field as the anchor point.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 44063fa2-55e7-4465-9c40-b82e31889965

📥 Commits

Reviewing files that changed from the base of the PR and between 3b6ef9d and ee7e063.

📒 Files selected for processing (15)
  • docs/docs.go
  • docs/swagger.json
  • docs/swagger.yaml
  • internal/api/handler/oscal/profile_compliance.go
  • internal/api/handler/oscal/profile_compliance_unit_test.go
  • internal/api/handler/oscal/ssp_leverage.go
  • internal/api/handler/oscal/ssp_leverage_test.go
  • internal/api/handler/oscal/ssp_leverage_unit_test.go
  • internal/service/migrator.go
  • internal/service/relational/filters.go
  • internal/service/relational/system_security_plan.go
  • internal/service/worker/risk_evidence_worker.go
  • internal/service/worker/risk_evidence_worker_responsibility_integration_test.go
  • internal/service/worker/risk_evidence_worker_test.go
  • internal/tests/migrate.go

Comment thread internal/service/relational/filters.go
Comment thread internal/service/relational/filters.go Outdated
…ing and FK cascade

Adds a composite index leading with ssp_id so ResponsibilityPosture's lookup
can use it (the primary key leads with filter_id instead), and adds the
missing ssp_id -> system_security_plans FK with ON DELETE CASCADE, mirroring
the existing filters.ssp_id constraint.
@saltpy-cs saltpy-cs merged commit bfe8045 into main Jul 9, 2026
5 checks passed
@saltpy-cs saltpy-cs deleted the feat/BCH-1339 branch July 9, 2026 13:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant