From 712a6f39f6ef59080a59dc1266b62d1d83eb38cc Mon Sep 17 00:00:00 2001 From: Kyle Felter Date: Tue, 7 Jul 2026 21:40:29 -0500 Subject: [PATCH 1/3] feat: Add UEFI credential REST endpoint Signed-off-by: Kyle Felter --- .../api/pkg/api/handler/ueficredential.go | 80 +++++++ .../pkg/api/handler/ueficredential_test.go | 146 ++++++++++++ rest-api/api/pkg/api/model/ueficredential.go | 76 +++++++ .../api/pkg/api/model/ueficredential_test.go | 75 ++++++ rest-api/api/pkg/api/routes.go | 7 + rest-api/api/pkg/api/routes_test.go | 4 +- rest-api/cli/pkg/commands_test.go | 23 ++ rest-api/openapi/spec.yaml | 85 +++++++ rest-api/sdk/standard/api_uefi_credential.go | 173 ++++++++++++++ rest-api/sdk/standard/client.go | 3 + .../sdk/standard/model_uefi_credential.go | 186 +++++++++++++++ .../standard/model_uefi_credential_request.go | 215 ++++++++++++++++++ 12 files changed, 1072 insertions(+), 1 deletion(-) create mode 100644 rest-api/api/pkg/api/handler/ueficredential.go create mode 100644 rest-api/api/pkg/api/handler/ueficredential_test.go create mode 100644 rest-api/api/pkg/api/model/ueficredential.go create mode 100644 rest-api/api/pkg/api/model/ueficredential_test.go create mode 100644 rest-api/sdk/standard/api_uefi_credential.go create mode 100644 rest-api/sdk/standard/model_uefi_credential.go create mode 100644 rest-api/sdk/standard/model_uefi_credential_request.go diff --git a/rest-api/api/pkg/api/handler/ueficredential.go b/rest-api/api/pkg/api/handler/ueficredential.go new file mode 100644 index 0000000000..9ccb373f48 --- /dev/null +++ b/rest-api/api/pkg/api/handler/ueficredential.go @@ -0,0 +1,80 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package handler + +import ( + "net/http" + + "github.com/labstack/echo/v4" + + "github.com/NVIDIA/infra-controller/rest-api/api/pkg/api/handler/util/common" + "github.com/NVIDIA/infra-controller/rest-api/api/pkg/api/model" + sc "github.com/NVIDIA/infra-controller/rest-api/api/pkg/client/site" + cutil "github.com/NVIDIA/infra-controller/rest-api/common/pkg/util" + cdb "github.com/NVIDIA/infra-controller/rest-api/db/pkg/db" +) + +// CreateUEFICredentialHandler creates a site-default host or DPU UEFI credential. +type CreateUEFICredentialHandler struct { + dbSession *cdb.Session + scp *sc.ClientPool + tracerSpan *cutil.TracerSpan +} + +// NewCreateUEFICredentialHandler returns a handler for creating a UEFI credential. +func NewCreateUEFICredentialHandler(dbSession *cdb.Session, scp *sc.ClientPool) CreateUEFICredentialHandler { + return CreateUEFICredentialHandler{ + dbSession: dbSession, + scp: scp, + tracerSpan: cutil.NewTracerSpan(), + } +} + +// Handle godoc +// @Summary Create UEFI Credential +// @Description Create a site-default host or DPU UEFI credential. Equivalent to `nico-admin-cli credential add-uefi`. +// @Tags uefi-credential +// @Accept json +// @Produce json +// @Security ApiKeyAuth +// @Param org path string true "Name of NGC organization" +// @Param request body model.APIUEFICredentialRequest true "UEFI credential" +// @Success 201 {object} model.APIUEFICredential +// @Router /v2/org/{org}/nico/credential/uefi [post] +func (h CreateUEFICredentialHandler) Handle(c echo.Context) error { + org, dbUser, ctx, logger, handlerSpan := common.SetupHandler("UEFICredential", "Create", c, h.tracerSpan) + if handlerSpan != nil { + defer handlerSpan.End() + } + + var apiReq model.APIUEFICredentialRequest + if err := c.Bind(&apiReq); err != nil { + return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, "Invalid request body", nil) + } + if err := apiReq.Validate(); err != nil { + return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, err.Error(), nil) + } + + stc, siteID, apiErr := common.AuthorizeProviderSiteForCore(common.AuthorizeProviderSiteForCoreInput{ + Ctx: ctx, + Logger: logger, + DBSession: h.dbSession, + SCP: h.scp, + Org: org, + User: dbUser, + SiteID: apiReq.SiteID, + }) + if apiErr != nil { + return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, apiErr.Data) + } + + logger.Info().Str("kind", string(apiReq.Kind)).Str("siteID", apiReq.SiteID).Msg("creating UEFI credential via Core proxy") + + if apiErr := common.ExecuteCoreGRPC(ctx, stc, createCredentialMethod, apiReq.ToProto(), nil, siteID, "password"); apiErr != nil { + logAPIError(logger, apiErr, "failed to create UEFI credential") + return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, nil) + } + + return c.JSON(http.StatusCreated, apiReq.ToResponse()) +} diff --git a/rest-api/api/pkg/api/handler/ueficredential_test.go b/rest-api/api/pkg/api/handler/ueficredential_test.go new file mode 100644 index 0000000000..9dca055caf --- /dev/null +++ b/rest-api/api/pkg/api/handler/ueficredential_test.go @@ -0,0 +1,146 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package handler + +import ( + "context" + "encoding/json" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/labstack/echo/v4" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + tmocks "go.temporal.io/sdk/mocks" + "google.golang.org/protobuf/encoding/protojson" + + "github.com/NVIDIA/infra-controller/rest-api/api/pkg/api/handler/util/common" + "github.com/NVIDIA/infra-controller/rest-api/api/pkg/api/model" + sc "github.com/NVIDIA/infra-controller/rest-api/api/pkg/client/site" + authz "github.com/NVIDIA/infra-controller/rest-api/auth/pkg/authorization" + "github.com/NVIDIA/infra-controller/rest-api/common/pkg/coreproxy" + cutil "github.com/NVIDIA/infra-controller/rest-api/common/pkg/util" + cdbm "github.com/NVIDIA/infra-controller/rest-api/db/pkg/db/model" + cwssaws "github.com/NVIDIA/infra-controller/rest-api/workflow-schema/schema/site-agent/workflows/v1" +) + +func TestCreateUEFICredentialHandlerProxiesCredential(t *testing.T) { + for _, tc := range []struct { + kind model.UEFICredentialKind + credentialType cwssaws.CredentialType + }{ + {model.UEFICredentialKindHost, cwssaws.CredentialType_HostUefi}, + {model.UEFICredentialKindDPU, cwssaws.CredentialType_DpuUefi}, + } { + t.Run(string(tc.kind), func(t *testing.T) { + fixture := newUEFICredentialHandlerFixture(t) + rec, proxiedReq := fixture.request(t, model.APIUEFICredentialRequest{ + SiteID: fixture.siteID, + Kind: tc.kind, + Password: "secret-password", + }) + assert.Equal(t, http.StatusCreated, rec.Code) + assert.Equal(t, createCredentialMethod, proxiedReq.FullMethod) + assert.NotContains(t, string(proxiedReq.RequestJSON), "secret-password") + assert.NotEmpty(t, proxiedReq.EncryptedSecrets) + + var coreReq cwssaws.CredentialCreationRequest + require.NoError(t, protojson.Unmarshal(proxiedReq.RequestJSON, &coreReq)) + assert.Equal(t, tc.credentialType, coreReq.GetCredentialType()) + assert.Equal(t, coreproxy.RedactedPlaceholder, coreReq.GetPassword()) + + var resp model.APIUEFICredential + require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp)) + assert.Equal(t, fixture.siteID, resp.SiteID) + assert.Equal(t, tc.kind, resp.Kind) + assert.NotContains(t, rec.Body.String(), "password") + }) + } +} + +func TestCreateUEFICredentialHandlerRejectsInvalidRequest(t *testing.T) { + fixture := newUEFICredentialHandlerFixture(t) + rec, _ := fixture.request(t, model.APIUEFICredentialRequest{ + SiteID: fixture.siteID, + Kind: model.UEFICredentialKind("invalid"), + Password: "secret-password", + }) + assert.Equal(t, http.StatusBadRequest, rec.Code) +} + +type uefiCredentialHandlerFixture struct { + org string + siteID string + user interface{} + handler CreateUEFICredentialHandler + proxiedReq *coreproxy.Request +} + +func newUEFICredentialHandlerFixture(t *testing.T) uefiCredentialHandlerFixture { + t.Helper() + + dbSession := common.TestInitDB(t) + t.Cleanup(dbSession.Close) + common.TestSetupSchema(t, dbSession) + + org := "test-org" + user := common.TestBuildUser(t, dbSession, "test-starfleet-id", org, []string{authz.ProviderAdminRole}) + ip := common.TestBuildInfrastructureProvider(t, dbSession, "Test Infrastructure Provider", org, user) + site := common.TestBuildSite(t, dbSession, ip, "Test Site", user) + sDAO := cdbm.NewSiteDAO(dbSession) + _, err := sDAO.Update(context.Background(), nil, cdbm.SiteUpdateInput{ + SiteID: site.ID, + Status: cutil.GetPtr(cdbm.SiteStatusRegistered), + }) + require.NoError(t, err) + + proxiedReq := &coreproxy.Request{} + wrun := &tmocks.WorkflowRun{} + wrun.On("Get", mock.Anything, mock.Anything).Return(nil) + + tsc := &tmocks.Client{} + tsc.On( + "ExecuteWorkflow", + mock.Anything, + mock.Anything, + coreproxy.WorkflowName, + mock.MatchedBy(func(req coreproxy.Request) bool { + *proxiedReq = req + return true + }), + ).Return(wrun, nil) + + scp := sc.NewClientPool(nil) + scp.IDClientMap[site.ID.String()] = tsc + + return uefiCredentialHandlerFixture{ + org: org, + siteID: site.ID.String(), + user: user, + handler: NewCreateUEFICredentialHandler(dbSession, scp), + proxiedReq: proxiedReq, + } +} + +func (f uefiCredentialHandlerFixture) request(t *testing.T, apiReq model.APIUEFICredentialRequest) (*httptest.ResponseRecorder, coreproxy.Request) { + t.Helper() + + body, err := json.Marshal(apiReq) + require.NoError(t, err) + + e := echo.New() + req := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(string(body))) + req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) + rec := httptest.NewRecorder() + ec := e.NewContext(req, rec) + ec.SetParamNames("orgName") + ec.SetParamValues(f.org) + ec.Set("user", f.user) + + require.NoError(t, f.handler.Handle(ec)) + return rec, *f.proxiedReq +} diff --git a/rest-api/api/pkg/api/model/ueficredential.go b/rest-api/api/pkg/api/model/ueficredential.go new file mode 100644 index 0000000000..746a1f5030 --- /dev/null +++ b/rest-api/api/pkg/api/model/ueficredential.go @@ -0,0 +1,76 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package model + +import ( + validation "github.com/go-ozzo/ozzo-validation/v4" + validationis "github.com/go-ozzo/ozzo-validation/v4/is" + + cwssaws "github.com/NVIDIA/infra-controller/rest-api/workflow-schema/schema/site-agent/workflows/v1" +) + +// UEFICredentialKind selects the site-default UEFI credential to create. +type UEFICredentialKind string + +const ( + // UEFICredentialKindHost creates the site-default host UEFI credential. + UEFICredentialKindHost UEFICredentialKind = "Host" + // UEFICredentialKindDPU creates the site-default DPU UEFI credential. + UEFICredentialKindDPU UEFICredentialKind = "DPU" +) + +// APIUEFICredentialRequest creates a site-default UEFI credential. +type APIUEFICredentialRequest struct { + // SiteID is the ID of the Site where the credential is stored. + SiteID string `json:"siteId"` + // Kind selects the host or DPU UEFI credential. + Kind UEFICredentialKind `json:"kind"` + // Password is the credential password. + Password string `json:"password"` +} + +// APIUEFICredential is the UEFI credential response with the password omitted. +type APIUEFICredential struct { + // SiteID is the ID of the Site where the credential is stored. + SiteID string `json:"siteId"` + // Kind identifies the UEFI credential that was stored. + Kind UEFICredentialKind `json:"kind"` +} + +// Validate checks the request before it is converted to a proto. +func (r *APIUEFICredentialRequest) Validate() error { + if err := validation.ValidateStruct(r, + validation.Field(&r.SiteID, + validation.Required.Error(validationErrorValueRequired), + validationis.UUID.Error(validationErrorInvalidUUID)), + validation.Field(&r.Kind, + validation.Required.Error(validationErrorValueRequired), + validation.In(UEFICredentialKindHost, UEFICredentialKindDPU).Error("invalid kind (expected \"Host\" or \"DPU\")")), + validation.Field(&r.Password, + validation.Required.Error("password is required")), + ); err != nil { + return err + } + return nil +} + +// ToProto converts the validated request into a CredentialCreationRequest. +func (r *APIUEFICredentialRequest) ToProto() *cwssaws.CredentialCreationRequest { + credentialType := cwssaws.CredentialType_HostUefi + if r.Kind == UEFICredentialKindDPU { + credentialType = cwssaws.CredentialType_DpuUefi + } + return &cwssaws.CredentialCreationRequest{ + CredentialType: credentialType, + Password: r.Password, + } +} + +// ToResponse returns the accepted request data without the credential password. +func (r *APIUEFICredentialRequest) ToResponse() *APIUEFICredential { + return &APIUEFICredential{ + SiteID: r.SiteID, + Kind: r.Kind, + } +} diff --git a/rest-api/api/pkg/api/model/ueficredential_test.go b/rest-api/api/pkg/api/model/ueficredential_test.go new file mode 100644 index 0000000000..09b793ff8d --- /dev/null +++ b/rest-api/api/pkg/api/model/ueficredential_test.go @@ -0,0 +1,75 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package model + +import ( + "encoding/json" + "testing" + + "github.com/google/uuid" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + cwssaws "github.com/NVIDIA/infra-controller/rest-api/workflow-schema/schema/site-agent/workflows/v1" +) + +func TestAPIUEFICredentialRequestValidate(t *testing.T) { + siteID := uuid.NewString() + cases := []struct { + name string + req APIUEFICredentialRequest + wantErr bool + }{ + {"Host ok", APIUEFICredentialRequest{SiteID: siteID, Kind: UEFICredentialKindHost, Password: "pw"}, false}, + {"DPU ok", APIUEFICredentialRequest{SiteID: siteID, Kind: UEFICredentialKindDPU, Password: "pw"}, false}, + {"missing siteId", APIUEFICredentialRequest{Kind: UEFICredentialKindHost, Password: "pw"}, true}, + {"invalid siteId", APIUEFICredentialRequest{SiteID: "bad-site-id", Kind: UEFICredentialKindHost, Password: "pw"}, true}, + {"missing password", APIUEFICredentialRequest{SiteID: siteID, Kind: UEFICredentialKindHost}, true}, + {"invalid kind", APIUEFICredentialRequest{SiteID: siteID, Kind: UEFICredentialKind("nope"), Password: "pw"}, true}, + } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + err := tc.req.Validate() + if tc.wantErr { + assert.Error(t, err) + } else { + assert.NoError(t, err) + } + }) + } +} + +func TestAPIUEFICredentialRequestToProto(t *testing.T) { + for _, tc := range []struct { + kind UEFICredentialKind + credentialType cwssaws.CredentialType + }{ + {UEFICredentialKindHost, cwssaws.CredentialType_HostUefi}, + {UEFICredentialKindDPU, cwssaws.CredentialType_DpuUefi}, + } { + t.Run(string(tc.kind), func(t *testing.T) { + req := APIUEFICredentialRequest{Kind: tc.kind, Password: "pw"} + p := req.ToProto() + assert.Equal(t, tc.credentialType, p.GetCredentialType()) + assert.Equal(t, "pw", p.GetPassword()) + }) + } +} + +func TestAPIUEFICredentialRequestToResponseOmitsPassword(t *testing.T) { + req := APIUEFICredentialRequest{ + SiteID: uuid.NewString(), + Kind: UEFICredentialKindHost, + Password: "pw", + } + + resp := req.ToResponse() + assert.Equal(t, req.SiteID, resp.SiteID) + assert.Equal(t, req.Kind, resp.Kind) + + body, err := json.Marshal(resp) + require.NoError(t, err) + assert.NotContains(t, string(body), "password") + assert.NotContains(t, string(body), req.Password) +} diff --git a/rest-api/api/pkg/api/routes.go b/rest-api/api/pkg/api/routes.go index bf57c771e1..5741eefab2 100644 --- a/rest-api/api/pkg/api/routes.go +++ b/rest-api/api/pkg/api/routes.go @@ -37,6 +37,13 @@ func NewAPIRoutes(dbSession *cdb.Session, tc tClient.Client, tnc tClient.Namespa Method: http.MethodPut, Handler: apiHandler.NewCreateOrUpdateBMCCredentialHandler(dbSession, scp, cfg), }, + // Site-default UEFI credential endpoint (Provider Admin); equivalent to + // the admin CLI `credential add-uefi` command. + { + Path: apiPathPrefix + "/credential/uefi", + Method: http.MethodPost, + Handler: apiHandler.NewCreateUEFICredentialHandler(dbSession, scp), + }, // User endpoint { Path: apiPathPrefix + "/user/current", diff --git a/rest-api/api/pkg/api/routes_test.go b/rest-api/api/pkg/api/routes_test.go index 7cc900e9a5..c6de7acad0 100644 --- a/rest-api/api/pkg/api/routes_test.go +++ b/rest-api/api/pkg/api/routes_test.go @@ -35,7 +35,7 @@ func TestNewAPIRoutes(t *testing.T) { routeCount := map[string]int{ "metadata": 1, - "credential": 1, + "credential": 2, "service-account": 1, "infrastructure-provider": 4, "tenant": 4, @@ -112,6 +112,8 @@ func TestNewAPIRoutes(t *testing.T) { bmcCredentialPath := "/org/:orgName/" + cfg.GetAPIName() + "/credential/bmc" assertRouteExists(t, got, http.MethodPut, bmcCredentialPath) + uefiCredentialPath := "/org/:orgName/" + cfg.GetAPIName() + "/credential/uefi" + assertRouteExists(t, got, http.MethodPost, uefiCredentialPath) machineAdminPath := "/org/:orgName/" + cfg.GetAPIName() + "/machine/:id" assertRouteExists(t, got, http.MethodPatch, machineAdminPath+"/bmc/reset") diff --git a/rest-api/cli/pkg/commands_test.go b/rest-api/cli/pkg/commands_test.go index ce206e2ede..3497349e2d 100644 --- a/rest-api/cli/pkg/commands_test.go +++ b/rest-api/cli/pkg/commands_test.go @@ -855,6 +855,29 @@ func TestNewApp_CurrentSingletonCommandSurface(t *testing.T) { } } +func TestNewApp_UEFICredentialCreateCommand(t *testing.T) { + app, err := NewApp(openapi.Spec) + require.NoError(t, err, "NewApp failed") + + var credential *cli.Command + for _, command := range app.Commands { + if command.Name == "uefi-credential" { + credential = command + break + } + } + require.NotNil(t, credential, "UEFI credential must be exposed by the embedded OpenAPI spec") + + var create *cli.Command + for _, command := range credential.Subcommands { + if command.Name == "create" { + create = command + break + } + } + require.NotNil(t, create, "UEFI credential must expose a create command") +} + // TestBuildCommands_CurrentSingletonsAreRunnable asserts that every // get-current- singleton in the embedded spec is reachable from the // non-interactive CLI under the `current` action that the interactive TUI diff --git a/rest-api/openapi/spec.yaml b/rest-api/openapi/spec.yaml index dafd044124..fd9ef336ac 100644 --- a/rest-api/openapi/spec.yaml +++ b/rest-api/openapi/spec.yaml @@ -121,6 +121,9 @@ tags: - name: BMC Credential description: |- BMC Credential endpoints allow creating and updating BMC credentials across all Machines of a Site + - name: UEFI Credential + description: |- + UEFI Credential endpoints allow creating site-default host and DPU UEFI credentials for a Site - name: Allocation description: |- Allocations are the mechanism by which Provider can delegate Network and Compute resources to Tenant. @@ -1196,6 +1199,47 @@ paths: Create or update a site-wide or per-BMC root credential. Equivalent to `carbide-admin-cli credential add-bmc`. + User must have authorization role with `PROVIDER_ADMIN` suffix. + '/v2/org/{org}/nico/credential/uefi': + parameters: + - schema: + type: string + name: org + in: path + required: true + description: Name of the Org + post: + summary: Create UEFI Credential + tags: + - UEFI Credential + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/UEFICredentialRequest' + responses: + '201': + description: UEFI credential was created + content: + application/json: + schema: + $ref: '#/components/schemas/UEFICredential' + '400': + $ref: '#/components/responses/ValidationError' + '403': + $ref: '#/components/responses/ForbiddenError' + '409': + description: The selected site-default UEFI credential already exists + content: + application/json: + schema: + $ref: '#/components/schemas/NICoAPIError' + operationId: create-uefi-credential + description: |- + Create a site-default host or DPU UEFI credential. The request fails + if the selected site-default credential already exists. + User must have authorization role with `PROVIDER_ADMIN` suffix. '/v2/org/{org}/nico/allocation': parameters: @@ -13540,6 +13584,47 @@ components: macAddress: type: string description: BMC MAC address. Required for kind BMCRoot, ignored for SiteWideRoot. + UEFICredentialRequest: + type: object + title: UEFICredentialRequest + description: Request to create a site-default UEFI credential. + required: + - siteId + - kind + - password + properties: + siteId: + type: string + format: uuid + description: ID of the Site where the credential is stored. + kind: + type: string + description: Which site-default UEFI credential to create. + enum: + - Host + - DPU + password: + type: string + minLength: 1 + description: Credential password. + UEFICredential: + type: object + title: UEFICredential + description: UEFI credential metadata returned after creation. The password is never returned. + required: + - siteId + - kind + properties: + siteId: + type: string + format: uuid + description: ID of the Site where the credential is stored. + kind: + type: string + description: Which site-default UEFI credential was created. + enum: + - Host + - DPU BMCResetRequest: type: object title: BMCResetRequest diff --git a/rest-api/sdk/standard/api_uefi_credential.go b/rest-api/sdk/standard/api_uefi_credential.go new file mode 100644 index 0000000000..6a8cf21f1f --- /dev/null +++ b/rest-api/sdk/standard/api_uefi_credential.go @@ -0,0 +1,173 @@ +/* +NVIDIA Infra Controller REST API + +NVIDIA Infra Controller REST API allows users to create and manage resources, e.g., VPCs, Subnets, and Instances, across all connected NVIDIA Infra Controller datacenters, also referred to as Sites. + +API version: 2.0.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package standard + +import ( + "bytes" + "context" + "io" + "net/http" + "net/url" + "strings" +) + +// UEFICredentialAPIService UEFICredentialAPI service +type UEFICredentialAPIService service + +type ApiCreateUefiCredentialRequest struct { + ctx context.Context + ApiService *UEFICredentialAPIService + org string + uEFICredentialRequest *UEFICredentialRequest +} + +func (r ApiCreateUefiCredentialRequest) UEFICredentialRequest(uEFICredentialRequest UEFICredentialRequest) ApiCreateUefiCredentialRequest { + r.uEFICredentialRequest = &uEFICredentialRequest + return r +} + +func (r ApiCreateUefiCredentialRequest) Execute() (*UEFICredential, *http.Response, error) { + return r.ApiService.CreateUefiCredentialExecute(r) +} + +/* +CreateUefiCredential Create UEFI Credential + +Create a site-default host or DPU UEFI credential. The request fails +if the selected site-default credential already exists. + +User must have authorization role with `PROVIDER_ADMIN` suffix. + + @param ctx context.Context - for authentication, logging, cancellation, deadlines, tracing, etc. Passed from http.Request or context.Background(). + @param org Name of the Org + @return ApiCreateUefiCredentialRequest +*/ +func (a *UEFICredentialAPIService) CreateUefiCredential(ctx context.Context, org string) ApiCreateUefiCredentialRequest { + return ApiCreateUefiCredentialRequest{ + ApiService: a, + ctx: ctx, + org: org, + } +} + +// Execute executes the request +// +// @return UEFICredential +func (a *UEFICredentialAPIService) CreateUefiCredentialExecute(r ApiCreateUefiCredentialRequest) (*UEFICredential, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *UEFICredential + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "UEFICredentialAPIService.CreateUefiCredential") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/v2/org/{org}/nico/credential/uefi" + localVarPath = strings.Replace(localVarPath, "{"+"org"+"}", url.PathEscape(parameterValueToString(r.org, "org")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if r.uEFICredentialRequest == nil { + return localVarReturnValue, nil, reportError("uEFICredentialRequest is required and must be specified") + } + + // to determine the Content-Type header + localVarHTTPContentTypes := []string{"application/json"} + + // set Content-Type header + localVarHTTPContentType := selectHeaderContentType(localVarHTTPContentTypes) + if localVarHTTPContentType != "" { + localVarHeaderParams["Content-Type"] = localVarHTTPContentType + } + + // to determine the Accept header + localVarHTTPHeaderAccepts := []string{"application/json"} + + // set Accept header + localVarHTTPHeaderAccept := selectHeaderAccept(localVarHTTPHeaderAccepts) + if localVarHTTPHeaderAccept != "" { + localVarHeaderParams["Accept"] = localVarHTTPHeaderAccept + } + // body params + localVarPostBody = r.uEFICredentialRequest + req, err := a.client.prepareRequest(r.ctx, localVarPath, localVarHTTPMethod, localVarPostBody, localVarHeaderParams, localVarQueryParams, localVarFormParams, formFiles) + if err != nil { + return localVarReturnValue, nil, err + } + + localVarHTTPResponse, err := a.client.callAPI(req) + if err != nil || localVarHTTPResponse == nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + localVarBody, err := io.ReadAll(localVarHTTPResponse.Body) + localVarHTTPResponse.Body.Close() + localVarHTTPResponse.Body = io.NopCloser(bytes.NewBuffer(localVarBody)) + if err != nil { + return localVarReturnValue, localVarHTTPResponse, err + } + + if localVarHTTPResponse.StatusCode >= 300 { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: localVarHTTPResponse.Status, + } + if localVarHTTPResponse.StatusCode == 400 { + var v NICoAPIError + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 403 { + var v NICoAPIError + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + return localVarReturnValue, localVarHTTPResponse, newErr + } + if localVarHTTPResponse.StatusCode == 409 { + var v NICoAPIError + err = a.client.decode(&v, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr.error = err.Error() + return localVarReturnValue, localVarHTTPResponse, newErr + } + newErr.error = formatErrorMessage(localVarHTTPResponse.Status, &v) + newErr.model = v + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + err = a.client.decode(&localVarReturnValue, localVarBody, localVarHTTPResponse.Header.Get("Content-Type")) + if err != nil { + newErr := &GenericOpenAPIError{ + body: localVarBody, + error: err.Error(), + } + return localVarReturnValue, localVarHTTPResponse, newErr + } + + return localVarReturnValue, localVarHTTPResponse, nil +} diff --git a/rest-api/sdk/standard/client.go b/rest-api/sdk/standard/client.go index 8ae75d9346..b63ad339fe 100644 --- a/rest-api/sdk/standard/client.go +++ b/rest-api/sdk/standard/client.go @@ -121,6 +121,8 @@ type APIClient struct { TrayAPI *TrayAPIService + UEFICredentialAPI *UEFICredentialAPIService + UserAPI *UserAPIService VPCAPI *VPCAPIService @@ -181,6 +183,7 @@ func NewAPIClient(cfg *Configuration) *APIClient { c.TenantAccountAPI = (*TenantAccountAPIService)(&c.common) c.TenantIdentityAPI = (*TenantIdentityAPIService)(&c.common) c.TrayAPI = (*TrayAPIService)(&c.common) + c.UEFICredentialAPI = (*UEFICredentialAPIService)(&c.common) c.UserAPI = (*UserAPIService)(&c.common) c.VPCAPI = (*VPCAPIService)(&c.common) c.VPCPeeringAPI = (*VPCPeeringAPIService)(&c.common) diff --git a/rest-api/sdk/standard/model_uefi_credential.go b/rest-api/sdk/standard/model_uefi_credential.go new file mode 100644 index 0000000000..a39021ce16 --- /dev/null +++ b/rest-api/sdk/standard/model_uefi_credential.go @@ -0,0 +1,186 @@ +/* +NVIDIA Infra Controller REST API + +NVIDIA Infra Controller REST API allows users to create and manage resources, e.g., VPCs, Subnets, and Instances, across all connected NVIDIA Infra Controller datacenters, also referred to as Sites. + +API version: 2.0.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package standard + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the UEFICredential type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &UEFICredential{} + +// UEFICredential UEFI credential metadata returned after creation. The password is never returned. +type UEFICredential struct { + // ID of the Site where the credential is stored. + SiteId string `json:"siteId"` + // Which site-default UEFI credential was created. + Kind string `json:"kind"` +} + +type _UEFICredential UEFICredential + +// NewUEFICredential instantiates a new UEFICredential object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewUEFICredential(siteId string, kind string) *UEFICredential { + this := UEFICredential{} + this.SiteId = siteId + this.Kind = kind + return &this +} + +// NewUEFICredentialWithDefaults instantiates a new UEFICredential object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewUEFICredentialWithDefaults() *UEFICredential { + this := UEFICredential{} + return &this +} + +// GetSiteId returns the SiteId field value +func (o *UEFICredential) GetSiteId() string { + if o == nil { + var ret string + return ret + } + + return o.SiteId +} + +// GetSiteIdOk returns a tuple with the SiteId field value +// and a boolean to check if the value has been set. +func (o *UEFICredential) GetSiteIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.SiteId, true +} + +// SetSiteId sets field value +func (o *UEFICredential) SetSiteId(v string) { + o.SiteId = v +} + +// GetKind returns the Kind field value +func (o *UEFICredential) GetKind() string { + if o == nil { + var ret string + return ret + } + + return o.Kind +} + +// GetKindOk returns a tuple with the Kind field value +// and a boolean to check if the value has been set. +func (o *UEFICredential) GetKindOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Kind, true +} + +// SetKind sets field value +func (o *UEFICredential) SetKind(v string) { + o.Kind = v +} + +func (o UEFICredential) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o UEFICredential) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["siteId"] = o.SiteId + toSerialize["kind"] = o.Kind + return toSerialize, nil +} + +func (o *UEFICredential) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "siteId", + "kind", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if value, exists := allProperties[requiredProperty]; !exists || value == nil { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varUEFICredential := _UEFICredential{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varUEFICredential) + + if err != nil { + return err + } + + *o = UEFICredential(varUEFICredential) + + return err +} + +type NullableUEFICredential struct { + value *UEFICredential + isSet bool +} + +func (v NullableUEFICredential) Get() *UEFICredential { + return v.value +} + +func (v *NullableUEFICredential) Set(val *UEFICredential) { + v.value = val + v.isSet = true +} + +func (v NullableUEFICredential) IsSet() bool { + return v.isSet +} + +func (v *NullableUEFICredential) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableUEFICredential(val *UEFICredential) *NullableUEFICredential { + return &NullableUEFICredential{value: val, isSet: true} +} + +func (v NullableUEFICredential) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableUEFICredential) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/rest-api/sdk/standard/model_uefi_credential_request.go b/rest-api/sdk/standard/model_uefi_credential_request.go new file mode 100644 index 0000000000..db463ecb0a --- /dev/null +++ b/rest-api/sdk/standard/model_uefi_credential_request.go @@ -0,0 +1,215 @@ +/* +NVIDIA Infra Controller REST API + +NVIDIA Infra Controller REST API allows users to create and manage resources, e.g., VPCs, Subnets, and Instances, across all connected NVIDIA Infra Controller datacenters, also referred to as Sites. + +API version: 2.0.0 +*/ + +// Code generated by OpenAPI Generator (https://openapi-generator.tech); DO NOT EDIT. + +package standard + +import ( + "bytes" + "encoding/json" + "fmt" +) + +// checks if the UEFICredentialRequest type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &UEFICredentialRequest{} + +// UEFICredentialRequest Request to create a site-default UEFI credential. +type UEFICredentialRequest struct { + // ID of the Site where the credential is stored. + SiteId string `json:"siteId"` + // Which site-default UEFI credential to create. + Kind string `json:"kind"` + // Credential password. + Password string `json:"password"` +} + +type _UEFICredentialRequest UEFICredentialRequest + +// NewUEFICredentialRequest instantiates a new UEFICredentialRequest object +// This constructor will assign default values to properties that have it defined, +// and makes sure properties required by API are set, but the set of arguments +// will change when the set of required properties is changed +func NewUEFICredentialRequest(siteId string, kind string, password string) *UEFICredentialRequest { + this := UEFICredentialRequest{} + this.SiteId = siteId + this.Kind = kind + this.Password = password + return &this +} + +// NewUEFICredentialRequestWithDefaults instantiates a new UEFICredentialRequest object +// This constructor will only assign default values to properties that have it defined, +// but it doesn't guarantee that properties required by API are set +func NewUEFICredentialRequestWithDefaults() *UEFICredentialRequest { + this := UEFICredentialRequest{} + return &this +} + +// GetSiteId returns the SiteId field value +func (o *UEFICredentialRequest) GetSiteId() string { + if o == nil { + var ret string + return ret + } + + return o.SiteId +} + +// GetSiteIdOk returns a tuple with the SiteId field value +// and a boolean to check if the value has been set. +func (o *UEFICredentialRequest) GetSiteIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.SiteId, true +} + +// SetSiteId sets field value +func (o *UEFICredentialRequest) SetSiteId(v string) { + o.SiteId = v +} + +// GetKind returns the Kind field value +func (o *UEFICredentialRequest) GetKind() string { + if o == nil { + var ret string + return ret + } + + return o.Kind +} + +// GetKindOk returns a tuple with the Kind field value +// and a boolean to check if the value has been set. +func (o *UEFICredentialRequest) GetKindOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Kind, true +} + +// SetKind sets field value +func (o *UEFICredentialRequest) SetKind(v string) { + o.Kind = v +} + +// GetPassword returns the Password field value +func (o *UEFICredentialRequest) GetPassword() string { + if o == nil { + var ret string + return ret + } + + return o.Password +} + +// GetPasswordOk returns a tuple with the Password field value +// and a boolean to check if the value has been set. +func (o *UEFICredentialRequest) GetPasswordOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.Password, true +} + +// SetPassword sets field value +func (o *UEFICredentialRequest) SetPassword(v string) { + o.Password = v +} + +func (o UEFICredentialRequest) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o UEFICredentialRequest) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["siteId"] = o.SiteId + toSerialize["kind"] = o.Kind + toSerialize["password"] = o.Password + return toSerialize, nil +} + +func (o *UEFICredentialRequest) UnmarshalJSON(data []byte) (err error) { + // This validates that all required properties are included in the JSON object + // by unmarshalling the object into a generic map with string keys and checking + // that every required field exists as a key in the generic map. + requiredProperties := []string{ + "siteId", + "kind", + "password", + } + + allProperties := make(map[string]interface{}) + + err = json.Unmarshal(data, &allProperties) + + if err != nil { + return err + } + + for _, requiredProperty := range requiredProperties { + if value, exists := allProperties[requiredProperty]; !exists || value == nil { + return fmt.Errorf("no value given for required property %v", requiredProperty) + } + } + + varUEFICredentialRequest := _UEFICredentialRequest{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varUEFICredentialRequest) + + if err != nil { + return err + } + + *o = UEFICredentialRequest(varUEFICredentialRequest) + + return err +} + +type NullableUEFICredentialRequest struct { + value *UEFICredentialRequest + isSet bool +} + +func (v NullableUEFICredentialRequest) Get() *UEFICredentialRequest { + return v.value +} + +func (v *NullableUEFICredentialRequest) Set(val *UEFICredentialRequest) { + v.value = val + v.isSet = true +} + +func (v NullableUEFICredentialRequest) IsSet() bool { + return v.isSet +} + +func (v *NullableUEFICredentialRequest) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableUEFICredentialRequest(val *UEFICredentialRequest) *NullableUEFICredentialRequest { + return &NullableUEFICredentialRequest{value: val, isSet: true} +} + +func (v NullableUEFICredentialRequest) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableUEFICredentialRequest) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} From 2c41f241af2af60d7101b4aa0fad94c431fe5fdd Mon Sep 17 00:00:00 2001 From: Kyle Felter Date: Thu, 9 Jul 2026 18:28:54 -0500 Subject: [PATCH 2/3] fix: Update UEFI credential proto imports Signed-off-by: Kyle Felter --- rest-api/api/pkg/api/handler/ueficredential_test.go | 10 +++++----- rest-api/api/pkg/api/model/ueficredential.go | 10 +++++----- rest-api/api/pkg/api/model/ueficredential_test.go | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/rest-api/api/pkg/api/handler/ueficredential_test.go b/rest-api/api/pkg/api/handler/ueficredential_test.go index 9dca055caf..c3b7d1d9c1 100644 --- a/rest-api/api/pkg/api/handler/ueficredential_test.go +++ b/rest-api/api/pkg/api/handler/ueficredential_test.go @@ -25,16 +25,16 @@ import ( "github.com/NVIDIA/infra-controller/rest-api/common/pkg/coreproxy" cutil "github.com/NVIDIA/infra-controller/rest-api/common/pkg/util" cdbm "github.com/NVIDIA/infra-controller/rest-api/db/pkg/db/model" - cwssaws "github.com/NVIDIA/infra-controller/rest-api/workflow-schema/schema/site-agent/workflows/v1" + corev1 "github.com/NVIDIA/infra-controller/rest-api/proto/core/gen/v1" ) func TestCreateUEFICredentialHandlerProxiesCredential(t *testing.T) { for _, tc := range []struct { kind model.UEFICredentialKind - credentialType cwssaws.CredentialType + credentialType corev1.CredentialType }{ - {model.UEFICredentialKindHost, cwssaws.CredentialType_HostUefi}, - {model.UEFICredentialKindDPU, cwssaws.CredentialType_DpuUefi}, + {model.UEFICredentialKindHost, corev1.CredentialType_HostUefi}, + {model.UEFICredentialKindDPU, corev1.CredentialType_DpuUefi}, } { t.Run(string(tc.kind), func(t *testing.T) { fixture := newUEFICredentialHandlerFixture(t) @@ -48,7 +48,7 @@ func TestCreateUEFICredentialHandlerProxiesCredential(t *testing.T) { assert.NotContains(t, string(proxiedReq.RequestJSON), "secret-password") assert.NotEmpty(t, proxiedReq.EncryptedSecrets) - var coreReq cwssaws.CredentialCreationRequest + var coreReq corev1.CredentialCreationRequest require.NoError(t, protojson.Unmarshal(proxiedReq.RequestJSON, &coreReq)) assert.Equal(t, tc.credentialType, coreReq.GetCredentialType()) assert.Equal(t, coreproxy.RedactedPlaceholder, coreReq.GetPassword()) diff --git a/rest-api/api/pkg/api/model/ueficredential.go b/rest-api/api/pkg/api/model/ueficredential.go index 746a1f5030..9476cda3bd 100644 --- a/rest-api/api/pkg/api/model/ueficredential.go +++ b/rest-api/api/pkg/api/model/ueficredential.go @@ -7,7 +7,7 @@ import ( validation "github.com/go-ozzo/ozzo-validation/v4" validationis "github.com/go-ozzo/ozzo-validation/v4/is" - cwssaws "github.com/NVIDIA/infra-controller/rest-api/workflow-schema/schema/site-agent/workflows/v1" + corev1 "github.com/NVIDIA/infra-controller/rest-api/proto/core/gen/v1" ) // UEFICredentialKind selects the site-default UEFI credential to create. @@ -56,12 +56,12 @@ func (r *APIUEFICredentialRequest) Validate() error { } // ToProto converts the validated request into a CredentialCreationRequest. -func (r *APIUEFICredentialRequest) ToProto() *cwssaws.CredentialCreationRequest { - credentialType := cwssaws.CredentialType_HostUefi +func (r *APIUEFICredentialRequest) ToProto() *corev1.CredentialCreationRequest { + credentialType := corev1.CredentialType_HostUefi if r.Kind == UEFICredentialKindDPU { - credentialType = cwssaws.CredentialType_DpuUefi + credentialType = corev1.CredentialType_DpuUefi } - return &cwssaws.CredentialCreationRequest{ + return &corev1.CredentialCreationRequest{ CredentialType: credentialType, Password: r.Password, } diff --git a/rest-api/api/pkg/api/model/ueficredential_test.go b/rest-api/api/pkg/api/model/ueficredential_test.go index 09b793ff8d..61fe0ed9a2 100644 --- a/rest-api/api/pkg/api/model/ueficredential_test.go +++ b/rest-api/api/pkg/api/model/ueficredential_test.go @@ -11,7 +11,7 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" - cwssaws "github.com/NVIDIA/infra-controller/rest-api/workflow-schema/schema/site-agent/workflows/v1" + corev1 "github.com/NVIDIA/infra-controller/rest-api/proto/core/gen/v1" ) func TestAPIUEFICredentialRequestValidate(t *testing.T) { @@ -43,10 +43,10 @@ func TestAPIUEFICredentialRequestValidate(t *testing.T) { func TestAPIUEFICredentialRequestToProto(t *testing.T) { for _, tc := range []struct { kind UEFICredentialKind - credentialType cwssaws.CredentialType + credentialType corev1.CredentialType }{ - {UEFICredentialKindHost, cwssaws.CredentialType_HostUefi}, - {UEFICredentialKindDPU, cwssaws.CredentialType_DpuUefi}, + {UEFICredentialKindHost, corev1.CredentialType_HostUefi}, + {UEFICredentialKindDPU, corev1.CredentialType_DpuUefi}, } { t.Run(string(tc.kind), func(t *testing.T) { req := APIUEFICredentialRequest{Kind: tc.kind, Password: "pw"} From 727eb8686829c727cd0550d36b824e4366ec82b3 Mon Sep 17 00:00:00 2001 From: Kyle Felter Date: Thu, 9 Jul 2026 18:50:34 -0500 Subject: [PATCH 3/3] fix: Add generated SDK source headers Signed-off-by: Kyle Felter --- rest-api/sdk/standard/api_uefi_credential.go | 3 +++ rest-api/sdk/standard/model_uefi_credential.go | 3 +++ rest-api/sdk/standard/model_uefi_credential_request.go | 3 +++ 3 files changed, 9 insertions(+) diff --git a/rest-api/sdk/standard/api_uefi_credential.go b/rest-api/sdk/standard/api_uefi_credential.go index 6a8cf21f1f..b074ad9f5e 100644 --- a/rest-api/sdk/standard/api_uefi_credential.go +++ b/rest-api/sdk/standard/api_uefi_credential.go @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + /* NVIDIA Infra Controller REST API diff --git a/rest-api/sdk/standard/model_uefi_credential.go b/rest-api/sdk/standard/model_uefi_credential.go index a39021ce16..82bae2a7a9 100644 --- a/rest-api/sdk/standard/model_uefi_credential.go +++ b/rest-api/sdk/standard/model_uefi_credential.go @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + /* NVIDIA Infra Controller REST API diff --git a/rest-api/sdk/standard/model_uefi_credential_request.go b/rest-api/sdk/standard/model_uefi_credential_request.go index db463ecb0a..880c512d4f 100644 --- a/rest-api/sdk/standard/model_uefi_credential_request.go +++ b/rest-api/sdk/standard/model_uefi_credential_request.go @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + /* NVIDIA Infra Controller REST API