Skip to content

Commit

Permalink
Update audit to use int timestamp
Browse files Browse the repository at this point in the history
  • Loading branch information
akclace committed Dec 13, 2024
1 parent 20266eb commit 7e674ab
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 53 deletions.
1 change: 1 addition & 0 deletions internal/app/dev/styling.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ func (s *AppStyle) setupTailwindConfig(templateLocations []string, sourceFS *app
}
buf.WriteString(fmt.Sprintf("'%s'", path.Join(workFS.Root, "action", "*.go.html")))

templateLocations = append(templateLocations, "base_templates/*.go.html")
// Add the template locations to the input list
for _, loc := range templateLocations {
buf.WriteString(", ")
Expand Down
8 changes: 4 additions & 4 deletions internal/app/tests/styling_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ app = ace.app("testApp", custom_layout=True, routes = [ace.html("/")],

data, err = workFS.ReadFile("style/tailwind.config.js")
testutil.AssertNoError(t, err)
testutil.AssertStringMatch(t, "tailwind.config.js", `module.exports = { content: ['action/*.go.html', '*.go.html'], theme: { extend: {}, }, plugins: [ ], }`, string(data))
testutil.AssertStringMatch(t, "tailwind.config.js", `module.exports = { content: ['action/*.go.html', '*.go.html', 'base_templates/*.go.html'], theme: { extend: {}, }, plugins: [ ], }`, string(data))
}

func TestStyleDaisyUI(t *testing.T) {
Expand All @@ -103,7 +103,7 @@ app = ace.app("testApp", custom_layout=True, routes = [ace.html("/")],

data, err = workFS.ReadFile("style/tailwind.config.js")
testutil.AssertNoError(t, err)
testutil.AssertStringMatch(t, "tailwind.config.js", `module.exports = { content: ['action/*.go.html', '*.go.html'], theme: { extend: {}, }, plugins: [ require("daisyui") ], daisyui: { themes: ["emerald", "night"], }, }`, string(data))
testutil.AssertStringMatch(t, "tailwind.config.js", `module.exports = { content: ['action/*.go.html', '*.go.html', 'base_templates/*.go.html'], theme: { extend: {}, }, plugins: [ require("daisyui") ], daisyui: { themes: ["emerald", "night"], }, }`, string(data))
}

func TestStyleDaisyUIThemes(t *testing.T) {
Expand All @@ -125,7 +125,7 @@ app = ace.app("testApp", custom_layout=True, routes = [ace.html("/")],

data, err = workFS.ReadFile("style/tailwind.config.js")
testutil.AssertNoError(t, err)
testutil.AssertStringMatch(t, "tailwind.config.js", `module.exports = { content: ['action/*.go.html', '*.go.html'], theme: { extend: {}, }, plugins: [ require("daisyui") ], daisyui: { themes: ["cupcake", "dark", "emerald", "night"], }, }`, string(data))
testutil.AssertStringMatch(t, "tailwind.config.js", `module.exports = { content: ['action/*.go.html', '*.go.html', 'base_templates/*.go.html'], theme: { extend: {}, }, plugins: [ require("daisyui") ], daisyui: { themes: ["cupcake", "dark", "emerald", "night"], }, }`, string(data))
}

func TestStyleDaisyUILight(t *testing.T) {
Expand All @@ -147,7 +147,7 @@ app = ace.app("testApp", custom_layout=True, routes = [ace.html("/")],

data, err = workFS.ReadFile("style/tailwind.config.js")
testutil.AssertNoError(t, err)
testutil.AssertStringMatch(t, "tailwind.config.js", `module.exports = { content: ['action/*.go.html', '*.go.html'], theme: { extend: {}, }, plugins: [ require("daisyui") ], daisyui: { themes: ["abc", "cupcake", "xyz"], }, }`, string(data))
testutil.AssertStringMatch(t, "tailwind.config.js", `module.exports = { content: ['action/*.go.html', '*.go.html', 'base_templates/*.go.html'], theme: { extend: {}, }, plugins: [ require("daisyui") ], daisyui: { themes: ["abc", "cupcake", "xyz"], }, }`, string(data))
}

func TestStyleCustom(t *testing.T) {
Expand Down
2 changes: 1 addition & 1 deletion internal/server/app_apis.go
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ func (s *Server) setupApp(appEntry *types.AppEntry, tx types.Transaction) (*app.
DiskReadFS: appfs.NewDiskReadFS(&appLogger, appPath, *appEntry.Metadata.SpecFiles),
})
return app.NewApp(sourceFS, workFS, &appLogger, appEntry, &s.config.System,
s.config.Plugins, s.config.AppConfig, s.notifyClose, s.secretsManager.EvalTemplate, s.insertAuditEvent)
s.config.Plugins, s.config.AppConfig, s.notifyClose, s.secretsManager.EvalTemplate, s.InsertAuditEvent)
}

func (s *Server) GetAppApi(ctx context.Context, appPath string) (*types.AppGetResponse, error) {
Expand Down
12 changes: 6 additions & 6 deletions internal/server/apps.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,12 +180,11 @@ func (a *AppStore) DeleteAppsAudit(ctx context.Context, pathDomain []types.AppPa
appMap := getAppInfoMap(appInfo)

event := types.AuditEvent{
RequestId: system.GetContextRequestId(ctx),
CreateTime: time.Now(),
UserId: system.GetContextUserId(ctx),
EventType: types.EventTypeSystem,
Operation: op,
Status: "Success",
RequestId: system.GetContextRequestId(ctx),
UserId: system.GetContextUserId(ctx),
EventType: types.EventTypeSystem,
Operation: op,
Status: "Success",
}

for _, pd := range pathDomain {
Expand All @@ -196,6 +195,7 @@ func (a *AppStore) DeleteAppsAudit(ctx context.Context, pathDomain []types.AppPa

event.Target = pd.String()
event.AppId = appInfo.Id
event.CreateTime = time.Now()

if err := a.server.InsertAuditEvent(&event); err != nil {
return err
Expand Down
13 changes: 3 additions & 10 deletions internal/server/audit_middleware.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (s *Server) initAuditDB(connectString string) error {
return err
}

if _, err := s.auditDB.Exec(`create table IF NOT EXISTS audit (rid text, app_id text, create_time timestamp,` +
if _, err := s.auditDB.Exec(`create table IF NOT EXISTS audit (rid text, app_id text, create_time int,` +
`user_id text, event_type text, operation text, target text, status text, detail text)`); err != nil {
return err
}
Expand All @@ -51,17 +51,10 @@ func (s *Server) initAuditDB(connectString string) error {
return nil
}

func (s *Server) insertAuditEvent(event *types.AuditEvent) error {
_, err := s.auditDB.Exec(`insert into audit (rid, app_id, create_time, user_id, event_type, operation, target, status, detail) `+
`values (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
event.RequestId, event.AppId, event.CreateTime, event.UserId, event.EventType, event.Operation, event.Target, event.Status, event.Detail)
return err
}

func (s *Server) InsertAuditEvent(event *types.AuditEvent) error {
_, err := s.auditDB.Exec(`insert into audit (rid, app_id, create_time, user_id, event_type, operation, target, status, detail) `+
`values (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
event.RequestId, event.AppId, event.CreateTime, event.UserId, event.EventType, event.Operation, event.Target, event.Status, event.Detail)
event.RequestId, event.AppId, event.CreateTime.UnixNano(), event.UserId, event.EventType, event.Operation, event.Target, event.Status, event.Detail)
return err
}

Expand Down Expand Up @@ -141,7 +134,7 @@ func (server *Server) handleStatus(next http.Handler) http.Handler {
Detail: fmt.Sprintf("%s %s %s %d %d", r.Method, r.Host, r.URL.Path, crw.statusCode, duration.Milliseconds()),
}

if err := server.insertAuditEvent(&event); err != nil {
if err := server.InsertAuditEvent(&event); err != nil {
server.Error().Err(err).Msg("error inserting audit event")
}
})
Expand Down
73 changes: 51 additions & 22 deletions internal/server/clace_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package server
import (
"cmp"
"fmt"
"strconv"
"strings"
"time"

Expand All @@ -20,6 +21,7 @@ func initClacePlugin(server *Server) {
c := &clacePlugin{}
pluginFuncs := []plugin.PluginFunc{
app.CreatePluginApiName(c.ListApps, app.READ, "list_apps"),
app.CreatePluginApiName(c.ListAllApps, app.READ, "list_all_apps"),
app.CreatePluginApiName(c.ListAuditEvents, app.READ, "list_audit_events"),
}

Expand Down Expand Up @@ -68,11 +70,18 @@ func getAppUrl(app types.AppInfo, server *Server) string {
}
}

func (c *clacePlugin) ListAllApps(thread *starlark.Thread, builtin *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return c.listAppsImpl(thread, builtin, args, kwargs, false, "list_all_apps")
}

func (c *clacePlugin) ListApps(thread *starlark.Thread, builtin *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
return c.listAppsImpl(thread, builtin, args, kwargs, true, "list_apps")
}

func (c *clacePlugin) listAppsImpl(thread *starlark.Thread, _ *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple, permCheck bool, apiName string) (starlark.Value, error) {
var query starlark.String
var include_internal starlark.Bool
if err := starlark.UnpackArgs("list_apps", args, kwargs, "query?", &query, "include_internal?", &include_internal); err != nil {
if err := starlark.UnpackArgs(apiName, args, kwargs, "query?", &query, "include_internal?", &include_internal); err != nil {
return nil, err
}

Expand All @@ -84,7 +93,7 @@ func (c *clacePlugin) ListApps(thread *starlark.Thread, builtin *starlark.Builti
userId := system.GetRequestUserId(thread)
ret := starlark.List{}
for _, app := range apps {
if !c.verifyHasAccess(userId, app.Auth) {
if permCheck && !c.verifyHasAccess(userId, app.Auth) {
continue
}

Expand Down Expand Up @@ -131,12 +140,11 @@ func (c *clacePlugin) ListApps(thread *starlark.Thread, builtin *starlark.Builti

func (c *clacePlugin) ListAuditEvents(thread *starlark.Thread, builtin *starlark.Builtin, args starlark.Tuple, kwargs []starlark.Tuple) (starlark.Value, error) {
var appGlob, userId, eventType, operation, target, status, rid, detail starlark.String
var startDate, endDate starlark.String
beforeTimestamp := starlark.MakeInt64(0)
limit := starlark.MakeInt(100)
var startDate, endDate, beforeTimestamp starlark.String
limit := starlark.MakeInt(20)
if err := starlark.UnpackArgs("list_audit_events", args, kwargs, "app_glob?", &appGlob, "user_id?", &userId, "event_type?",
&eventType, "operation?", &operation, "target?", &target, "status?", &status, "startDate", &startDate, "endDate?", &endDate,
"rid?", &rid, "detail?", &detail, "offset?", &limit, "before_timestamp?", &beforeTimestamp); err != nil {
&eventType, "operation?", &operation, "target?", &target, "status?", &status, "start_date", &startDate, "end_date?", &endDate,
"rid?", &rid, "detail?", &detail, "limit?", &limit, "before_timestamp?", &beforeTimestamp); err != nil {
return nil, err
}

Expand All @@ -150,14 +158,12 @@ func (c *clacePlugin) ListAuditEvents(thread *starlark.Thread, builtin *starlark
if err != nil {
return nil, err
}
if len(appInfo) > 0 {
appIds := []string{}
for _, app := range appInfo {
appIds = append(appIds, "\""+string(app.Id)+"\"")
}

filterConditions = append(filterConditions, fmt.Sprintf("app_id in (%s)", strings.Join(appIds, ",")))
appIds := []string{}
for _, app := range appInfo {
appIds = append(appIds, "\""+string(app.Id)+"\"")
}

filterConditions = append(filterConditions, fmt.Sprintf("app_id in (%s)", strings.Join(appIds, ",")))
}

queryParams := []any{}
Expand Down Expand Up @@ -193,13 +199,13 @@ func (c *clacePlugin) ListAuditEvents(thread *starlark.Thread, builtin *starlark

startDateStr := strings.TrimSpace(startDate.GoString())
if startDateStr != "" {
filterConditions = append(filterConditions, "date(create_time) >= date(?)")
filterConditions = append(filterConditions, `create_time >= strftime('%s', ?) * 1000000000`)
queryParams = append(queryParams, startDateStr)
}

endDateStr := strings.TrimSpace(endDate.GoString())
if endDateStr != "" {
filterConditions = append(filterConditions, "date(create_time) <= date(?)")
filterConditions = append(filterConditions, `create_time <= (strftime('%s', ?) + 86400) * 1000000000`)
queryParams = append(queryParams, endDateStr)
}

Expand All @@ -215,10 +221,14 @@ func (c *clacePlugin) ListAuditEvents(thread *starlark.Thread, builtin *starlark
queryParams = append(queryParams, detailStr)
}

beforeTimestampVal, _ := beforeTimestamp.Int64()
if beforeTimestampVal > 0 {
query.WriteString(" datetime(create_time) < datetime(?)")
queryParams = append(queryParams, beforeTimestampVal)
beforeTimestampStr := strings.TrimSpace(beforeTimestamp.GoString())
if beforeTimestampStr != "" {
filterConditions = append(filterConditions, " create_time < ?")
bt, err := strconv.ParseInt(beforeTimestampStr, 10, 64)
if err != nil {
return nil, fmt.Errorf("before_timestamp has to be a valid in value in milliseconds")
}
queryParams = append(queryParams, bt)
}

if len(filterConditions) > 0 {
Expand All @@ -240,19 +250,38 @@ func (c *clacePlugin) ListAuditEvents(thread *starlark.Thread, builtin *starlark
return nil, err
}

apps, err := c.server.apps.GetAllApps()
if err != nil {
return nil, err
}
appIdMap := map[types.AppId]types.AppInfo{}
for _, app := range apps {
appIdMap[app.Id] = app
}

ret := starlark.List{}
for rows.Next() {
var rid, appId, userId, eventType, operation, target, status, detail string
var createTime time.Time
var createTime int64
err := rows.Scan(&rid, &appId, &createTime, &userId, &eventType, &operation, &target, &status, &detail)
if err != nil {
return nil, err
}

utcTime := time.Unix(0, createTime).UTC()

v := starlark.Dict{}
v.SetKey(starlark.String("rid"), starlark.String(rid))
v.SetKey(starlark.String("app_id"), starlark.String(appId))
v.SetKey(starlark.String("create_time"), starlark.String(createTime.Format("2006-01-02T15:04:05.999Z")))
if appInfo, ok := appIdMap[types.AppId(appId)]; ok {
v.SetKey(starlark.String("app_name"), starlark.String(appInfo.Name))
v.SetKey(starlark.String("app_path"), starlark.String(appInfo.AppPathDomain.String()))
} else {
v.SetKey(starlark.String("app_name"), starlark.String(""))
v.SetKey(starlark.String("app_path"), starlark.String(""))
}
v.SetKey(starlark.String("create_time_epoch"), starlark.String(strconv.FormatInt(createTime, 10)))
v.SetKey(starlark.String("create_time"), starlark.String(utcTime.Format("2006-01-02T15:04:05.999Z")))
v.SetKey(starlark.String("user_id"), starlark.String(userId))
v.SetKey(starlark.String("event_type"), starlark.String(eventType))
v.SetKey(starlark.String("operation"), starlark.String(operation))
Expand Down
14 changes: 7 additions & 7 deletions internal/server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ func (h *Handler) apiHandler(w http.ResponseWriter, r *http.Request, enableBasic
}

defer func() {
if err := h.server.insertAuditEvent(&event); err != nil {
if err := h.server.InsertAuditEvent(&event); err != nil {
h.Error().Err(err).Msg("error inserting audit event")
}
}()
Expand Down Expand Up @@ -415,7 +415,7 @@ func (h *Handler) webhookHandler(w http.ResponseWriter, r *http.Request, webhook
}

defer func() {
if err := h.server.insertAuditEvent(&event); err != nil {
if err := h.server.InsertAuditEvent(&event); err != nil {
h.Error().Err(err).Msg("error inserting audit event")
}
}()
Expand Down Expand Up @@ -903,7 +903,7 @@ func (h *Handler) serveInternal(enableBasicAuth bool) http.Handler {

// Get apps
r.Get("/apps", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
h.apiHandler(w, r, enableBasicAuth, "list_app", h.getApps)
h.apiHandler(w, r, enableBasicAuth, "list_apps", h.getApps)
}))

// Get app
Expand All @@ -918,22 +918,22 @@ func (h *Handler) serveInternal(enableBasicAuth bool) http.Handler {

// Delete app
r.Delete("/app", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
h.apiHandler(w, r, enableBasicAuth, "delete_app", h.deleteApps)
h.apiHandler(w, r, enableBasicAuth, "delete_apps", h.deleteApps)
}))

// API to approve the plugin usage and permissions for the app
r.Post("/approve", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
h.apiHandler(w, r, enableBasicAuth, "approve_app", h.approveApps)
h.apiHandler(w, r, enableBasicAuth, "approve_apps", h.approveApps)
}))

// API to reload apps
r.Post("/reload", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
h.apiHandler(w, r, enableBasicAuth, "reload_app", h.reloadApps)
h.apiHandler(w, r, enableBasicAuth, "reload_apps", h.reloadApps)
}))

// API to promote apps
r.Post("/promote", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
h.apiHandler(w, r, enableBasicAuth, "promote_app", h.promoteApps)
h.apiHandler(w, r, enableBasicAuth, "promote_apps", h.promoteApps)
}))

// API to create a preview version of an app
Expand Down
2 changes: 1 addition & 1 deletion internal/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ func (s *Server) GetListAppsApp() (*app.App, error) {
subLogger := s.Logger.With().Str("id", string(appEntry.Id)).Logger()
appLogger := types.Logger{Logger: &subLogger}
s.listAppsApp, err = app.NewApp(sourceFS, nil, &appLogger, &appEntry, &s.config.System,
s.config.Plugins, s.config.AppConfig, s.notifyClose, s.secretsManager.EvalTemplate, s.insertAuditEvent)
s.config.Plugins, s.config.AppConfig, s.notifyClose, s.secretsManager.EvalTemplate, s.InsertAuditEvent)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions tests/audit_app/app.star
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ def handler(req):
if len(events) != 0:
return "Error: expected no audit events, got %d %s" % (len(events), events)

ret = clace.list_audit_events(operation="reload_app")
ret = clace.list_audit_events(operation="reload_apps")
events = ret.value
if len(events) == 0:
return "Error: expected some audit events, got %d %s" % (len(events), events)
if events[0]["operation"] != "reload_app":
if events[0]["operation"] != "reload_apps":
return "Invalid event2 %s" % events[0]

return "OK"
Expand Down

0 comments on commit 7e674ab

Please sign in to comment.