Skip to content

Commit

Permalink
feat: adds an api to download audit/event logs
Browse files Browse the repository at this point in the history
  • Loading branch information
madhavilosetty-intel authored and rsdmike committed Jan 9, 2025
1 parent b48f139 commit f916a2a
Show file tree
Hide file tree
Showing 16 changed files with 386 additions and 16 deletions.
2 changes: 1 addition & 1 deletion .github/.golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ linters-settings:
lines: 100
statements: 45
gocognit:
min-complexity: 15
min-complexity: 16
gocyclo:
min-complexity: 15
cyclop:
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ jobs:
- name: golangci-lint
uses: reviewdog/action-golangci-lint@dd3fda91790ca90e75049e5c767509dc0ec7d99b # v2.7.0
with:
fail_on_error: true
fail-level: error
golangci_lint_flags: "--config=.github/.golangci.yml ./..."

yamllint:
Expand Down Expand Up @@ -98,7 +98,8 @@ jobs:
strategy:
matrix:
go-version: [1.22.x, 1.23.x]
os: [windows-2019, windows-2022, ubuntu-22.04, ubuntu-20.04, ubuntu-24.04]
os:
[windows-2019, windows-2022, ubuntu-22.04, ubuntu-20.04, ubuntu-24.04]
steps:
- name: Harden Runner
uses: step-security/harden-runner@0080882f6c36860b6ba35c610c98ce87d4e2f26f # v2.10.2
Expand Down
2 changes: 1 addition & 1 deletion .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ linters-settings:
lines: 100
statements: 45
gocognit:
min-complexity: 15
min-complexity: 16
gocyclo:
min-complexity: 15
cyclop:
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ mock: ### run mockgen
mockgen -source ./internal/usecase/devices/interfaces.go -package mocks -mock_names Repository=MockDeviceManagementRepository,Feature=MockDeviceManagementFeature > ./internal/mocks/devicemanagement_mocks.go
mockgen -source ./internal/usecase/amtexplorer/interfaces.go -package mocks -mock_names Repository=MockAMTExplorerRepository,Feature=MockAMTExplorerFeature,WSMAN=MockAMTExplorerWSMAN > ./internal/mocks/amtexplorer_mocks.go
mockgen -source ./internal/usecase/devices/wsman/interfaces.go -package mocks > ./internal/mocks/wsman_mocks.go
mockgen -source ./internal/usecase/export/interface.go -package mocks > ./internal/mocks/export_mocks.go
mockgen -source ./internal/usecase/domains/interfaces.go -package mocks -mock_names Repository=MockDomainsRepository,Feature=MockDomainsFeature > ./internal/mocks/domains_mocks.go
mockgen -source ./internal/controller/ws/v1/interface.go -package mocks > ./internal/mocks/wsv1_mocks.go
mockgen -source ./pkg/logger/logger.go -package mocks -mock_names Interface=MockLogger > ./internal/mocks/logger_mocks.go
Expand Down
2 changes: 1 addition & 1 deletion internal/controller/http/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ func NewRouter(handler *gin.Engine, l logger.Interface, t usecase.Usecases, cfg
h2 := protected.Group("/v1")
{
v1.NewDeviceRoutes(h2, t.Devices, l)
v1.NewAmtRoutes(h2, t.Devices, t.AMTExplorer, l)
v1.NewAmtRoutes(h2, t.Devices, t.AMTExplorer, t.Exporter, l)
}

h := protected.Group("/v1/admin")
Expand Down
86 changes: 84 additions & 2 deletions internal/controller/http/v1/devicemanagement.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
package v1

import (
"io"
"net/http"
"strconv"

"github.com/gin-gonic/gin"
"github.com/open-amt-cloud-toolkit/go-wsman-messages/v2/pkg/wsman/amt/auditlog"

"github.com/open-amt-cloud-toolkit/console/internal/entity/dto/v1"
"github.com/open-amt-cloud-toolkit/console/internal/usecase/amtexplorer"
"github.com/open-amt-cloud-toolkit/console/internal/usecase/devices"
"github.com/open-amt-cloud-toolkit/console/internal/usecase/export"
"github.com/open-amt-cloud-toolkit/console/pkg/logger"
)

type deviceManagementRoutes struct {
d devices.Feature
a amtexplorer.Feature
e export.Exporter
l logger.Interface
}

func NewAmtRoutes(handler *gin.RouterGroup, d devices.Feature, amt amtexplorer.Feature, l logger.Interface) {
r := &deviceManagementRoutes{d, amt, l}
func NewAmtRoutes(handler *gin.RouterGroup, d devices.Feature, amt amtexplorer.Feature, e export.Exporter, l logger.Interface) {
r := &deviceManagementRoutes{d, amt, e, l}

h := handler.Group("/amt")
{
Expand All @@ -41,7 +45,9 @@ func NewAmtRoutes(handler *gin.RouterGroup, d devices.Feature, amt amtexplorer.F
h.GET("power/capabilities/:guid", r.getPowerCapabilities)

h.GET("log/audit/:guid", r.getAuditLog)
h.GET("log/audit/:guid/download", r.downloadAuditLog)
h.GET("log/event/:guid", r.getEventLog)
h.GET("log/event/:guid/download", r.downloadEventLog)
h.GET("generalSettings/:guid", r.getGeneralSettings)

h.GET("userConsentCode/cancel/:guid", r.cancelUserConsentCode)
Expand Down Expand Up @@ -336,6 +342,51 @@ func (r *deviceManagementRoutes) getAuditLog(c *gin.Context) {
c.JSON(http.StatusOK, auditLogs)
}

func (r *deviceManagementRoutes) downloadAuditLog(c *gin.Context) {
guid := c.Param("guid")

var allRecords []auditlog.AuditLogRecord

startIndex := 1

for {
auditLogs, err := r.d.GetAuditLog(c.Request.Context(), startIndex, guid)
if err != nil {
r.l.Error(err, "http - v1 - getAuditLog")
ErrorResponse(c, err)

return
}

allRecords = append(allRecords, auditLogs.Records...)

if len(allRecords) >= auditLogs.TotalCount {
break
}

startIndex += len(auditLogs.Records)
}

// Convert logs to CSV
csvReader, err := r.e.ExportAuditLogsCSV(allRecords)
if err != nil {
r.l.Error(err, "http - v1 - downloadAuditLog")
ErrorResponse(c, err)

return
}

// Serve the CSV file
c.Header("Content-Disposition", "attachment; filename=audit_logs.csv")
c.Header("Content-Type", "text/csv")

_, err = io.Copy(c.Writer, csvReader)
if err != nil {
r.l.Error(err, "http - v1 - downloadAuditLog")
ErrorResponse(c, err)
}
}

func (r *deviceManagementRoutes) getEventLog(c *gin.Context) {
guid := c.Param("guid")

Expand All @@ -350,6 +401,37 @@ func (r *deviceManagementRoutes) getEventLog(c *gin.Context) {
c.JSON(http.StatusOK, eventLogs)
}

func (r *deviceManagementRoutes) downloadEventLog(c *gin.Context) {
guid := c.Param("guid")

eventLogs, err := r.d.GetEventLog(c.Request.Context(), guid)
if err != nil {
r.l.Error(err, "http - v1 - getEventLog")
ErrorResponse(c, err)

return
}

// Convert logs to CSV
csvReader, err := r.e.ExportEventLogsCSV(eventLogs)
if err != nil {
r.l.Error(err, "http - v1 - downloadEventLog")
ErrorResponse(c, err)

return
}

// Serve the CSV file
c.Header("Content-Disposition", "attachment; filename=event_logs.csv")
c.Header("Content-Type", "text/csv")

_, err = io.Copy(c.Writer, csvReader)
if err != nil {
r.l.Error(err, "http - v1 - downloadEventLog")
ErrorResponse(c, err)
}
}

func (r *deviceManagementRoutes) setBootOptions(c *gin.Context) {
guid := c.Param("guid")

Expand Down
3 changes: 2 additions & 1 deletion internal/controller/http/v1/devicemanagement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,11 @@ func deviceManagementTest(t *testing.T) (*mocks.MockDeviceManagementFeature, *gi
log := logger.New("error")
deviceManagement := mocks.NewMockDeviceManagementFeature(mockCtl)
amtExplorerMock := mocks.NewMockAMTExplorerFeature(mockCtl)
exporterMock := mocks.NewMockExporter(mockCtl)
engine := gin.New()
handler := engine.Group("/api/v1")

NewAmtRoutes(handler, deviceManagement, amtExplorerMock, log)
NewAmtRoutes(handler, deviceManagement, amtExplorerMock, exporterMock, log)

return deviceManagement, engine
}
Expand Down
72 changes: 72 additions & 0 deletions internal/mocks/export_mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion internal/usecase/devices/interceptor_private_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,10 @@ func TestHandleAuthenticationSession(t *testing.T) {

require.IsType(t, tc.expectedResultType, result)

if len(tc.expectedResultType.([]byte)) > 0 {
expectedResult, ok := tc.expectedResultType.([]byte)
require.True(t, ok)

if len(expectedResult) > 0 {
require.NotEmpty(t, result)
}

Expand Down
10 changes: 5 additions & 5 deletions internal/usecase/devices/redirection_wsman_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func (m *MockClient) Send(data []byte) error {
func (m *MockClient) Receive() ([]byte, error) {
args := m.Called()

return args.Get(0).([]byte), args.Error(1)
return args.Get(0).([]byte), args.Error(1) //nolint:errcheck // It's a test...
}

func (m *MockClient) CloseConnection() error {
Expand All @@ -48,25 +48,25 @@ func (m *MockClient) CloseConnection() error {
func (m *MockClient) Post(msg string) ([]byte, error) {
args := m.Called(msg)

return args.Get(0).([]byte), args.Error(1)
return args.Get(0).([]byte), args.Error(1) //nolint:errcheck // It's a test...
}

func (m *MockClient) Listen() ([]byte, error) {
args := m.Called()

return args.Get(0).([]byte), args.Error(1)
return args.Get(0).([]byte), args.Error(1) //nolint:errcheck // It's a test...
}

func (m *MockClient) IsAuthenticated() bool {
args := m.Called()

return args.Get(0).(bool)
return args.Get(0).(bool) //nolint:errcheck // It's a test...
}

func (m *MockClient) GetServerCertificate() (*tls.Certificate, error) {
args := m.Called()

return args.Get(0).(*tls.Certificate), args.Error(1)
return args.Get(0).(*tls.Certificate), args.Error(1) //nolint:errcheck // It's a test...
}

type wsmanTest struct {
Expand Down
14 changes: 14 additions & 0 deletions internal/usecase/export/interface.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package export

import (
"io"

"github.com/open-amt-cloud-toolkit/go-wsman-messages/v2/pkg/wsman/amt/auditlog"

"github.com/open-amt-cloud-toolkit/console/internal/entity/dto/v1"
)

type Exporter interface {
ExportAuditLogsCSV(logs []auditlog.AuditLogRecord) (io.Reader, error) // Converts logs to CSV and returns a reader
ExportEventLogsCSV(logs []dto.EventLog) (io.Reader, error) // Converts logs to CSV and returns a reader
}
Loading

0 comments on commit f916a2a

Please sign in to comment.