Skip to content

fix: auto-create diagram groupings on first diagram POST#415

Merged
gusfcarvalho merged 1 commit into
mainfrom
gc-fix-diagram-group-autocreate
Jun 11, 2026
Merged

fix: auto-create diagram groupings on first diagram POST#415
gusfcarvalho merged 1 commit into
mainfrom
gc-fix-diagram-group-autocreate

Conversation

@gusfcarvalho

@gusfcarvalho gusfcarvalho commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Problem

POST /api/oscal/system-security-plans/{id}/system-characteristics/{network-architecture|data-flow|authorization-boundary}/diagrams returns 404 when the SSP's system characteristics lack that grouping — and nothing can create the grouping: PUT /system-characteristics deliberately Omits all three. So for SSPs imported without a grouping (e.g. the ToDo demo SSP, which only has an authorization boundary), the UI's Add Diagram button can never succeed:

Could not create Network Architecture diagram: no network architecture for system security plan f8c1a2b3-...

Fix

The three create-diagram handlers now create the missing grouping row (attached to the existing system characteristics) before inserting the diagram. A missing system-characteristics row still 404s. Godoc/swagger updated.

Tests

  • Updated TestCreateNetworkArchitectureDiagram_Negative / TestCreateDataFlowDiagram_Negative: the missing-grouping case now asserts 201 + a follow-up GET returns the grouping containing the diagram (previously asserted 404).
  • make reviewable green locally (swag + lint + full integration suite).

🤖 Generated with Claude Code

Summary by CodeRabbit

Documentation

  • Updated OpenAPI specifications for Authorization Boundary, Data Flow, and Network Architecture diagram creation endpoints to document improved behavior.

Bug Fixes

  • Diagram creation endpoints now automatically create missing parent groupings if they don't exist, eliminating previous errors and improving user experience.

Creating a diagram under network-architecture, data-flow, or
authorization-boundary returned 404 when the SSP's system
characteristics lacked that grouping, and no endpoint could create it
(PUT /system-characteristics deliberately omits the three groupings).
This made 'Add Diagram' permanently fail in the UI for SSPs imported
without the groupings (e.g. the ToDo demo SSP).

The create-diagram handlers now create the missing grouping row,
attached to the existing system characteristics, before inserting the
diagram. A missing system-characteristics row still 404s.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Three diagram creation endpoints (Authorization Boundary, Data Flow, Network Architecture) now auto-create missing OSCAL grouping records in the database instead of returning 404. Implementation, tests, and API documentation are updated consistently to reflect the new behavior.

Changes

Auto-Create OSCAL Groupings for Diagram Endpoints

Layer / File(s) Summary
Auto-create grouping logic in diagram endpoints
internal/api/handler/oscal/system_security_plans.go
CreateCharacteristicsNetworkArchitectureDiagram, CreateCharacteristicsDataFlowDiagram, and CreateCharacteristicsAuthorizationBoundaryDiagram now insert the corresponding grouping row when it is missing but SystemCharacteristics.ID exists, before creating the diagram.
Test updates for auto-create behavior
internal/api/handler/oscal/system_security_plans_test.go
Negative test cases updated to expect 201 on diagram POST when grouping is initially missing; follow-up GET assertions verify the grouping and diagram were persisted instead of treating missing groupings as not-found errors.
API documentation for auto-create endpoints
docs/docs.go, docs/swagger.json, docs/swagger.yaml
OpenAPI operation descriptions for all three diagram creation endpoints updated to explicitly state that the Authorization Boundary, Data Flow, or Network Architecture grouping is created if it does not already exist.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

A rabbit hops through endpoints three,
Auto-grouping them with glee,
Diagrams plant where none existed,
No more 404s—logic persisted! 🐰✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: auto-create diagram groupings on first diagram POST' accurately and concisely summarizes the main change across all modified files—enabling automatic creation of missing diagram groupings when POST requests are made to diagram endpoints.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


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 and usage tips.

@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

Caution

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

⚠️ Outside diff range comments (1)
internal/api/handler/oscal/system_security_plans_test.go (1)

2483-2528: 🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Add a negative-path test for Authorization Boundary missing-grouping auto-create parity.

TestCreateNetworkArchitectureDiagram_Negative and TestCreateDataFlowDiagram_Negative now verify auto-creation when the grouping row is missing, but TestCreateAuthorizationBoundaryDiagram_Negative still only checks invalid IDs/body. Please add the equivalent “missing grouping → POST returns 201 → GET returns grouping with created diagram” case for AB to lock in the same contract and prevent endpoint drift.

🤖 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/api/handler/oscal/system_security_plans_test.go` around lines 2483 -
2528, Add a negative-path case in
TestCreateAuthorizationBoundaryDiagram_Negative mirroring
TestCreateNetworkArchitectureDiagram_Negative and
TestCreateDataFlowDiagram_Negative: create an SSP via suite.createBasicSSP()
that does NOT include SystemCharacteristics.AuthorizationBoundary, POST a
Diagram (oscalTypes_1_1_3.Diagram) to the
"/api/oscal/system-security-plans/{ssp.UUID}/system-characteristics/authorization-boundary/diagrams"
endpoint using suite.createRequest() and server.E().ServeHTTP and assert
http.StatusCreated (201), then perform a GET of the SSP and assert that
SystemCharacteristics.AuthorizationBoundary was auto-created and contains the
posted Diagram (matching UUID/Description); use the same request helpers
(suite.createRequest, server.E().ServeHTTP) and assertion style as the other
negative tests to keep parity.
🤖 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 `@docs/swagger.json`:
- Line 16628: The swagger YAML is out of sync: docs/swagger.yaml is missing the
updated descriptions for Authorization Boundary and Network Architecture that
appear in docs/swagger.json and docs/docs.go (e.g., the “grouping if it does not
exist yet” text around the Authorization Boundary description at the
Authorization Boundary, Data Flow, and Network Architecture endpoints). Re-run
your Swagger generator (e.g., run swag init) to regenerate docs/swagger.yaml so
its description strings match docs/swagger.json and docs/docs.go, then verify
the Authorization Boundary, Data Flow, and Network Architecture operation
descriptions all include the “grouping if it does not exist yet” phrasing.

In `@internal/api/handler/oscal/system_security_plans.go`:
- Around line 603-610: The code is creating relational.NetworkArchitecture (na)
before validating the incoming request and is doing grouping + diagram creation
as separate writes; move the request binding and UUID validation (ctx.Bind and
any ID parsing) to occur before any DB mutation, then wrap the "ensure grouping
+ create diagram" sequence in a single DB transaction using h.db.Transaction so
both the grouping create and the na create use the transactional tx (e.g.,
replace h.db.Create calls with tx.Create inside the transaction closure), check
for existing grouping within the transaction and only create if missing to avoid
race/duplicate errors, and convert DB errors into appropriate HTTP responses
(handle unique-constraint conflicts vs internal errors); apply the same change
to the other two handlers referenced (around the other blocks at 848-855 and
1089-1096).

---

Outside diff comments:
In `@internal/api/handler/oscal/system_security_plans_test.go`:
- Around line 2483-2528: Add a negative-path case in
TestCreateAuthorizationBoundaryDiagram_Negative mirroring
TestCreateNetworkArchitectureDiagram_Negative and
TestCreateDataFlowDiagram_Negative: create an SSP via suite.createBasicSSP()
that does NOT include SystemCharacteristics.AuthorizationBoundary, POST a
Diagram (oscalTypes_1_1_3.Diagram) to the
"/api/oscal/system-security-plans/{ssp.UUID}/system-characteristics/authorization-boundary/diagrams"
endpoint using suite.createRequest() and server.E().ServeHTTP and assert
http.StatusCreated (201), then perform a GET of the SSP and assert that
SystemCharacteristics.AuthorizationBoundary was auto-created and contains the
posted Diagram (matching UUID/Description); use the same request helpers
(suite.createRequest, server.E().ServeHTTP) and assertion style as the other
negative tests to keep parity.
🪄 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: 231613cb-992a-477b-98b1-4ea99678be42

📥 Commits

Reviewing files that changed from the base of the PR and between 61d8149 and 6cec4b9.

📒 Files selected for processing (5)
  • docs/docs.go
  • docs/swagger.json
  • docs/swagger.yaml
  • internal/api/handler/oscal/system_security_plans.go
  • internal/api/handler/oscal/system_security_plans_test.go

Comment thread docs/swagger.json
"/oscal/system-security-plans/{id}/system-characteristics/authorization-boundary/diagrams": {
"post": {
"description": "Creates a new Diagram under the Authorization Boundary of a System Security Plan.",
"description": "Creates a new Diagram under the Authorization Boundary of a System Security Plan. Creates the Authorization Boundary grouping if it does not exist yet.",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Verify consistency of auto-create descriptions across all three generated swagger artifacts.

echo "=== Checking swagger.json ==="
rg -n "Creates the Authorization Boundary grouping if it does not exist yet" docs/swagger.json
rg -n "Creates the Data Flow grouping if it does not exist yet" docs/swagger.json
rg -n "Creates the Network Architecture grouping if it does not exist yet" docs/swagger.json

echo -e "\n=== Checking swagger.yaml ==="
rg -n "Creates the Authorization Boundary grouping if it does not exist yet" docs/swagger.yaml
rg -n "Creates the Data Flow grouping if it does not exist yet" docs/swagger.yaml
rg -n "Creates the Network Architecture grouping if it does not exist yet" docs/swagger.yaml

echo -e "\n=== Checking docs.go ==="
rg -n "Creates the Authorization Boundary grouping if it does not exist yet" docs/docs.go
rg -n "Creates the Data Flow grouping if it does not exist yet" docs/docs.go
rg -n "Creates the Network Architecture grouping if it does not exist yet" docs/docs.go

Repository: compliance-framework/api

Length of output: 1324


Fix Swagger YAML description inconsistency across generated artifacts

  • docs/swagger.json and docs/docs.go contain the updated descriptions for Authorization Boundary (16628), Data Flow (16893), and Network Architecture (17158).
  • docs/swagger.yaml contains only the updated Data Flow description (but is missing the Authorization Boundary and Network Architecture “grouping if it does not exist yet” descriptions).
  • Re-run the swagger generation (e.g., swag init) and ensure docs/swagger.yaml is regenerated to match the other artifacts.
🤖 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 `@docs/swagger.json` at line 16628, The swagger YAML is out of sync:
docs/swagger.yaml is missing the updated descriptions for Authorization Boundary
and Network Architecture that appear in docs/swagger.json and docs/docs.go
(e.g., the “grouping if it does not exist yet” text around the Authorization
Boundary description at the Authorization Boundary, Data Flow, and Network
Architecture endpoints). Re-run your Swagger generator (e.g., run swag init) to
regenerate docs/swagger.yaml so its description strings match docs/swagger.json
and docs/docs.go, then verify the Authorization Boundary, Data Flow, and Network
Architecture operation descriptions all include the “grouping if it does not
exist yet” phrasing.

Source: Learnings

Comment on lines +603 to +610
if ssp.SystemCharacteristics.ID == nil {
return ctx.JSON(http.StatusNotFound, api.NewError(fmt.Errorf("no system characteristics for system security plan %s", idParam)))
}
na = &relational.NetworkArchitecture{SystemCharacteristicsId: *ssp.SystemCharacteristics.ID}
if err := h.db.Create(na).Error; err != nil {
h.sugar.Errorf("Failed to create network architecture: %v", err)
return ctx.JSON(http.StatusInternalServerError, api.NewError(err))
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make grouping+diagram creation atomic and validate input before mutating DB.

All three handlers can persist a new grouping before ctx.Bind/UUID validation runs, so malformed requests can return 400 after mutating state. They also perform grouping create and diagram create as separate writes, so concurrent “first diagram” calls can race into duplicate-group or unique-constraint 500 paths.

Wrap “ensure grouping + create diagram” in one transaction, and move request bind/validation before any write.

Suggested pattern (apply to all three handlers)
- // ensure/create grouping first
- if group == nil || group.ID == nil {
-   if ssp.SystemCharacteristics.ID == nil { ...404... }
-   group = &relational.<Grouping>{SystemCharacteristicsId: *ssp.SystemCharacteristics.ID}
-   if err := h.db.Create(group).Error; err != nil { ...500... }
- }
-
- // then bind/validate diagram
+ // bind/validate first (no side effects on 400)
+ var oscalDiag oscalTypes_1_1_3.Diagram
+ if err := ctx.Bind(&oscalDiag); err != nil { ...400... }
+ if oscalDiag.UUID == "" { ...400... }
+ if _, err := uuid.Parse(oscalDiag.UUID); err != nil { ...400... }
+
+ err = h.db.Transaction(func(tx *gorm.DB) error {
+   // idempotent ensure-grouping (conflict-safe)
+   // then create diagram under resolved grouping ID
+   // return error to rollback both on any failure
+   return nil
+ })
+ if err != nil { ...500... }

Also applies to: 848-855, 1089-1096

🤖 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/api/handler/oscal/system_security_plans.go` around lines 603 - 610,
The code is creating relational.NetworkArchitecture (na) before validating the
incoming request and is doing grouping + diagram creation as separate writes;
move the request binding and UUID validation (ctx.Bind and any ID parsing) to
occur before any DB mutation, then wrap the "ensure grouping + create diagram"
sequence in a single DB transaction using h.db.Transaction so both the grouping
create and the na create use the transactional tx (e.g., replace h.db.Create
calls with tx.Create inside the transaction closure), check for existing
grouping within the transaction and only create if missing to avoid
race/duplicate errors, and convert DB errors into appropriate HTTP responses
(handle unique-constraint conflicts vs internal errors); apply the same change
to the other two handlers referenced (around the other blocks at 848-855 and
1089-1096).

@gusfcarvalho gusfcarvalho merged commit 5b95a17 into main Jun 11, 2026
5 checks passed
@gusfcarvalho gusfcarvalho deleted the gc-fix-diagram-group-autocreate branch June 11, 2026 17:04
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