Skip to content

Commit

Permalink
Add in Correct Create Auditing (#69)
Browse files Browse the repository at this point in the history
Previously when something was created, we just said exactly that, but we
didn't say what, because we had no idea.  Modify the lookup on creation
so we have access to the response, can extract the metadata, and get the
new ID.  Obviously this means every API will need to be updated...
  • Loading branch information
spjmurray authored Jul 16, 2024
1 parent 69b97cb commit c2ad32a
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 18 deletions.
4 changes: 2 additions & 2 deletions charts/core/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ description: A Helm chart for deploying Unikorn Core

type: application

version: v0.1.61
appVersion: v0.1.61
version: v0.1.62
appVersion: v0.1.62

icon: https://assets.unikorn-cloud.org/images/logos/dark-on-light/icon.svg

Expand Down
42 changes: 33 additions & 9 deletions pkg/server/middleware/audit/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package audit

import (
"encoding/json"
"net/http"
"regexp"
"strings"
Expand Down Expand Up @@ -59,24 +60,41 @@ func New(next http.Handler, openapi *openapi.Schema, application, version string
}

// getResource will resolve to a resource type.
func getResource(route *routers.Route, params map[string]string) *Resource {
// We are looking for "/.../resource/{idParameter}"
// or failing that "/.../resource"
matches := regexp.MustCompile(`/([^/]+)/{([^/}]+)}$`).FindStringSubmatch(route.Path)
if matches == nil {
func getResource(w *middleware.LoggingResponseWriter, r *http.Request, route *routers.Route, params map[string]string) *Resource {
// Creates rely on the response containing the resource ID in the response metadata.
if r.Method == http.MethodPost {
// Nothing written, possibly a bug somewhere?
if w.Body() == nil {
return nil
}

var metadata struct {
Metadata openapi.ResourceReadMetadata `json:"metadata"`
}

// Not a canonical API resource, possibly a bug somewhere?
if err := json.Unmarshal(w.Body().Bytes(), &metadata); err != nil {
return nil
}

segments := strings.Split(route.Path, "/")

return &Resource{
Type: segments[len(segments)-1],
ID: metadata.Metadata.Id,
}
}

resource := &Resource{
// Read, updates and deletes you can get the information from the route.
matches := regexp.MustCompile(`/([^/]+)/{([^/}]+)}$`).FindStringSubmatch(route.Path)
if matches == nil {
return nil
}

return &Resource{
Type: matches[1],
ID: params[matches[2]],
}

return resource
}

// ServeHTTP implements the http.Handler interface.
Expand Down Expand Up @@ -112,6 +130,12 @@ func (l *Logger) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}

// If you cannot derive the resource, then discard.
resource := getResource(writer, r, route, params)
if resource == nil {
return
}

logParams := []any{
"component", &Component{
Name: l.application,
Expand All @@ -124,7 +148,7 @@ func (l *Logger) ServeHTTP(w http.ResponseWriter, r *http.Request) {
Verb: r.Method,
},
"scope", params,
"resource", getResource(route, params),
"resource", resource,
"result", &Result{
Status: writer.StatusCode(),
},
Expand Down
8 changes: 7 additions & 1 deletion pkg/server/middleware/opentelemetry/opentelemetry.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,10 +202,16 @@ func httpRequestAttributes(r *http.Request) []attribute.KeyValue {
}

func httpResponseAttributes(w *middleware.LoggingResponseWriter) []attribute.KeyValue {
var bodySize int

if body := w.Body(); body != nil {
bodySize = body.Len()
}

var attr []attribute.KeyValue

attr = append(attr, semconv.HTTPResponseStatusCode(w.StatusCode()))
attr = append(attr, semconv.HTTPResponseBodySize(w.ContentLength()))
attr = append(attr, semconv.HTTPResponseBodySize(bodySize))
attr = append(attr, httpHeaderAttributes(w.Header(), "http.response.header")...)

return attr
Expand Down
17 changes: 11 additions & 6 deletions pkg/server/middleware/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@ limitations under the License.
package middleware

import (
"bytes"
"net/http"
)

// LoggingResponseWriter is the ubiquitous reimplementation of a response
// writer that allows access to the HTTP status code in middleware.
type LoggingResponseWriter struct {
next http.ResponseWriter
code int
contentLength int
next http.ResponseWriter
code int
body *bytes.Buffer
}

func NewLoggingResponseWriter(next http.ResponseWriter) *LoggingResponseWriter {
Expand All @@ -42,7 +43,11 @@ func (w *LoggingResponseWriter) Header() http.Header {
}

func (w *LoggingResponseWriter) Write(body []byte) (int, error) {
w.contentLength += len(body)
if w.body == nil {
w.body = &bytes.Buffer{}
}

w.body.Write(body)

return w.next.Write(body)
}
Expand All @@ -60,6 +65,6 @@ func (w *LoggingResponseWriter) StatusCode() int {
return w.code
}

func (w *LoggingResponseWriter) ContentLength() int {
return w.contentLength
func (w *LoggingResponseWriter) Body() *bytes.Buffer {
return w.body
}

0 comments on commit c2ad32a

Please sign in to comment.