package api import ( "context" "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/audit/messaging" auditV1 "dev.azure.com/schwarzit/schwarzit.stackit-public/audit-go.git/gen/go/audit/v1" "errors" "strings" "google.golang.org/protobuf/proto" ) const DataTypeLegacyAuditEventV1 = "audit.v1.LegacyAuditEvent" // LegacyTopicNameResolver implements TopicNameResolver. // A hard-coded topic name is used, routing identifiers are ignored. type LegacyTopicNameResolver struct { topicName string } // Resolve implements TopicNameResolver.Resolve func (r *LegacyTopicNameResolver) Resolve(*RoutableIdentifier) (string, error) { return r.topicName, nil } // LegacyTopicNameConfig provides topic name information required for the topic name resolution. type LegacyTopicNameConfig struct { TopicName string } // LegacyAuditApi is an implementation of AuditApi to send events to the legacy audit log system. // // Note: The implementation will be deprecated and replaced with the "routableAuditApi" once the new audit log routing is implemented type LegacyAuditApi struct { messagingApi *messaging.Api topicNameResolver *TopicNameResolver validator *ProtobufValidator } // NewLegacyAuditApi 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 NewLegacyAuditApi( messagingApi *messaging.Api, topicNameConfig LegacyTopicNameConfig, validator ProtobufValidator, ) (*AuditApi, error) { if messagingApi == nil { return nil, ErrMessagingApiNil } // Topic resolver if topicNameConfig.TopicName == "" { return nil, errors.New("topic name is required") } var topicNameResolver TopicNameResolver = &LegacyTopicNameResolver{topicName: topicNameConfig.TopicName} // Audit api var auditApi AuditApi = &LegacyAuditApi{ messagingApi: messagingApi, topicNameResolver: &topicNameResolver, validator: &validator, } return &auditApi, nil } // Log implements AuditApi.Log func (a *LegacyAuditApi) 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 *LegacyAuditApi) 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 *LegacyAuditApi) 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 *LegacyAuditApi) 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 } // Reject event type data-access as the downstream services // cannot handle it at the moment if strings.HasSuffix(event.LogName, string(EventTypeDataAccess)) { return nil, ErrUnsupportedEventTypeDataAccess } // 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: ContentTypeCloudEventsJson, DataType: DataTypeLegacyAuditEventV1, Subject: event.ProtoPayload.ResourceName, Data: legacyBytes, TraceParent: traceParent, TraceState: traceState, } return &message, nil } // Send implements AuditApi.Send func (a *LegacyAuditApi) Send( ctx context.Context, routableIdentifier *RoutableIdentifier, cloudEvent *CloudEvent, ) error { return send(a.topicNameResolver, a.messagingApi, ctx, routableIdentifier, cloudEvent) }