Skip to content

feat: surface cross-SSP inherited controls in compliance + lineage#457

Open
ccf-lisa[bot] wants to merge 3 commits into
mainfrom
gc-feat-compliance-for-exports-imports
Open

feat: surface cross-SSP inherited controls in compliance + lineage#457
ccf-lisa[bot] wants to merge 3 commits into
mainfrom
gc-feat-compliance-for-exports-imports

Conversation

@ccf-lisa

@ccf-lisa ccf-lisa Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

What

Makes cross-SSP leveraged authorization first-class in the two compliance read surfaces. Today an inherited control (downstream subscribes to an upstream export offering, recorded in ssp_leverage_links) shows no "inherited" indication and, when fully guaranteed upstream with no downstream evidence, reads as unknown (compliance) / attention ⚠ (lineage). This adds a first-class inherited bucket, leverage badge metadata, and a drawer endpoint.

Changes

  • New neutral internal/service/leverage package — the leverage projection/aggregation was extracted here so internal/api/handler (lineage) can read it without an import cycle (handler/oscal imports handler, not vice-versa). oscal keeps behavior-preserving type aliases + delegating wrappers, so every existing endpoint/test is unchanged. Shared evidence status-count/collapse logic moved to relational/evidence.go.
  • Summarize + AggregateByControl — bulk cross-SSP link summary (live-derived satisfaction, never the stored column; ~7 queries regardless of link count) folded into per-(SSP, control-id) aggregates with the pinned credit rule (≥1 link, all active, all live-full).
  • Compliance-progress enrichment (GET /oscal/profiles/:id/compliance-progress?sspId=) — new inherited count in summary + groups, computedStatus:"inherited", and a per-control leverage badge payload. inherited counts as compliant + assessed. Evidence always wins.
  • Lineage engine — new PostureInherited rung (above not-applicable/planned, below evidence), inherited in compliance/postureCounts/sspBreakdown, and an optional leverage badge on control-node overlays and /ssps rows. derivePosture gained an inheritedCredit arg.
  • New endpoint GET /api/lineage/nodes/:key/leverage — per-downstream-SSP inherited detail (link, upstream origin + titles, responsibilities, per-responsibility posture, drift risk), read-guarded like /ssps.
  • Swagger regenerated (make swag).

Semantics (pinned)

  • Matching is by UPPER-folded control-id only (no catalog id) — same precedent as implStatusBySSP.
  • Credit = ≥1 link AND all links active AND all links live-derived full AND evidence collapses to unknown AND control in scope. Evidence wins both directions; partial/drifted/revoked links get no credit but still surface a badge.
  • Percent math: inherited joins satisfied in compliancePercent; joins satisfied+notSatisfied in assessedPercent.

Tests

  • Unit: internal/service/leverage/leverage_test.go (credit rules, worst-status precedence, statement-scope collapse, case-fold, origin dedupe, DriftDedupeKey, vacuous-full).
  • Updated lineage_test.go TestDerivePosture for the 4-arg signature + inherited-ladder cases.
  • Integration: lineage_leverage_integration_test.go (credit/roots/breakdown//ssps//leverage drawer, drift, evidence-wins, partial→no-credit) and oscal/profile_compliance_leverage_integration_test.go (credit, partial, no-sspId).

Verification

go build ./..., make test, make test-integration (new + regression leverage/shared-responsibility/lineage/compliance suites + perf guard), make swag, make lint — all green.

🤖 Generated with Claude Code

@ccf-lisa

ccf-lisa Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

This PR has been green across several automated review passes (build, unit + integration suites, lint, swagger) with no inline review threads or CI failures raised. Requesting a human review to move it forward. lisa will keep addressing any inline threads and CI failures as they come in.

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

Findings inline (3, none blocking). Clean import-cycle extraction into the neutral leverage package, behavior-preserving aliases keep every existing endpoint byte-for-byte, good unit + integration coverage, all CI green.

Headline: one Medium (the /leverage drawer builds the whole lineage engine — full evidence corpus included — to use just two fields) and two Low semantic/consistency flags (vacuous-full links now count toward the compliance %, and a parent control's posture badge doesn't reflect inherited children the way it reflects satisfied ones). All three are worth a look but none block merge.

Comment thread internal/api/handler/lineage_leverage.go Outdated
Comment thread internal/service/leverage/summary.go Outdated
Comment thread internal/api/handler/lineage.go

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

Re-reviewed at d48dcb9 — all three prior findings resolved, nothing new, all CI green (build/vet/gofmt/unit local + lint/unit/integration/check-diff on CI).

  • Medium (drawer engine cost): fixed. LeverageDetail drops buildEngine(nil,nil) entirely — control existence is now a targeted relational.Control lookup on (catalog_id, id) with a proper ErrRecordNotFound→404, and downstream+upstream SSP titles come from a single Preload("Metadata") keyed on the ids ProjectForControl already returns (deduped, nil-guarded). No more full-corpus load per drawer open.
  • Low (vacuous credit): fixed. AggregateByControl now gates Credit on TotalResponsibilities > 0, so a dangling/empty link no longer inflates the compliance %. DeriveSatisfaction's vacuous-full is intentionally unchanged (Subscribe relies on it), and a TestAggregateByControl_ZeroResponsibilitiesNoCredit case locks in the new behavior.
  • Low (posture badge vs bar): confirmed deliberate — the API emits both node.SSP.Posture (own badge) and node.PostureCounts/SSPBreakdown (roll-up bar) on purpose, and the UI renders the bar for structural nodes. No API change warranted.

Nice work. LGTM.

@ccf-lisa

ccf-lisa Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

PR approved. Marking ready for e2e.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant