Skip to content

Commit 55bb77d

Browse files
committed
feat: Add support for sensitive query
1 parent 9c4b24d commit 55bb77d

File tree

4 files changed

+81
-0
lines changed

4 files changed

+81
-0
lines changed

cli/query.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ func NewQueryCmd() *cobra.Command {
2929
limit int
3030
offset int
3131
count bool
32+
sensitive bool
3233
)
3334

3435
cmd := &cobra.Command{
@@ -136,6 +137,10 @@ through the audit history.`,
136137
filter = filter.WithCommandPattern(cmdPattern)
137138
}
138139

140+
if sensitive {
141+
filter = filter.WithSensitive(true)
142+
}
143+
139144
// Handle count-only mode
140145
if count {
141146
n, err := app.Store.CountEvents(ctx, filter)
@@ -181,6 +186,7 @@ through the audit history.`,
181186
cmd.Flags().IntVar(&limit, "limit", 100, "maximum results")
182187
cmd.Flags().IntVar(&offset, "offset", 0, "skip first n results")
183188
cmd.Flags().BoolVar(&count, "count", false, "show count only")
189+
cmd.Flags().BoolVar(&sensitive, "sensitive", false, "filter to events involving sensitive file access")
184190

185191
return cmd
186192
}

core/events/filter.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ type EventFilter struct {
2424
FilePattern string
2525
// CommandPattern is a glob pattern to filter by command.
2626
CommandPattern string
27+
// Sensitive filters to events involving sensitive file access when non-nil.
28+
Sensitive *bool
2729
// Limit is the maximum number of results.
2830
Limit int
2931
// Offset is the number of results to skip.
@@ -85,6 +87,12 @@ func (f *EventFilter) WithCommandPattern(pattern string) *EventFilter {
8587
return f
8688
}
8789

90+
// WithSensitive sets the Sensitive filter.
91+
func (f *EventFilter) WithSensitive(sensitive bool) *EventFilter {
92+
f.Sensitive = &sensitive
93+
return f
94+
}
95+
8896
// WithLimit sets the Limit.
8997
func (f *EventFilter) WithLimit(limit int) *EventFilter {
9098
f.Limit = limit

storage/sqlite.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -854,6 +854,9 @@ func buildEventPredicates(filter *events.EventFilter) []predicate.AuditEvent {
854854
}))
855855
}))
856856
}
857+
if filter.Sensitive != nil {
858+
predicates = append(predicates, auditevent.IsSensitiveEQ(*filter.Sensitive))
859+
}
857860
if filter.CommandPattern != "" {
858861
pattern := filter.CommandPattern
859862
predicates = append(predicates, predicate.AuditEvent(func(s *entsql.Selector) {

storage/sqlite_test.go

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,70 @@ func TestSQLiteStore_QueryEventsWithStatusFilter(t *testing.T) {
948948
}
949949
}
950950

951+
func TestSQLiteStore_QueryEventsWithSensitiveFilter(t *testing.T) {
952+
store, cleanup := setupTestStore(t)
953+
defer cleanup()
954+
955+
ctx := context.Background()
956+
sessionID := uuid.New()
957+
now := time.Now().UTC()
958+
959+
createTestSession(t, store, sessionID, "claude-code")
960+
961+
for i, sensitive := range []bool{false, true, false, true, true} {
962+
payload, _ := json.Marshal(events.FileReadPayload{Path: "/some/file"})
963+
event := &events.Event{
964+
ID: uuid.New(),
965+
SessionID: sessionID,
966+
Sequence: i + 1,
967+
Timestamp: now.Add(time.Duration(i) * time.Minute),
968+
AgentName: "claude-code",
969+
ActionType: events.ActionFileRead,
970+
ResultStatus: events.ResultSuccess,
971+
Payload: payload,
972+
IsSensitive: sensitive,
973+
}
974+
err := store.SaveEvent(ctx, event)
975+
require.NoError(t, err)
976+
}
977+
978+
boolPtr := func(b bool) *bool { return &b }
979+
980+
tests := []struct {
981+
name string
982+
sensitive *bool
983+
want int
984+
}{
985+
{
986+
name: "no filter returns all",
987+
sensitive: nil,
988+
want: 5,
989+
},
990+
{
991+
name: "filter sensitive only",
992+
sensitive: boolPtr(true),
993+
want: 3,
994+
},
995+
{
996+
name: "filter non-sensitive only",
997+
sensitive: boolPtr(false),
998+
want: 2,
999+
},
1000+
}
1001+
1002+
for _, tt := range tests {
1003+
t.Run(tt.name, func(t *testing.T) {
1004+
filter := events.NewEventFilter()
1005+
if tt.sensitive != nil {
1006+
filter = filter.WithSensitive(*tt.sensitive)
1007+
}
1008+
results, err := store.QueryEvents(ctx, filter)
1009+
require.NoError(t, err)
1010+
assert.Len(t, results, tt.want)
1011+
})
1012+
}
1013+
}
1014+
9511015
func TestQueryEventsAfterCompoundCursor(t *testing.T) {
9521016
store, cleanup := setupTestStore(t)
9531017
defer cleanup()

0 commit comments

Comments
 (0)