From afb0f6f77de02b8072f5bc83be2d058892138b47 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 11 Jun 2025 17:24:11 -0700 Subject: [PATCH 1/5] openapi-internal: no implicit ErrorMessage --- openapi-internal.yaml | 28 ---------------------------- 1 file changed, 28 deletions(-) diff --git a/openapi-internal.yaml b/openapi-internal.yaml index 29a4d12..46e32e2 100644 --- a/openapi-internal.yaml +++ b/openapi-internal.yaml @@ -116,13 +116,6 @@ paths: - Mapfixes parameters: - $ref: '#/components/parameters/MapfixID' - - name: ErrorMessage - in: query - required: true - schema: - type: string - minLength: 0 - maxLength: 4096 responses: "204": description: Successful response @@ -157,13 +150,6 @@ paths: - Mapfixes parameters: - $ref: '#/components/parameters/MapfixID' - - name: ErrorMessage - in: query - required: true - schema: - type: string - minLength: 0 - maxLength: 4096 responses: "204": description: Successful response @@ -321,13 +307,6 @@ paths: - Submissions parameters: - $ref: '#/components/parameters/SubmissionID' - - name: ErrorMessage - in: query - required: true - schema: - type: string - minLength: 0 - maxLength: 4096 responses: "204": description: Successful response @@ -362,13 +341,6 @@ paths: - Submissions parameters: - $ref: '#/components/parameters/SubmissionID' - - name: ErrorMessage - in: query - required: true - schema: - type: string - minLength: 0 - maxLength: 4096 responses: "204": description: Successful response -- 2.49.1 From 7fd505ff10a62f93be9a398c555b5848c3c6affd Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 11 Jun 2025 17:28:03 -0700 Subject: [PATCH 2/5] openapi-internal: endpoints post error to audit log --- openapi-internal.yaml | 48 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/openapi-internal.yaml b/openapi-internal.yaml index 46e32e2..8166333 100644 --- a/openapi-internal.yaml +++ b/openapi-internal.yaml @@ -65,6 +65,30 @@ paths: application/json: schema: $ref: "#/components/schemas/Error" + /mapfixes/{MapfixID}/error: + post: + summary: Validator posts an error to the audit log + operationId: createMapfixAuditError + tags: + - Mapfixes + parameters: + - $ref: '#/components/parameters/MapfixID' + - name: ErrorMessage + in: query + required: true + schema: + type: string + minLength: 0 + maxLength: 4096 + responses: + "204": + description: Successful response + default: + description: General Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" /mapfixes/{MapfixID}/status/validator-submitted: post: summary: (Internal endpoint) Role Validator changes status from Submitting -> Submitted @@ -256,6 +280,30 @@ paths: application/json: schema: $ref: "#/components/schemas/Error" + /submissions/{SubmissionID}/error: + post: + summary: Validator posts an error to the audit log + operationId: createSubmissionAuditError + tags: + - Submissions + parameters: + - $ref: '#/components/parameters/SubmissionID' + - name: ErrorMessage + in: query + required: true + schema: + type: string + minLength: 0 + maxLength: 4096 + responses: + "204": + description: Successful response + default: + description: General Error + content: + application/json: + schema: + $ref: "#/components/schemas/Error" /submissions/{SubmissionID}/status/validator-submitted: post: summary: (Internal endpoint) Role Validator changes status from Submitting -> Submitted -- 2.49.1 From 68afcf1d91ed786ef42cf0271a9bf4076f3c54b1 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 11 Jun 2025 17:28:59 -0700 Subject: [PATCH 3/5] openapi: generate --- pkg/internal/oas_client_gen.go | 302 +++++++++--- pkg/internal/oas_handlers_gen.go | 322 ++++++++++++- pkg/internal/oas_operations_gen.go | 2 + pkg/internal/oas_parameters_gen.go | 536 ++++++++++++---------- pkg/internal/oas_response_decoders_gen.go | 120 +++++ pkg/internal/oas_response_encoders_gen.go | 14 + pkg/internal/oas_router_gen.go | 92 ++++ pkg/internal/oas_schemas_gen.go | 6 + pkg/internal/oas_server_gen.go | 12 + pkg/internal/oas_unimplemented_gen.go | 18 + 10 files changed, 1090 insertions(+), 334 deletions(-) diff --git a/pkg/internal/oas_client_gen.go b/pkg/internal/oas_client_gen.go index f7e2439..927f983 100644 --- a/pkg/internal/oas_client_gen.go +++ b/pkg/internal/oas_client_gen.go @@ -100,6 +100,12 @@ type Invoker interface { // // POST /mapfixes CreateMapfix(ctx context.Context, request *MapfixCreate) (*MapfixID, error) + // CreateMapfixAuditError invokes createMapfixAuditError operation. + // + // Validator posts an error to the audit log. + // + // POST /mapfixes/{MapfixID}/error + CreateMapfixAuditError(ctx context.Context, params CreateMapfixAuditErrorParams) error // CreateScript invokes createScript operation. // // Create a new script. @@ -118,6 +124,12 @@ type Invoker interface { // // POST /submissions CreateSubmission(ctx context.Context, request *SubmissionCreate) (*SubmissionID, error) + // CreateSubmissionAuditError invokes createSubmissionAuditError operation. + // + // Validator posts an error to the audit log. + // + // POST /submissions/{SubmissionID}/error + CreateSubmissionAuditError(ctx context.Context, params CreateSubmissionAuditErrorParams) error // GetScript invokes getScript operation. // // Get the specified script by ID. @@ -266,24 +278,6 @@ func (c *Client) sendActionMapfixAccepted(ctx context.Context, params ActionMapf pathParts[2] = "/status/validator-failed" uri.AddPathParts(u, pathParts[:]...) - stage = "EncodeQueryParams" - q := uri.NewQueryEncoder() - { - // Encode "ErrorMessage" parameter. - cfg := uri.QueryParameterEncodingConfig{ - Name: "ErrorMessage", - Style: uri.QueryStyleForm, - Explode: true, - } - - if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - return e.EncodeValue(conv.StringToString(params.ErrorMessage)) - }); err != nil { - return res, errors.Wrap(err, "encode query") - } - } - u.RawQuery = q.Values().Encode() - stage = "EncodeRequest" r, err := ht.NewRequest(ctx, "POST", u) if err != nil { @@ -375,24 +369,6 @@ func (c *Client) sendActionMapfixRequestChanges(ctx context.Context, params Acti pathParts[2] = "/status/validator-request-changes" uri.AddPathParts(u, pathParts[:]...) - stage = "EncodeQueryParams" - q := uri.NewQueryEncoder() - { - // Encode "ErrorMessage" parameter. - cfg := uri.QueryParameterEncodingConfig{ - Name: "ErrorMessage", - Style: uri.QueryStyleForm, - Explode: true, - } - - if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - return e.EncodeValue(conv.StringToString(params.ErrorMessage)) - }); err != nil { - return res, errors.Wrap(err, "encode query") - } - } - u.RawQuery = q.Values().Encode() - stage = "EncodeRequest" r, err := ht.NewRequest(ctx, "POST", u) if err != nil { @@ -926,24 +902,6 @@ func (c *Client) sendActionSubmissionAccepted(ctx context.Context, params Action pathParts[2] = "/status/validator-failed" uri.AddPathParts(u, pathParts[:]...) - stage = "EncodeQueryParams" - q := uri.NewQueryEncoder() - { - // Encode "ErrorMessage" parameter. - cfg := uri.QueryParameterEncodingConfig{ - Name: "ErrorMessage", - Style: uri.QueryStyleForm, - Explode: true, - } - - if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - return e.EncodeValue(conv.StringToString(params.ErrorMessage)) - }); err != nil { - return res, errors.Wrap(err, "encode query") - } - } - u.RawQuery = q.Values().Encode() - stage = "EncodeRequest" r, err := ht.NewRequest(ctx, "POST", u) if err != nil { @@ -1035,24 +993,6 @@ func (c *Client) sendActionSubmissionRequestChanges(ctx context.Context, params pathParts[2] = "/status/validator-request-changes" uri.AddPathParts(u, pathParts[:]...) - stage = "EncodeQueryParams" - q := uri.NewQueryEncoder() - { - // Encode "ErrorMessage" parameter. - cfg := uri.QueryParameterEncodingConfig{ - Name: "ErrorMessage", - Style: uri.QueryStyleForm, - Explode: true, - } - - if err := q.EncodeParam(cfg, func(e uri.Encoder) error { - return e.EncodeValue(conv.StringToString(params.ErrorMessage)) - }); err != nil { - return res, errors.Wrap(err, "encode query") - } - } - u.RawQuery = q.Values().Encode() - stage = "EncodeRequest" r, err := ht.NewRequest(ctx, "POST", u) if err != nil { @@ -1501,6 +1441,115 @@ func (c *Client) sendCreateMapfix(ctx context.Context, request *MapfixCreate) (r return result, nil } +// CreateMapfixAuditError invokes createMapfixAuditError operation. +// +// Validator posts an error to the audit log. +// +// POST /mapfixes/{MapfixID}/error +func (c *Client) CreateMapfixAuditError(ctx context.Context, params CreateMapfixAuditErrorParams) error { + _, err := c.sendCreateMapfixAuditError(ctx, params) + return err +} + +func (c *Client) sendCreateMapfixAuditError(ctx context.Context, params CreateMapfixAuditErrorParams) (res *CreateMapfixAuditErrorNoContent, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("createMapfixAuditError"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/error"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, CreateMapfixAuditErrorOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [3]string + pathParts[0] = "/mapfixes/" + { + // Encode "MapfixID" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "MapfixID", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + return e.EncodeValue(conv.Int64ToString(params.MapfixID)) + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + pathParts[2] = "/error" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeQueryParams" + q := uri.NewQueryEncoder() + { + // Encode "ErrorMessage" parameter. + cfg := uri.QueryParameterEncodingConfig{ + Name: "ErrorMessage", + Style: uri.QueryStyleForm, + Explode: true, + } + + if err := q.EncodeParam(cfg, func(e uri.Encoder) error { + return e.EncodeValue(conv.StringToString(params.ErrorMessage)) + }); err != nil { + return res, errors.Wrap(err, "encode query") + } + } + u.RawQuery = q.Values().Encode() + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeCreateMapfixAuditErrorResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + // CreateScript invokes createScript operation. // // Create a new script. @@ -1726,6 +1775,115 @@ func (c *Client) sendCreateSubmission(ctx context.Context, request *SubmissionCr return result, nil } +// CreateSubmissionAuditError invokes createSubmissionAuditError operation. +// +// Validator posts an error to the audit log. +// +// POST /submissions/{SubmissionID}/error +func (c *Client) CreateSubmissionAuditError(ctx context.Context, params CreateSubmissionAuditErrorParams) error { + _, err := c.sendCreateSubmissionAuditError(ctx, params) + return err +} + +func (c *Client) sendCreateSubmissionAuditError(ctx context.Context, params CreateSubmissionAuditErrorParams) (res *CreateSubmissionAuditErrorNoContent, err error) { + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("createSubmissionAuditError"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/error"), + } + + // Run stopwatch. + startTime := time.Now() + defer func() { + // Use floating point division here for higher precision (instead of Millisecond method). + elapsedDuration := time.Since(startTime) + c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...)) + }() + + // Increment request counter. + c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + + // Start a span for this request. + ctx, span := c.cfg.Tracer.Start(ctx, CreateSubmissionAuditErrorOperation, + trace.WithAttributes(otelAttrs...), + clientSpanKind, + ) + // Track stage for error reporting. + var stage string + defer func() { + if err != nil { + span.RecordError(err) + span.SetStatus(codes.Error, stage) + c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...)) + } + span.End() + }() + + stage = "BuildURL" + u := uri.Clone(c.requestURL(ctx)) + var pathParts [3]string + pathParts[0] = "/submissions/" + { + // Encode "SubmissionID" parameter. + e := uri.NewPathEncoder(uri.PathEncoderConfig{ + Param: "SubmissionID", + Style: uri.PathStyleSimple, + Explode: false, + }) + if err := func() error { + return e.EncodeValue(conv.Int64ToString(params.SubmissionID)) + }(); err != nil { + return res, errors.Wrap(err, "encode path") + } + encoded, err := e.Result() + if err != nil { + return res, errors.Wrap(err, "encode path") + } + pathParts[1] = encoded + } + pathParts[2] = "/error" + uri.AddPathParts(u, pathParts[:]...) + + stage = "EncodeQueryParams" + q := uri.NewQueryEncoder() + { + // Encode "ErrorMessage" parameter. + cfg := uri.QueryParameterEncodingConfig{ + Name: "ErrorMessage", + Style: uri.QueryStyleForm, + Explode: true, + } + + if err := q.EncodeParam(cfg, func(e uri.Encoder) error { + return e.EncodeValue(conv.StringToString(params.ErrorMessage)) + }); err != nil { + return res, errors.Wrap(err, "encode query") + } + } + u.RawQuery = q.Values().Encode() + + stage = "EncodeRequest" + r, err := ht.NewRequest(ctx, "POST", u) + if err != nil { + return res, errors.Wrap(err, "create request") + } + + stage = "SendRequest" + resp, err := c.cfg.Client.Do(r) + if err != nil { + return res, errors.Wrap(err, "do request") + } + defer resp.Body.Close() + + stage = "DecodeResponse" + result, err := decodeCreateSubmissionAuditErrorResponse(resp) + if err != nil { + return res, errors.Wrap(err, "decode response") + } + + return result, nil +} + // GetScript invokes getScript operation. // // Get the specified script by ID. diff --git a/pkg/internal/oas_handlers_gen.go b/pkg/internal/oas_handlers_gen.go index 638edd6..a7c67c7 100644 --- a/pkg/internal/oas_handlers_gen.go +++ b/pkg/internal/oas_handlers_gen.go @@ -128,10 +128,6 @@ func (s *Server) handleActionMapfixAcceptedRequest(args [1]string, argsEscaped b Name: "MapfixID", In: "path", }: params.MapfixID, - { - Name: "ErrorMessage", - In: "query", - }: params.ErrorMessage, }, Raw: r, } @@ -281,10 +277,6 @@ func (s *Server) handleActionMapfixRequestChangesRequest(args [1]string, argsEsc Name: "MapfixID", In: "path", }: params.MapfixID, - { - Name: "ErrorMessage", - In: "query", - }: params.ErrorMessage, }, Raw: r, } @@ -1050,10 +1042,6 @@ func (s *Server) handleActionSubmissionAcceptedRequest(args [1]string, argsEscap Name: "SubmissionID", In: "path", }: params.SubmissionID, - { - Name: "ErrorMessage", - In: "query", - }: params.ErrorMessage, }, Raw: r, } @@ -1203,10 +1191,6 @@ func (s *Server) handleActionSubmissionRequestChangesRequest(args [1]string, arg Name: "SubmissionID", In: "path", }: params.SubmissionID, - { - Name: "ErrorMessage", - In: "query", - }: params.ErrorMessage, }, Raw: r, } @@ -1874,6 +1858,159 @@ func (s *Server) handleCreateMapfixRequest(args [0]string, argsEscaped bool, w h } } +// handleCreateMapfixAuditErrorRequest handles createMapfixAuditError operation. +// +// Validator posts an error to the audit log. +// +// POST /mapfixes/{MapfixID}/error +func (s *Server) handleCreateMapfixAuditErrorRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + statusWriter := &codeRecorder{ResponseWriter: w} + w = statusWriter + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("createMapfixAuditError"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/mapfixes/{MapfixID}/error"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), CreateMapfixAuditErrorOperation, + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Add Labeler to context. + labeler := &Labeler{attrs: otelAttrs} + ctx = contextWithLabeler(ctx, labeler) + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + code := statusWriter.status + if code != 0 { + codeAttr := semconv.HTTPResponseStatusCode(code) + attrs = append(attrs, codeAttr) + span.SetAttributes(codeAttr) + } + attrOpt := metric.WithAttributes(attrs...) + + // Increment request counter. + s.requests.Add(ctx, 1, attrOpt) + + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) + }() + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + + // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status + // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, + // unless there was another error (e.g., network error receiving the response body; or 3xx codes with + // max redirects exceeded), in which case status MUST be set to Error. + code := statusWriter.status + if code >= 100 && code < 500 { + span.SetStatus(codes.Error, stage) + } + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + if code != 0 { + attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) + } + + s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: CreateMapfixAuditErrorOperation, + ID: "createMapfixAuditError", + } + ) + params, err := decodeCreateMapfixAuditErrorParams(args, argsEscaped, r) + if err != nil { + err = &ogenerrors.DecodeParamsError{ + OperationContext: opErrContext, + Err: err, + } + defer recordError("DecodeParams", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + + var response *CreateMapfixAuditErrorNoContent + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: CreateMapfixAuditErrorOperation, + OperationSummary: "Validator posts an error to the audit log", + OperationID: "createMapfixAuditError", + Body: nil, + Params: middleware.Parameters{ + { + Name: "MapfixID", + In: "path", + }: params.MapfixID, + { + Name: "ErrorMessage", + In: "query", + }: params.ErrorMessage, + }, + Raw: r, + } + + type ( + Request = struct{} + Params = CreateMapfixAuditErrorParams + Response = *CreateMapfixAuditErrorNoContent + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackCreateMapfixAuditErrorParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + err = s.h.CreateMapfixAuditError(ctx, params) + return response, err + }, + ) + } else { + err = s.h.CreateMapfixAuditError(ctx, params) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + defer recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + defer recordError("Internal", err) + } + return + } + + if err := encodeCreateMapfixAuditErrorResponse(response, w, span); err != nil { + defer recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + // handleCreateScriptRequest handles createScript operation. // // Create a new script. @@ -2321,6 +2458,159 @@ func (s *Server) handleCreateSubmissionRequest(args [0]string, argsEscaped bool, } } +// handleCreateSubmissionAuditErrorRequest handles createSubmissionAuditError operation. +// +// Validator posts an error to the audit log. +// +// POST /submissions/{SubmissionID}/error +func (s *Server) handleCreateSubmissionAuditErrorRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) { + statusWriter := &codeRecorder{ResponseWriter: w} + w = statusWriter + otelAttrs := []attribute.KeyValue{ + otelogen.OperationID("createSubmissionAuditError"), + semconv.HTTPRequestMethodKey.String("POST"), + semconv.HTTPRouteKey.String("/submissions/{SubmissionID}/error"), + } + + // Start a span for this request. + ctx, span := s.cfg.Tracer.Start(r.Context(), CreateSubmissionAuditErrorOperation, + trace.WithAttributes(otelAttrs...), + serverSpanKind, + ) + defer span.End() + + // Add Labeler to context. + labeler := &Labeler{attrs: otelAttrs} + ctx = contextWithLabeler(ctx, labeler) + + // Run stopwatch. + startTime := time.Now() + defer func() { + elapsedDuration := time.Since(startTime) + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + code := statusWriter.status + if code != 0 { + codeAttr := semconv.HTTPResponseStatusCode(code) + attrs = append(attrs, codeAttr) + span.SetAttributes(codeAttr) + } + attrOpt := metric.WithAttributes(attrs...) + + // Increment request counter. + s.requests.Add(ctx, 1, attrOpt) + + // Use floating point division here for higher precision (instead of Millisecond method). + s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt) + }() + + var ( + recordError = func(stage string, err error) { + span.RecordError(err) + + // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status + // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges, + // unless there was another error (e.g., network error receiving the response body; or 3xx codes with + // max redirects exceeded), in which case status MUST be set to Error. + code := statusWriter.status + if code >= 100 && code < 500 { + span.SetStatus(codes.Error, stage) + } + + attrSet := labeler.AttributeSet() + attrs := attrSet.ToSlice() + if code != 0 { + attrs = append(attrs, semconv.HTTPResponseStatusCode(code)) + } + + s.errors.Add(ctx, 1, metric.WithAttributes(attrs...)) + } + err error + opErrContext = ogenerrors.OperationContext{ + Name: CreateSubmissionAuditErrorOperation, + ID: "createSubmissionAuditError", + } + ) + params, err := decodeCreateSubmissionAuditErrorParams(args, argsEscaped, r) + if err != nil { + err = &ogenerrors.DecodeParamsError{ + OperationContext: opErrContext, + Err: err, + } + defer recordError("DecodeParams", err) + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + + var response *CreateSubmissionAuditErrorNoContent + if m := s.cfg.Middleware; m != nil { + mreq := middleware.Request{ + Context: ctx, + OperationName: CreateSubmissionAuditErrorOperation, + OperationSummary: "Validator posts an error to the audit log", + OperationID: "createSubmissionAuditError", + Body: nil, + Params: middleware.Parameters{ + { + Name: "SubmissionID", + In: "path", + }: params.SubmissionID, + { + Name: "ErrorMessage", + In: "query", + }: params.ErrorMessage, + }, + Raw: r, + } + + type ( + Request = struct{} + Params = CreateSubmissionAuditErrorParams + Response = *CreateSubmissionAuditErrorNoContent + ) + response, err = middleware.HookMiddleware[ + Request, + Params, + Response, + ]( + m, + mreq, + unpackCreateSubmissionAuditErrorParams, + func(ctx context.Context, request Request, params Params) (response Response, err error) { + err = s.h.CreateSubmissionAuditError(ctx, params) + return response, err + }, + ) + } else { + err = s.h.CreateSubmissionAuditError(ctx, params) + } + if err != nil { + if errRes, ok := errors.Into[*ErrorStatusCode](err); ok { + if err := encodeErrorResponse(errRes, w, span); err != nil { + defer recordError("Internal", err) + } + return + } + if errors.Is(err, ht.ErrNotImplemented) { + s.cfg.ErrorHandler(ctx, w, r, err) + return + } + if err := encodeErrorResponse(s.h.NewError(ctx, err), w, span); err != nil { + defer recordError("Internal", err) + } + return + } + + if err := encodeCreateSubmissionAuditErrorResponse(response, w, span); err != nil { + defer recordError("EncodeResponse", err) + if !errors.Is(err, ht.ErrInternalServerErrorResponse) { + s.cfg.ErrorHandler(ctx, w, r, err) + } + return + } +} + // handleGetScriptRequest handles getScript operation. // // Get the specified script by ID. diff --git a/pkg/internal/oas_operations_gen.go b/pkg/internal/oas_operations_gen.go index 9ddc04b..1ee0aac 100644 --- a/pkg/internal/oas_operations_gen.go +++ b/pkg/internal/oas_operations_gen.go @@ -18,9 +18,11 @@ const ( ActionSubmissionUploadedOperation OperationName = "ActionSubmissionUploaded" ActionSubmissionValidatedOperation OperationName = "ActionSubmissionValidated" CreateMapfixOperation OperationName = "CreateMapfix" + CreateMapfixAuditErrorOperation OperationName = "CreateMapfixAuditError" CreateScriptOperation OperationName = "CreateScript" CreateScriptPolicyOperation OperationName = "CreateScriptPolicy" CreateSubmissionOperation OperationName = "CreateSubmission" + CreateSubmissionAuditErrorOperation OperationName = "CreateSubmissionAuditError" GetScriptOperation OperationName = "GetScript" ListScriptPolicyOperation OperationName = "ListScriptPolicy" ListScriptsOperation OperationName = "ListScripts" diff --git a/pkg/internal/oas_parameters_gen.go b/pkg/internal/oas_parameters_gen.go index f041c7f..e8f11fd 100644 --- a/pkg/internal/oas_parameters_gen.go +++ b/pkg/internal/oas_parameters_gen.go @@ -18,8 +18,7 @@ import ( // ActionMapfixAcceptedParams is parameters of actionMapfixAccepted operation. type ActionMapfixAcceptedParams struct { // The unique identifier for a submission. - MapfixID int64 - ErrorMessage string + MapfixID int64 } func unpackActionMapfixAcceptedParams(packed middleware.Parameters) (params ActionMapfixAcceptedParams) { @@ -30,18 +29,10 @@ func unpackActionMapfixAcceptedParams(packed middleware.Parameters) (params Acti } params.MapfixID = packed[key].(int64) } - { - key := middleware.ParameterKey{ - Name: "ErrorMessage", - In: "query", - } - params.ErrorMessage = packed[key].(string) - } return params } func decodeActionMapfixAcceptedParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionMapfixAcceptedParams, _ error) { - q := uri.NewQueryDecoder(r.URL.Query()) // Decode path: MapfixID. if err := func() error { param := args[0] @@ -104,66 +95,13 @@ func decodeActionMapfixAcceptedParams(args [1]string, argsEscaped bool, r *http. Err: err, } } - // Decode query: ErrorMessage. - if err := func() error { - cfg := uri.QueryParameterDecodingConfig{ - Name: "ErrorMessage", - Style: uri.QueryStyleForm, - Explode: true, - } - - if err := q.HasParam(cfg); err == nil { - if err := q.DecodeParam(cfg, func(d uri.Decoder) error { - val, err := d.DecodeValue() - if err != nil { - return err - } - - c, err := conv.ToString(val) - if err != nil { - return err - } - - params.ErrorMessage = c - return nil - }); err != nil { - return err - } - if err := func() error { - if err := (validate.String{ - MinLength: 0, - MinLengthSet: true, - MaxLength: 4096, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, - }).Validate(string(params.ErrorMessage)); err != nil { - return errors.Wrap(err, "string") - } - return nil - }(); err != nil { - return err - } - } else { - return err - } - return nil - }(); err != nil { - return params, &ogenerrors.DecodeParamError{ - Name: "ErrorMessage", - In: "query", - Err: err, - } - } return params, nil } // ActionMapfixRequestChangesParams is parameters of actionMapfixRequestChanges operation. type ActionMapfixRequestChangesParams struct { // The unique identifier for a submission. - MapfixID int64 - ErrorMessage string + MapfixID int64 } func unpackActionMapfixRequestChangesParams(packed middleware.Parameters) (params ActionMapfixRequestChangesParams) { @@ -174,18 +112,10 @@ func unpackActionMapfixRequestChangesParams(packed middleware.Parameters) (param } params.MapfixID = packed[key].(int64) } - { - key := middleware.ParameterKey{ - Name: "ErrorMessage", - In: "query", - } - params.ErrorMessage = packed[key].(string) - } return params } func decodeActionMapfixRequestChangesParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionMapfixRequestChangesParams, _ error) { - q := uri.NewQueryDecoder(r.URL.Query()) // Decode path: MapfixID. if err := func() error { param := args[0] @@ -248,58 +178,6 @@ func decodeActionMapfixRequestChangesParams(args [1]string, argsEscaped bool, r Err: err, } } - // Decode query: ErrorMessage. - if err := func() error { - cfg := uri.QueryParameterDecodingConfig{ - Name: "ErrorMessage", - Style: uri.QueryStyleForm, - Explode: true, - } - - if err := q.HasParam(cfg); err == nil { - if err := q.DecodeParam(cfg, func(d uri.Decoder) error { - val, err := d.DecodeValue() - if err != nil { - return err - } - - c, err := conv.ToString(val) - if err != nil { - return err - } - - params.ErrorMessage = c - return nil - }); err != nil { - return err - } - if err := func() error { - if err := (validate.String{ - MinLength: 0, - MinLengthSet: true, - MaxLength: 4096, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, - }).Validate(string(params.ErrorMessage)); err != nil { - return errors.Wrap(err, "string") - } - return nil - }(); err != nil { - return err - } - } else { - return err - } - return nil - }(); err != nil { - return params, &ogenerrors.DecodeParamError{ - Name: "ErrorMessage", - In: "query", - Err: err, - } - } return params, nil } @@ -943,7 +821,6 @@ func decodeActionOperationFailedParams(args [1]string, argsEscaped bool, r *http type ActionSubmissionAcceptedParams struct { // The unique identifier for a submission. SubmissionID int64 - ErrorMessage string } func unpackActionSubmissionAcceptedParams(packed middleware.Parameters) (params ActionSubmissionAcceptedParams) { @@ -954,18 +831,10 @@ func unpackActionSubmissionAcceptedParams(packed middleware.Parameters) (params } params.SubmissionID = packed[key].(int64) } - { - key := middleware.ParameterKey{ - Name: "ErrorMessage", - In: "query", - } - params.ErrorMessage = packed[key].(string) - } return params } func decodeActionSubmissionAcceptedParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionSubmissionAcceptedParams, _ error) { - q := uri.NewQueryDecoder(r.URL.Query()) // Decode path: SubmissionID. if err := func() error { param := args[0] @@ -1028,58 +897,6 @@ func decodeActionSubmissionAcceptedParams(args [1]string, argsEscaped bool, r *h Err: err, } } - // Decode query: ErrorMessage. - if err := func() error { - cfg := uri.QueryParameterDecodingConfig{ - Name: "ErrorMessage", - Style: uri.QueryStyleForm, - Explode: true, - } - - if err := q.HasParam(cfg); err == nil { - if err := q.DecodeParam(cfg, func(d uri.Decoder) error { - val, err := d.DecodeValue() - if err != nil { - return err - } - - c, err := conv.ToString(val) - if err != nil { - return err - } - - params.ErrorMessage = c - return nil - }); err != nil { - return err - } - if err := func() error { - if err := (validate.String{ - MinLength: 0, - MinLengthSet: true, - MaxLength: 4096, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, - }).Validate(string(params.ErrorMessage)); err != nil { - return errors.Wrap(err, "string") - } - return nil - }(); err != nil { - return err - } - } else { - return err - } - return nil - }(); err != nil { - return params, &ogenerrors.DecodeParamError{ - Name: "ErrorMessage", - In: "query", - Err: err, - } - } return params, nil } @@ -1087,7 +904,6 @@ func decodeActionSubmissionAcceptedParams(args [1]string, argsEscaped bool, r *h type ActionSubmissionRequestChangesParams struct { // The unique identifier for a submission. SubmissionID int64 - ErrorMessage string } func unpackActionSubmissionRequestChangesParams(packed middleware.Parameters) (params ActionSubmissionRequestChangesParams) { @@ -1098,18 +914,10 @@ func unpackActionSubmissionRequestChangesParams(packed middleware.Parameters) (p } params.SubmissionID = packed[key].(int64) } - { - key := middleware.ParameterKey{ - Name: "ErrorMessage", - In: "query", - } - params.ErrorMessage = packed[key].(string) - } return params } func decodeActionSubmissionRequestChangesParams(args [1]string, argsEscaped bool, r *http.Request) (params ActionSubmissionRequestChangesParams, _ error) { - q := uri.NewQueryDecoder(r.URL.Query()) // Decode path: SubmissionID. if err := func() error { param := args[0] @@ -1172,58 +980,6 @@ func decodeActionSubmissionRequestChangesParams(args [1]string, argsEscaped bool Err: err, } } - // Decode query: ErrorMessage. - if err := func() error { - cfg := uri.QueryParameterDecodingConfig{ - Name: "ErrorMessage", - Style: uri.QueryStyleForm, - Explode: true, - } - - if err := q.HasParam(cfg); err == nil { - if err := q.DecodeParam(cfg, func(d uri.Decoder) error { - val, err := d.DecodeValue() - if err != nil { - return err - } - - c, err := conv.ToString(val) - if err != nil { - return err - } - - params.ErrorMessage = c - return nil - }); err != nil { - return err - } - if err := func() error { - if err := (validate.String{ - MinLength: 0, - MinLengthSet: true, - MaxLength: 4096, - MaxLengthSet: true, - Email: false, - Hostname: false, - Regex: nil, - }).Validate(string(params.ErrorMessage)); err != nil { - return errors.Wrap(err, "string") - } - return nil - }(); err != nil { - return err - } - } else { - return err - } - return nil - }(); err != nil { - return params, &ogenerrors.DecodeParamError{ - Name: "ErrorMessage", - In: "query", - Err: err, - } - } return params, nil } @@ -1781,6 +1537,294 @@ func decodeActionSubmissionValidatedParams(args [1]string, argsEscaped bool, r * return params, nil } +// CreateMapfixAuditErrorParams is parameters of createMapfixAuditError operation. +type CreateMapfixAuditErrorParams struct { + // The unique identifier for a submission. + MapfixID int64 + ErrorMessage string +} + +func unpackCreateMapfixAuditErrorParams(packed middleware.Parameters) (params CreateMapfixAuditErrorParams) { + { + key := middleware.ParameterKey{ + Name: "MapfixID", + In: "path", + } + params.MapfixID = packed[key].(int64) + } + { + key := middleware.ParameterKey{ + Name: "ErrorMessage", + In: "query", + } + params.ErrorMessage = packed[key].(string) + } + return params +} + +func decodeCreateMapfixAuditErrorParams(args [1]string, argsEscaped bool, r *http.Request) (params CreateMapfixAuditErrorParams, _ error) { + q := uri.NewQueryDecoder(r.URL.Query()) + // Decode path: MapfixID. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "MapfixID", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt64(val) + if err != nil { + return err + } + + params.MapfixID = c + return nil + }(); err != nil { + return err + } + if err := func() error { + if err := (validate.Int{ + MinSet: true, + Min: 0, + MaxSet: false, + Max: 0, + MinExclusive: false, + MaxExclusive: false, + MultipleOfSet: false, + MultipleOf: 0, + }).Validate(int64(params.MapfixID)); err != nil { + return errors.Wrap(err, "int") + } + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "MapfixID", + In: "path", + Err: err, + } + } + // Decode query: ErrorMessage. + if err := func() error { + cfg := uri.QueryParameterDecodingConfig{ + Name: "ErrorMessage", + Style: uri.QueryStyleForm, + Explode: true, + } + + if err := q.HasParam(cfg); err == nil { + if err := q.DecodeParam(cfg, func(d uri.Decoder) error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToString(val) + if err != nil { + return err + } + + params.ErrorMessage = c + return nil + }); err != nil { + return err + } + if err := func() error { + if err := (validate.String{ + MinLength: 0, + MinLengthSet: true, + MaxLength: 4096, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + }).Validate(string(params.ErrorMessage)); err != nil { + return errors.Wrap(err, "string") + } + return nil + }(); err != nil { + return err + } + } else { + return err + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "ErrorMessage", + In: "query", + Err: err, + } + } + return params, nil +} + +// CreateSubmissionAuditErrorParams is parameters of createSubmissionAuditError operation. +type CreateSubmissionAuditErrorParams struct { + // The unique identifier for a submission. + SubmissionID int64 + ErrorMessage string +} + +func unpackCreateSubmissionAuditErrorParams(packed middleware.Parameters) (params CreateSubmissionAuditErrorParams) { + { + key := middleware.ParameterKey{ + Name: "SubmissionID", + In: "path", + } + params.SubmissionID = packed[key].(int64) + } + { + key := middleware.ParameterKey{ + Name: "ErrorMessage", + In: "query", + } + params.ErrorMessage = packed[key].(string) + } + return params +} + +func decodeCreateSubmissionAuditErrorParams(args [1]string, argsEscaped bool, r *http.Request) (params CreateSubmissionAuditErrorParams, _ error) { + q := uri.NewQueryDecoder(r.URL.Query()) + // Decode path: SubmissionID. + if err := func() error { + param := args[0] + if argsEscaped { + unescaped, err := url.PathUnescape(args[0]) + if err != nil { + return errors.Wrap(err, "unescape path") + } + param = unescaped + } + if len(param) > 0 { + d := uri.NewPathDecoder(uri.PathDecoderConfig{ + Param: "SubmissionID", + Value: param, + Style: uri.PathStyleSimple, + Explode: false, + }) + + if err := func() error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToInt64(val) + if err != nil { + return err + } + + params.SubmissionID = c + return nil + }(); err != nil { + return err + } + if err := func() error { + if err := (validate.Int{ + MinSet: true, + Min: 0, + MaxSet: false, + Max: 0, + MinExclusive: false, + MaxExclusive: false, + MultipleOfSet: false, + MultipleOf: 0, + }).Validate(int64(params.SubmissionID)); err != nil { + return errors.Wrap(err, "int") + } + return nil + }(); err != nil { + return err + } + } else { + return validate.ErrFieldRequired + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "SubmissionID", + In: "path", + Err: err, + } + } + // Decode query: ErrorMessage. + if err := func() error { + cfg := uri.QueryParameterDecodingConfig{ + Name: "ErrorMessage", + Style: uri.QueryStyleForm, + Explode: true, + } + + if err := q.HasParam(cfg); err == nil { + if err := q.DecodeParam(cfg, func(d uri.Decoder) error { + val, err := d.DecodeValue() + if err != nil { + return err + } + + c, err := conv.ToString(val) + if err != nil { + return err + } + + params.ErrorMessage = c + return nil + }); err != nil { + return err + } + if err := func() error { + if err := (validate.String{ + MinLength: 0, + MinLengthSet: true, + MaxLength: 4096, + MaxLengthSet: true, + Email: false, + Hostname: false, + Regex: nil, + }).Validate(string(params.ErrorMessage)); err != nil { + return errors.Wrap(err, "string") + } + return nil + }(); err != nil { + return err + } + } else { + return err + } + return nil + }(); err != nil { + return params, &ogenerrors.DecodeParamError{ + Name: "ErrorMessage", + In: "query", + Err: err, + } + } + return params, nil +} + // GetScriptParams is parameters of getScript operation. type GetScriptParams struct { // The unique identifier for a script. diff --git a/pkg/internal/oas_response_decoders_gen.go b/pkg/internal/oas_response_decoders_gen.go index 77616ac..28f2f29 100644 --- a/pkg/internal/oas_response_decoders_gen.go +++ b/pkg/internal/oas_response_decoders_gen.go @@ -776,6 +776,66 @@ func decodeCreateMapfixResponse(resp *http.Response) (res *MapfixID, _ error) { return res, errors.Wrap(defRes, "error") } +func decodeCreateMapfixAuditErrorResponse(resp *http.Response) (res *CreateMapfixAuditErrorNoContent, _ error) { + switch resp.StatusCode { + case 204: + // Code 204. + return &CreateMapfixAuditErrorNoContent{}, nil + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + func decodeCreateScriptResponse(resp *http.Response) (res *ScriptID, _ error) { switch resp.StatusCode { case 201: @@ -1079,6 +1139,66 @@ func decodeCreateSubmissionResponse(resp *http.Response) (res *SubmissionID, _ e return res, errors.Wrap(defRes, "error") } +func decodeCreateSubmissionAuditErrorResponse(resp *http.Response) (res *CreateSubmissionAuditErrorNoContent, _ error) { + switch resp.StatusCode { + case 204: + // Code 204. + return &CreateSubmissionAuditErrorNoContent{}, nil + } + // Convenient error response. + defRes, err := func() (res *ErrorStatusCode, err error) { + ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type")) + if err != nil { + return res, errors.Wrap(err, "parse media type") + } + switch { + case ct == "application/json": + buf, err := io.ReadAll(resp.Body) + if err != nil { + return res, err + } + d := jx.DecodeBytes(buf) + + var response Error + if err := func() error { + if err := response.Decode(d); err != nil { + return err + } + if err := d.Skip(); err != io.EOF { + return errors.New("unexpected trailing data") + } + return nil + }(); err != nil { + err = &ogenerrors.DecodeBodyError{ + ContentType: ct, + Body: buf, + Err: err, + } + return res, err + } + // Validate response. + if err := func() error { + if err := response.Validate(); err != nil { + return err + } + return nil + }(); err != nil { + return res, errors.Wrap(err, "validate") + } + return &ErrorStatusCode{ + StatusCode: resp.StatusCode, + Response: response, + }, nil + default: + return res, validate.InvalidContentType(ct) + } + }() + if err != nil { + return res, errors.Wrapf(err, "default (code %d)", resp.StatusCode) + } + return res, errors.Wrap(defRes, "error") +} + func decodeGetScriptResponse(resp *http.Response) (res *Script, _ error) { switch resp.StatusCode { case 200: diff --git a/pkg/internal/oas_response_encoders_gen.go b/pkg/internal/oas_response_encoders_gen.go index 024126c..5cde190 100644 --- a/pkg/internal/oas_response_encoders_gen.go +++ b/pkg/internal/oas_response_encoders_gen.go @@ -104,6 +104,13 @@ func encodeCreateMapfixResponse(response *MapfixID, w http.ResponseWriter, span return nil } +func encodeCreateMapfixAuditErrorResponse(response *CreateMapfixAuditErrorNoContent, w http.ResponseWriter, span trace.Span) error { + w.WriteHeader(204) + span.SetStatus(codes.Ok, http.StatusText(204)) + + return nil +} + func encodeCreateScriptResponse(response *ScriptID, w http.ResponseWriter, span trace.Span) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(201) @@ -146,6 +153,13 @@ func encodeCreateSubmissionResponse(response *SubmissionID, w http.ResponseWrite return nil } +func encodeCreateSubmissionAuditErrorResponse(response *CreateSubmissionAuditErrorNoContent, w http.ResponseWriter, span trace.Span) error { + w.WriteHeader(204) + span.SetStatus(codes.Ok, http.StatusText(204)) + + return nil +} + func encodeGetScriptResponse(response *Script, w http.ResponseWriter, span trace.Span) error { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(200) diff --git a/pkg/internal/oas_router_gen.go b/pkg/internal/oas_router_gen.go index 43be2cc..a6615a9 100644 --- a/pkg/internal/oas_router_gen.go +++ b/pkg/internal/oas_router_gen.go @@ -113,6 +113,28 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { break } switch elem[0] { + case 'e': // Prefix: "error" + + if l := len("error"); len(elem) >= l && elem[0:l] == "error" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleCreateMapfixAuditErrorRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + case 's': // Prefix: "status/validator-" if l := len("status/validator-"); len(elem) >= l && elem[0:l] == "status/validator-" { @@ -464,6 +486,28 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { break } switch elem[0] { + case 'e': // Prefix: "error" + + if l := len("error"); len(elem) >= l && elem[0:l] == "error" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch r.Method { + case "POST": + s.handleCreateSubmissionAuditErrorRequest([1]string{ + args[0], + }, elemIsEscaped, w, r) + default: + s.notAllowed(w, r, "POST") + } + + return + } + case 's': // Prefix: "status/validator-" if l := len("status/validator-"); len(elem) >= l && elem[0:l] == "status/validator-" { @@ -768,6 +812,30 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { break } switch elem[0] { + case 'e': // Prefix: "error" + + if l := len("error"); len(elem) >= l && elem[0:l] == "error" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = CreateMapfixAuditErrorOperation + r.summary = "Validator posts an error to the audit log" + r.operationID = "createMapfixAuditError" + r.pathPattern = "/mapfixes/{MapfixID}/error" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + case 's': // Prefix: "status/validator-" if l := len("status/validator-"); len(elem) >= l && elem[0:l] == "status/validator-" { @@ -1159,6 +1227,30 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) { break } switch elem[0] { + case 'e': // Prefix: "error" + + if l := len("error"); len(elem) >= l && elem[0:l] == "error" { + elem = elem[l:] + } else { + break + } + + if len(elem) == 0 { + // Leaf node. + switch method { + case "POST": + r.name = CreateSubmissionAuditErrorOperation + r.summary = "Validator posts an error to the audit log" + r.operationID = "createSubmissionAuditError" + r.pathPattern = "/submissions/{SubmissionID}/error" + r.args = args + r.count = 1 + return r, true + default: + return + } + } + case 's': // Prefix: "status/validator-" if l := len("status/validator-"); len(elem) >= l && elem[0:l] == "status/validator-" { diff --git a/pkg/internal/oas_schemas_gen.go b/pkg/internal/oas_schemas_gen.go index 86ef488..16c6e42 100644 --- a/pkg/internal/oas_schemas_gen.go +++ b/pkg/internal/oas_schemas_gen.go @@ -43,6 +43,12 @@ type ActionSubmissionUploadedNoContent struct{} // ActionSubmissionValidatedNoContent is response for ActionSubmissionValidated operation. type ActionSubmissionValidatedNoContent struct{} +// CreateMapfixAuditErrorNoContent is response for CreateMapfixAuditError operation. +type CreateMapfixAuditErrorNoContent struct{} + +// CreateSubmissionAuditErrorNoContent is response for CreateSubmissionAuditError operation. +type CreateSubmissionAuditErrorNoContent struct{} + // Represents error object. // Ref: #/components/schemas/Error type Error struct { diff --git a/pkg/internal/oas_server_gen.go b/pkg/internal/oas_server_gen.go index 7350a9c..b091f81 100644 --- a/pkg/internal/oas_server_gen.go +++ b/pkg/internal/oas_server_gen.go @@ -80,6 +80,12 @@ type Handler interface { // // POST /mapfixes CreateMapfix(ctx context.Context, req *MapfixCreate) (*MapfixID, error) + // CreateMapfixAuditError implements createMapfixAuditError operation. + // + // Validator posts an error to the audit log. + // + // POST /mapfixes/{MapfixID}/error + CreateMapfixAuditError(ctx context.Context, params CreateMapfixAuditErrorParams) error // CreateScript implements createScript operation. // // Create a new script. @@ -98,6 +104,12 @@ type Handler interface { // // POST /submissions CreateSubmission(ctx context.Context, req *SubmissionCreate) (*SubmissionID, error) + // CreateSubmissionAuditError implements createSubmissionAuditError operation. + // + // Validator posts an error to the audit log. + // + // POST /submissions/{SubmissionID}/error + CreateSubmissionAuditError(ctx context.Context, params CreateSubmissionAuditErrorParams) error // GetScript implements getScript operation. // // Get the specified script by ID. diff --git a/pkg/internal/oas_unimplemented_gen.go b/pkg/internal/oas_unimplemented_gen.go index 46a4c7e..666fc14 100644 --- a/pkg/internal/oas_unimplemented_gen.go +++ b/pkg/internal/oas_unimplemented_gen.go @@ -121,6 +121,15 @@ func (UnimplementedHandler) CreateMapfix(ctx context.Context, req *MapfixCreate) return r, ht.ErrNotImplemented } +// CreateMapfixAuditError implements createMapfixAuditError operation. +// +// Validator posts an error to the audit log. +// +// POST /mapfixes/{MapfixID}/error +func (UnimplementedHandler) CreateMapfixAuditError(ctx context.Context, params CreateMapfixAuditErrorParams) error { + return ht.ErrNotImplemented +} + // CreateScript implements createScript operation. // // Create a new script. @@ -148,6 +157,15 @@ func (UnimplementedHandler) CreateSubmission(ctx context.Context, req *Submissio return r, ht.ErrNotImplemented } +// CreateSubmissionAuditError implements createSubmissionAuditError operation. +// +// Validator posts an error to the audit log. +// +// POST /submissions/{SubmissionID}/error +func (UnimplementedHandler) CreateSubmissionAuditError(ctx context.Context, params CreateSubmissionAuditErrorParams) error { + return ht.ErrNotImplemented +} + // GetScript implements getScript operation. // // Get the specified script by ID. -- 2.49.1 From 620717856f20d15399a67ab6661ebfd75b6eea20 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 11 Jun 2025 17:34:39 -0700 Subject: [PATCH 4/5] submissions: change error to explicit endpoint --- pkg/service_internal/mapfixes.go | 60 ++++++++++------------------ pkg/service_internal/submissions.go | 62 ++++++++++------------------- 2 files changed, 42 insertions(+), 80 deletions(-) diff --git a/pkg/service_internal/mapfixes.go b/pkg/service_internal/mapfixes.go index 3a86ae9..7c44a89 100644 --- a/pkg/service_internal/mapfixes.go +++ b/pkg/service_internal/mapfixes.go @@ -113,25 +113,6 @@ func (svc *Service) ActionMapfixRequestChanges(ctx context.Context, params inter return err } - { - event_data := model.AuditEventDataError{ - Error: params.ErrorMessage, - } - - err = svc.CreateAuditEventError( - ctx, - ValidtorUserID, - model.Resource{ - ID: params.MapfixID, - Type: model.ResourceMapfix, - }, - event_data, - ) - if err != nil { - return err - } - } - event_data := model.AuditEventDataAction{ TargetStatus: uint32(target_status), } @@ -174,26 +155,6 @@ func (svc *Service) ActionMapfixAccepted(ctx context.Context, params internal.Ac return err } - //push an error audit event - { - event_data := model.AuditEventDataError{ - Error: params.ErrorMessage, - } - - err = svc.CreateAuditEventError( - ctx, - ValidtorUserID, - model.Resource{ - ID: params.MapfixID, - Type: model.ResourceMapfix, - }, - event_data, - ) - if err != nil { - return err - } - } - // push an action audit event event_data := model.AuditEventDataAction{ TargetStatus: uint32(target_status), @@ -240,6 +201,27 @@ func (svc *Service) ActionMapfixUploaded(ctx context.Context, params internal.Ac ) } +// CreateMapfixAuditError implements createMapfixAuditError operation. +// +// Post an error to the audit log +// +// POST /mapfixes/{MapfixID}/error +func (svc *Service) CreateMapfixAuditError(ctx context.Context, params internal.CreateMapfixAuditErrorParams) (error) { + event_data := model.AuditEventDataError{ + Error: params.ErrorMessage, + } + + return svc.CreateAuditEventError( + ctx, + ValidtorUserID, + model.Resource{ + ID: params.MapfixID, + Type: model.ResourceMapfix, + }, + event_data, + ) +} + // POST /mapfixes func (svc *Service) CreateMapfix(ctx context.Context, request *internal.MapfixCreate) (*internal.MapfixID, error) { // sanitization diff --git a/pkg/service_internal/submissions.go b/pkg/service_internal/submissions.go index 23d7415..910b8f8 100644 --- a/pkg/service_internal/submissions.go +++ b/pkg/service_internal/submissions.go @@ -113,26 +113,6 @@ func (svc *Service) ActionSubmissionRequestChanges(ctx context.Context, params i return err } - //push an error audit event - { - event_data := model.AuditEventDataError{ - Error: params.ErrorMessage, - } - - err = svc.CreateAuditEventError( - ctx, - ValidtorUserID, - model.Resource{ - ID: params.SubmissionID, - Type: model.ResourceSubmission, - }, - event_data, - ) - if err != nil { - return err - } - } - // push an action audit event event_data := model.AuditEventDataAction{ TargetStatus: uint32(target_status), @@ -194,27 +174,6 @@ func (svc *Service) ActionSubmissionAccepted(ctx context.Context, params interna return err } - - //push an error audit event - { - event_data := model.AuditEventDataError{ - Error: params.ErrorMessage, - } - - err = svc.CreateAuditEventError( - ctx, - ValidtorUserID, - model.Resource{ - ID: params.SubmissionID, - Type: model.ResourceSubmission, - }, - event_data, - ) - if err != nil { - return err - } - } - // push an action audit event event_data := model.AuditEventDataAction{ TargetStatus: uint32(target_status), @@ -262,6 +221,27 @@ func (svc *Service) ActionSubmissionUploaded(ctx context.Context, params interna ) } +// CreateSubmissionAuditError implements createSubmissionAuditError operation. +// +// Post an error to the audit log +// +// POST /submissions/{SubmissionID}/error +func (svc *Service) CreateSubmissionAuditError(ctx context.Context, params internal.CreateSubmissionAuditErrorParams) (error) { + event_data := model.AuditEventDataError{ + Error: params.ErrorMessage, + } + + return svc.CreateAuditEventError( + ctx, + ValidtorUserID, + model.Resource{ + ID: params.SubmissionID, + Type: model.ResourceSubmission, + }, + event_data, + ) +} + // POST /submissions func (svc *Service) CreateSubmission(ctx context.Context, request *internal.SubmissionCreate) (*internal.SubmissionID, error) { // sanitization -- 2.49.1 From 16e9a1c403808499c88b8aa007120840263d2106 Mon Sep 17 00:00:00 2001 From: Quaternions Date: Wed, 11 Jun 2025 17:46:47 -0700 Subject: [PATCH 5/5] validation: change error to explicit endpoint --- validation/api/src/internal.rs | 18 ++++++------- validation/api/src/types.rs | 14 ++++++++-- validation/src/check_mapfix.rs | 37 +++++++++++++++++---------- validation/src/check_submission.rs | 37 +++++++++++++++++---------- validation/src/validate_mapfix.rs | 8 +++++- validation/src/validate_submission.rs | 8 +++++- 6 files changed, 82 insertions(+), 40 deletions(-) diff --git a/validation/api/src/internal.rs b/validation/api/src/internal.rs index 7ed9516..28fe19c 100644 --- a/validation/api/src/internal.rs +++ b/validation/api/src/internal.rs @@ -162,9 +162,7 @@ impl Context{ .json().await.map_err(Error::ReqwestJson) } // simple submission endpoints - action!("submissions",action_submission_request_changes,config,ActionSubmissionRequestChangesRequest,"status/validator-request-changes",config.SubmissionID.0, - ("ErrorMessage",config.ErrorMessage.as_str()) - ); + action!("submissions",action_submission_request_changes,config,ActionSubmissionRequestChangesRequest,"status/validator-request-changes",config.SubmissionID.0,); action!("submissions",action_submission_submitted,config,ActionSubmissionSubmittedRequest,"status/validator-submitted",config.SubmissionID.0, ("ModelVersion",config.ModelVersion.to_string().as_str()) ("DisplayName",config.DisplayName.as_str()) @@ -179,7 +177,8 @@ impl Context{ action!("submissions",action_submission_uploaded,config,ActionSubmissionUploadedRequest,"status/validator-uploaded",config.SubmissionID.0, ("UploadedAssetID",config.UploadedAssetID.to_string().as_str()) ); - action!("submissions",action_submission_accepted,config,ActionSubmissionAcceptedRequest,"status/validator-failed",config.SubmissionID.0, + action!("submissions",action_submission_accepted,config,ActionSubmissionAcceptedRequest,"status/validator-failed",config.SubmissionID.0,); + action!("submissions",create_submission_audit_error,config,CreateSubmissionAuditErrorRequest,"error",config.SubmissionID.0, ("ErrorMessage",config.ErrorMessage.as_str()) ); pub async fn create_mapfix(&self,config:CreateMapfixRequest<'_>)->Result{ @@ -194,9 +193,7 @@ impl Context{ .json().await.map_err(Error::ReqwestJson) } // simple mapfixes endpoints - action!("mapfixes",action_mapfix_request_changes,config,ActionMapfixRequestChangesRequest,"status/validator-request-changes",config.MapfixID.0, - ("ErrorMessage",config.ErrorMessage.as_str()) - ); + action!("mapfixes",action_mapfix_request_changes,config,ActionMapfixRequestChangesRequest,"status/validator-request-changes",config.MapfixID.0,); action!("mapfixes",action_mapfix_submitted,config,ActionMapfixSubmittedRequest,"status/validator-submitted",config.MapfixID.0, ("ModelVersion",config.ModelVersion.to_string().as_str()) ("DisplayName",config.DisplayName.as_str()) @@ -209,11 +206,12 @@ impl Context{ ("ValidatedModelVersion",config.ModelVersion.to_string().as_str()) ); action!("mapfixes",action_mapfix_uploaded,config,ActionMapfixUploadedRequest,"status/validator-uploaded",config.MapfixID.0,); - action!("mapfixes",action_mapfix_accepted,config,ActionMapfixAcceptedRequest,"status/validator-failed",config.MapfixID.0, - ("ErrorMessage",config.ErrorMessage.as_str()) - ); + action!("mapfixes",action_mapfix_accepted,config,ActionMapfixAcceptedRequest,"status/validator-failed",config.MapfixID.0,); // simple operation endpoint action!("operations",action_operation_failed,config,ActionOperationFailedRequest,"status/operation-failed",config.OperationID.0, ("StatusMessage",config.StatusMessage.as_str()) ); + action!("mapfixes",create_mapfix_audit_error,config,CreateMapfixAuditErrorRequest,"error",config.MapfixID.0, + ("ErrorMessage",config.ErrorMessage.as_str()) + ); } diff --git a/validation/api/src/types.rs b/validation/api/src/types.rs index 1969599..0ccb5d1 100644 --- a/validation/api/src/types.rs +++ b/validation/api/src/types.rs @@ -348,7 +348,6 @@ pub struct ActionSubmissionSubmittedRequest{ #[derive(Clone,Debug)] pub struct ActionSubmissionRequestChangesRequest{ pub SubmissionID:SubmissionID, - pub ErrorMessage:String, } #[allow(nonstandard_style)] @@ -362,6 +361,12 @@ pub struct ActionSubmissionUploadedRequest{ #[derive(Clone,Debug)] pub struct ActionSubmissionAcceptedRequest{ pub SubmissionID:SubmissionID, +} + +#[allow(nonstandard_style)] +#[derive(Clone,Debug)] +pub struct CreateSubmissionAuditErrorRequest{ + pub SubmissionID:SubmissionID, pub ErrorMessage:String, } @@ -390,7 +395,6 @@ pub struct ActionMapfixSubmittedRequest{ #[derive(Clone,Debug)] pub struct ActionMapfixRequestChangesRequest{ pub MapfixID:MapfixID, - pub ErrorMessage:String, } #[allow(nonstandard_style)] @@ -403,6 +407,12 @@ pub struct ActionMapfixUploadedRequest{ #[derive(Clone,Debug)] pub struct ActionMapfixAcceptedRequest{ pub MapfixID:MapfixID, +} + +#[allow(nonstandard_style)] +#[derive(Clone,Debug)] +pub struct CreateMapfixAuditErrorRequest{ + pub MapfixID:MapfixID, pub ErrorMessage:String, } diff --git a/validation/src/check_mapfix.rs b/validation/src/check_mapfix.rs index c2eed90..e66b323 100644 --- a/validation/src/check_mapfix.rs +++ b/validation/src/check_mapfix.rs @@ -21,18 +21,23 @@ impl crate::message_handler::MessageHandler{ // update the mapfix depending on the result match check_result{ - Ok(CheckReportAndVersion{status:Ok(map_info),version})=>self.api.action_mapfix_submitted( - submissions_api::types::ActionMapfixSubmittedRequest{ - MapfixID:mapfix_id, - ModelVersion:version, - DisplayName:map_info.display_name, - Creator:map_info.creator, - GameID:map_info.game_id.into(), - } - ).await.map_err(Error::ApiActionMapfixCheck)?, + Ok(CheckReportAndVersion{status:Ok(map_info),version})=>{ + self.api.action_mapfix_submitted( + submissions_api::types::ActionMapfixSubmittedRequest{ + MapfixID:mapfix_id, + ModelVersion:version, + DisplayName:map_info.display_name, + Creator:map_info.creator, + GameID:map_info.game_id.into(), + } + ).await.map_err(Error::ApiActionMapfixCheck)?; + + // Do not proceed to request changes + return Ok(()); + }, // update the mapfix model status to request changes - Ok(CheckReportAndVersion{status:Err(report),..})=>self.api.action_mapfix_request_changes( - submissions_api::types::ActionMapfixRequestChangesRequest{ + Ok(CheckReportAndVersion{status:Err(report),..})=>self.api.create_mapfix_audit_error( + submissions_api::types::CreateMapfixAuditErrorRequest{ MapfixID:mapfix_id, ErrorMessage:report.summary, } @@ -42,8 +47,8 @@ impl crate::message_handler::MessageHandler{ // log error println!("[check_mapfix] Error: {e}"); - self.api.action_mapfix_request_changes( - submissions_api::types::ActionMapfixRequestChangesRequest{ + self.api.create_mapfix_audit_error( + submissions_api::types::CreateMapfixAuditErrorRequest{ MapfixID:mapfix_id, ErrorMessage:e.to_string(), } @@ -51,6 +56,12 @@ impl crate::message_handler::MessageHandler{ }, } + self.api.action_mapfix_request_changes( + submissions_api::types::ActionMapfixRequestChangesRequest{ + MapfixID:mapfix_id, + } + ).await.map_err(Error::ApiActionMapfixCheck)?; + Ok(()) } } diff --git a/validation/src/check_submission.rs b/validation/src/check_submission.rs index 37ae360..596f8e0 100644 --- a/validation/src/check_submission.rs +++ b/validation/src/check_submission.rs @@ -22,18 +22,23 @@ impl crate::message_handler::MessageHandler{ // update the submission depending on the result match check_result{ // update the submission model status to submitted - Ok(CheckReportAndVersion{status:Ok(map_info),version})=>self.api.action_submission_submitted( - submissions_api::types::ActionSubmissionSubmittedRequest{ - SubmissionID:submission_id, - ModelVersion:version, - DisplayName:map_info.display_name, - Creator:map_info.creator, - GameID:map_info.game_id.into(), - } - ).await.map_err(Error::ApiActionSubmissionCheck)?, + Ok(CheckReportAndVersion{status:Ok(map_info),version})=>{ + self.api.action_submission_submitted( + submissions_api::types::ActionSubmissionSubmittedRequest{ + SubmissionID:submission_id, + ModelVersion:version, + DisplayName:map_info.display_name, + Creator:map_info.creator, + GameID:map_info.game_id.into(), + } + ).await.map_err(Error::ApiActionSubmissionCheck)?; + + // Do not proceed to request changes + return Ok(()); + }, // update the submission model status to request changes - Ok(CheckReportAndVersion{status:Err(report),..})=>self.api.action_submission_request_changes( - submissions_api::types::ActionSubmissionRequestChangesRequest{ + Ok(CheckReportAndVersion{status:Err(report),..})=>self.api.create_submission_audit_error( + submissions_api::types::CreateSubmissionAuditErrorRequest{ SubmissionID:submission_id, ErrorMessage:report.summary, } @@ -43,8 +48,8 @@ impl crate::message_handler::MessageHandler{ // log error println!("[check_submission] Error: {e}"); - self.api.action_submission_request_changes( - submissions_api::types::ActionSubmissionRequestChangesRequest{ + self.api.create_submission_audit_error( + submissions_api::types::CreateSubmissionAuditErrorRequest{ SubmissionID:submission_id, ErrorMessage:e.to_string(), } @@ -52,6 +57,12 @@ impl crate::message_handler::MessageHandler{ }, } + self.api.action_submission_request_changes( + submissions_api::types::ActionSubmissionRequestChangesRequest{ + SubmissionID:submission_id, + } + ).await.map_err(Error::ApiActionSubmissionCheck)?; + Ok(()) } } diff --git a/validation/src/validate_mapfix.rs b/validation/src/validate_mapfix.rs index 93e087f..bce1639 100644 --- a/validation/src/validate_mapfix.rs +++ b/validation/src/validate_mapfix.rs @@ -29,10 +29,16 @@ impl crate::message_handler::MessageHandler{ // log error println!("[validate_mapfix] Error: {e}"); + self.api.create_mapfix_audit_error( + submissions_api::types::CreateMapfixAuditErrorRequest{ + MapfixID:mapfix_id, + ErrorMessage:e.to_string(), + } + ).await.map_err(Error::ApiActionMapfixValidate)?; + // update the mapfix model status to accepted self.api.action_mapfix_accepted(submissions_api::types::ActionMapfixAcceptedRequest{ MapfixID:mapfix_id, - ErrorMessage:e.to_string(), }).await.map_err(Error::ApiActionMapfixValidate)?; }, } diff --git a/validation/src/validate_submission.rs b/validation/src/validate_submission.rs index 6f6b4c4..000ce41 100644 --- a/validation/src/validate_submission.rs +++ b/validation/src/validate_submission.rs @@ -29,10 +29,16 @@ impl crate::message_handler::MessageHandler{ // log error println!("[validate_submission] Error: {e}"); + self.api.create_submission_audit_error( + submissions_api::types::CreateSubmissionAuditErrorRequest{ + SubmissionID:submission_id, + ErrorMessage:e.to_string(), + } + ).await.map_err(Error::ApiActionSubmissionValidate)?; + // update the submission model status to accepted self.api.action_submission_accepted(submissions_api::types::ActionSubmissionAcceptedRequest{ SubmissionID:submission_id, - ErrorMessage:e.to_string(), }).await.map_err(Error::ApiActionSubmissionValidate)?; }, } -- 2.49.1