Skip to content

refactor(ssp): extract SSP creation and profile attachment into a service - #523

Open
ccf-lisa[bot] wants to merge 1 commit into
feat/ssp-templates-1-modelfrom
feat/ssp-templates-2-ssp-service
Open

ccf-lisa[bot] wants to merge 1 commit into
feat/ssp-templates-1-modelfrom
feat/ssp-templates-2-ssp-service

Conversation

@ccf-lisa

@ccf-lisa ccf-lisa Bot commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Place in the stack

SSP templates (feature 2 of ssp-templates.md), PR B2 of 5. Base: B1 (#522, feat/ssp-templates-1-model), on top of the SSP scope stack (#516–#520).

What it adds

A pure refactor, with no behaviour change. SSP creation and profile attachment move out of SystemSecurityPlanHandler.Create and AddProfile into a new internal/service/relational/sspservice.Service. B4's discovery needs the same code to create SSPs inside its own transaction.

  • Create(db, oscalSSP) unmarshals the SSP, stamps last-modified and the OSCAL version, and stores it. Callers validate the SSP first; the handler still runs validateSSPInput.

  • AttachProfile(db, sspID, profileID) takes the same steps as before:

    1. load the SSP and the profile;
    2. insert the binding with ON CONFLICT DO NOTHING;
    3. resolve the profile's controls;
    4. ensure a control implementation exists;
    5. create the missing implemented requirements, matched case-insensitively and stored with canonical casing.

    The writes run in db.Transaction, which becomes a savepoint when db is already a transaction. It returns ErrSSPNotFound, ErrProfileNotFound, ErrProfileAlreadyBound or ErrNoResolvedControls, and the handler maps them to the same status codes and messages as before (404/404/409/400).

  • Profile control resolution stays in the oscal handler: the cache, the pivot table and the full-resolution fallback. It is injected as a ControlResolver func, because services cannot import internal/api.

How it was tested

  • Existing SSP handler suites pass unchanged: the whole internal/api/handler/oscal integration package, including system_security_plans* and system_security_plan_profiles_integration_test.
  • New sspservice/service_integration_test.go covers:
    • attachment creates only the missing requirements, case-insensitively;
    • the not-found, already-bound and no-controls errors, with no binding left behind;
    • both calls take part in a caller's transaction, so a rollback leaves nothing.
  • Gate on this branch:
    • make swag (no doc change), make lint (only the existing SA1019 in internal/api/metrics.go), make test, go vet -tags integration ./...;
    • integration suites of internal/api/handler/oscal and sspservice;
    • make check-diff.

Changed lines excluding generated swagger: 385.

Deviations from design

None. The control resolver is injected rather than moved into the service; see the lisa-design note. B4 wires the same resolver into the discovery worker.

Open questions for reviewers

  • Should profile control resolution (getControlIDsForProfile, extractControlIDsFromProfile, the process-wide cache) move out of the oscal handler package into a service? This PR injects it to stay a pure refactor. B4 passes the handler's resolver to the worker from where both are built.

🤖 Generated with Claude Code

@coderabbitai

coderabbitai Bot commented Oct 19, 2026 •

Copy link
Copy Markdown

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 76f05d96-7d8b-4576-b905-03b43cc85944

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

…vice

Move the bodies of SystemSecurityPlanHandler.Create and AddProfile into
sspservice.Service, which takes the *gorm.DB to run on so SSP template
discovery can call it inside a transaction. The handlers call it; responses
and status codes are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

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

ccf-review: APPROVE

no findings.

Stack (gh stack 521): #516 → #517 → #518 → #519 → #520 → #522 → #523 → #524 → #525 → #526

This branch has not been deployed

No deployments
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