audit-go/audit/api/api_legacy_dynamic.go

152 lines
4.5 KiB
Go

package api
import (
"context"
"dev.azure.com/schwarzit/schwarzit.stackit-core-platform/common-audit.git/audit/messaging"
auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-core-platform/common-audit.git/gen/go/audit/v1"
"errors"
"fmt"
"google.golang.org/protobuf/proto"
)
type ContextKey string
const ContextKeyTopic ContextKey = "topic"
var ErrNoTopicNameProvided = errors.New("no topic name provided")
var ErrTopicNameEmpty = errors.New("empty topic name provided")
// DynamicLegacyAuditApi is an implementation of AuditApi to send events to the legacy audit log system
// by setting the topic name explicitly in the context with the key "topic".
//
// Note: The implementation will be deprecated and replaced with the "routableAuditApi" once the new audit log routing is implemented
type DynamicLegacyAuditApi struct {
messagingApi *messaging.Api
validator *ProtobufValidator
}
// NewDynamicLegacyAuditApi can be used to initialize the audit log api.
//
// Note: The NewLegacyAuditApi method will be deprecated and replaced with "newRoutableAuditApi" once the new audit log routing is implemented
func NewDynamicLegacyAuditApi(
messagingApi *messaging.Api,
validator ProtobufValidator,
) (*AuditApi, error) {
if messagingApi == nil {
return nil, ErrMessagingApiNil
}
// Audit api
var auditApi AuditApi = &DynamicLegacyAuditApi{
messagingApi: messagingApi,
validator: &validator,
}
return &auditApi, nil
}
// Log implements AuditApi.Log
func (a *DynamicLegacyAuditApi) Log(
ctx context.Context,
event *auditV1.AuditLogEntry,
visibility auditV1.Visibility,
routableIdentifier *RoutableIdentifier,
) error {
return a.LogWithTrace(ctx, event, visibility, routableIdentifier, nil, nil)
}
// LogWithTrace implements AuditApi.LogWithTrace
func (a *DynamicLegacyAuditApi) LogWithTrace(
ctx context.Context,
event *auditV1.AuditLogEntry,
visibility auditV1.Visibility,
routableIdentifier *RoutableIdentifier,
traceParent *string,
traceState *string,
) error {
cloudEvent, err := a.ValidateAndSerializeWithTrace(event, visibility, routableIdentifier, traceParent, traceState)
if err != nil {
return err
}
return a.Send(ctx, routableIdentifier, cloudEvent)
}
// ValidateAndSerialize implements AuditApi.ValidateAndSerialize.
// It serializes the event into the byte representation of the legacy audit log system.
func (a *DynamicLegacyAuditApi) ValidateAndSerialize(
event *auditV1.AuditLogEntry,
visibility auditV1.Visibility,
routableIdentifier *RoutableIdentifier,
) (*CloudEvent, error) {
return a.ValidateAndSerializeWithTrace(event, visibility, routableIdentifier, nil, nil)
}
// ValidateAndSerializeWithTrace implements AuditApi.ValidateAndSerializeWithTrace.
// It serializes the event into the byte representation of the legacy audit log system.
func (a *DynamicLegacyAuditApi) ValidateAndSerializeWithTrace(
event *auditV1.AuditLogEntry,
visibility auditV1.Visibility,
routableIdentifier *RoutableIdentifier,
traceParent *string,
traceState *string,
) (*CloudEvent, error) {
routableEvent, err := validateAndSerializePartially(a.validator, event, visibility, routableIdentifier)
if err != nil {
return nil, err
}
// Do nothing with the serialized data in the legacy solution
_, err = proto.Marshal(routableEvent)
if err != nil {
return nil, err
}
// Convert attributes
legacyBytes, err := convertAndSerializeIntoLegacyFormat(event, routableEvent)
if err != nil {
return nil, err
}
message := CloudEvent{
SpecVersion: "1.0",
Source: event.ProtoPayload.ServiceName,
Id: event.InsertId,
Time: event.ProtoPayload.RequestMetadata.RequestAttributes.Time.AsTime(),
DataContentType: ContentTypeCloudEventsProtobuf,
DataType: fmt.Sprintf("%v", routableEvent.ProtoReflect().Descriptor().FullName()),
Subject: event.ProtoPayload.ResourceName,
Data: legacyBytes,
TraceParent: traceParent,
TraceState: traceState,
}
return &message, nil
}
// Send implements AuditApi.Send
//
// Requires to have the topic name set as key "topic" in the context.
func (a *DynamicLegacyAuditApi) Send(
ctx context.Context,
routableIdentifier *RoutableIdentifier,
cloudEvent *CloudEvent,
) error {
rawTopicName := ctx.Value(ContextKeyTopic)
if rawTopicName == nil {
return ErrNoTopicNameProvided
}
topicName := fmt.Sprintf("%s", rawTopicName)
if len(topicName) == 0 {
return ErrTopicNameEmpty
}
var topicNameResolver TopicNameResolver = &LegacyTopicNameResolver{topicName: topicName}
return send(&topicNameResolver, a.messagingApi, ctx, routableIdentifier, cloudEvent)
}