Skip to content

feat: Add generic Core gRPC proxy and BMC credential endpoints#2477

Open
kfelternv wants to merge 2 commits into
NVIDIA:mainfrom
kfelternv:nico-site-grpc-proxy
Open

feat: Add generic Core gRPC proxy and BMC credential endpoints#2477
kfelternv wants to merge 2 commits into
NVIDIA:mainfrom
kfelternv:nico-site-grpc-proxy

Conversation

@kfelternv

@kfelternv kfelternv commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Summary (AI Assisted PR Description to add detail and links to code)

This PR adds a generic Temporal-backed Core gRPC proxy for REST API operations that need to call on-site NICo Core methods. The first consumer is PUT /v2/org/{org}/nico/credential/bmc, which stores site-wide or per-BMC root credentials by forwarding a typed forge.Forge/CreateCredential request to the site.

Why

Today, each REST operation that needs to reach NICo Core tends to grow its own workflow, activity, request type, and site-side plumbing. This PR adds one shared internal transport for curated REST handlers: handlers still own auth, validation, request shaping, and API design, but the cloud-to-site Temporal hop is generic. The shared contract lives in coreproxy.

The BMC credential endpoint needs this path because the REST API must accept an administrative secret, validate it, and deliver it to on-site Core without recording the password in Temporal history.

Design

The new coreproxy package defines the shared workflow contract:

  • FullMethod: the Core gRPC method to invoke, for example /forge.Forge/CreateCredential.
  • RequestJSON: the typed protobuf request encoded as protojson, with configured secret fields replaced by [REDACTED].
  • EncryptedSecrets: an encrypted sidecar containing only the redacted secret fields.
  • ResponseJSON: the Core gRPC response encoded as protojson.

ExecuteCoreGRPC is the cloud-side helper. It accepts an already validated protobuf request, converts it to protojson, redacts requested secret fields, and encrypts those fields before starting the workflow. This follows the existing site-bound Temporal secret pattern used by OTP rotation: the cloud workflow encrypts the new OTP with EncryptData(..., site.ID.String()) before calling ExecuteWorkflow("RotateTemporalCertAccessOTP", ...), and the site-agent decrypts it with DecryptData(..., ManagerAccess.Conf.EB.Temporal.ClusterID) before writing it into the local bootstrap secret. ExecuteCoreGRPC applies that same pattern to a generic secret sidecar, then starts the shared InvokeCoreGRPC workflow on the site task queue.

On site, the registered InvokeCoreGRPC workflow runs one activity, InvokeCoreGRPCOnSite. The activity decrypts EncryptedSecrets, merges the secret fields back into the request JSON, and then invokes Core through InvokeJSON, which resolves the requested unary forge.Forge method, dynamically builds the request/response messages, invokes Core over the existing gRPC client, and returns the response as protojson.

The site-agent registers the shared workflow and activity through the Core gRPC manager in RegisterSubscriber.

Secret Handling

The proxy does not encrypt the whole request. It splits the payload so non-secret request fields remain readable for Temporal debugging, while sensitive fields such as password are removed from RequestJSON and carried only in EncryptedSecrets. The redaction and merge behavior is implemented by RedactSecrets and MergeSecrets.

For the BMC credential endpoint, the handler calls the proxy with password as the secret field, so the Temporal-visible request contains [REDACTED] instead of the credential password. That call is in SetBMCCredentialHandler.Handle.

BMC Credential Endpoint

Adds PUT /v2/org/{org}/nico/credential/bmc for Provider Admin users.

The handler:

  • Validates org membership and Provider Admin role in authorizeSite.
  • Requires siteId and confirms the site belongs to the org's infrastructure provider in authorizeSite.
  • Validates the request body through APIBMCCredentialRequest.Validate.
  • Maps the REST request to CredentialCreationRequest through ToProto.
  • Proxies the request to forge.Forge/CreateCredential through ExecuteCoreGRPC.
  • Returns 204 No Content on success.

Supported credential kinds are defined in bmccredential.go:

  • Site-wide BMC root credential.
  • Per-BMC root credential, which requires macAddress.

The route is registered in routes.go and documented in the OpenAPI spec with BMCCredentialRequest.

Testing

@copy-pr-bot

copy-pr-bot Bot commented Jun 11, 2026

Copy link
Copy Markdown

Auto-sync is disabled for draft pull requests in this repository. Workflows must be run manually.

Contributors can view more details about this message here.

@coderabbitai

coderabbitai Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6c8e0071-be69-4cad-aa3c-b1ed4e78a0dd

📥 Commits

Reviewing files that changed from the base of the PR and between 517006d and 6682b6e.

📒 Files selected for processing (4)
  • rest-api/api/pkg/api/handler/util/common/coreproxy.go
  • rest-api/common/pkg/coreproxy/coreproxy.go
  • rest-api/site-agent/pkg/components/managers/coregrpc/subscriber.go
  • rest-api/site-workflow/pkg/workflow/coreproxy.go
🚧 Files skipped from review as they are similar to previous changes (4)
  • rest-api/common/pkg/coreproxy/coreproxy.go
  • rest-api/site-workflow/pkg/workflow/coreproxy.go
  • rest-api/site-agent/pkg/components/managers/coregrpc/subscriber.go
  • rest-api/api/pkg/api/handler/util/common/coreproxy.go

Summary by CodeRabbit

  • New Features
    • Added a new REST API endpoint to create/update BMC credentials (site-wide root or per-BMC root), including optional username and conditional MAC requirements.
    • Added secure, per-site proxying to core operations for credential creation with HTTP 204 No Content on success.
  • Documentation
    • Updated the OpenAPI spec with the new endpoint and BMCCredentialRequest schema.
  • Tests
    • Added unit tests covering request validation, request-to-core mapping, and secret redaction/merge behavior.

Walkthrough

Introduces a generic Temporal-based gRPC proxy infrastructure that routes REST API calls to on-site NICo Core gRPC methods with AES-encrypted secret redaction in Temporal history. Implements a new PUT /v2/org/{org}/nico/credential/bmc endpoint using this infrastructure to forward BMC credential creation requests to forge.Forge/CreateCredential.

Changes

Generic Core gRPC Proxy with BMC Credential Endpoint

Layer / File(s) Summary
Shared coreproxy contract: types, redaction, and merge helpers
rest-api/common/pkg/coreproxy/coreproxy.go, rest-api/common/pkg/coreproxy/coreproxy_test.go
Defines WorkflowName, RedactedPlaceholder, Request/Response structs, and RedactSecrets/MergeSecrets helpers for safe secret handling in Temporal history. Tests validate round-trip redaction, no-op behavior when no secret fields are specified, and empty-secrets merge.
Dynamic gRPC JSON transcoder (forge.Forge service)
rest-api/site-workflow/pkg/grpc/client/core_proxy.go, rest-api/site-workflow/pkg/grpc/client/core_proxy_test.go
Adds CoreGrpcClient.InvokeJSON backed by invokeJSONConn that resolves method descriptors from the global proto registry, constructs dynamic protobuf messages, unmarshals JSON input (discarding unknown fields), invokes the unary RPC, and marshals the response to JSON. ErrUnknownCoreMethod guards unsupported methods.
Temporal workflow and activity for on-site gRPC proxy
rest-api/site-workflow/pkg/workflow/coreproxy.go, rest-api/site-workflow/pkg/activity/coreproxy.go
Adds the InvokeCoreGRPC workflow (2-minute timeout, single attempt, no retries) and ManageCoreProxy activity that checks client connectivity, decrypts and merges secrets from the encrypted request, delegates to InvokeJSON, and returns coreproxy.Response.
Site-agent interface update and workflow/activity registration
rest-api/site-agent/pkg/components/managers/managerapi/coregrpc_api.go, rest-api/site-agent/pkg/components/managers/coregrpc/subscriber.go, rest-api/site-agent/pkg/components/managers/workflow/orchestrator.go
Updates CoreGrpcInterface.RegisterSubscriber to return error. Implements RegisterSubscriber in the coregrpc manager to register the InvokeCoreGRPC workflow and InvokeCoreGRPCOnSite activity with the Temporal worker, and wires the call into the orchestrator registration sequence.
Cloud-side ExecuteCoreGRPC Temporal proxy utility
rest-api/api/pkg/api/handler/util/common/coreproxy.go
Adds ExecuteCoreGRPC: protojson-encodes the request, optionally redacts and AES-encrypts secret fields for Temporal-history safety, starts the coreproxy.WorkflowName workflow, distinguishes timeout (HTTP 502) from other errors, and decodes the protojson response if provided.
BMC credential model: validation, proto mapping, and tests
rest-api/api/pkg/api/model/bmccredential.go, rest-api/api/pkg/api/model/bmccredential_test.go
Defines APIBMCCredentialRequest with Validate() (password required; macAddress required for bmc-root) and ToProto() (maps to cwssaws.CredentialCreationRequest). Table-driven tests cover validation edge cases and proto field mapping for both credential kinds.
BMC credential REST handler, route registration, and OpenAPI spec
rest-api/api/pkg/api/handler/bmccredential.go, rest-api/api/pkg/api/routes.go, rest-api/openapi/spec.yaml
Implements bmcCredentialBase.authorizeSite (validates caller, enforces ProviderAdminRole, resolves and verifies siteId) and SetBMCCredentialHandler.Handle (proxies to ExecuteCoreGRPC with password redacted, returns HTTP 204). Registers the route and adds the PUT /v2/org/{org}/nico/credential/bmc operation with BMCCredentialRequest schema to OpenAPI.
Route registration test verification
rest-api/api/pkg/api/routes_test.go
Updates TestNewAPIRoutes to expect the credential route category and asserts the PUT endpoint is registered at /org/:orgName/<apiName>/credential/bmc.

Sequence Diagram

sequenceDiagram
  participant Client
  participant SetBMCCredentialHandler
  participant ExecuteCoreGRPC
  participant TemporalCloud as Temporal (Cloud)
  participant InvokeCoreGRPCOnSite as InvokeCoreGRPCOnSite Activity
  participant CoreGrpcClient

  rect rgba(70, 130, 180, 0.5)
    note over SetBMCCredentialHandler: Authorization & Validation
    Client->>SetBMCCredentialHandler: PUT /org/:orgName/nico/credential/bmc
    SetBMCCredentialHandler->>SetBMCCredentialHandler: Validate APIBMCCredentialRequest
    SetBMCCredentialHandler->>SetBMCCredentialHandler: authorizeSite → ProviderAdminRole + siteId check
  end

  rect rgba(60, 179, 113, 0.5)
    note over ExecuteCoreGRPC,TemporalCloud: Secret redaction + Temporal dispatch
    SetBMCCredentialHandler->>ExecuteCoreGRPC: forge.Forge/CreateCredential, req, secretKey, "password"
    ExecuteCoreGRPC->>ExecuteCoreGRPC: protojson encode → RedactSecrets → AES encrypt
    ExecuteCoreGRPC->>TemporalCloud: start InvokeCoreGRPC(coreproxy.Request{redactedJSON, encryptedSecrets})
  end

  rect rgba(210, 105, 30, 0.5)
    note over InvokeCoreGRPCOnSite,CoreGrpcClient: On-site secret restore + gRPC call
    TemporalCloud->>InvokeCoreGRPCOnSite: execute activity
    InvokeCoreGRPCOnSite->>InvokeCoreGRPCOnSite: AES decrypt + MergeSecrets → full reqJSON
    InvokeCoreGRPCOnSite->>CoreGrpcClient: InvokeJSON(ctx, CreateCredential, fullReqJSON)
    CoreGrpcClient-->>InvokeCoreGRPCOnSite: respJSON
    InvokeCoreGRPCOnSite-->>TemporalCloud: coreproxy.Response
  end

  TemporalCloud-->>ExecuteCoreGRPC: coreproxy.Response
  ExecuteCoreGRPC-->>SetBMCCredentialHandler: HTTP 200
  SetBMCCredentialHandler-->>Client: HTTP 204 No Content
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.89% 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
Title check ✅ Passed The title accurately summarizes the primary changes: introducing a generic Core gRPC proxy mechanism and adding BMC credential endpoints, which are the two main components of this PR.
Description check ✅ Passed The description is comprehensive and directly related to the changeset, explaining the motivation, design, secret handling strategy, endpoint implementation, and testing approach with proper citations to code locations.
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.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

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

Thanks for the great implementation @kfelternv! I’ll go through this as soon as I can and leave some notes.

@kfelternv kfelternv force-pushed the nico-site-grpc-proxy branch from a17f8ff to 732e3e0 Compare June 18, 2026 18:23
@kfelternv kfelternv marked this pull request as ready for review June 18, 2026 18:23
@kfelternv kfelternv requested a review from a team as a code owner June 18, 2026 18:23
@kfelternv

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 18, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@github-actions

github-actions Bot commented Jun 18, 2026

Copy link
Copy Markdown

🔍 Container Scan Summary

Service Total Critical High Medium Low Other
nico-flow 126 14 55 44 5 8
nico-nsm 133 11 45 66 11 0
nico-psm 128 14 57 44 5 8
nico-rest-api 192 17 89 70 8 8
nico-rest-cert-manager 105 6 52 35 4 8
nico-rest-db 126 14 55 44 5 8
nico-rest-site-agent 125 14 55 44 4 8
nico-rest-site-manager 112 7 53 40 4 8
nico-rest-workflow 128 14 57 44 5 8
TOTAL 1175 111 518 431 51 64

Per-CVE detail lives in the per-service grype-* artifacts (JSON + SARIF). Severity counts only — no CVE IDs published here.

@github-actions

Copy link
Copy Markdown

@github-actions

Copy link
Copy Markdown

🔐 TruffleHog Secret Scan

No secrets or credentials found!

Your code has been scanned for 700+ types of secrets and credentials. All clear! 🎉

🔗 View scan details

🕐 Last updated: 2026-06-18 18:25:58 UTC | Commit: 732e3e0

@copy-pr-bot

copy-pr-bot Bot commented Jun 19, 2026

Copy link
Copy Markdown

This pull request requires additional validation before any workflows can run on NVIDIA's runners.

Pull request vetters can view their responsibilities here.

Contributors can view more details about this message here.

@kfelternv kfelternv force-pushed the nico-site-grpc-proxy branch from 3ce7963 to 517006d Compare June 19, 2026 19:50
@kfelternv

Copy link
Copy Markdown
Contributor Author

/ok to test 6682b6e

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.

2 participants