Skip to content

BCH-1340: Auto-generate downstream risks for non-compliant leveraged responsibilities (Phase 4)#450

Merged
saltpy-cs merged 2 commits into
mainfrom
feat/BCH-1340
Jul 10, 2026
Merged

BCH-1340: Auto-generate downstream risks for non-compliant leveraged responsibilities (Phase 4)#450
saltpy-cs merged 2 commits into
mainfrom
feat/BCH-1340

Conversation

@saltpy-cs

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

Copy link
Copy Markdown
Contributor

Summary

Phase 4 of Cross-SSP Control Export/Import: non-compliant evidence on a downstream customer-responsibility now auto-generates a downstream-local risk attached to that responsibility, reusing the existing evidence→Risk-Template worker. Depends on Phase 3 (#448, merged).

  • New risk_responsibility_links(risk_id, responsibility_uuid) table.
  • New RiskSourceTypeInheritedResponsibility = "inherited-responsibility" (+ IsValid() + manifest doc value).
  • resolveSSPsViaFilters now returns responsibility matches separately from control matches ([]resolvedResponsibilityInfo), since a responsibility match feeds a structurally different risk — dedupe-keyed on ssp_id:template_id:responsibility:<uuid>, linked via risk_responsibility_links, one risk per (SSP, responsibility) pair rather than per (SSP, template).
  • createOrUpdateRisksForResponsibilities/createNewResponsibilityRisk/updateExistingResponsibilityRisk/createResponsibilityRiskLinks mirror the existing control-arm functions.
  • Auto-remediation on satisfied evidence needed zero changes to handleEvidenceResolution — it already operates generically on any risk with a risk_evidence_links row, and these new risks get one too.
  • Promote-to-POA&M works unchanged (verified via RiskService.PromoteToPoam, not modified).

Note: this changes resolveSSPsViaFilters's return signature (added in #448/BCH-1339). That's intentional — BCH-1339 explicitly deferred risk generation to this ticket, so nothing depended on the old merged shape.

Test plan

  • Unit tests (sqlite): create/dedupe/reopen-from-remediated for responsibility risks, link idempotency, dedupe-key collision avoidance across SSPs, and a dedicated test proving handleEvidenceResolution auto-remediates an inherited-responsibility risk untouched.
  • Integration tests (real Postgres): main scenario (create → dedupe → satisfied-flip → remediated), isolation (a filter_controls-only match never creates an inherited-responsibility risk anywhere), promote-to-POA&M.
  • Regression: all pre-existing tests pass, including updating 3 BCH-1339 tests whose assertions targeted the old merged-shape return value.
  • make reviewable (swag + lint + full integration suite) passes clean.

Out of scope

Upstream drift risk (Phase 5).

Summary by CodeRabbit

  • New Features

    • Added support for risks created from inherited responsibility relationships, including the new inherited-responsibility source type and lifecycle handling.
    • Evidence processing now recognizes downstream responsibility matches and creates/updates the corresponding risks automatically.
  • Bug Fixes

    • Improved deduplication for repeated evidence runs to prevent duplicate responsibility-based risks.
    • Responsibility-based risks now correctly update, reopen when new failing evidence arrives, and remediate when evidence is satisfied.
  • Tests

    • Added integration coverage and expanded worker tests for inherited-responsibility risk flows.

…responsibilities (Phase 4)

Non-compliant evidence on a downstream customer-responsibility now
auto-generates a downstream-local risk attached to that responsibility,
reusing the existing evidence-to-Risk-Template worker:

- New risk_responsibility_links(risk_id, responsibility_uuid) table.
- New RiskSourceTypeInheritedResponsibility = "inherited-responsibility".
- resolveSSPsViaFilters now returns responsibility matches separately from
  control matches, since they feed a structurally different risk
  (dedupe-keyed on the responsibility uuid, linked via
  risk_responsibility_links, one risk per SSP+responsibility rather than
  per SSP+template).
- createOrUpdateRisksForResponsibilities creates/dedupes/reopens these
  risks, mirroring createNewRiskForSSP. Auto-remediation on satisfied
  evidence requires no changes to handleEvidenceResolution — it already
  operates generically on any risk with a risk_evidence_links row.
- Promote-to-POA&M works unchanged (verified, not modified).

Upstream risk stays upstream: a filter_controls-only match never creates
an inherited-responsibility risk anywhere.
@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds the inherited-responsibility risk source type and RiskResponsibilityLink model with migrations. Extends evidence processing to resolve responsibility matches and manage linked risks through creation, deduplication, remediation, and integration-tested workflows.

Changes

Inherited Responsibility Risk Feature

Layer / File(s) Summary
Data model, migrations, and manifest
internal/service/relational/risks/..., internal/authz/manifest.yaml, internal/service/migrator.go, internal/tests/migrate.go
Adds the responsibility link model, source type, authorization vocabulary, and migration coverage.
Responsibility match resolution
internal/service/worker/risk_evidence_worker.go
Resolves downstream responsibility matches through filter and leverage-link queries alongside SSP matches.
Responsibility risk lifecycle
internal/service/worker/risk_evidence_worker.go
Creates, updates, deduplicates, reopens, links, and emits events for inherited-responsibility risks.
Unit and resolution coverage
internal/service/worker/risk_evidence_worker_test.go
Tests responsibility resolution, lifecycle operations, deduplication, linking, and auto-remediation.
Integration lifecycle coverage
internal/service/worker/risk_evidence_worker_*integration_test.go, internal/service/worker/risk_evidence_worker_test_helpers_test.go
Adds seeded integration scenarios for creation, deduplication, remediation, isolation, and POA&M promotion.

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

Sequence Diagram(s)

sequenceDiagram
  participant Worker as RiskEvidenceWorker
  participant Resolver as resolveSSPsViaFilters
  participant Database
  Worker->>Resolver: resolve evidence labels
  Resolver->>Database: query filter and leverage relationships
  Database-->>Resolver: return SSP and responsibility matches
  Resolver-->>Worker: return resolution results
  Worker->>Database: create or update inherited-responsibility risks
  Worker->>Database: persist evidence and responsibility links
Loading

Possibly related PRs

Suggested labels: ready-for-e2e

Poem

A rabbit follows risks downstream,
With links and evidence passed around.
Dedupe keeps the burrow bright,
Remediation sets things right.
Hop, hop—the tests take flight! 🐇

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% 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 clearly and accurately summarizes the main change: auto-generating downstream risks for leveraged responsibilities in Phase 4.
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/authz/manifest.yaml`:
- Line 146: The manifest’s documented `source_type` values are out of sync with
`RiskSourceType.IsValid()` because `risk-promotion` is listed but not accepted
by the risk model. Update the manifest entry to match the validation in
`RiskSourceType.IsValid()` and `BeforeCreate` by either removing
`risk-promotion` from the allowed values or adding a corresponding
`RiskSourceTypeRiskPromotion` constant and validation branch so the documented
set and runtime checks are consistent.

In
`@internal/service/worker/risk_evidence_worker_inherited_responsibility_integration_test.go`:
- Around line 51-98: The two seeding helpers in
InheritedResponsibilityRiskIntegrationSuite duplicate the logic already present
in the responsibility integration tests, so move the shared setup into a common
test helper and reuse it from both suites. Keep the existing behavior of
seedLeveragedResponsibility by allowing it to return the extra upstreamSSPID,
but centralize the shared export/provided/responsibility/link and filter
creation logic in a helper such as risk_evidence_worker_test_helpers_test.go so
both seedLeveragedResponsibility and seedResponsibilityFilter stay aligned.
🪄 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: eb0ff99e-c285-4c0f-97e2-5c05eea1f794

📥 Commits

Reviewing files that changed from the base of the PR and between 0b6572b and 126d7b8.

📒 Files selected for processing (9)
  • internal/authz/manifest.yaml
  • internal/service/migrator.go
  • internal/service/relational/risks/links.go
  • internal/service/relational/risks/models.go
  • internal/service/worker/risk_evidence_worker.go
  • internal/service/worker/risk_evidence_worker_inherited_responsibility_integration_test.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/authz/manifest.yaml Outdated
…elper duplication

Removes risk-promotion from risk.source_type's doc comment — it's actually
a PoamItemSourceType value, not a RiskSourceType one, and was never
accepted by RiskSourceType.IsValid(). Also centralizes the leveraged-
responsibility seeding helpers shared by the BCH-1339 and BCH-1340
integration suites into a single test helper file.

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
internal/service/worker/risk_evidence_worker_inherited_responsibility_integration_test.go (1)

84-84: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

evidence.End.Add(1) adds only 1 nanosecond, not one day.

time.Duration(1) is 1 nanosecond. While this technically makes the satisfied evidence "newer" than the original, it's fragile and unclear — especially since the EvidenceEnd arg on line 89 is a full day later ("2026-01-02T00:00:00Z" vs "2026-01-01T00:00:00Z"). Use AddDate(0, 0, 1) to add a full day, aligning the DB End field with the arg and making the intent obvious.

🔧 Proposed fix
 		Start:     evidence.Start,
-		End:       evidence.End.Add(1),
+		End:       evidence.End.AddDate(0, 0, 1),
 		Status:    datatypes.NewJSONType(oscalTypes_1_1_3.ObjectiveStatus{State: "satisfied"}),
🤖 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
`@internal/service/worker/risk_evidence_worker_inherited_responsibility_integration_test.go`
at line 84, In the evidence fixture using `evidence.End.Add(1)`, replace it with
`evidence.End.AddDate(0, 0, 1)` so the `End` field advances by one full day and
matches the `EvidenceEnd` argument.
🤖 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.

Outside diff comments:
In
`@internal/service/worker/risk_evidence_worker_inherited_responsibility_integration_test.go`:
- Line 84: In the evidence fixture using `evidence.End.Add(1)`, replace it with
`evidence.End.AddDate(0, 0, 1)` so the `End` field advances by one full day and
matches the `EvidenceEnd` argument.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 1c18a91b-d991-4ac0-aa10-b8dc3261f8ba

📥 Commits

Reviewing files that changed from the base of the PR and between 126d7b8 and c7ff731.

📒 Files selected for processing (4)
  • internal/authz/manifest.yaml
  • internal/service/worker/risk_evidence_worker_inherited_responsibility_integration_test.go
  • internal/service/worker/risk_evidence_worker_responsibility_integration_test.go
  • internal/service/worker/risk_evidence_worker_test_helpers_test.go

@saltpy-cs saltpy-cs merged commit 57d0226 into main Jul 10, 2026
5 checks passed
@saltpy-cs saltpy-cs deleted the feat/BCH-1340 branch July 10, 2026 08:46
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