Skip to content

[CSM Portal] Add PATCH /projects/{id} to csm-integration-service - #1204

Closed
rksk wants to merge 1 commit into
wso2-open-operations:mainfrom
rksk:acp-bff-project-patch
Closed

rksk wants to merge 1 commit into
wso2-open-operations:mainfrom
rksk:acp-bff-project-patch

Conversation

@rksk

@rksk rksk commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Adds PATCH /projects/{id} to operations/csm-integration-service, forwarding to the entity-service's ServiceNow-backed project update operation (merged in [CSM Portal] Add project/account contact search, closure fields, and project update endpoint #1191).
  • This is the correct home for the ACP (Account Closure Process) write path: ACP is an M2M automation job with no end-user session, and csm-integration-service (merged in [CSM Integration Service] Add new Go service for third-party account/project search #1202) exists specifically to serve M2M/third-party consumers through Choreo's API Manager gateway — unlike apps/csm-portal/backend, which is a BFF for the CSM Portal's own JWT-authenticated end users.
  • Supersedes the original scope of this PR. This PR originally added the same endpoint to the CSM Portal BFF (apps/csm-portal/backend); that was the wrong component for an M2M caller and has been replaced with this implementation instead.

Goals

  • Let the ACP automation write the three closure sub-state fields (endDateClosureState, invoiceDueDateClosureState, complianceViolationClosureState) plus the pre-existing hasAgent/hasKbReferences toggles, through the M2M-facing service, not the BFF.

Approach

  • internal/entity/entity.go: new Client.UpdateProject (PATCH /projects/{id}), matching this file's existing client-method pattern.
  • internal/handler/projects.go: extended entityProjectClient interface; new ProjectHandler.UpdateProject — path-scoped, UUID-validated, body-capped, JSON-validated, forwarded and returned verbatim.
  • No auth check added — this service has none by design (see its CLAUDE.md); Choreo's API Manager gateway is the trust boundary. A caller with no forwarded x-user-id-token gets a mapped 401 from the upstream ServiceNow-only operation, which is expected and documented, not worked around.
  • cmd/server/main.go: registered the route.
  • openapi.yaml: documented the operation, including the 401 case per this service's own convention for ServiceNow-backed operations.

Test plan

  • make test (vet + race-detector)
  • make build
  • gofmt -l on changed files (clean)
  • New TestUpdateProject: invalid/empty UUID rejected, body-size cap enforced, invalid JSON rejected, body forwarded verbatim and response returned verbatim, upstream errors mapped correctly

Release note

PATCH /projects/{id} is now available on the CSM Integration Service for M2M consumers.

Documentation

Updated operations/csm-integration-service/openapi.yaml.

Security checks

  • Secure coding standards followed: yes
  • FindSecurityBugs/static analysis: N/A for Go — go vet ran clean
  • No secrets committed: yes

Related PRs

Depends on #1191 (entity-service project update endpoint) and #1202 (csm-integration-service itself).

Adds an opaque-passthrough handler for the ACP closure-state fields
(and existing hasAgent/hasKbReferences toggles) on the Go BFF, mirroring
the entity-service's PATCH /projects/{id} contract. Auth-checks and
UUID-validates the path id, caps and forwards the body verbatim, and
returns the upstream response as-is -- no BFF-level RBAC beyond
"authenticated user", matching this codebase's existing convention for
PATCH endpoints (e.g. PatchCallRequest) of letting the entity service
reject unsupported writes.
@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a PATCH /projects/{id} endpoint with OpenAPI contracts, request validation, entity-service delegation, error mapping, route registration, and handler tests.

Changes

Project update flow

Layer / File(s) Summary
Project update API contract
apps/csm-portal/backend/openapi.yaml
Documents the PATCH operation and defines request and response schemas for closure-state and KB/agent toggle updates.
Handler validation and delegation
apps/csm-portal/backend/internal/handler/projects.go, apps/csm-portal/backend/internal/handler/helpers_test.go, apps/csm-portal/backend/internal/handler/projects_test.go
Adds authenticated UUID and JSON validation, request-size enforcement, entity delegation, upstream error mapping, mock support, and coverage for validation and response behavior.
Route and entity client wiring
apps/csm-portal/backend/cmd/server/main.go, apps/csm-portal/backend/internal/entity/entity.go
Registers PATCH /projects/{id} and adds the escaped-ID entity client request wrapper.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant HTTPClient
  participant ProjectHandler
  participant EntityClient
  HTTPClient->>ProjectHandler: PATCH /projects/{id} with JSON body
  ProjectHandler->>ProjectHandler: Authenticate and validate request
  ProjectHandler->>EntityClient: UpdateProject(ctx, id, body)
  EntityClient-->>ProjectHandler: JSON response or error
  ProjectHandler-->>HTTPClient: 200 response or mapped error
Loading

Possibly related PRs

Suggested labels: Type/Improvement, Entity Service

Suggested reviewers: rashmika998

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the main change: adding a PATCH /projects/{id} pass-through endpoint to the CSM Portal BFF.
Description check ✅ Passed The description covers the change, goals, approach, tests, release note, docs, and security checks, though some template sections are omitted.
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.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
apps/csm-portal/backend/openapi.yaml

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

🔧 golangci-lint (2.12.2)

level=error msg="[linters_context] typechecking error: pattern ./...: directory prefix . does not contain main module or its selected dependencies"


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.

@rksk

rksk commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

@coderabbitai resume

@coderabbitai

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Reviews resumed.

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

Actionable comments posted: 1

🤖 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 `@apps/csm-portal/backend/openapi.yaml`:
- Around line 951-956: Close the project-update payload contract across all
affected sites: in apps/csm-portal/backend/openapi.yaml lines 951-956, document
that the BFF rejects malformed, empty, and unsupported payloads; in
apps/csm-portal/backend/openapi.yaml lines 4999-5018, set additionalProperties
to false; in apps/csm-portal/backend/internal/handler/projects.go lines 182-185,
validate a non-empty object containing only documented fields with their
documented types before forwarding the original bytes; and in
apps/csm-portal/backend/internal/handler/projects_test.go lines 331-340, add
rejection cases for {}, null, [], unknown fields, and invalid types, asserting
the upstream client is not called.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: abac8110-401b-44c0-a5fb-405c858156ee

📥 Commits

Reviewing files that changed from the base of the PR and between 59831a5 and 8bb27cf.

📒 Files selected for processing (6)
  • apps/csm-portal/backend/cmd/server/main.go
  • apps/csm-portal/backend/internal/entity/entity.go
  • apps/csm-portal/backend/internal/handler/helpers_test.go
  • apps/csm-portal/backend/internal/handler/projects.go
  • apps/csm-portal/backend/internal/handler/projects_test.go
  • apps/csm-portal/backend/openapi.yaml

Comment on lines +951 to +956
patch:
summary: Update a project's closure sub-state fields or KB/agent toggles.
description: >
Request body is forwarded to the integration service as-is and the
response is returned verbatim. At least one field must be provided;
the integration service validates this and rejects an empty update.

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.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Close and enforce the project-update payload contract.

The handler forwards {}, null, arrays, scalars, wrongly typed values, and undeclared fields because json.Valid only checks syntax; this contradicts the documented object/minimum-field contract and sends unexpected input upstream.

  • apps/csm-portal/backend/openapi.yaml#L951-L956: state that the BFF rejects malformed, empty, and unsupported update payloads rather than delegating empty-update validation.
  • apps/csm-portal/backend/openapi.yaml#L4999-L5018: add additionalProperties: false.
  • apps/csm-portal/backend/internal/handler/projects.go#L182-L185: validate a non-empty object with only the documented fields and their documented types before forwarding the original bytes.
  • apps/csm-portal/backend/internal/handler/projects_test.go#L331-L340: add rejection cases for {}, null, [], unknown fields, and invalid field types; assert the client is not called.

As per coding guidelines, “Validate and reject unexpected input at the boundary (path params, body size, JSON structure) before forwarding requests to upstream services.”

📍 Affects 3 files
  • apps/csm-portal/backend/openapi.yaml#L951-L956 (this comment)
  • apps/csm-portal/backend/openapi.yaml#L4999-L5018
  • apps/csm-portal/backend/internal/handler/projects.go#L182-L185
  • apps/csm-portal/backend/internal/handler/projects_test.go#L331-L340
🤖 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 `@apps/csm-portal/backend/openapi.yaml` around lines 951 - 956, Close the
project-update payload contract across all affected sites: in
apps/csm-portal/backend/openapi.yaml lines 951-956, document that the BFF
rejects malformed, empty, and unsupported payloads; in
apps/csm-portal/backend/openapi.yaml lines 4999-5018, set additionalProperties
to false; in apps/csm-portal/backend/internal/handler/projects.go lines 182-185,
validate a non-empty object containing only documented fields with their
documented types before forwarding the original bytes; and in
apps/csm-portal/backend/internal/handler/projects_test.go lines 331-340, add
rejection cases for {}, null, [], unknown fields, and invalid types, asserting
the upstream client is not called.

Source: Coding guidelines

@rksk

rksk commented Jul 22, 2026

Copy link
Copy Markdown
Contributor Author

Closing — this endpoint doesn't belong in this component. The CSM Portal BFF is for the CSM Portal's own end-user sessions (JWT-validated), but the caller that needs to patch project closure-state (the ACP automation job) is M2M with no end user in the loop. That's exactly what operations/csm-integration-service exists for. Reimplementing there instead: #1205

@rksk rksk closed this Jul 22, 2026
@rksk rksk changed the title [CSM Portal] Add PATCH /projects/{id} pass-through to BFF [CSM Portal] Add PATCH /projects/{id} to csm-integration-service Jul 22, 2026
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