From cc4c71c715133b071ba57c939a2d7d5622e9060c Mon Sep 17 00:00:00 2001 From: Kyle Felter Date: Mon, 13 Jul 2026 19:42:37 -0500 Subject: [PATCH 1/4] feat: Add measured boot trust approvals Signed-off-by: Kyle Felter --- .../api/pkg/api/handler/measurementtrust.go | 243 ++++++++ .../pkg/api/handler/measurementtrust_test.go | 236 ++++++++ .../api/pkg/api/model/measurementtrust.go | 252 +++++++++ .../pkg/api/model/measurementtrust_test.go | 113 ++++ rest-api/api/pkg/api/routes.go | 31 ++ rest-api/api/pkg/api/routes_test.go | 8 + rest-api/openapi/spec.yaml | 383 +++++++++++++ .../api_measured_boot_trusted_machine.go | 518 ++++++++++++++++++ .../api_measured_boot_trusted_profile.go | 518 ++++++++++++++++++ rest-api/sdk/standard/client.go | 6 + .../model_measurement_trusted_machine.go | 327 +++++++++++ ...surement_trusted_machine_create_request.go | 289 ++++++++++ .../model_measurement_trusted_profile.go | 327 +++++++++++ ...surement_trusted_profile_create_request.go | 289 ++++++++++ 14 files changed, 3540 insertions(+) create mode 100644 rest-api/api/pkg/api/handler/measurementtrust.go create mode 100644 rest-api/api/pkg/api/handler/measurementtrust_test.go create mode 100644 rest-api/api/pkg/api/model/measurementtrust.go create mode 100644 rest-api/api/pkg/api/model/measurementtrust_test.go create mode 100644 rest-api/sdk/standard/api_measured_boot_trusted_machine.go create mode 100644 rest-api/sdk/standard/api_measured_boot_trusted_profile.go create mode 100644 rest-api/sdk/standard/model_measurement_trusted_machine.go create mode 100644 rest-api/sdk/standard/model_measurement_trusted_machine_create_request.go create mode 100644 rest-api/sdk/standard/model_measurement_trusted_profile.go create mode 100644 rest-api/sdk/standard/model_measurement_trusted_profile_create_request.go diff --git a/rest-api/api/pkg/api/handler/measurementtrust.go b/rest-api/api/pkg/api/handler/measurementtrust.go new file mode 100644 index 0000000000..66e8b7c7a0 --- /dev/null +++ b/rest-api/api/pkg/api/handler/measurementtrust.go @@ -0,0 +1,243 @@ +// 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" + corev1 "github.com/NVIDIA/infra-controller/rest-api/proto/core/gen/v1" +) + +type measurementTrustHandler struct { + dbSession *cdb.Session + scp *sc.ClientPool + tracerSpan *cutil.TracerSpan +} + +func newMeasurementTrustHandler(dbSession *cdb.Session, scp *sc.ClientPool) measurementTrustHandler { + return measurementTrustHandler{ + dbSession: dbSession, + scp: scp, + tracerSpan: cutil.NewTracerSpan(), + } +} + +// CreateMeasurementTrustedMachineHandler creates a machine trust approval. +type CreateMeasurementTrustedMachineHandler struct{ measurementTrustHandler } + +// NewCreateMeasurementTrustedMachineHandler returns a machine trust approval creation handler. +func NewCreateMeasurementTrustedMachineHandler(dbSession *cdb.Session, scp *sc.ClientPool) CreateMeasurementTrustedMachineHandler { + return CreateMeasurementTrustedMachineHandler{newMeasurementTrustHandler(dbSession, scp)} +} + +// Handle creates a machine trust approval. +func (h CreateMeasurementTrustedMachineHandler) Handle(c echo.Context) error { + org, dbUser, ctx, logger, handlerSpan := common.SetupHandler("MeasurementTrustedMachine", "Create", c, h.tracerSpan) + if handlerSpan != nil { + defer handlerSpan.End() + } + + var apiReq model.APIMeasurementTrustedMachineCreateRequest + 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) + } + + coreResp := &corev1.AddMeasurementTrustedMachineResponse{} + apiErr = common.ExecuteCoreGRPC(ctx, stc, corev1.Forge_AddMeasurementTrustedMachine_FullMethodName, apiReq.ToProto(), coreResp, siteID) + if apiErr != nil { + logAPIError(logger, apiErr, "failed to create machine trust approval") + return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, nil) + } + return c.JSON(http.StatusCreated, model.APIMeasurementTrustedMachineFromProto(coreResp.GetApprovalRecord())) +} + +// ListMeasurementTrustedMachinesHandler lists machine trust approvals. +type ListMeasurementTrustedMachinesHandler struct{ measurementTrustHandler } + +// NewListMeasurementTrustedMachinesHandler returns a machine trust approval list handler. +func NewListMeasurementTrustedMachinesHandler(dbSession *cdb.Session, scp *sc.ClientPool) ListMeasurementTrustedMachinesHandler { + return ListMeasurementTrustedMachinesHandler{newMeasurementTrustHandler(dbSession, scp)} +} + +// Handle lists machine trust approvals. +func (h ListMeasurementTrustedMachinesHandler) Handle(c echo.Context) error { + org, dbUser, ctx, logger, handlerSpan := common.SetupHandler("MeasurementTrustedMachine", "List", c, h.tracerSpan) + if handlerSpan != nil { + defer handlerSpan.End() + } + + stc, siteID, apiErr := common.AuthorizeProviderSiteForCore(common.AuthorizeProviderSiteForCoreInput{ + Ctx: ctx, Logger: logger, DBSession: h.dbSession, SCP: h.scp, Org: org, User: dbUser, SiteID: c.QueryParam("siteId"), + }) + if apiErr != nil { + return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, apiErr.Data) + } + + coreResp := &corev1.ListMeasurementTrustedMachinesResponse{} + apiErr = common.ExecuteCoreGRPC(ctx, stc, corev1.Forge_ListMeasurementTrustedMachines_FullMethodName, &corev1.ListMeasurementTrustedMachinesRequest{}, coreResp, siteID) + if apiErr != nil { + logAPIError(logger, apiErr, "failed to list machine trust approvals") + return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, nil) + } + return c.JSON(http.StatusOK, model.APIMeasurementTrustedMachinesFromProto(coreResp.GetApprovalRecords())) +} + +// DeleteMeasurementTrustedMachineHandler deletes a machine trust approval. +type DeleteMeasurementTrustedMachineHandler struct{ measurementTrustHandler } + +// NewDeleteMeasurementTrustedMachineHandler returns a machine trust approval deletion handler. +func NewDeleteMeasurementTrustedMachineHandler(dbSession *cdb.Session, scp *sc.ClientPool) DeleteMeasurementTrustedMachineHandler { + return DeleteMeasurementTrustedMachineHandler{newMeasurementTrustHandler(dbSession, scp)} +} + +// Handle deletes a machine trust approval. +func (h DeleteMeasurementTrustedMachineHandler) Handle(c echo.Context) error { + org, dbUser, ctx, logger, handlerSpan := common.SetupHandler("MeasurementTrustedMachine", "Delete", c, h.tracerSpan) + if handlerSpan != nil { + defer handlerSpan.End() + } + + coreReq, err := model.MeasurementTrustedMachineRemoveProto(c.QueryParam("selector"), c.Param("id")) + if 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: c.QueryParam("siteId"), + }) + if apiErr != nil { + return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, apiErr.Data) + } + + coreResp := &corev1.RemoveMeasurementTrustedMachineResponse{} + apiErr = common.ExecuteCoreGRPC(ctx, stc, corev1.Forge_RemoveMeasurementTrustedMachine_FullMethodName, coreReq, coreResp, siteID) + if apiErr != nil { + logAPIError(logger, apiErr, "failed to delete machine trust approval") + return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, nil) + } + return c.JSON(http.StatusOK, model.APIMeasurementTrustedMachineFromProto(coreResp.GetApprovalRecord())) +} + +// CreateMeasurementTrustedProfileHandler creates a profile trust approval. +type CreateMeasurementTrustedProfileHandler struct{ measurementTrustHandler } + +// NewCreateMeasurementTrustedProfileHandler returns a profile trust approval creation handler. +func NewCreateMeasurementTrustedProfileHandler(dbSession *cdb.Session, scp *sc.ClientPool) CreateMeasurementTrustedProfileHandler { + return CreateMeasurementTrustedProfileHandler{newMeasurementTrustHandler(dbSession, scp)} +} + +// Handle creates a profile trust approval. +func (h CreateMeasurementTrustedProfileHandler) Handle(c echo.Context) error { + org, dbUser, ctx, logger, handlerSpan := common.SetupHandler("MeasurementTrustedProfile", "Create", c, h.tracerSpan) + if handlerSpan != nil { + defer handlerSpan.End() + } + + var apiReq model.APIMeasurementTrustedProfileCreateRequest + 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) + } + + coreResp := &corev1.AddMeasurementTrustedProfileResponse{} + apiErr = common.ExecuteCoreGRPC(ctx, stc, corev1.Forge_AddMeasurementTrustedProfile_FullMethodName, apiReq.ToProto(), coreResp, siteID) + if apiErr != nil { + logAPIError(logger, apiErr, "failed to create profile trust approval") + return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, nil) + } + return c.JSON(http.StatusCreated, model.APIMeasurementTrustedProfileFromProto(coreResp.GetApprovalRecord())) +} + +// ListMeasurementTrustedProfilesHandler lists profile trust approvals. +type ListMeasurementTrustedProfilesHandler struct{ measurementTrustHandler } + +// NewListMeasurementTrustedProfilesHandler returns a profile trust approval list handler. +func NewListMeasurementTrustedProfilesHandler(dbSession *cdb.Session, scp *sc.ClientPool) ListMeasurementTrustedProfilesHandler { + return ListMeasurementTrustedProfilesHandler{newMeasurementTrustHandler(dbSession, scp)} +} + +// Handle lists profile trust approvals. +func (h ListMeasurementTrustedProfilesHandler) Handle(c echo.Context) error { + org, dbUser, ctx, logger, handlerSpan := common.SetupHandler("MeasurementTrustedProfile", "List", c, h.tracerSpan) + if handlerSpan != nil { + defer handlerSpan.End() + } + + stc, siteID, apiErr := common.AuthorizeProviderSiteForCore(common.AuthorizeProviderSiteForCoreInput{ + Ctx: ctx, Logger: logger, DBSession: h.dbSession, SCP: h.scp, Org: org, User: dbUser, SiteID: c.QueryParam("siteId"), + }) + if apiErr != nil { + return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, apiErr.Data) + } + + coreResp := &corev1.ListMeasurementTrustedProfilesResponse{} + apiErr = common.ExecuteCoreGRPC(ctx, stc, corev1.Forge_ListMeasurementTrustedProfiles_FullMethodName, &corev1.ListMeasurementTrustedProfilesRequest{}, coreResp, siteID) + if apiErr != nil { + logAPIError(logger, apiErr, "failed to list profile trust approvals") + return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, nil) + } + return c.JSON(http.StatusOK, model.APIMeasurementTrustedProfilesFromProto(coreResp.GetApprovalRecords())) +} + +// DeleteMeasurementTrustedProfileHandler deletes a profile trust approval. +type DeleteMeasurementTrustedProfileHandler struct{ measurementTrustHandler } + +// NewDeleteMeasurementTrustedProfileHandler returns a profile trust approval deletion handler. +func NewDeleteMeasurementTrustedProfileHandler(dbSession *cdb.Session, scp *sc.ClientPool) DeleteMeasurementTrustedProfileHandler { + return DeleteMeasurementTrustedProfileHandler{newMeasurementTrustHandler(dbSession, scp)} +} + +// Handle deletes a profile trust approval. +func (h DeleteMeasurementTrustedProfileHandler) Handle(c echo.Context) error { + org, dbUser, ctx, logger, handlerSpan := common.SetupHandler("MeasurementTrustedProfile", "Delete", c, h.tracerSpan) + if handlerSpan != nil { + defer handlerSpan.End() + } + + coreReq, err := model.MeasurementTrustedProfileRemoveProto(c.QueryParam("selector"), c.Param("id")) + if 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: c.QueryParam("siteId"), + }) + if apiErr != nil { + return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, apiErr.Data) + } + + coreResp := &corev1.RemoveMeasurementTrustedProfileResponse{} + apiErr = common.ExecuteCoreGRPC(ctx, stc, corev1.Forge_RemoveMeasurementTrustedProfile_FullMethodName, coreReq, coreResp, siteID) + if apiErr != nil { + logAPIError(logger, apiErr, "failed to delete profile trust approval") + return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, nil) + } + return c.JSON(http.StatusOK, model.APIMeasurementTrustedProfileFromProto(coreResp.GetApprovalRecord())) +} diff --git a/rest-api/api/pkg/api/handler/measurementtrust_test.go b/rest-api/api/pkg/api/handler/measurementtrust_test.go new file mode 100644 index 0000000000..24b1df6775 --- /dev/null +++ b/rest-api/api/pkg/api/handler/measurementtrust_test.go @@ -0,0 +1,236 @@ +// 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" + "google.golang.org/protobuf/proto" + + "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" + cdb "github.com/NVIDIA/infra-controller/rest-api/db/pkg/db" + cdbm "github.com/NVIDIA/infra-controller/rest-api/db/pkg/db/model" + corev1 "github.com/NVIDIA/infra-controller/rest-api/proto/core/gen/v1" +) + +func TestCreateMeasurementTrustedMachineHandler(t *testing.T) { + record := &corev1.MeasurementApprovedMachineRecordPb{ + ApprovalId: &corev1.MeasurementApprovedMachineId{Value: "00000000-0000-0000-0000-000000000010"}, + MachineId: "*", + ApprovalType: corev1.MeasurementApprovedTypePb_Persist, + } + fixture := newMeasurementTrustHandlerFixture(t, &corev1.AddMeasurementTrustedMachineResponse{ApprovalRecord: record}, nil) + handler := NewCreateMeasurementTrustedMachineHandler(fixture.dbSession, fixture.scp) + + rec := fixture.request(t, handler.Handle, http.MethodPost, "/", "", model.APIMeasurementTrustedMachineCreateRequest{ + SiteID: fixture.siteID, + MachineID: "*", + ApprovalType: model.MeasurementTrustApprovalTypePersist, + }) + assert.Equal(t, http.StatusCreated, rec.Code) + assert.Equal(t, corev1.Forge_AddMeasurementTrustedMachine_FullMethodName, fixture.proxiedReq.FullMethod) + + var coreReq corev1.AddMeasurementTrustedMachineRequest + require.NoError(t, protojson.Unmarshal(fixture.proxiedReq.RequestJSON, &coreReq)) + assert.Equal(t, "*", coreReq.GetMachineId()) + assert.Equal(t, corev1.MeasurementApprovedTypePb_Persist, coreReq.GetApprovalType()) + + var resp model.APIMeasurementTrustedMachine + require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp)) + assert.Equal(t, record.GetApprovalId().GetValue(), resp.ApprovalID) +} + +func TestListMeasurementTrustedMachinesHandler(t *testing.T) { + record := &corev1.MeasurementApprovedMachineRecordPb{ + ApprovalId: &corev1.MeasurementApprovedMachineId{Value: "00000000-0000-0000-0000-000000000010"}, + MachineId: "00000000-0000-0000-0000-000000000011", + } + fixture := newMeasurementTrustHandlerFixture(t, &corev1.ListMeasurementTrustedMachinesResponse{ApprovalRecords: []*corev1.MeasurementApprovedMachineRecordPb{record}}, nil) + handler := NewListMeasurementTrustedMachinesHandler(fixture.dbSession, fixture.scp) + + rec := fixture.request(t, handler.Handle, http.MethodGet, "/?siteId="+fixture.siteID, "", nil) + assert.Equal(t, http.StatusOK, rec.Code) + assert.Equal(t, corev1.Forge_ListMeasurementTrustedMachines_FullMethodName, fixture.proxiedReq.FullMethod) + + var resp []*model.APIMeasurementTrustedMachine + require.NoError(t, json.Unmarshal(rec.Body.Bytes(), &resp)) + require.Len(t, resp, 1) + assert.Equal(t, record.GetMachineId(), resp[0].MachineID) +} + +func TestDeleteMeasurementTrustedMachineHandler(t *testing.T) { + record := &corev1.MeasurementApprovedMachineRecordPb{ + ApprovalId: &corev1.MeasurementApprovedMachineId{Value: "00000000-0000-0000-0000-000000000010"}, + MachineId: "00000000-0000-0000-0000-000000000011", + } + fixture := newMeasurementTrustHandlerFixture(t, &corev1.RemoveMeasurementTrustedMachineResponse{ApprovalRecord: record}, nil) + handler := NewDeleteMeasurementTrustedMachineHandler(fixture.dbSession, fixture.scp) + + target := "/?siteId=" + fixture.siteID + "&selector=" + model.MeasurementTrustedMachineSelectorMachineID + rec := fixture.request(t, handler.Handle, http.MethodDelete, target, record.GetMachineId(), nil) + assert.Equal(t, http.StatusOK, rec.Code) + assert.Equal(t, corev1.Forge_RemoveMeasurementTrustedMachine_FullMethodName, fixture.proxiedReq.FullMethod) + + var coreReq corev1.RemoveMeasurementTrustedMachineRequest + require.NoError(t, protojson.Unmarshal(fixture.proxiedReq.RequestJSON, &coreReq)) + assert.Equal(t, record.GetMachineId(), coreReq.GetMachineId()) +} + +func TestCreateMeasurementTrustedProfileHandler(t *testing.T) { + record := &corev1.MeasurementApprovedProfileRecordPb{ + ApprovalId: &corev1.MeasurementApprovedProfileId{Value: "00000000-0000-0000-0000-000000000010"}, + ProfileId: &corev1.MeasurementSystemProfileId{Value: "00000000-0000-0000-0000-000000000012"}, + } + fixture := newMeasurementTrustHandlerFixture(t, &corev1.AddMeasurementTrustedProfileResponse{ApprovalRecord: record}, nil) + handler := NewCreateMeasurementTrustedProfileHandler(fixture.dbSession, fixture.scp) + + rec := fixture.request(t, handler.Handle, http.MethodPost, "/", "", model.APIMeasurementTrustedProfileCreateRequest{ + SiteID: fixture.siteID, + ProfileID: record.GetProfileId().GetValue(), + ApprovalType: model.MeasurementTrustApprovalTypeOneshot, + }) + assert.Equal(t, http.StatusCreated, rec.Code) + assert.Equal(t, corev1.Forge_AddMeasurementTrustedProfile_FullMethodName, fixture.proxiedReq.FullMethod) +} + +func TestListMeasurementTrustedProfilesHandler(t *testing.T) { + record := &corev1.MeasurementApprovedProfileRecordPb{ + ApprovalId: &corev1.MeasurementApprovedProfileId{Value: "00000000-0000-0000-0000-000000000010"}, + ProfileId: &corev1.MeasurementSystemProfileId{Value: "00000000-0000-0000-0000-000000000012"}, + } + fixture := newMeasurementTrustHandlerFixture(t, &corev1.ListMeasurementTrustedProfilesResponse{ApprovalRecords: []*corev1.MeasurementApprovedProfileRecordPb{record}}, nil) + handler := NewListMeasurementTrustedProfilesHandler(fixture.dbSession, fixture.scp) + + rec := fixture.request(t, handler.Handle, http.MethodGet, "/?siteId="+fixture.siteID, "", nil) + assert.Equal(t, http.StatusOK, rec.Code) + assert.Equal(t, corev1.Forge_ListMeasurementTrustedProfiles_FullMethodName, fixture.proxiedReq.FullMethod) +} + +func TestDeleteMeasurementTrustedProfileHandler(t *testing.T) { + record := &corev1.MeasurementApprovedProfileRecordPb{ + ApprovalId: &corev1.MeasurementApprovedProfileId{Value: "00000000-0000-0000-0000-000000000010"}, + ProfileId: &corev1.MeasurementSystemProfileId{Value: "00000000-0000-0000-0000-000000000012"}, + } + fixture := newMeasurementTrustHandlerFixture(t, &corev1.RemoveMeasurementTrustedProfileResponse{ApprovalRecord: record}, nil) + handler := NewDeleteMeasurementTrustedProfileHandler(fixture.dbSession, fixture.scp) + + target := "/?siteId=" + fixture.siteID + "&selector=" + model.MeasurementTrustedProfileSelectorApprovalID + rec := fixture.request(t, handler.Handle, http.MethodDelete, target, record.GetApprovalId().GetValue(), nil) + assert.Equal(t, http.StatusOK, rec.Code) + assert.Equal(t, corev1.Forge_RemoveMeasurementTrustedProfile_FullMethodName, fixture.proxiedReq.FullMethod) +} + +func TestMeasurementTrustHandlersRejectInvalidInput(t *testing.T) { + fixture := newMeasurementTrustHandlerFixture(t, nil, nil) + createHandler := NewCreateMeasurementTrustedMachineHandler(fixture.dbSession, fixture.scp) + deleteHandler := NewDeleteMeasurementTrustedProfileHandler(fixture.dbSession, fixture.scp) + + rec := fixture.request(t, createHandler.Handle, http.MethodPost, "/", "", model.APIMeasurementTrustedMachineCreateRequest{ + SiteID: fixture.siteID, + MachineID: "invalid", + ApprovalType: model.MeasurementTrustApprovalTypeOneshot, + }) + assert.Equal(t, http.StatusBadRequest, rec.Code) + + rec = fixture.request(t, deleteHandler.Handle, http.MethodDelete, "/?siteId="+fixture.siteID+"&selector=invalid", "invalid", nil) + assert.Equal(t, http.StatusBadRequest, rec.Code) +} + +func TestMeasurementTrustHandlerRequiresProviderAdmin(t *testing.T) { + fixture := newMeasurementTrustHandlerFixture(t, nil, []string{authz.TenantAdminRole}) + handler := NewListMeasurementTrustedMachinesHandler(fixture.dbSession, fixture.scp) + + rec := fixture.request(t, handler.Handle, http.MethodGet, "/?siteId="+fixture.siteID, "", nil) + assert.Equal(t, http.StatusForbidden, rec.Code) +} + +type measurementTrustHandlerFixture struct { + dbSession *cdb.Session + scp *sc.ClientPool + org string + siteID string + user *cdbm.User + proxiedReq *coreproxy.Request +} + +func newMeasurementTrustHandlerFixture(t *testing.T, response proto.Message, roles []string) measurementTrustHandlerFixture { + t.Helper() + + dbSession := common.TestInitDB(t) + t.Cleanup(dbSession.Close) + common.TestSetupSchema(t, dbSession) + + if roles == nil { + roles = []string{authz.ProviderAdminRole} + } + org := "test-org" + user := common.TestBuildUser(t, dbSession, "test-starfleet-id", org, roles) + 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).Run(func(args mock.Arguments) { + if response == nil { + return + } + responseJSON, err := protojson.Marshal(response) + require.NoError(t, err) + args.Get(1).(*coreproxy.Response).ResponseJSON = responseJSON + }).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 measurementTrustHandlerFixture{ + dbSession: dbSession, scp: scp, org: org, siteID: site.ID.String(), user: user, proxiedReq: proxiedReq, + } +} + +func (f measurementTrustHandlerFixture) request(t *testing.T, handler func(echo.Context) error, method, target, id string, body any) *httptest.ResponseRecorder { + t.Helper() + + var requestBody string + if body != nil { + data, err := json.Marshal(body) + require.NoError(t, err) + requestBody = string(data) + } + req := httptest.NewRequest(method, target, strings.NewReader(requestBody)) + req.Header.Set(echo.HeaderContentType, echo.MIMEApplicationJSON) + rec := httptest.NewRecorder() + e := echo.New() + ec := e.NewContext(req, rec) + ec.SetParamNames("orgName", "id") + ec.SetParamValues(f.org, id) + ec.Set("user", f.user) + + require.NoError(t, handler(ec)) + return rec +} diff --git a/rest-api/api/pkg/api/model/measurementtrust.go b/rest-api/api/pkg/api/model/measurementtrust.go new file mode 100644 index 0000000000..f3b5e2c3a2 --- /dev/null +++ b/rest-api/api/pkg/api/model/measurementtrust.go @@ -0,0 +1,252 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package model + +import ( + "fmt" + "time" + + validation "github.com/go-ozzo/ozzo-validation/v4" + validationis "github.com/go-ozzo/ozzo-validation/v4/is" + + corev1 "github.com/NVIDIA/infra-controller/rest-api/proto/core/gen/v1" +) + +// Measurement trust approval types exposed by the REST API. +const ( + MeasurementTrustApprovalTypeOneshot = "Oneshot" + MeasurementTrustApprovalTypePersist = "Persist" +) + +// Selectors supported when deleting a machine trust approval. +const ( + MeasurementTrustedMachineSelectorApprovalID = "ApprovalId" + MeasurementTrustedMachineSelectorMachineID = "MachineId" +) + +// Selectors supported when deleting a profile trust approval. +const ( + MeasurementTrustedProfileSelectorApprovalID = "ApprovalId" + MeasurementTrustedProfileSelectorProfileID = "ProfileId" +) + +// APIMeasurementTrustedMachineCreateRequest creates a machine trust approval. +type APIMeasurementTrustedMachineCreateRequest struct { + SiteID string `json:"siteId"` + MachineID string `json:"machineId"` + ApprovalType string `json:"approvalType"` + PCRRegisters string `json:"pcrRegisters,omitempty"` + Comments string `json:"comments,omitempty"` +} + +// APIMeasurementTrustedProfileCreateRequest creates a profile trust approval. +type APIMeasurementTrustedProfileCreateRequest struct { + SiteID string `json:"siteId"` + ProfileID string `json:"profileId"` + ApprovalType string `json:"approvalType"` + PCRRegisters string `json:"pcrRegisters,omitempty"` + Comments string `json:"comments,omitempty"` +} + +// APIMeasurementTrustedMachine is a machine trust approval. +type APIMeasurementTrustedMachine struct { + ApprovalID string `json:"approvalId"` + MachineID string `json:"machineId"` + ApprovalType string `json:"approvalType"` + PCRRegisters string `json:"pcrRegisters,omitempty"` + Comments string `json:"comments,omitempty"` + Created *time.Time `json:"created,omitempty"` +} + +// APIMeasurementTrustedProfile is a profile trust approval. +type APIMeasurementTrustedProfile struct { + ApprovalID string `json:"approvalId"` + ProfileID string `json:"profileId"` + ApprovalType string `json:"approvalType"` + PCRRegisters string `json:"pcrRegisters,omitempty"` + Comments string `json:"comments,omitempty"` + Created *time.Time `json:"created,omitempty"` +} + +// Validate checks a machine trust approval request. +func (r *APIMeasurementTrustedMachineCreateRequest) Validate() error { + if err := validation.ValidateStruct(r, + validation.Field(&r.SiteID, validation.Required.Error(validationErrorValueRequired), validationis.UUID.Error(validationErrorInvalidUUID)), + validation.Field(&r.MachineID, validation.Required.Error(validationErrorValueRequired)), + validation.Field(&r.ApprovalType, validation.Required.Error(validationErrorValueRequired)), + ); err != nil { + return err + } + if r.MachineID != "*" { + if err := validation.Validate(r.MachineID, validationis.UUID.Error(validationErrorInvalidUUID)); err != nil { + return fmt.Errorf("machineId: %w", err) + } + } + return validateMeasurementTrustApprovalType(r.ApprovalType) +} + +// Validate checks a profile trust approval request. +func (r *APIMeasurementTrustedProfileCreateRequest) Validate() error { + if err := validation.ValidateStruct(r, + validation.Field(&r.SiteID, validation.Required.Error(validationErrorValueRequired), validationis.UUID.Error(validationErrorInvalidUUID)), + validation.Field(&r.ProfileID, validation.Required.Error(validationErrorValueRequired), validationis.UUID.Error(validationErrorInvalidUUID)), + validation.Field(&r.ApprovalType, validation.Required.Error(validationErrorValueRequired)), + ); err != nil { + return err + } + return validateMeasurementTrustApprovalType(r.ApprovalType) +} + +// ToProto converts a validated machine trust approval request to its Core message. +func (r *APIMeasurementTrustedMachineCreateRequest) ToProto() *corev1.AddMeasurementTrustedMachineRequest { + return &corev1.AddMeasurementTrustedMachineRequest{ + MachineId: r.MachineID, + ApprovalType: measurementTrustApprovalTypeToProto(r.ApprovalType), + PcrRegisters: r.PCRRegisters, + Comments: r.Comments, + } +} + +// ToProto converts a validated profile trust approval request to its Core message. +func (r *APIMeasurementTrustedProfileCreateRequest) ToProto() *corev1.AddMeasurementTrustedProfileRequest { + req := &corev1.AddMeasurementTrustedProfileRequest{ + ProfileId: &corev1.MeasurementSystemProfileId{Value: r.ProfileID}, + ApprovalType: measurementTrustApprovalTypeToProto(r.ApprovalType), + } + if r.PCRRegisters != "" { + req.PcrRegisters = &r.PCRRegisters + } + if r.Comments != "" { + req.Comments = &r.Comments + } + return req +} + +// APIMeasurementTrustedMachineFromProto converts one Core machine trust record. +func APIMeasurementTrustedMachineFromProto(record *corev1.MeasurementApprovedMachineRecordPb) *APIMeasurementTrustedMachine { + if record == nil { + return nil + } + resp := &APIMeasurementTrustedMachine{ + ApprovalID: record.GetApprovalId().GetValue(), + MachineID: record.GetMachineId(), + ApprovalType: measurementTrustApprovalTypeFromProto(record.GetApprovalType()), + PCRRegisters: record.GetPcrRegisters(), + Comments: record.GetComments(), + } + if ts := record.GetTs(); ts != nil { + created := ts.AsTime().UTC() + resp.Created = &created + } + return resp +} + +// APIMeasurementTrustedProfileFromProto converts one Core profile trust record. +func APIMeasurementTrustedProfileFromProto(record *corev1.MeasurementApprovedProfileRecordPb) *APIMeasurementTrustedProfile { + if record == nil { + return nil + } + resp := &APIMeasurementTrustedProfile{ + ApprovalID: record.GetApprovalId().GetValue(), + ProfileID: record.GetProfileId().GetValue(), + ApprovalType: measurementTrustApprovalTypeFromProto(record.GetApprovalType()), + PCRRegisters: record.GetPcrRegisters(), + Comments: record.GetComments(), + } + if ts := record.GetTs(); ts != nil { + created := ts.AsTime().UTC() + resp.Created = &created + } + return resp +} + +// APIMeasurementTrustedMachinesFromProto converts Core machine trust records. +func APIMeasurementTrustedMachinesFromProto(records []*corev1.MeasurementApprovedMachineRecordPb) []*APIMeasurementTrustedMachine { + result := make([]*APIMeasurementTrustedMachine, 0, len(records)) + for _, record := range records { + result = append(result, APIMeasurementTrustedMachineFromProto(record)) + } + return result +} + +// APIMeasurementTrustedProfilesFromProto converts Core profile trust records. +func APIMeasurementTrustedProfilesFromProto(records []*corev1.MeasurementApprovedProfileRecordPb) []*APIMeasurementTrustedProfile { + result := make([]*APIMeasurementTrustedProfile, 0, len(records)) + for _, record := range records { + result = append(result, APIMeasurementTrustedProfileFromProto(record)) + } + return result +} + +// MeasurementTrustedMachineRemoveProto builds and validates a Core machine removal request. +func MeasurementTrustedMachineRemoveProto(selector, id string) (*corev1.RemoveMeasurementTrustedMachineRequest, error) { + switch selector { + case MeasurementTrustedMachineSelectorApprovalID: + if err := validation.Validate(id, validation.Required, validationis.UUID); err != nil { + return nil, fmt.Errorf("id: %w", err) + } + return &corev1.RemoveMeasurementTrustedMachineRequest{ + Selector: &corev1.RemoveMeasurementTrustedMachineRequest_ApprovalId{ + ApprovalId: &corev1.MeasurementApprovedMachineId{Value: id}, + }, + }, nil + case MeasurementTrustedMachineSelectorMachineID: + if id != "*" { + if err := validation.Validate(id, validation.Required, validationis.UUID); err != nil { + return nil, fmt.Errorf("id: %w", err) + } + } + return &corev1.RemoveMeasurementTrustedMachineRequest{ + Selector: &corev1.RemoveMeasurementTrustedMachineRequest_MachineId{MachineId: id}, + }, nil + default: + return nil, fmt.Errorf("invalid selector %q (expected %q or %q)", selector, MeasurementTrustedMachineSelectorApprovalID, MeasurementTrustedMachineSelectorMachineID) + } +} + +// MeasurementTrustedProfileRemoveProto builds and validates a Core profile removal request. +func MeasurementTrustedProfileRemoveProto(selector, id string) (*corev1.RemoveMeasurementTrustedProfileRequest, error) { + if err := validation.Validate(id, validation.Required, validationis.UUID); err != nil { + return nil, fmt.Errorf("id: %w", err) + } + switch selector { + case MeasurementTrustedProfileSelectorApprovalID: + return &corev1.RemoveMeasurementTrustedProfileRequest{ + Selector: &corev1.RemoveMeasurementTrustedProfileRequest_ApprovalId{ + ApprovalId: &corev1.MeasurementApprovedProfileId{Value: id}, + }, + }, nil + case MeasurementTrustedProfileSelectorProfileID: + return &corev1.RemoveMeasurementTrustedProfileRequest{ + Selector: &corev1.RemoveMeasurementTrustedProfileRequest_ProfileId{ + ProfileId: &corev1.MeasurementSystemProfileId{Value: id}, + }, + }, nil + default: + return nil, fmt.Errorf("invalid selector %q (expected %q or %q)", selector, MeasurementTrustedProfileSelectorApprovalID, MeasurementTrustedProfileSelectorProfileID) + } +} + +func validateMeasurementTrustApprovalType(approvalType string) error { + switch approvalType { + case MeasurementTrustApprovalTypeOneshot, MeasurementTrustApprovalTypePersist: + return nil + default: + return fmt.Errorf("invalid approvalType %q (expected %q or %q)", approvalType, MeasurementTrustApprovalTypeOneshot, MeasurementTrustApprovalTypePersist) + } +} + +func measurementTrustApprovalTypeToProto(approvalType string) corev1.MeasurementApprovedTypePb { + if approvalType == MeasurementTrustApprovalTypePersist { + return corev1.MeasurementApprovedTypePb_Persist + } + return corev1.MeasurementApprovedTypePb_Oneshot +} + +func measurementTrustApprovalTypeFromProto(approvalType corev1.MeasurementApprovedTypePb) string { + if approvalType == corev1.MeasurementApprovedTypePb_Persist { + return MeasurementTrustApprovalTypePersist + } + return MeasurementTrustApprovalTypeOneshot +} diff --git a/rest-api/api/pkg/api/model/measurementtrust_test.go b/rest-api/api/pkg/api/model/measurementtrust_test.go new file mode 100644 index 0000000000..60dbc84908 --- /dev/null +++ b/rest-api/api/pkg/api/model/measurementtrust_test.go @@ -0,0 +1,113 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +package model + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "google.golang.org/protobuf/types/known/timestamppb" + + corev1 "github.com/NVIDIA/infra-controller/rest-api/proto/core/gen/v1" +) + +func TestMeasurementTrustedMachineCreateRequest(t *testing.T) { + req := APIMeasurementTrustedMachineCreateRequest{ + SiteID: "00000000-0000-0000-0000-000000000001", + MachineID: "*", + ApprovalType: MeasurementTrustApprovalTypePersist, + PCRRegisters: "0,3,5,6", + Comments: "trusted fleet", + } + require.NoError(t, req.Validate()) + + protoReq := req.ToProto() + assert.Equal(t, "*", protoReq.GetMachineId()) + assert.Equal(t, corev1.MeasurementApprovedTypePb_Persist, protoReq.GetApprovalType()) + assert.Equal(t, "0,3,5,6", protoReq.GetPcrRegisters()) + assert.Equal(t, "trusted fleet", protoReq.GetComments()) +} + +func TestMeasurementTrustedMachineCreateRequestRejectsInvalidMachine(t *testing.T) { + req := APIMeasurementTrustedMachineCreateRequest{ + SiteID: "00000000-0000-0000-0000-000000000001", + MachineID: "not-a-machine-id", + ApprovalType: MeasurementTrustApprovalTypeOneshot, + } + assert.ErrorContains(t, req.Validate(), "machineId") +} + +func TestMeasurementTrustedProfileCreateRequest(t *testing.T) { + req := APIMeasurementTrustedProfileCreateRequest{ + SiteID: "00000000-0000-0000-0000-000000000001", + ProfileID: "00000000-0000-0000-0000-000000000002", + ApprovalType: MeasurementTrustApprovalTypeOneshot, + } + require.NoError(t, req.Validate()) + + protoReq := req.ToProto() + assert.Equal(t, req.ProfileID, protoReq.GetProfileId().GetValue()) + assert.Equal(t, corev1.MeasurementApprovedTypePb_Oneshot, protoReq.GetApprovalType()) + assert.Nil(t, protoReq.PcrRegisters) + assert.Nil(t, protoReq.Comments) +} + +func TestMeasurementTrustCreateRequestRejectsInvalidApprovalType(t *testing.T) { + req := APIMeasurementTrustedMachineCreateRequest{ + SiteID: "00000000-0000-0000-0000-000000000001", + MachineID: "00000000-0000-0000-0000-000000000002", + ApprovalType: "Forever", + } + assert.ErrorContains(t, req.Validate(), "approvalType") +} + +func TestMeasurementTrustRemoveProtoSelectors(t *testing.T) { + id := "00000000-0000-0000-0000-000000000001" + + machineByApproval, err := MeasurementTrustedMachineRemoveProto(MeasurementTrustedMachineSelectorApprovalID, id) + require.NoError(t, err) + assert.Equal(t, id, machineByApproval.GetApprovalId().GetValue()) + + machineByMachine, err := MeasurementTrustedMachineRemoveProto(MeasurementTrustedMachineSelectorMachineID, id) + require.NoError(t, err) + assert.Equal(t, id, machineByMachine.GetMachineId()) + + profileByApproval, err := MeasurementTrustedProfileRemoveProto(MeasurementTrustedProfileSelectorApprovalID, id) + require.NoError(t, err) + assert.Equal(t, id, profileByApproval.GetApprovalId().GetValue()) + + profileByProfile, err := MeasurementTrustedProfileRemoveProto(MeasurementTrustedProfileSelectorProfileID, id) + require.NoError(t, err) + assert.Equal(t, id, profileByProfile.GetProfileId().GetValue()) + + _, err = MeasurementTrustedMachineRemoveProto("invalid", id) + assert.ErrorContains(t, err, "invalid selector") +} + +func TestMeasurementTrustResponsesFromProto(t *testing.T) { + created := time.Date(2026, 7, 13, 20, 0, 0, 0, time.UTC) + machine := APIMeasurementTrustedMachineFromProto(&corev1.MeasurementApprovedMachineRecordPb{ + ApprovalId: &corev1.MeasurementApprovedMachineId{Value: "00000000-0000-0000-0000-000000000001"}, + MachineId: "00000000-0000-0000-0000-000000000002", + ApprovalType: corev1.MeasurementApprovedTypePb_Persist, + PcrRegisters: "0,7", + Comments: "trusted machine", + Ts: timestamppb.New(created), + }) + require.NotNil(t, machine) + assert.Equal(t, MeasurementTrustApprovalTypePersist, machine.ApprovalType) + assert.Equal(t, created, *machine.Created) + + profile := APIMeasurementTrustedProfileFromProto(&corev1.MeasurementApprovedProfileRecordPb{ + ApprovalId: &corev1.MeasurementApprovedProfileId{Value: "00000000-0000-0000-0000-000000000003"}, + ProfileId: &corev1.MeasurementSystemProfileId{Value: "00000000-0000-0000-0000-000000000004"}, + ApprovalType: corev1.MeasurementApprovedTypePb_Oneshot, + Ts: timestamppb.New(created), + }) + require.NotNil(t, profile) + assert.Equal(t, MeasurementTrustApprovalTypeOneshot, profile.ApprovalType) + assert.Equal(t, created, *profile.Created) +} diff --git a/rest-api/api/pkg/api/routes.go b/rest-api/api/pkg/api/routes.go index 1c499eaa2a..6200931257 100644 --- a/rest-api/api/pkg/api/routes.go +++ b/rest-api/api/pkg/api/routes.go @@ -44,6 +44,37 @@ func NewAPIRoutes(dbSession *cdb.Session, tc tClient.Client, tnc tClient.Namespa Method: http.MethodPost, Handler: apiHandler.NewCreateUEFICredentialHandler(dbSession, scp), }, + // Measured-boot machine and profile trust approvals (Provider Admin). + { + Path: apiPathPrefix + "/measured-boot/trusted-machine", + Method: http.MethodPost, + Handler: apiHandler.NewCreateMeasurementTrustedMachineHandler(dbSession, scp), + }, + { + Path: apiPathPrefix + "/measured-boot/trusted-machine", + Method: http.MethodGet, + Handler: apiHandler.NewListMeasurementTrustedMachinesHandler(dbSession, scp), + }, + { + Path: apiPathPrefix + "/measured-boot/trusted-machine/:id", + Method: http.MethodDelete, + Handler: apiHandler.NewDeleteMeasurementTrustedMachineHandler(dbSession, scp), + }, + { + Path: apiPathPrefix + "/measured-boot/trusted-profile", + Method: http.MethodPost, + Handler: apiHandler.NewCreateMeasurementTrustedProfileHandler(dbSession, scp), + }, + { + Path: apiPathPrefix + "/measured-boot/trusted-profile", + Method: http.MethodGet, + Handler: apiHandler.NewListMeasurementTrustedProfilesHandler(dbSession, scp), + }, + { + Path: apiPathPrefix + "/measured-boot/trusted-profile/:id", + Method: http.MethodDelete, + Handler: apiHandler.NewDeleteMeasurementTrustedProfileHandler(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 c6de7acad0..bb1f4155e1 100644 --- a/rest-api/api/pkg/api/routes_test.go +++ b/rest-api/api/pkg/api/routes_test.go @@ -36,6 +36,7 @@ func TestNewAPIRoutes(t *testing.T) { routeCount := map[string]int{ "metadata": 1, "credential": 2, + "measured-boot": 6, "service-account": 1, "infrastructure-provider": 4, "tenant": 4, @@ -114,6 +115,13 @@ func TestNewAPIRoutes(t *testing.T) { assertRouteExists(t, got, http.MethodPut, bmcCredentialPath) uefiCredentialPath := "/org/:orgName/" + cfg.GetAPIName() + "/credential/uefi" assertRouteExists(t, got, http.MethodPost, uefiCredentialPath) + measurementTrustPath := "/org/:orgName/" + cfg.GetAPIName() + "/measured-boot" + assertRouteExists(t, got, http.MethodPost, measurementTrustPath+"/trusted-machine") + assertRouteExists(t, got, http.MethodGet, measurementTrustPath+"/trusted-machine") + assertRouteExists(t, got, http.MethodDelete, measurementTrustPath+"/trusted-machine/:id") + assertRouteExists(t, got, http.MethodPost, measurementTrustPath+"/trusted-profile") + assertRouteExists(t, got, http.MethodGet, measurementTrustPath+"/trusted-profile") + assertRouteExists(t, got, http.MethodDelete, measurementTrustPath+"/trusted-profile/:id") machineAdminPath := "/org/:orgName/" + cfg.GetAPIName() + "/machine/:id" assertRouteExists(t, got, http.MethodPatch, machineAdminPath+"/bmc/reset") diff --git a/rest-api/openapi/spec.yaml b/rest-api/openapi/spec.yaml index 227c4700e5..f6ca22f166 100644 --- a/rest-api/openapi/spec.yaml +++ b/rest-api/openapi/spec.yaml @@ -124,6 +124,12 @@ tags: - name: UEFI Credential description: |- UEFI Credential endpoints allow creating site-default host and DPU UEFI credentials for a Site + - name: Measured Boot Trusted Machine + description: |- + Measured Boot Trusted Machine endpoints manage automatic measurement promotion approvals for Machines at a Site + - name: Measured Boot Trusted Profile + description: |- + Measured Boot Trusted Profile endpoints manage automatic measurement promotion approvals for system profiles at a Site - name: Allocation description: |- Allocations are the mechanism by which Provider can delegate Network and Compute resources to Tenant. @@ -1249,6 +1255,261 @@ paths: if the selected site-default credential already exists. User must have authorization role with `PROVIDER_ADMIN` suffix. + '/v2/org/{org}/nico/measured-boot/trusted-machine': + parameters: + - schema: + type: string + name: org + in: path + required: true + description: Name of the Org + post: + summary: Create Measured Boot Trusted Machine Approval + tags: + - Measured Boot Trusted Machine + operationId: create-measurement-trusted-machine + description: |- + Approve a Machine, or all Machines using `*`, for automatic promotion of its next measured-boot report. + + Org must have an Infrastructure Provider entity that owns the Site. User must have authorization role with `PROVIDER_ADMIN` suffix. + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/MeasurementTrustedMachineCreateRequest' + responses: + '201': + description: Measured Boot trusted Machine approval was created + content: + application/json: + schema: + $ref: '#/components/schemas/MeasurementTrustedMachine' + '400': + $ref: '#/components/responses/ValidationError' + '403': + $ref: '#/components/responses/ForbiddenError' + '404': + $ref: '#/components/responses/NotFoundError' + '500': + $ref: '#/components/responses/GenericHttpError' + get: + summary: Retrieve All Measured Boot Trusted Machine Approvals + tags: + - Measured Boot Trusted Machine + operationId: get-all-measurement-trusted-machine + description: |- + Retrieve all measured-boot trusted Machine approvals for a Site. + + Org must have an Infrastructure Provider entity that owns the Site. User must have authorization role with `PROVIDER_ADMIN` suffix. + parameters: + - schema: + type: string + format: uuid + name: siteId + in: query + required: true + description: ID of the Site + responses: + '200': + description: Measured Boot trusted Machine approvals + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/MeasurementTrustedMachine' + '400': + $ref: '#/components/responses/ValidationError' + '403': + $ref: '#/components/responses/ForbiddenError' + '404': + $ref: '#/components/responses/NotFoundError' + '500': + $ref: '#/components/responses/GenericHttpError' + '/v2/org/{org}/nico/measured-boot/trusted-machine/{id}': + parameters: + - schema: + type: string + name: org + in: path + required: true + description: Name of the Org + - schema: + type: string + name: id + in: path + required: true + description: Approval ID or Machine ID, as selected by the selector query parameter + delete: + summary: Delete Measured Boot Trusted Machine Approval + tags: + - Measured Boot Trusted Machine + operationId: delete-measurement-trusted-machine + description: |- + Delete a measured-boot trusted Machine approval by approval ID or Machine ID. + + Org must have an Infrastructure Provider entity that owns the Site. User must have authorization role with `PROVIDER_ADMIN` suffix. + parameters: + - schema: + type: string + format: uuid + name: siteId + in: query + required: true + description: ID of the Site + - schema: + type: string + enum: + - ApprovalId + - MachineId + name: selector + in: query + required: true + description: Whether id identifies the approval or the Machine + responses: + '200': + description: Deleted measured-boot trusted Machine approval + content: + application/json: + schema: + $ref: '#/components/schemas/MeasurementTrustedMachine' + '400': + $ref: '#/components/responses/ValidationError' + '403': + $ref: '#/components/responses/ForbiddenError' + '404': + $ref: '#/components/responses/NotFoundError' + '500': + $ref: '#/components/responses/GenericHttpError' + '/v2/org/{org}/nico/measured-boot/trusted-profile': + parameters: + - schema: + type: string + name: org + in: path + required: true + description: Name of the Org + post: + summary: Create Measured Boot Trusted Profile Approval + tags: + - Measured Boot Trusted Profile + operationId: create-measurement-trusted-profile + description: |- + Approve a measured-boot system profile for automatic promotion of reports from matching Machines. + + Org must have an Infrastructure Provider entity that owns the Site. User must have authorization role with `PROVIDER_ADMIN` suffix. + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/MeasurementTrustedProfileCreateRequest' + responses: + '201': + description: Measured Boot trusted Profile approval was created + content: + application/json: + schema: + $ref: '#/components/schemas/MeasurementTrustedProfile' + '400': + $ref: '#/components/responses/ValidationError' + '403': + $ref: '#/components/responses/ForbiddenError' + '404': + $ref: '#/components/responses/NotFoundError' + '500': + $ref: '#/components/responses/GenericHttpError' + get: + summary: Retrieve All Measured Boot Trusted Profile Approvals + tags: + - Measured Boot Trusted Profile + operationId: get-all-measurement-trusted-profile + description: |- + Retrieve all measured-boot trusted Profile approvals for a Site. + + Org must have an Infrastructure Provider entity that owns the Site. User must have authorization role with `PROVIDER_ADMIN` suffix. + parameters: + - schema: + type: string + format: uuid + name: siteId + in: query + required: true + description: ID of the Site + responses: + '200': + description: Measured Boot trusted Profile approvals + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/MeasurementTrustedProfile' + '400': + $ref: '#/components/responses/ValidationError' + '403': + $ref: '#/components/responses/ForbiddenError' + '404': + $ref: '#/components/responses/NotFoundError' + '500': + $ref: '#/components/responses/GenericHttpError' + '/v2/org/{org}/nico/measured-boot/trusted-profile/{id}': + parameters: + - schema: + type: string + name: org + in: path + required: true + description: Name of the Org + - schema: + type: string + format: uuid + name: id + in: path + required: true + description: Approval ID or Profile ID, as selected by the selector query parameter + delete: + summary: Delete Measured Boot Trusted Profile Approval + tags: + - Measured Boot Trusted Profile + operationId: delete-measurement-trusted-profile + description: |- + Delete a measured-boot trusted Profile approval by approval ID or Profile ID. + + Org must have an Infrastructure Provider entity that owns the Site. User must have authorization role with `PROVIDER_ADMIN` suffix. + parameters: + - schema: + type: string + format: uuid + name: siteId + in: query + required: true + description: ID of the Site + - schema: + type: string + enum: + - ApprovalId + - ProfileId + name: selector + in: query + required: true + description: Whether id identifies the approval or the system profile + responses: + '200': + description: Deleted measured-boot trusted Profile approval + content: + application/json: + schema: + $ref: '#/components/schemas/MeasurementTrustedProfile' + '400': + $ref: '#/components/responses/ValidationError' + '403': + $ref: '#/components/responses/ForbiddenError' + '404': + $ref: '#/components/responses/NotFoundError' + '500': + $ref: '#/components/responses/GenericHttpError' '/v2/org/{org}/nico/allocation': parameters: - schema: @@ -13550,6 +13811,128 @@ paths: $ref: '#/components/responses/GenericHttpError' components: schemas: + MeasurementTrustedMachineCreateRequest: + type: object + title: MeasurementTrustedMachineCreateRequest + description: Request to approve a Machine for automatic promotion of measured-boot reports. + required: + - siteId + - machineId + - approvalType + properties: + siteId: + type: string + format: uuid + description: ID of the Site where the approval applies. + machineId: + type: string + description: Machine UUID, or `*` to approve all Machines at the Site. + approvalType: + type: string + enum: + - Oneshot + - Persist + description: Whether the approval is consumed once or persists for future reports. + pcrRegisters: + type: string + description: Optional comma-separated PCR register selector. All registers are used when omitted. + comments: + type: string + description: Optional operator comments about the approval. + MeasurementTrustedMachine: + type: object + title: MeasurementTrustedMachine + description: A measured-boot trusted Machine approval. + required: + - approvalId + - machineId + - approvalType + properties: + approvalId: + type: string + format: uuid + description: Unique approval ID. + machineId: + type: string + description: Machine UUID, or `*` when the approval applies to all Machines. + approvalType: + type: string + enum: + - Oneshot + - Persist + description: Whether the approval is consumed once or persists for future reports. + pcrRegisters: + type: string + description: Optional comma-separated PCR register selector. + comments: + type: string + description: Optional operator comments about the approval. + created: + type: string + format: date-time + description: Time when the approval was created. + MeasurementTrustedProfileCreateRequest: + type: object + title: MeasurementTrustedProfileCreateRequest + description: Request to approve a system profile for automatic promotion of measured-boot reports. + required: + - siteId + - profileId + - approvalType + properties: + siteId: + type: string + format: uuid + description: ID of the Site where the approval applies. + profileId: + type: string + format: uuid + description: ID of the measured-boot system profile. + approvalType: + type: string + enum: + - Oneshot + - Persist + description: Whether the approval is consumed once or persists for future reports. + pcrRegisters: + type: string + description: Optional comma-separated PCR register selector. All registers are used when omitted. + comments: + type: string + description: Optional operator comments about the approval. + MeasurementTrustedProfile: + type: object + title: MeasurementTrustedProfile + description: A measured-boot trusted system profile approval. + required: + - approvalId + - profileId + - approvalType + properties: + approvalId: + type: string + format: uuid + description: Unique approval ID. + profileId: + type: string + format: uuid + description: ID of the measured-boot system profile. + approvalType: + type: string + enum: + - Oneshot + - Persist + description: Whether the approval is consumed once or persists for future reports. + pcrRegisters: + type: string + description: Optional comma-separated PCR register selector. + comments: + type: string + description: Optional operator comments about the approval. + created: + type: string + format: date-time + description: Time when the approval was created. BMCCredentialRequest: type: object title: BMCCredentialRequest diff --git a/rest-api/sdk/standard/api_measured_boot_trusted_machine.go b/rest-api/sdk/standard/api_measured_boot_trusted_machine.go new file mode 100644 index 0000000000..fa0a8f3290 --- /dev/null +++ b/rest-api/sdk/standard/api_measured_boot_trusted_machine.go @@ -0,0 +1,518 @@ +/* +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" +) + +// MeasuredBootTrustedMachineAPIService MeasuredBootTrustedMachineAPI service +type MeasuredBootTrustedMachineAPIService service + +type ApiCreateMeasurementTrustedMachineRequest struct { + ctx context.Context + ApiService *MeasuredBootTrustedMachineAPIService + org string + measurementTrustedMachineCreateRequest *MeasurementTrustedMachineCreateRequest +} + +func (r ApiCreateMeasurementTrustedMachineRequest) MeasurementTrustedMachineCreateRequest(measurementTrustedMachineCreateRequest MeasurementTrustedMachineCreateRequest) ApiCreateMeasurementTrustedMachineRequest { + r.measurementTrustedMachineCreateRequest = &measurementTrustedMachineCreateRequest + return r +} + +func (r ApiCreateMeasurementTrustedMachineRequest) Execute() (*MeasurementTrustedMachine, *http.Response, error) { + return r.ApiService.CreateMeasurementTrustedMachineExecute(r) +} + +/* +CreateMeasurementTrustedMachine Create Measured Boot Trusted Machine Approval + +Approve a Machine, or all Machines using `*`, for automatic promotion of its next measured-boot report. + +Org must have an Infrastructure Provider entity that owns the Site. 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 ApiCreateMeasurementTrustedMachineRequest +*/ +func (a *MeasuredBootTrustedMachineAPIService) CreateMeasurementTrustedMachine(ctx context.Context, org string) ApiCreateMeasurementTrustedMachineRequest { + return ApiCreateMeasurementTrustedMachineRequest{ + ApiService: a, + ctx: ctx, + org: org, + } +} + +// Execute executes the request +// +// @return MeasurementTrustedMachine +func (a *MeasuredBootTrustedMachineAPIService) CreateMeasurementTrustedMachineExecute(r ApiCreateMeasurementTrustedMachineRequest) (*MeasurementTrustedMachine, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *MeasurementTrustedMachine + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "MeasuredBootTrustedMachineAPIService.CreateMeasurementTrustedMachine") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/v2/org/{org}/nico/measured-boot/trusted-machine" + 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.measurementTrustedMachineCreateRequest == nil { + return localVarReturnValue, nil, reportError("measurementTrustedMachineCreateRequest 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.measurementTrustedMachineCreateRequest + 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 == 404 { + 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 == 500 { + 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 +} + +type ApiDeleteMeasurementTrustedMachineRequest struct { + ctx context.Context + ApiService *MeasuredBootTrustedMachineAPIService + siteId *string + selector *string + org string + id string +} + +// ID of the Site +func (r ApiDeleteMeasurementTrustedMachineRequest) SiteId(siteId string) ApiDeleteMeasurementTrustedMachineRequest { + r.siteId = &siteId + return r +} + +// Whether id identifies the approval or the Machine +func (r ApiDeleteMeasurementTrustedMachineRequest) Selector(selector string) ApiDeleteMeasurementTrustedMachineRequest { + r.selector = &selector + return r +} + +func (r ApiDeleteMeasurementTrustedMachineRequest) Execute() (*MeasurementTrustedMachine, *http.Response, error) { + return r.ApiService.DeleteMeasurementTrustedMachineExecute(r) +} + +/* +DeleteMeasurementTrustedMachine Delete Measured Boot Trusted Machine Approval + +Delete a measured-boot trusted Machine approval by approval ID or Machine ID. + +Org must have an Infrastructure Provider entity that owns the Site. 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 + @param id Approval ID or Machine ID, as selected by the selector query parameter + @return ApiDeleteMeasurementTrustedMachineRequest +*/ +func (a *MeasuredBootTrustedMachineAPIService) DeleteMeasurementTrustedMachine(ctx context.Context, org string, id string) ApiDeleteMeasurementTrustedMachineRequest { + return ApiDeleteMeasurementTrustedMachineRequest{ + ApiService: a, + ctx: ctx, + org: org, + id: id, + } +} + +// Execute executes the request +// +// @return MeasurementTrustedMachine +func (a *MeasuredBootTrustedMachineAPIService) DeleteMeasurementTrustedMachineExecute(r ApiDeleteMeasurementTrustedMachineRequest) (*MeasurementTrustedMachine, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodDelete + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *MeasurementTrustedMachine + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "MeasuredBootTrustedMachineAPIService.DeleteMeasurementTrustedMachine") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/v2/org/{org}/nico/measured-boot/trusted-machine/{id}" + localVarPath = strings.Replace(localVarPath, "{"+"org"+"}", url.PathEscape(parameterValueToString(r.org, "org")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if r.siteId == nil { + return localVarReturnValue, nil, reportError("siteId is required and must be specified") + } + if r.selector == nil { + return localVarReturnValue, nil, reportError("selector is required and must be specified") + } + + parameterAddToHeaderOrQuery(localVarQueryParams, "siteId", r.siteId, "form", "") + parameterAddToHeaderOrQuery(localVarQueryParams, "selector", r.selector, "form", "") + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // 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 + } + 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 == 404 { + 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 == 500 { + 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 +} + +type ApiGetAllMeasurementTrustedMachineRequest struct { + ctx context.Context + ApiService *MeasuredBootTrustedMachineAPIService + siteId *string + org string +} + +// ID of the Site +func (r ApiGetAllMeasurementTrustedMachineRequest) SiteId(siteId string) ApiGetAllMeasurementTrustedMachineRequest { + r.siteId = &siteId + return r +} + +func (r ApiGetAllMeasurementTrustedMachineRequest) Execute() ([]MeasurementTrustedMachine, *http.Response, error) { + return r.ApiService.GetAllMeasurementTrustedMachineExecute(r) +} + +/* +GetAllMeasurementTrustedMachine Retrieve All Measured Boot Trusted Machine Approvals + +Retrieve all measured-boot trusted Machine approvals for a Site. + +Org must have an Infrastructure Provider entity that owns the Site. 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 ApiGetAllMeasurementTrustedMachineRequest +*/ +func (a *MeasuredBootTrustedMachineAPIService) GetAllMeasurementTrustedMachine(ctx context.Context, org string) ApiGetAllMeasurementTrustedMachineRequest { + return ApiGetAllMeasurementTrustedMachineRequest{ + ApiService: a, + ctx: ctx, + org: org, + } +} + +// Execute executes the request +// +// @return []MeasurementTrustedMachine +func (a *MeasuredBootTrustedMachineAPIService) GetAllMeasurementTrustedMachineExecute(r ApiGetAllMeasurementTrustedMachineRequest) ([]MeasurementTrustedMachine, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue []MeasurementTrustedMachine + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "MeasuredBootTrustedMachineAPIService.GetAllMeasurementTrustedMachine") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/v2/org/{org}/nico/measured-boot/trusted-machine" + 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.siteId == nil { + return localVarReturnValue, nil, reportError("siteId is required and must be specified") + } + + parameterAddToHeaderOrQuery(localVarQueryParams, "siteId", r.siteId, "form", "") + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // 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 + } + 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 == 404 { + 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 == 500 { + 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/api_measured_boot_trusted_profile.go b/rest-api/sdk/standard/api_measured_boot_trusted_profile.go new file mode 100644 index 0000000000..950c14ff70 --- /dev/null +++ b/rest-api/sdk/standard/api_measured_boot_trusted_profile.go @@ -0,0 +1,518 @@ +/* +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" +) + +// MeasuredBootTrustedProfileAPIService MeasuredBootTrustedProfileAPI service +type MeasuredBootTrustedProfileAPIService service + +type ApiCreateMeasurementTrustedProfileRequest struct { + ctx context.Context + ApiService *MeasuredBootTrustedProfileAPIService + org string + measurementTrustedProfileCreateRequest *MeasurementTrustedProfileCreateRequest +} + +func (r ApiCreateMeasurementTrustedProfileRequest) MeasurementTrustedProfileCreateRequest(measurementTrustedProfileCreateRequest MeasurementTrustedProfileCreateRequest) ApiCreateMeasurementTrustedProfileRequest { + r.measurementTrustedProfileCreateRequest = &measurementTrustedProfileCreateRequest + return r +} + +func (r ApiCreateMeasurementTrustedProfileRequest) Execute() (*MeasurementTrustedProfile, *http.Response, error) { + return r.ApiService.CreateMeasurementTrustedProfileExecute(r) +} + +/* +CreateMeasurementTrustedProfile Create Measured Boot Trusted Profile Approval + +Approve a measured-boot system profile for automatic promotion of reports from matching Machines. + +Org must have an Infrastructure Provider entity that owns the Site. 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 ApiCreateMeasurementTrustedProfileRequest +*/ +func (a *MeasuredBootTrustedProfileAPIService) CreateMeasurementTrustedProfile(ctx context.Context, org string) ApiCreateMeasurementTrustedProfileRequest { + return ApiCreateMeasurementTrustedProfileRequest{ + ApiService: a, + ctx: ctx, + org: org, + } +} + +// Execute executes the request +// +// @return MeasurementTrustedProfile +func (a *MeasuredBootTrustedProfileAPIService) CreateMeasurementTrustedProfileExecute(r ApiCreateMeasurementTrustedProfileRequest) (*MeasurementTrustedProfile, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodPost + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *MeasurementTrustedProfile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "MeasuredBootTrustedProfileAPIService.CreateMeasurementTrustedProfile") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/v2/org/{org}/nico/measured-boot/trusted-profile" + 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.measurementTrustedProfileCreateRequest == nil { + return localVarReturnValue, nil, reportError("measurementTrustedProfileCreateRequest 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.measurementTrustedProfileCreateRequest + 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 == 404 { + 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 == 500 { + 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 +} + +type ApiDeleteMeasurementTrustedProfileRequest struct { + ctx context.Context + ApiService *MeasuredBootTrustedProfileAPIService + siteId *string + selector *string + org string + id string +} + +// ID of the Site +func (r ApiDeleteMeasurementTrustedProfileRequest) SiteId(siteId string) ApiDeleteMeasurementTrustedProfileRequest { + r.siteId = &siteId + return r +} + +// Whether id identifies the approval or the system profile +func (r ApiDeleteMeasurementTrustedProfileRequest) Selector(selector string) ApiDeleteMeasurementTrustedProfileRequest { + r.selector = &selector + return r +} + +func (r ApiDeleteMeasurementTrustedProfileRequest) Execute() (*MeasurementTrustedProfile, *http.Response, error) { + return r.ApiService.DeleteMeasurementTrustedProfileExecute(r) +} + +/* +DeleteMeasurementTrustedProfile Delete Measured Boot Trusted Profile Approval + +Delete a measured-boot trusted Profile approval by approval ID or Profile ID. + +Org must have an Infrastructure Provider entity that owns the Site. 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 + @param id Approval ID or Profile ID, as selected by the selector query parameter + @return ApiDeleteMeasurementTrustedProfileRequest +*/ +func (a *MeasuredBootTrustedProfileAPIService) DeleteMeasurementTrustedProfile(ctx context.Context, org string, id string) ApiDeleteMeasurementTrustedProfileRequest { + return ApiDeleteMeasurementTrustedProfileRequest{ + ApiService: a, + ctx: ctx, + org: org, + id: id, + } +} + +// Execute executes the request +// +// @return MeasurementTrustedProfile +func (a *MeasuredBootTrustedProfileAPIService) DeleteMeasurementTrustedProfileExecute(r ApiDeleteMeasurementTrustedProfileRequest) (*MeasurementTrustedProfile, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodDelete + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue *MeasurementTrustedProfile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "MeasuredBootTrustedProfileAPIService.DeleteMeasurementTrustedProfile") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/v2/org/{org}/nico/measured-boot/trusted-profile/{id}" + localVarPath = strings.Replace(localVarPath, "{"+"org"+"}", url.PathEscape(parameterValueToString(r.org, "org")), -1) + localVarPath = strings.Replace(localVarPath, "{"+"id"+"}", url.PathEscape(parameterValueToString(r.id, "id")), -1) + + localVarHeaderParams := make(map[string]string) + localVarQueryParams := url.Values{} + localVarFormParams := url.Values{} + if r.siteId == nil { + return localVarReturnValue, nil, reportError("siteId is required and must be specified") + } + if r.selector == nil { + return localVarReturnValue, nil, reportError("selector is required and must be specified") + } + + parameterAddToHeaderOrQuery(localVarQueryParams, "siteId", r.siteId, "form", "") + parameterAddToHeaderOrQuery(localVarQueryParams, "selector", r.selector, "form", "") + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // 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 + } + 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 == 404 { + 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 == 500 { + 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 +} + +type ApiGetAllMeasurementTrustedProfileRequest struct { + ctx context.Context + ApiService *MeasuredBootTrustedProfileAPIService + siteId *string + org string +} + +// ID of the Site +func (r ApiGetAllMeasurementTrustedProfileRequest) SiteId(siteId string) ApiGetAllMeasurementTrustedProfileRequest { + r.siteId = &siteId + return r +} + +func (r ApiGetAllMeasurementTrustedProfileRequest) Execute() ([]MeasurementTrustedProfile, *http.Response, error) { + return r.ApiService.GetAllMeasurementTrustedProfileExecute(r) +} + +/* +GetAllMeasurementTrustedProfile Retrieve All Measured Boot Trusted Profile Approvals + +Retrieve all measured-boot trusted Profile approvals for a Site. + +Org must have an Infrastructure Provider entity that owns the Site. 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 ApiGetAllMeasurementTrustedProfileRequest +*/ +func (a *MeasuredBootTrustedProfileAPIService) GetAllMeasurementTrustedProfile(ctx context.Context, org string) ApiGetAllMeasurementTrustedProfileRequest { + return ApiGetAllMeasurementTrustedProfileRequest{ + ApiService: a, + ctx: ctx, + org: org, + } +} + +// Execute executes the request +// +// @return []MeasurementTrustedProfile +func (a *MeasuredBootTrustedProfileAPIService) GetAllMeasurementTrustedProfileExecute(r ApiGetAllMeasurementTrustedProfileRequest) ([]MeasurementTrustedProfile, *http.Response, error) { + var ( + localVarHTTPMethod = http.MethodGet + localVarPostBody interface{} + formFiles []formFile + localVarReturnValue []MeasurementTrustedProfile + ) + + localBasePath, err := a.client.cfg.ServerURLWithContext(r.ctx, "MeasuredBootTrustedProfileAPIService.GetAllMeasurementTrustedProfile") + if err != nil { + return localVarReturnValue, nil, &GenericOpenAPIError{error: err.Error()} + } + + localVarPath := localBasePath + "/v2/org/{org}/nico/measured-boot/trusted-profile" + 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.siteId == nil { + return localVarReturnValue, nil, reportError("siteId is required and must be specified") + } + + parameterAddToHeaderOrQuery(localVarQueryParams, "siteId", r.siteId, "form", "") + // to determine the Content-Type header + localVarHTTPContentTypes := []string{} + + // 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 + } + 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 == 404 { + 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 == 500 { + 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 f457710425..0891270a4a 100644 --- a/rest-api/sdk/standard/client.go +++ b/rest-api/sdk/standard/client.go @@ -87,6 +87,10 @@ type APIClient struct { MachineAPI *MachineAPIService + MeasuredBootTrustedMachineAPI *MeasuredBootTrustedMachineAPIService + + MeasuredBootTrustedProfileAPI *MeasuredBootTrustedProfileAPIService + MetadataAPI *MetadataAPIService NVLinkLogicalPartitionAPI *NVLinkLogicalPartitionAPIService @@ -166,6 +170,8 @@ func NewAPIClient(cfg *Configuration) *APIClient { c.InstanceAPI = (*InstanceAPIService)(&c.common) c.InstanceTypeAPI = (*InstanceTypeAPIService)(&c.common) c.MachineAPI = (*MachineAPIService)(&c.common) + c.MeasuredBootTrustedMachineAPI = (*MeasuredBootTrustedMachineAPIService)(&c.common) + c.MeasuredBootTrustedProfileAPI = (*MeasuredBootTrustedProfileAPIService)(&c.common) c.MetadataAPI = (*MetadataAPIService)(&c.common) c.NVLinkLogicalPartitionAPI = (*NVLinkLogicalPartitionAPIService)(&c.common) c.NetworkSecurityGroupAPI = (*NetworkSecurityGroupAPIService)(&c.common) diff --git a/rest-api/sdk/standard/model_measurement_trusted_machine.go b/rest-api/sdk/standard/model_measurement_trusted_machine.go new file mode 100644 index 0000000000..dc95789b49 --- /dev/null +++ b/rest-api/sdk/standard/model_measurement_trusted_machine.go @@ -0,0 +1,327 @@ +/* +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" + "time" +) + +// checks if the MeasurementTrustedMachine type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &MeasurementTrustedMachine{} + +// MeasurementTrustedMachine A measured-boot trusted Machine approval. +type MeasurementTrustedMachine struct { + // Unique approval ID. + ApprovalId string `json:"approvalId"` + // Machine UUID, or `*` when the approval applies to all Machines. + MachineId string `json:"machineId"` + // Whether the approval is consumed once or persists for future reports. + ApprovalType string `json:"approvalType"` + // Optional comma-separated PCR register selector. + PcrRegisters *string `json:"pcrRegisters,omitempty"` + // Optional operator comments about the approval. + Comments *string `json:"comments,omitempty"` + // Time when the approval was created. + Created *time.Time `json:"created,omitempty"` +} + +type _MeasurementTrustedMachine MeasurementTrustedMachine + +// NewMeasurementTrustedMachine instantiates a new MeasurementTrustedMachine 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 NewMeasurementTrustedMachine(approvalId string, machineId string, approvalType string) *MeasurementTrustedMachine { + this := MeasurementTrustedMachine{} + this.ApprovalId = approvalId + this.MachineId = machineId + this.ApprovalType = approvalType + return &this +} + +// NewMeasurementTrustedMachineWithDefaults instantiates a new MeasurementTrustedMachine 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 NewMeasurementTrustedMachineWithDefaults() *MeasurementTrustedMachine { + this := MeasurementTrustedMachine{} + return &this +} + +// GetApprovalId returns the ApprovalId field value +func (o *MeasurementTrustedMachine) GetApprovalId() string { + if o == nil { + var ret string + return ret + } + + return o.ApprovalId +} + +// GetApprovalIdOk returns a tuple with the ApprovalId field value +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedMachine) GetApprovalIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.ApprovalId, true +} + +// SetApprovalId sets field value +func (o *MeasurementTrustedMachine) SetApprovalId(v string) { + o.ApprovalId = v +} + +// GetMachineId returns the MachineId field value +func (o *MeasurementTrustedMachine) GetMachineId() string { + if o == nil { + var ret string + return ret + } + + return o.MachineId +} + +// GetMachineIdOk returns a tuple with the MachineId field value +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedMachine) GetMachineIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.MachineId, true +} + +// SetMachineId sets field value +func (o *MeasurementTrustedMachine) SetMachineId(v string) { + o.MachineId = v +} + +// GetApprovalType returns the ApprovalType field value +func (o *MeasurementTrustedMachine) GetApprovalType() string { + if o == nil { + var ret string + return ret + } + + return o.ApprovalType +} + +// GetApprovalTypeOk returns a tuple with the ApprovalType field value +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedMachine) GetApprovalTypeOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.ApprovalType, true +} + +// SetApprovalType sets field value +func (o *MeasurementTrustedMachine) SetApprovalType(v string) { + o.ApprovalType = v +} + +// GetPcrRegisters returns the PcrRegisters field value if set, zero value otherwise. +func (o *MeasurementTrustedMachine) GetPcrRegisters() string { + if o == nil || IsNil(o.PcrRegisters) { + var ret string + return ret + } + return *o.PcrRegisters +} + +// GetPcrRegistersOk returns a tuple with the PcrRegisters field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedMachine) GetPcrRegistersOk() (*string, bool) { + if o == nil || IsNil(o.PcrRegisters) { + return nil, false + } + return o.PcrRegisters, true +} + +// HasPcrRegisters returns a boolean if a field has been set. +func (o *MeasurementTrustedMachine) HasPcrRegisters() bool { + if o != nil && !IsNil(o.PcrRegisters) { + return true + } + + return false +} + +// SetPcrRegisters gets a reference to the given string and assigns it to the PcrRegisters field. +func (o *MeasurementTrustedMachine) SetPcrRegisters(v string) { + o.PcrRegisters = &v +} + +// GetComments returns the Comments field value if set, zero value otherwise. +func (o *MeasurementTrustedMachine) GetComments() string { + if o == nil || IsNil(o.Comments) { + var ret string + return ret + } + return *o.Comments +} + +// GetCommentsOk returns a tuple with the Comments field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedMachine) GetCommentsOk() (*string, bool) { + if o == nil || IsNil(o.Comments) { + return nil, false + } + return o.Comments, true +} + +// HasComments returns a boolean if a field has been set. +func (o *MeasurementTrustedMachine) HasComments() bool { + if o != nil && !IsNil(o.Comments) { + return true + } + + return false +} + +// SetComments gets a reference to the given string and assigns it to the Comments field. +func (o *MeasurementTrustedMachine) SetComments(v string) { + o.Comments = &v +} + +// GetCreated returns the Created field value if set, zero value otherwise. +func (o *MeasurementTrustedMachine) GetCreated() time.Time { + if o == nil || IsNil(o.Created) { + var ret time.Time + return ret + } + return *o.Created +} + +// GetCreatedOk returns a tuple with the Created field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedMachine) GetCreatedOk() (*time.Time, bool) { + if o == nil || IsNil(o.Created) { + return nil, false + } + return o.Created, true +} + +// HasCreated returns a boolean if a field has been set. +func (o *MeasurementTrustedMachine) HasCreated() bool { + if o != nil && !IsNil(o.Created) { + return true + } + + return false +} + +// SetCreated gets a reference to the given time.Time and assigns it to the Created field. +func (o *MeasurementTrustedMachine) SetCreated(v time.Time) { + o.Created = &v +} + +func (o MeasurementTrustedMachine) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o MeasurementTrustedMachine) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["approvalId"] = o.ApprovalId + toSerialize["machineId"] = o.MachineId + toSerialize["approvalType"] = o.ApprovalType + if !IsNil(o.PcrRegisters) { + toSerialize["pcrRegisters"] = o.PcrRegisters + } + if !IsNil(o.Comments) { + toSerialize["comments"] = o.Comments + } + if !IsNil(o.Created) { + toSerialize["created"] = o.Created + } + return toSerialize, nil +} + +func (o *MeasurementTrustedMachine) 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{ + "approvalId", + "machineId", + "approvalType", + } + + 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) + } + } + + varMeasurementTrustedMachine := _MeasurementTrustedMachine{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varMeasurementTrustedMachine) + + if err != nil { + return err + } + + *o = MeasurementTrustedMachine(varMeasurementTrustedMachine) + + return err +} + +type NullableMeasurementTrustedMachine struct { + value *MeasurementTrustedMachine + isSet bool +} + +func (v NullableMeasurementTrustedMachine) Get() *MeasurementTrustedMachine { + return v.value +} + +func (v *NullableMeasurementTrustedMachine) Set(val *MeasurementTrustedMachine) { + v.value = val + v.isSet = true +} + +func (v NullableMeasurementTrustedMachine) IsSet() bool { + return v.isSet +} + +func (v *NullableMeasurementTrustedMachine) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableMeasurementTrustedMachine(val *MeasurementTrustedMachine) *NullableMeasurementTrustedMachine { + return &NullableMeasurementTrustedMachine{value: val, isSet: true} +} + +func (v NullableMeasurementTrustedMachine) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableMeasurementTrustedMachine) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/rest-api/sdk/standard/model_measurement_trusted_machine_create_request.go b/rest-api/sdk/standard/model_measurement_trusted_machine_create_request.go new file mode 100644 index 0000000000..a091bd656b --- /dev/null +++ b/rest-api/sdk/standard/model_measurement_trusted_machine_create_request.go @@ -0,0 +1,289 @@ +/* +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 MeasurementTrustedMachineCreateRequest type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &MeasurementTrustedMachineCreateRequest{} + +// MeasurementTrustedMachineCreateRequest Request to approve a Machine for automatic promotion of measured-boot reports. +type MeasurementTrustedMachineCreateRequest struct { + // ID of the Site where the approval applies. + SiteId string `json:"siteId"` + // Machine UUID, or `*` to approve all Machines at the Site. + MachineId string `json:"machineId"` + // Whether the approval is consumed once or persists for future reports. + ApprovalType string `json:"approvalType"` + // Optional comma-separated PCR register selector. All registers are used when omitted. + PcrRegisters *string `json:"pcrRegisters,omitempty"` + // Optional operator comments about the approval. + Comments *string `json:"comments,omitempty"` +} + +type _MeasurementTrustedMachineCreateRequest MeasurementTrustedMachineCreateRequest + +// NewMeasurementTrustedMachineCreateRequest instantiates a new MeasurementTrustedMachineCreateRequest 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 NewMeasurementTrustedMachineCreateRequest(siteId string, machineId string, approvalType string) *MeasurementTrustedMachineCreateRequest { + this := MeasurementTrustedMachineCreateRequest{} + this.SiteId = siteId + this.MachineId = machineId + this.ApprovalType = approvalType + return &this +} + +// NewMeasurementTrustedMachineCreateRequestWithDefaults instantiates a new MeasurementTrustedMachineCreateRequest 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 NewMeasurementTrustedMachineCreateRequestWithDefaults() *MeasurementTrustedMachineCreateRequest { + this := MeasurementTrustedMachineCreateRequest{} + return &this +} + +// GetSiteId returns the SiteId field value +func (o *MeasurementTrustedMachineCreateRequest) 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 *MeasurementTrustedMachineCreateRequest) GetSiteIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.SiteId, true +} + +// SetSiteId sets field value +func (o *MeasurementTrustedMachineCreateRequest) SetSiteId(v string) { + o.SiteId = v +} + +// GetMachineId returns the MachineId field value +func (o *MeasurementTrustedMachineCreateRequest) GetMachineId() string { + if o == nil { + var ret string + return ret + } + + return o.MachineId +} + +// GetMachineIdOk returns a tuple with the MachineId field value +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedMachineCreateRequest) GetMachineIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.MachineId, true +} + +// SetMachineId sets field value +func (o *MeasurementTrustedMachineCreateRequest) SetMachineId(v string) { + o.MachineId = v +} + +// GetApprovalType returns the ApprovalType field value +func (o *MeasurementTrustedMachineCreateRequest) GetApprovalType() string { + if o == nil { + var ret string + return ret + } + + return o.ApprovalType +} + +// GetApprovalTypeOk returns a tuple with the ApprovalType field value +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedMachineCreateRequest) GetApprovalTypeOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.ApprovalType, true +} + +// SetApprovalType sets field value +func (o *MeasurementTrustedMachineCreateRequest) SetApprovalType(v string) { + o.ApprovalType = v +} + +// GetPcrRegisters returns the PcrRegisters field value if set, zero value otherwise. +func (o *MeasurementTrustedMachineCreateRequest) GetPcrRegisters() string { + if o == nil || IsNil(o.PcrRegisters) { + var ret string + return ret + } + return *o.PcrRegisters +} + +// GetPcrRegistersOk returns a tuple with the PcrRegisters field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedMachineCreateRequest) GetPcrRegistersOk() (*string, bool) { + if o == nil || IsNil(o.PcrRegisters) { + return nil, false + } + return o.PcrRegisters, true +} + +// HasPcrRegisters returns a boolean if a field has been set. +func (o *MeasurementTrustedMachineCreateRequest) HasPcrRegisters() bool { + if o != nil && !IsNil(o.PcrRegisters) { + return true + } + + return false +} + +// SetPcrRegisters gets a reference to the given string and assigns it to the PcrRegisters field. +func (o *MeasurementTrustedMachineCreateRequest) SetPcrRegisters(v string) { + o.PcrRegisters = &v +} + +// GetComments returns the Comments field value if set, zero value otherwise. +func (o *MeasurementTrustedMachineCreateRequest) GetComments() string { + if o == nil || IsNil(o.Comments) { + var ret string + return ret + } + return *o.Comments +} + +// GetCommentsOk returns a tuple with the Comments field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedMachineCreateRequest) GetCommentsOk() (*string, bool) { + if o == nil || IsNil(o.Comments) { + return nil, false + } + return o.Comments, true +} + +// HasComments returns a boolean if a field has been set. +func (o *MeasurementTrustedMachineCreateRequest) HasComments() bool { + if o != nil && !IsNil(o.Comments) { + return true + } + + return false +} + +// SetComments gets a reference to the given string and assigns it to the Comments field. +func (o *MeasurementTrustedMachineCreateRequest) SetComments(v string) { + o.Comments = &v +} + +func (o MeasurementTrustedMachineCreateRequest) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o MeasurementTrustedMachineCreateRequest) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["siteId"] = o.SiteId + toSerialize["machineId"] = o.MachineId + toSerialize["approvalType"] = o.ApprovalType + if !IsNil(o.PcrRegisters) { + toSerialize["pcrRegisters"] = o.PcrRegisters + } + if !IsNil(o.Comments) { + toSerialize["comments"] = o.Comments + } + return toSerialize, nil +} + +func (o *MeasurementTrustedMachineCreateRequest) 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", + "machineId", + "approvalType", + } + + 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) + } + } + + varMeasurementTrustedMachineCreateRequest := _MeasurementTrustedMachineCreateRequest{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varMeasurementTrustedMachineCreateRequest) + + if err != nil { + return err + } + + *o = MeasurementTrustedMachineCreateRequest(varMeasurementTrustedMachineCreateRequest) + + return err +} + +type NullableMeasurementTrustedMachineCreateRequest struct { + value *MeasurementTrustedMachineCreateRequest + isSet bool +} + +func (v NullableMeasurementTrustedMachineCreateRequest) Get() *MeasurementTrustedMachineCreateRequest { + return v.value +} + +func (v *NullableMeasurementTrustedMachineCreateRequest) Set(val *MeasurementTrustedMachineCreateRequest) { + v.value = val + v.isSet = true +} + +func (v NullableMeasurementTrustedMachineCreateRequest) IsSet() bool { + return v.isSet +} + +func (v *NullableMeasurementTrustedMachineCreateRequest) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableMeasurementTrustedMachineCreateRequest(val *MeasurementTrustedMachineCreateRequest) *NullableMeasurementTrustedMachineCreateRequest { + return &NullableMeasurementTrustedMachineCreateRequest{value: val, isSet: true} +} + +func (v NullableMeasurementTrustedMachineCreateRequest) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableMeasurementTrustedMachineCreateRequest) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/rest-api/sdk/standard/model_measurement_trusted_profile.go b/rest-api/sdk/standard/model_measurement_trusted_profile.go new file mode 100644 index 0000000000..a1737b3874 --- /dev/null +++ b/rest-api/sdk/standard/model_measurement_trusted_profile.go @@ -0,0 +1,327 @@ +/* +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" + "time" +) + +// checks if the MeasurementTrustedProfile type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &MeasurementTrustedProfile{} + +// MeasurementTrustedProfile A measured-boot trusted system profile approval. +type MeasurementTrustedProfile struct { + // Unique approval ID. + ApprovalId string `json:"approvalId"` + // ID of the measured-boot system profile. + ProfileId string `json:"profileId"` + // Whether the approval is consumed once or persists for future reports. + ApprovalType string `json:"approvalType"` + // Optional comma-separated PCR register selector. + PcrRegisters *string `json:"pcrRegisters,omitempty"` + // Optional operator comments about the approval. + Comments *string `json:"comments,omitempty"` + // Time when the approval was created. + Created *time.Time `json:"created,omitempty"` +} + +type _MeasurementTrustedProfile MeasurementTrustedProfile + +// NewMeasurementTrustedProfile instantiates a new MeasurementTrustedProfile 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 NewMeasurementTrustedProfile(approvalId string, profileId string, approvalType string) *MeasurementTrustedProfile { + this := MeasurementTrustedProfile{} + this.ApprovalId = approvalId + this.ProfileId = profileId + this.ApprovalType = approvalType + return &this +} + +// NewMeasurementTrustedProfileWithDefaults instantiates a new MeasurementTrustedProfile 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 NewMeasurementTrustedProfileWithDefaults() *MeasurementTrustedProfile { + this := MeasurementTrustedProfile{} + return &this +} + +// GetApprovalId returns the ApprovalId field value +func (o *MeasurementTrustedProfile) GetApprovalId() string { + if o == nil { + var ret string + return ret + } + + return o.ApprovalId +} + +// GetApprovalIdOk returns a tuple with the ApprovalId field value +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedProfile) GetApprovalIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.ApprovalId, true +} + +// SetApprovalId sets field value +func (o *MeasurementTrustedProfile) SetApprovalId(v string) { + o.ApprovalId = v +} + +// GetProfileId returns the ProfileId field value +func (o *MeasurementTrustedProfile) GetProfileId() string { + if o == nil { + var ret string + return ret + } + + return o.ProfileId +} + +// GetProfileIdOk returns a tuple with the ProfileId field value +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedProfile) GetProfileIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.ProfileId, true +} + +// SetProfileId sets field value +func (o *MeasurementTrustedProfile) SetProfileId(v string) { + o.ProfileId = v +} + +// GetApprovalType returns the ApprovalType field value +func (o *MeasurementTrustedProfile) GetApprovalType() string { + if o == nil { + var ret string + return ret + } + + return o.ApprovalType +} + +// GetApprovalTypeOk returns a tuple with the ApprovalType field value +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedProfile) GetApprovalTypeOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.ApprovalType, true +} + +// SetApprovalType sets field value +func (o *MeasurementTrustedProfile) SetApprovalType(v string) { + o.ApprovalType = v +} + +// GetPcrRegisters returns the PcrRegisters field value if set, zero value otherwise. +func (o *MeasurementTrustedProfile) GetPcrRegisters() string { + if o == nil || IsNil(o.PcrRegisters) { + var ret string + return ret + } + return *o.PcrRegisters +} + +// GetPcrRegistersOk returns a tuple with the PcrRegisters field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedProfile) GetPcrRegistersOk() (*string, bool) { + if o == nil || IsNil(o.PcrRegisters) { + return nil, false + } + return o.PcrRegisters, true +} + +// HasPcrRegisters returns a boolean if a field has been set. +func (o *MeasurementTrustedProfile) HasPcrRegisters() bool { + if o != nil && !IsNil(o.PcrRegisters) { + return true + } + + return false +} + +// SetPcrRegisters gets a reference to the given string and assigns it to the PcrRegisters field. +func (o *MeasurementTrustedProfile) SetPcrRegisters(v string) { + o.PcrRegisters = &v +} + +// GetComments returns the Comments field value if set, zero value otherwise. +func (o *MeasurementTrustedProfile) GetComments() string { + if o == nil || IsNil(o.Comments) { + var ret string + return ret + } + return *o.Comments +} + +// GetCommentsOk returns a tuple with the Comments field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedProfile) GetCommentsOk() (*string, bool) { + if o == nil || IsNil(o.Comments) { + return nil, false + } + return o.Comments, true +} + +// HasComments returns a boolean if a field has been set. +func (o *MeasurementTrustedProfile) HasComments() bool { + if o != nil && !IsNil(o.Comments) { + return true + } + + return false +} + +// SetComments gets a reference to the given string and assigns it to the Comments field. +func (o *MeasurementTrustedProfile) SetComments(v string) { + o.Comments = &v +} + +// GetCreated returns the Created field value if set, zero value otherwise. +func (o *MeasurementTrustedProfile) GetCreated() time.Time { + if o == nil || IsNil(o.Created) { + var ret time.Time + return ret + } + return *o.Created +} + +// GetCreatedOk returns a tuple with the Created field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedProfile) GetCreatedOk() (*time.Time, bool) { + if o == nil || IsNil(o.Created) { + return nil, false + } + return o.Created, true +} + +// HasCreated returns a boolean if a field has been set. +func (o *MeasurementTrustedProfile) HasCreated() bool { + if o != nil && !IsNil(o.Created) { + return true + } + + return false +} + +// SetCreated gets a reference to the given time.Time and assigns it to the Created field. +func (o *MeasurementTrustedProfile) SetCreated(v time.Time) { + o.Created = &v +} + +func (o MeasurementTrustedProfile) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o MeasurementTrustedProfile) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["approvalId"] = o.ApprovalId + toSerialize["profileId"] = o.ProfileId + toSerialize["approvalType"] = o.ApprovalType + if !IsNil(o.PcrRegisters) { + toSerialize["pcrRegisters"] = o.PcrRegisters + } + if !IsNil(o.Comments) { + toSerialize["comments"] = o.Comments + } + if !IsNil(o.Created) { + toSerialize["created"] = o.Created + } + return toSerialize, nil +} + +func (o *MeasurementTrustedProfile) 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{ + "approvalId", + "profileId", + "approvalType", + } + + 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) + } + } + + varMeasurementTrustedProfile := _MeasurementTrustedProfile{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varMeasurementTrustedProfile) + + if err != nil { + return err + } + + *o = MeasurementTrustedProfile(varMeasurementTrustedProfile) + + return err +} + +type NullableMeasurementTrustedProfile struct { + value *MeasurementTrustedProfile + isSet bool +} + +func (v NullableMeasurementTrustedProfile) Get() *MeasurementTrustedProfile { + return v.value +} + +func (v *NullableMeasurementTrustedProfile) Set(val *MeasurementTrustedProfile) { + v.value = val + v.isSet = true +} + +func (v NullableMeasurementTrustedProfile) IsSet() bool { + return v.isSet +} + +func (v *NullableMeasurementTrustedProfile) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableMeasurementTrustedProfile(val *MeasurementTrustedProfile) *NullableMeasurementTrustedProfile { + return &NullableMeasurementTrustedProfile{value: val, isSet: true} +} + +func (v NullableMeasurementTrustedProfile) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableMeasurementTrustedProfile) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} diff --git a/rest-api/sdk/standard/model_measurement_trusted_profile_create_request.go b/rest-api/sdk/standard/model_measurement_trusted_profile_create_request.go new file mode 100644 index 0000000000..5c2c7e8738 --- /dev/null +++ b/rest-api/sdk/standard/model_measurement_trusted_profile_create_request.go @@ -0,0 +1,289 @@ +/* +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 MeasurementTrustedProfileCreateRequest type satisfies the MappedNullable interface at compile time +var _ MappedNullable = &MeasurementTrustedProfileCreateRequest{} + +// MeasurementTrustedProfileCreateRequest Request to approve a system profile for automatic promotion of measured-boot reports. +type MeasurementTrustedProfileCreateRequest struct { + // ID of the Site where the approval applies. + SiteId string `json:"siteId"` + // ID of the measured-boot system profile. + ProfileId string `json:"profileId"` + // Whether the approval is consumed once or persists for future reports. + ApprovalType string `json:"approvalType"` + // Optional comma-separated PCR register selector. All registers are used when omitted. + PcrRegisters *string `json:"pcrRegisters,omitempty"` + // Optional operator comments about the approval. + Comments *string `json:"comments,omitempty"` +} + +type _MeasurementTrustedProfileCreateRequest MeasurementTrustedProfileCreateRequest + +// NewMeasurementTrustedProfileCreateRequest instantiates a new MeasurementTrustedProfileCreateRequest 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 NewMeasurementTrustedProfileCreateRequest(siteId string, profileId string, approvalType string) *MeasurementTrustedProfileCreateRequest { + this := MeasurementTrustedProfileCreateRequest{} + this.SiteId = siteId + this.ProfileId = profileId + this.ApprovalType = approvalType + return &this +} + +// NewMeasurementTrustedProfileCreateRequestWithDefaults instantiates a new MeasurementTrustedProfileCreateRequest 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 NewMeasurementTrustedProfileCreateRequestWithDefaults() *MeasurementTrustedProfileCreateRequest { + this := MeasurementTrustedProfileCreateRequest{} + return &this +} + +// GetSiteId returns the SiteId field value +func (o *MeasurementTrustedProfileCreateRequest) 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 *MeasurementTrustedProfileCreateRequest) GetSiteIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.SiteId, true +} + +// SetSiteId sets field value +func (o *MeasurementTrustedProfileCreateRequest) SetSiteId(v string) { + o.SiteId = v +} + +// GetProfileId returns the ProfileId field value +func (o *MeasurementTrustedProfileCreateRequest) GetProfileId() string { + if o == nil { + var ret string + return ret + } + + return o.ProfileId +} + +// GetProfileIdOk returns a tuple with the ProfileId field value +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedProfileCreateRequest) GetProfileIdOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.ProfileId, true +} + +// SetProfileId sets field value +func (o *MeasurementTrustedProfileCreateRequest) SetProfileId(v string) { + o.ProfileId = v +} + +// GetApprovalType returns the ApprovalType field value +func (o *MeasurementTrustedProfileCreateRequest) GetApprovalType() string { + if o == nil { + var ret string + return ret + } + + return o.ApprovalType +} + +// GetApprovalTypeOk returns a tuple with the ApprovalType field value +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedProfileCreateRequest) GetApprovalTypeOk() (*string, bool) { + if o == nil { + return nil, false + } + return &o.ApprovalType, true +} + +// SetApprovalType sets field value +func (o *MeasurementTrustedProfileCreateRequest) SetApprovalType(v string) { + o.ApprovalType = v +} + +// GetPcrRegisters returns the PcrRegisters field value if set, zero value otherwise. +func (o *MeasurementTrustedProfileCreateRequest) GetPcrRegisters() string { + if o == nil || IsNil(o.PcrRegisters) { + var ret string + return ret + } + return *o.PcrRegisters +} + +// GetPcrRegistersOk returns a tuple with the PcrRegisters field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedProfileCreateRequest) GetPcrRegistersOk() (*string, bool) { + if o == nil || IsNil(o.PcrRegisters) { + return nil, false + } + return o.PcrRegisters, true +} + +// HasPcrRegisters returns a boolean if a field has been set. +func (o *MeasurementTrustedProfileCreateRequest) HasPcrRegisters() bool { + if o != nil && !IsNil(o.PcrRegisters) { + return true + } + + return false +} + +// SetPcrRegisters gets a reference to the given string and assigns it to the PcrRegisters field. +func (o *MeasurementTrustedProfileCreateRequest) SetPcrRegisters(v string) { + o.PcrRegisters = &v +} + +// GetComments returns the Comments field value if set, zero value otherwise. +func (o *MeasurementTrustedProfileCreateRequest) GetComments() string { + if o == nil || IsNil(o.Comments) { + var ret string + return ret + } + return *o.Comments +} + +// GetCommentsOk returns a tuple with the Comments field value if set, nil otherwise +// and a boolean to check if the value has been set. +func (o *MeasurementTrustedProfileCreateRequest) GetCommentsOk() (*string, bool) { + if o == nil || IsNil(o.Comments) { + return nil, false + } + return o.Comments, true +} + +// HasComments returns a boolean if a field has been set. +func (o *MeasurementTrustedProfileCreateRequest) HasComments() bool { + if o != nil && !IsNil(o.Comments) { + return true + } + + return false +} + +// SetComments gets a reference to the given string and assigns it to the Comments field. +func (o *MeasurementTrustedProfileCreateRequest) SetComments(v string) { + o.Comments = &v +} + +func (o MeasurementTrustedProfileCreateRequest) MarshalJSON() ([]byte, error) { + toSerialize, err := o.ToMap() + if err != nil { + return []byte{}, err + } + return json.Marshal(toSerialize) +} + +func (o MeasurementTrustedProfileCreateRequest) ToMap() (map[string]interface{}, error) { + toSerialize := map[string]interface{}{} + toSerialize["siteId"] = o.SiteId + toSerialize["profileId"] = o.ProfileId + toSerialize["approvalType"] = o.ApprovalType + if !IsNil(o.PcrRegisters) { + toSerialize["pcrRegisters"] = o.PcrRegisters + } + if !IsNil(o.Comments) { + toSerialize["comments"] = o.Comments + } + return toSerialize, nil +} + +func (o *MeasurementTrustedProfileCreateRequest) 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", + "profileId", + "approvalType", + } + + 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) + } + } + + varMeasurementTrustedProfileCreateRequest := _MeasurementTrustedProfileCreateRequest{} + + decoder := json.NewDecoder(bytes.NewReader(data)) + decoder.DisallowUnknownFields() + err = decoder.Decode(&varMeasurementTrustedProfileCreateRequest) + + if err != nil { + return err + } + + *o = MeasurementTrustedProfileCreateRequest(varMeasurementTrustedProfileCreateRequest) + + return err +} + +type NullableMeasurementTrustedProfileCreateRequest struct { + value *MeasurementTrustedProfileCreateRequest + isSet bool +} + +func (v NullableMeasurementTrustedProfileCreateRequest) Get() *MeasurementTrustedProfileCreateRequest { + return v.value +} + +func (v *NullableMeasurementTrustedProfileCreateRequest) Set(val *MeasurementTrustedProfileCreateRequest) { + v.value = val + v.isSet = true +} + +func (v NullableMeasurementTrustedProfileCreateRequest) IsSet() bool { + return v.isSet +} + +func (v *NullableMeasurementTrustedProfileCreateRequest) Unset() { + v.value = nil + v.isSet = false +} + +func NewNullableMeasurementTrustedProfileCreateRequest(val *MeasurementTrustedProfileCreateRequest) *NullableMeasurementTrustedProfileCreateRequest { + return &NullableMeasurementTrustedProfileCreateRequest{value: val, isSet: true} +} + +func (v NullableMeasurementTrustedProfileCreateRequest) MarshalJSON() ([]byte, error) { + return json.Marshal(v.value) +} + +func (v *NullableMeasurementTrustedProfileCreateRequest) UnmarshalJSON(src []byte) error { + v.isSet = true + return json.Unmarshal(src, &v.value) +} From 60f09f38a6ee00f0bf1008006ca5185eff4d32ce Mon Sep 17 00:00:00 2001 From: Kyle Felter Date: Mon, 13 Jul 2026 20:46:23 -0500 Subject: [PATCH 2/4] feat: Add measured boot SDK headers --- rest-api/sdk/standard/api_measured_boot_trusted_machine.go | 3 +++ rest-api/sdk/standard/api_measured_boot_trusted_profile.go | 3 +++ rest-api/sdk/standard/model_measurement_trusted_machine.go | 3 +++ .../model_measurement_trusted_machine_create_request.go | 3 +++ rest-api/sdk/standard/model_measurement_trusted_profile.go | 3 +++ .../model_measurement_trusted_profile_create_request.go | 3 +++ 6 files changed, 18 insertions(+) diff --git a/rest-api/sdk/standard/api_measured_boot_trusted_machine.go b/rest-api/sdk/standard/api_measured_boot_trusted_machine.go index fa0a8f3290..54227071e8 100644 --- a/rest-api/sdk/standard/api_measured_boot_trusted_machine.go +++ b/rest-api/sdk/standard/api_measured_boot_trusted_machine.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/api_measured_boot_trusted_profile.go b/rest-api/sdk/standard/api_measured_boot_trusted_profile.go index 950c14ff70..ae62fe3295 100644 --- a/rest-api/sdk/standard/api_measured_boot_trusted_profile.go +++ b/rest-api/sdk/standard/api_measured_boot_trusted_profile.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_measurement_trusted_machine.go b/rest-api/sdk/standard/model_measurement_trusted_machine.go index dc95789b49..d2e1dac118 100644 --- a/rest-api/sdk/standard/model_measurement_trusted_machine.go +++ b/rest-api/sdk/standard/model_measurement_trusted_machine.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_measurement_trusted_machine_create_request.go b/rest-api/sdk/standard/model_measurement_trusted_machine_create_request.go index a091bd656b..bd0f4855ef 100644 --- a/rest-api/sdk/standard/model_measurement_trusted_machine_create_request.go +++ b/rest-api/sdk/standard/model_measurement_trusted_machine_create_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 diff --git a/rest-api/sdk/standard/model_measurement_trusted_profile.go b/rest-api/sdk/standard/model_measurement_trusted_profile.go index a1737b3874..faa51f859b 100644 --- a/rest-api/sdk/standard/model_measurement_trusted_profile.go +++ b/rest-api/sdk/standard/model_measurement_trusted_profile.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_measurement_trusted_profile_create_request.go b/rest-api/sdk/standard/model_measurement_trusted_profile_create_request.go index 5c2c7e8738..9d604f210d 100644 --- a/rest-api/sdk/standard/model_measurement_trusted_profile_create_request.go +++ b/rest-api/sdk/standard/model_measurement_trusted_profile_create_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 From d886233d5b6a4ca305c9e68456dca0e2c8f4065a Mon Sep 17 00:00:00 2001 From: Kyle Felter Date: Mon, 13 Jul 2026 21:04:42 -0500 Subject: [PATCH 3/4] refactor: Use measured boot conversion methods Signed-off-by: Kyle Felter --- .../api/pkg/api/handler/measurementtrust.go | 16 +++-- .../api/pkg/api/model/measurementtrust.go | 64 +++++++++++++------ .../pkg/api/model/measurementtrust_test.go | 22 +++++-- 3 files changed, 72 insertions(+), 30 deletions(-) diff --git a/rest-api/api/pkg/api/handler/measurementtrust.go b/rest-api/api/pkg/api/handler/measurementtrust.go index 66e8b7c7a0..1d3e414d44 100644 --- a/rest-api/api/pkg/api/handler/measurementtrust.go +++ b/rest-api/api/pkg/api/handler/measurementtrust.go @@ -66,7 +66,7 @@ func (h CreateMeasurementTrustedMachineHandler) Handle(c echo.Context) error { logAPIError(logger, apiErr, "failed to create machine trust approval") return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, nil) } - return c.JSON(http.StatusCreated, model.APIMeasurementTrustedMachineFromProto(coreResp.GetApprovalRecord())) + return c.JSON(http.StatusCreated, model.NewAPIMeasurementTrustedMachine(coreResp.GetApprovalRecord())) } // ListMeasurementTrustedMachinesHandler lists machine trust approvals. @@ -97,7 +97,9 @@ func (h ListMeasurementTrustedMachinesHandler) Handle(c echo.Context) error { logAPIError(logger, apiErr, "failed to list machine trust approvals") return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, nil) } - return c.JSON(http.StatusOK, model.APIMeasurementTrustedMachinesFromProto(coreResp.GetApprovalRecords())) + var resp model.APIMeasurementTrustedMachines + resp.FromProto(coreResp.GetApprovalRecords()) + return c.JSON(http.StatusOK, resp) } // DeleteMeasurementTrustedMachineHandler deletes a machine trust approval. @@ -133,7 +135,7 @@ func (h DeleteMeasurementTrustedMachineHandler) Handle(c echo.Context) error { logAPIError(logger, apiErr, "failed to delete machine trust approval") return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, nil) } - return c.JSON(http.StatusOK, model.APIMeasurementTrustedMachineFromProto(coreResp.GetApprovalRecord())) + return c.JSON(http.StatusOK, model.NewAPIMeasurementTrustedMachine(coreResp.GetApprovalRecord())) } // CreateMeasurementTrustedProfileHandler creates a profile trust approval. @@ -172,7 +174,7 @@ func (h CreateMeasurementTrustedProfileHandler) Handle(c echo.Context) error { logAPIError(logger, apiErr, "failed to create profile trust approval") return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, nil) } - return c.JSON(http.StatusCreated, model.APIMeasurementTrustedProfileFromProto(coreResp.GetApprovalRecord())) + return c.JSON(http.StatusCreated, model.NewAPIMeasurementTrustedProfile(coreResp.GetApprovalRecord())) } // ListMeasurementTrustedProfilesHandler lists profile trust approvals. @@ -203,7 +205,9 @@ func (h ListMeasurementTrustedProfilesHandler) Handle(c echo.Context) error { logAPIError(logger, apiErr, "failed to list profile trust approvals") return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, nil) } - return c.JSON(http.StatusOK, model.APIMeasurementTrustedProfilesFromProto(coreResp.GetApprovalRecords())) + var resp model.APIMeasurementTrustedProfiles + resp.FromProto(coreResp.GetApprovalRecords()) + return c.JSON(http.StatusOK, resp) } // DeleteMeasurementTrustedProfileHandler deletes a profile trust approval. @@ -239,5 +243,5 @@ func (h DeleteMeasurementTrustedProfileHandler) Handle(c echo.Context) error { logAPIError(logger, apiErr, "failed to delete profile trust approval") return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, nil) } - return c.JSON(http.StatusOK, model.APIMeasurementTrustedProfileFromProto(coreResp.GetApprovalRecord())) + return c.JSON(http.StatusOK, model.NewAPIMeasurementTrustedProfile(coreResp.GetApprovalRecord())) } diff --git a/rest-api/api/pkg/api/model/measurementtrust.go b/rest-api/api/pkg/api/model/measurementtrust.go index f3b5e2c3a2..c5a5406089 100644 --- a/rest-api/api/pkg/api/model/measurementtrust.go +++ b/rest-api/api/pkg/api/model/measurementtrust.go @@ -123,12 +123,22 @@ func (r *APIMeasurementTrustedProfileCreateRequest) ToProto() *corev1.AddMeasure return req } -// APIMeasurementTrustedMachineFromProto converts one Core machine trust record. -func APIMeasurementTrustedMachineFromProto(record *corev1.MeasurementApprovedMachineRecordPb) *APIMeasurementTrustedMachine { +// NewAPIMeasurementTrustedMachine creates an API model from a Core machine trust record. +func NewAPIMeasurementTrustedMachine(record *corev1.MeasurementApprovedMachineRecordPb) *APIMeasurementTrustedMachine { if record == nil { return nil } - resp := &APIMeasurementTrustedMachine{ + resp := &APIMeasurementTrustedMachine{} + resp.FromProto(record) + return resp +} + +// FromProto converts one Core machine trust record. +func (r *APIMeasurementTrustedMachine) FromProto(record *corev1.MeasurementApprovedMachineRecordPb) { + if record == nil { + return + } + *r = APIMeasurementTrustedMachine{ ApprovalID: record.GetApprovalId().GetValue(), MachineID: record.GetMachineId(), ApprovalType: measurementTrustApprovalTypeFromProto(record.GetApprovalType()), @@ -137,17 +147,26 @@ func APIMeasurementTrustedMachineFromProto(record *corev1.MeasurementApprovedMac } if ts := record.GetTs(); ts != nil { created := ts.AsTime().UTC() - resp.Created = &created + r.Created = &created } - return resp } -// APIMeasurementTrustedProfileFromProto converts one Core profile trust record. -func APIMeasurementTrustedProfileFromProto(record *corev1.MeasurementApprovedProfileRecordPb) *APIMeasurementTrustedProfile { +// NewAPIMeasurementTrustedProfile creates an API model from a Core profile trust record. +func NewAPIMeasurementTrustedProfile(record *corev1.MeasurementApprovedProfileRecordPb) *APIMeasurementTrustedProfile { if record == nil { return nil } - resp := &APIMeasurementTrustedProfile{ + resp := &APIMeasurementTrustedProfile{} + resp.FromProto(record) + return resp +} + +// FromProto converts one Core profile trust record. +func (r *APIMeasurementTrustedProfile) FromProto(record *corev1.MeasurementApprovedProfileRecordPb) { + if record == nil { + return + } + *r = APIMeasurementTrustedProfile{ ApprovalID: record.GetApprovalId().GetValue(), ProfileID: record.GetProfileId().GetValue(), ApprovalType: measurementTrustApprovalTypeFromProto(record.GetApprovalType()), @@ -156,27 +175,32 @@ func APIMeasurementTrustedProfileFromProto(record *corev1.MeasurementApprovedPro } if ts := record.GetTs(); ts != nil { created := ts.AsTime().UTC() - resp.Created = &created + r.Created = &created } - return resp } -// APIMeasurementTrustedMachinesFromProto converts Core machine trust records. -func APIMeasurementTrustedMachinesFromProto(records []*corev1.MeasurementApprovedMachineRecordPb) []*APIMeasurementTrustedMachine { - result := make([]*APIMeasurementTrustedMachine, 0, len(records)) +// APIMeasurementTrustedMachines is a list of machine trust approvals. +type APIMeasurementTrustedMachines []*APIMeasurementTrustedMachine + +// FromProto converts Core machine trust records. +func (r *APIMeasurementTrustedMachines) FromProto(records []*corev1.MeasurementApprovedMachineRecordPb) { + result := make(APIMeasurementTrustedMachines, 0, len(records)) for _, record := range records { - result = append(result, APIMeasurementTrustedMachineFromProto(record)) + result = append(result, NewAPIMeasurementTrustedMachine(record)) } - return result + *r = result } -// APIMeasurementTrustedProfilesFromProto converts Core profile trust records. -func APIMeasurementTrustedProfilesFromProto(records []*corev1.MeasurementApprovedProfileRecordPb) []*APIMeasurementTrustedProfile { - result := make([]*APIMeasurementTrustedProfile, 0, len(records)) +// APIMeasurementTrustedProfiles is a list of profile trust approvals. +type APIMeasurementTrustedProfiles []*APIMeasurementTrustedProfile + +// FromProto converts Core profile trust records. +func (r *APIMeasurementTrustedProfiles) FromProto(records []*corev1.MeasurementApprovedProfileRecordPb) { + result := make(APIMeasurementTrustedProfiles, 0, len(records)) for _, record := range records { - result = append(result, APIMeasurementTrustedProfileFromProto(record)) + result = append(result, NewAPIMeasurementTrustedProfile(record)) } - return result + *r = result } // MeasurementTrustedMachineRemoveProto builds and validates a Core machine removal request. diff --git a/rest-api/api/pkg/api/model/measurementtrust_test.go b/rest-api/api/pkg/api/model/measurementtrust_test.go index 60dbc84908..7cfd476399 100644 --- a/rest-api/api/pkg/api/model/measurementtrust_test.go +++ b/rest-api/api/pkg/api/model/measurementtrust_test.go @@ -89,25 +89,39 @@ func TestMeasurementTrustRemoveProtoSelectors(t *testing.T) { func TestMeasurementTrustResponsesFromProto(t *testing.T) { created := time.Date(2026, 7, 13, 20, 0, 0, 0, time.UTC) - machine := APIMeasurementTrustedMachineFromProto(&corev1.MeasurementApprovedMachineRecordPb{ + machineRecord := &corev1.MeasurementApprovedMachineRecordPb{ ApprovalId: &corev1.MeasurementApprovedMachineId{Value: "00000000-0000-0000-0000-000000000001"}, MachineId: "00000000-0000-0000-0000-000000000002", ApprovalType: corev1.MeasurementApprovedTypePb_Persist, PcrRegisters: "0,7", Comments: "trusted machine", Ts: timestamppb.New(created), - }) + } + machine := NewAPIMeasurementTrustedMachine(machineRecord) require.NotNil(t, machine) assert.Equal(t, MeasurementTrustApprovalTypePersist, machine.ApprovalType) assert.Equal(t, created, *machine.Created) - profile := APIMeasurementTrustedProfileFromProto(&corev1.MeasurementApprovedProfileRecordPb{ + profileRecord := &corev1.MeasurementApprovedProfileRecordPb{ ApprovalId: &corev1.MeasurementApprovedProfileId{Value: "00000000-0000-0000-0000-000000000003"}, ProfileId: &corev1.MeasurementSystemProfileId{Value: "00000000-0000-0000-0000-000000000004"}, ApprovalType: corev1.MeasurementApprovedTypePb_Oneshot, Ts: timestamppb.New(created), - }) + } + profile := NewAPIMeasurementTrustedProfile(profileRecord) require.NotNil(t, profile) assert.Equal(t, MeasurementTrustApprovalTypeOneshot, profile.ApprovalType) assert.Equal(t, created, *profile.Created) + + var machines APIMeasurementTrustedMachines + machines.FromProto([]*corev1.MeasurementApprovedMachineRecordPb{machineRecord, nil}) + require.Len(t, machines, 2) + assert.Equal(t, machine, machines[0]) + assert.Nil(t, machines[1]) + + var profiles APIMeasurementTrustedProfiles + profiles.FromProto([]*corev1.MeasurementApprovedProfileRecordPb{profileRecord, nil}) + require.Len(t, profiles, 2) + assert.Equal(t, profile, profiles[0]) + assert.Nil(t, profiles[1]) } From 6e0eee3357d44aeb1a8cf0964793c29a987d2869 Mon Sep 17 00:00:00 2001 From: Kyle Felter Date: Mon, 13 Jul 2026 23:23:17 -0500 Subject: [PATCH 4/4] refactor: Add measured boot delete requests Signed-off-by: Kyle Felter --- .../api/pkg/api/handler/measurementtrust.go | 12 +- .../pkg/api/handler/measurementtrust_test.go | 11 +- .../api/pkg/api/model/measurementtrust.go | 126 +++++++++++------- .../pkg/api/model/measurementtrust_test.go | 36 +++-- 4 files changed, 117 insertions(+), 68 deletions(-) diff --git a/rest-api/api/pkg/api/handler/measurementtrust.go b/rest-api/api/pkg/api/handler/measurementtrust.go index 1d3e414d44..4e4cd2e274 100644 --- a/rest-api/api/pkg/api/handler/measurementtrust.go +++ b/rest-api/api/pkg/api/handler/measurementtrust.go @@ -117,8 +117,8 @@ func (h DeleteMeasurementTrustedMachineHandler) Handle(c echo.Context) error { defer handlerSpan.End() } - coreReq, err := model.MeasurementTrustedMachineRemoveProto(c.QueryParam("selector"), c.Param("id")) - if err != nil { + apiReq := model.APIMeasurementTrustedMachineDeleteRequest{Selector: c.QueryParam("selector"), ID: c.Param("id")} + if err := apiReq.Validate(); err != nil { return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, err.Error(), nil) } @@ -130,7 +130,7 @@ func (h DeleteMeasurementTrustedMachineHandler) Handle(c echo.Context) error { } coreResp := &corev1.RemoveMeasurementTrustedMachineResponse{} - apiErr = common.ExecuteCoreGRPC(ctx, stc, corev1.Forge_RemoveMeasurementTrustedMachine_FullMethodName, coreReq, coreResp, siteID) + apiErr = common.ExecuteCoreGRPC(ctx, stc, corev1.Forge_RemoveMeasurementTrustedMachine_FullMethodName, apiReq.ToProto(), coreResp, siteID) if apiErr != nil { logAPIError(logger, apiErr, "failed to delete machine trust approval") return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, nil) @@ -225,8 +225,8 @@ func (h DeleteMeasurementTrustedProfileHandler) Handle(c echo.Context) error { defer handlerSpan.End() } - coreReq, err := model.MeasurementTrustedProfileRemoveProto(c.QueryParam("selector"), c.Param("id")) - if err != nil { + apiReq := model.APIMeasurementTrustedProfileDeleteRequest{Selector: c.QueryParam("selector"), ID: c.Param("id")} + if err := apiReq.Validate(); err != nil { return cutil.NewAPIErrorResponse(c, http.StatusBadRequest, err.Error(), nil) } @@ -238,7 +238,7 @@ func (h DeleteMeasurementTrustedProfileHandler) Handle(c echo.Context) error { } coreResp := &corev1.RemoveMeasurementTrustedProfileResponse{} - apiErr = common.ExecuteCoreGRPC(ctx, stc, corev1.Forge_RemoveMeasurementTrustedProfile_FullMethodName, coreReq, coreResp, siteID) + apiErr = common.ExecuteCoreGRPC(ctx, stc, corev1.Forge_RemoveMeasurementTrustedProfile_FullMethodName, apiReq.ToProto(), coreResp, siteID) if apiErr != nil { logAPIError(logger, apiErr, "failed to delete profile trust approval") return cutil.NewAPIErrorResponse(c, apiErr.Code, apiErr.Message, nil) diff --git a/rest-api/api/pkg/api/handler/measurementtrust_test.go b/rest-api/api/pkg/api/handler/measurementtrust_test.go index 24b1df6775..7dc0cab401 100644 --- a/rest-api/api/pkg/api/handler/measurementtrust_test.go +++ b/rest-api/api/pkg/api/handler/measurementtrust_test.go @@ -155,9 +155,16 @@ func TestMeasurementTrustHandlersRejectInvalidInput(t *testing.T) { func TestMeasurementTrustHandlerRequiresProviderAdmin(t *testing.T) { fixture := newMeasurementTrustHandlerFixture(t, nil, []string{authz.TenantAdminRole}) - handler := NewListMeasurementTrustedMachinesHandler(fixture.dbSession, fixture.scp) + listHandler := NewListMeasurementTrustedMachinesHandler(fixture.dbSession, fixture.scp) - rec := fixture.request(t, handler.Handle, http.MethodGet, "/?siteId="+fixture.siteID, "", nil) + rec := fixture.request(t, listHandler.Handle, http.MethodGet, "/?siteId="+fixture.siteID, "", nil) + assert.Equal(t, http.StatusForbidden, rec.Code) + + deleteHandler := NewDeleteMeasurementTrustedMachineHandler(fixture.dbSession, fixture.scp) + rec = fixture.request(t, deleteHandler.Handle, http.MethodDelete, "/?siteId="+fixture.siteID+"&selector=invalid", "invalid", nil) + assert.Equal(t, http.StatusBadRequest, rec.Code) + + rec = fixture.request(t, deleteHandler.Handle, http.MethodDelete, "/?siteId="+fixture.siteID+"&selector="+model.MeasurementTrustedMachineSelectorMachineID, "00000000-0000-0000-0000-000000000011", nil) assert.Equal(t, http.StatusForbidden, rec.Code) } diff --git a/rest-api/api/pkg/api/model/measurementtrust.go b/rest-api/api/pkg/api/model/measurementtrust.go index c5a5406089..3a015c5b3c 100644 --- a/rest-api/api/pkg/api/model/measurementtrust.go +++ b/rest-api/api/pkg/api/model/measurementtrust.go @@ -49,6 +49,18 @@ type APIMeasurementTrustedProfileCreateRequest struct { Comments string `json:"comments,omitempty"` } +// APIMeasurementTrustedMachineDeleteRequest deletes a machine trust approval. +type APIMeasurementTrustedMachineDeleteRequest struct { + Selector string `json:"-"` + ID string `json:"-"` +} + +// APIMeasurementTrustedProfileDeleteRequest deletes a profile trust approval. +type APIMeasurementTrustedProfileDeleteRequest struct { + Selector string `json:"-"` + ID string `json:"-"` +} + // APIMeasurementTrustedMachine is a machine trust approval. type APIMeasurementTrustedMachine struct { ApprovalID string `json:"approvalId"` @@ -98,6 +110,41 @@ func (r *APIMeasurementTrustedProfileCreateRequest) Validate() error { return validateMeasurementTrustApprovalType(r.ApprovalType) } +// Validate checks a machine trust approval deletion request. +func (r *APIMeasurementTrustedMachineDeleteRequest) Validate() error { + if err := validation.ValidateStruct(r, + validation.Field(&r.Selector, + validation.Required.Error(validationErrorValueRequired), + validation.In(MeasurementTrustedMachineSelectorApprovalID, MeasurementTrustedMachineSelectorMachineID). + Error(fmt.Sprintf("invalid selector %q (expected %q or %q)", r.Selector, MeasurementTrustedMachineSelectorApprovalID, MeasurementTrustedMachineSelectorMachineID)), + ), + validation.Field(&r.ID, validation.Required.Error(validationErrorValueRequired)), + ); err != nil { + return err + } + if r.Selector == MeasurementTrustedMachineSelectorApprovalID || r.ID != "*" { + if err := validation.Validate(r.ID, validationis.UUID.Error(validationErrorInvalidUUID)); err != nil { + return fmt.Errorf("id: %w", err) + } + } + return nil +} + +// Validate checks a profile trust approval deletion request. +func (r *APIMeasurementTrustedProfileDeleteRequest) Validate() error { + return validation.ValidateStruct(r, + validation.Field(&r.Selector, + validation.Required.Error(validationErrorValueRequired), + validation.In(MeasurementTrustedProfileSelectorApprovalID, MeasurementTrustedProfileSelectorProfileID). + Error(fmt.Sprintf("invalid selector %q (expected %q or %q)", r.Selector, MeasurementTrustedProfileSelectorApprovalID, MeasurementTrustedProfileSelectorProfileID)), + ), + validation.Field(&r.ID, + validation.Required.Error(validationErrorValueRequired), + validationis.UUID.Error(validationErrorInvalidUUID), + ), + ) +} + // ToProto converts a validated machine trust approval request to its Core message. func (r *APIMeasurementTrustedMachineCreateRequest) ToProto() *corev1.AddMeasurementTrustedMachineRequest { return &corev1.AddMeasurementTrustedMachineRequest{ @@ -123,6 +170,36 @@ func (r *APIMeasurementTrustedProfileCreateRequest) ToProto() *corev1.AddMeasure return req } +// ToProto converts a validated machine trust approval deletion request to its Core message. +func (r *APIMeasurementTrustedMachineDeleteRequest) ToProto() *corev1.RemoveMeasurementTrustedMachineRequest { + if r.Selector == MeasurementTrustedMachineSelectorApprovalID { + return &corev1.RemoveMeasurementTrustedMachineRequest{ + Selector: &corev1.RemoveMeasurementTrustedMachineRequest_ApprovalId{ + ApprovalId: &corev1.MeasurementApprovedMachineId{Value: r.ID}, + }, + } + } + return &corev1.RemoveMeasurementTrustedMachineRequest{ + Selector: &corev1.RemoveMeasurementTrustedMachineRequest_MachineId{MachineId: r.ID}, + } +} + +// ToProto converts a validated profile trust approval deletion request to its Core message. +func (r *APIMeasurementTrustedProfileDeleteRequest) ToProto() *corev1.RemoveMeasurementTrustedProfileRequest { + if r.Selector == MeasurementTrustedProfileSelectorApprovalID { + return &corev1.RemoveMeasurementTrustedProfileRequest{ + Selector: &corev1.RemoveMeasurementTrustedProfileRequest_ApprovalId{ + ApprovalId: &corev1.MeasurementApprovedProfileId{Value: r.ID}, + }, + } + } + return &corev1.RemoveMeasurementTrustedProfileRequest{ + Selector: &corev1.RemoveMeasurementTrustedProfileRequest_ProfileId{ + ProfileId: &corev1.MeasurementSystemProfileId{Value: r.ID}, + }, + } +} + // NewAPIMeasurementTrustedMachine creates an API model from a Core machine trust record. func NewAPIMeasurementTrustedMachine(record *corev1.MeasurementApprovedMachineRecordPb) *APIMeasurementTrustedMachine { if record == nil { @@ -203,55 +280,6 @@ func (r *APIMeasurementTrustedProfiles) FromProto(records []*corev1.MeasurementA *r = result } -// MeasurementTrustedMachineRemoveProto builds and validates a Core machine removal request. -func MeasurementTrustedMachineRemoveProto(selector, id string) (*corev1.RemoveMeasurementTrustedMachineRequest, error) { - switch selector { - case MeasurementTrustedMachineSelectorApprovalID: - if err := validation.Validate(id, validation.Required, validationis.UUID); err != nil { - return nil, fmt.Errorf("id: %w", err) - } - return &corev1.RemoveMeasurementTrustedMachineRequest{ - Selector: &corev1.RemoveMeasurementTrustedMachineRequest_ApprovalId{ - ApprovalId: &corev1.MeasurementApprovedMachineId{Value: id}, - }, - }, nil - case MeasurementTrustedMachineSelectorMachineID: - if id != "*" { - if err := validation.Validate(id, validation.Required, validationis.UUID); err != nil { - return nil, fmt.Errorf("id: %w", err) - } - } - return &corev1.RemoveMeasurementTrustedMachineRequest{ - Selector: &corev1.RemoveMeasurementTrustedMachineRequest_MachineId{MachineId: id}, - }, nil - default: - return nil, fmt.Errorf("invalid selector %q (expected %q or %q)", selector, MeasurementTrustedMachineSelectorApprovalID, MeasurementTrustedMachineSelectorMachineID) - } -} - -// MeasurementTrustedProfileRemoveProto builds and validates a Core profile removal request. -func MeasurementTrustedProfileRemoveProto(selector, id string) (*corev1.RemoveMeasurementTrustedProfileRequest, error) { - if err := validation.Validate(id, validation.Required, validationis.UUID); err != nil { - return nil, fmt.Errorf("id: %w", err) - } - switch selector { - case MeasurementTrustedProfileSelectorApprovalID: - return &corev1.RemoveMeasurementTrustedProfileRequest{ - Selector: &corev1.RemoveMeasurementTrustedProfileRequest_ApprovalId{ - ApprovalId: &corev1.MeasurementApprovedProfileId{Value: id}, - }, - }, nil - case MeasurementTrustedProfileSelectorProfileID: - return &corev1.RemoveMeasurementTrustedProfileRequest{ - Selector: &corev1.RemoveMeasurementTrustedProfileRequest_ProfileId{ - ProfileId: &corev1.MeasurementSystemProfileId{Value: id}, - }, - }, nil - default: - return nil, fmt.Errorf("invalid selector %q (expected %q or %q)", selector, MeasurementTrustedProfileSelectorApprovalID, MeasurementTrustedProfileSelectorProfileID) - } -} - func validateMeasurementTrustApprovalType(approvalType string) error { switch approvalType { case MeasurementTrustApprovalTypeOneshot, MeasurementTrustApprovalTypePersist: diff --git a/rest-api/api/pkg/api/model/measurementtrust_test.go b/rest-api/api/pkg/api/model/measurementtrust_test.go index 7cfd476399..9dbe50be56 100644 --- a/rest-api/api/pkg/api/model/measurementtrust_test.go +++ b/rest-api/api/pkg/api/model/measurementtrust_test.go @@ -64,27 +64,41 @@ func TestMeasurementTrustCreateRequestRejectsInvalidApprovalType(t *testing.T) { assert.ErrorContains(t, req.Validate(), "approvalType") } -func TestMeasurementTrustRemoveProtoSelectors(t *testing.T) { +func TestMeasurementTrustDeleteRequestSelectors(t *testing.T) { id := "00000000-0000-0000-0000-000000000001" - machineByApproval, err := MeasurementTrustedMachineRemoveProto(MeasurementTrustedMachineSelectorApprovalID, id) - require.NoError(t, err) + machineRequest := APIMeasurementTrustedMachineDeleteRequest{Selector: MeasurementTrustedMachineSelectorApprovalID, ID: id} + require.NoError(t, machineRequest.Validate()) + machineByApproval := machineRequest.ToProto() assert.Equal(t, id, machineByApproval.GetApprovalId().GetValue()) - machineByMachine, err := MeasurementTrustedMachineRemoveProto(MeasurementTrustedMachineSelectorMachineID, id) - require.NoError(t, err) + machineRequest = APIMeasurementTrustedMachineDeleteRequest{Selector: MeasurementTrustedMachineSelectorMachineID, ID: id} + require.NoError(t, machineRequest.Validate()) + machineByMachine := machineRequest.ToProto() assert.Equal(t, id, machineByMachine.GetMachineId()) - profileByApproval, err := MeasurementTrustedProfileRemoveProto(MeasurementTrustedProfileSelectorApprovalID, id) - require.NoError(t, err) + profileRequest := APIMeasurementTrustedProfileDeleteRequest{Selector: MeasurementTrustedProfileSelectorApprovalID, ID: id} + require.NoError(t, profileRequest.Validate()) + profileByApproval := profileRequest.ToProto() assert.Equal(t, id, profileByApproval.GetApprovalId().GetValue()) - profileByProfile, err := MeasurementTrustedProfileRemoveProto(MeasurementTrustedProfileSelectorProfileID, id) - require.NoError(t, err) + profileRequest = APIMeasurementTrustedProfileDeleteRequest{Selector: MeasurementTrustedProfileSelectorProfileID, ID: id} + require.NoError(t, profileRequest.Validate()) + profileByProfile := profileRequest.ToProto() assert.Equal(t, id, profileByProfile.GetProfileId().GetValue()) - _, err = MeasurementTrustedMachineRemoveProto("invalid", id) - assert.ErrorContains(t, err, "invalid selector") + machineRequest = APIMeasurementTrustedMachineDeleteRequest{Selector: MeasurementTrustedMachineSelectorMachineID, ID: "*"} + require.NoError(t, machineRequest.Validate()) + assert.Equal(t, "*", machineRequest.ToProto().GetMachineId()) + + machineRequest = APIMeasurementTrustedMachineDeleteRequest{Selector: MeasurementTrustedMachineSelectorApprovalID, ID: "*"} + assert.Error(t, machineRequest.Validate()) + + profileRequest = APIMeasurementTrustedProfileDeleteRequest{Selector: MeasurementTrustedProfileSelectorProfileID, ID: "*"} + assert.Error(t, profileRequest.Validate()) + + machineRequest = APIMeasurementTrustedMachineDeleteRequest{Selector: "invalid", ID: id} + assert.ErrorContains(t, machineRequest.Validate(), "invalid selector") } func TestMeasurementTrustResponsesFromProto(t *testing.T) {