Skip to content
This repository was archived by the owner on Apr 16, 2026. It is now read-only.

Commit 17734b4

Browse files
authored
Add cleanup indexes for ASB retention paths (#66)
1 parent d06830b commit 17734b4

3 files changed

Lines changed: 60 additions & 1 deletion

File tree

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
CREATE INDEX IF NOT EXISTS idx_sessions_state_expires
2+
ON sessions (state, expires_at);
3+
4+
CREATE INDEX IF NOT EXISTS idx_grants_session_id
5+
ON grants (session_id);
6+
7+
CREATE INDEX IF NOT EXISTS idx_grants_state_expires
8+
ON grants (state, expires_at);
9+
10+
CREATE INDEX IF NOT EXISTS idx_approvals_state_expires
11+
ON approvals (state, expires_at);
12+
13+
CREATE INDEX IF NOT EXISTS idx_artifacts_state_expires
14+
ON artifacts (state, expires_at);
15+
16+
CREATE INDEX IF NOT EXISTS idx_audit_events_created_at
17+
ON audit_events (created_at);

internal/store/postgres/repository.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,12 +137,16 @@ func (r *Repository) GetSession(ctx context.Context, sessionID string) (*core.Se
137137
return &session, nil
138138
}
139139

140+
const maxGrantsBySessionLookup = 10000
141+
140142
func (r *Repository) ListGrantsBySession(ctx context.Context, sessionID string) ([]*core.Grant, error) {
141143
rows, err := r.db.Query(ctx, `
142144
SELECT id, tenant_id, session_id, tool, capability, resource_ref, delivery_mode, connector_kind, approval_id, artifact_ref, state, requested_ttl_seconds, effective_ttl_seconds, expires_at, created_at, reason
143145
FROM grants
144146
WHERE session_id = $1
145-
`, sessionID)
147+
ORDER BY created_at ASC, id ASC
148+
LIMIT $2
149+
`, sessionID, maxGrantsBySessionLookup)
146150
if err != nil {
147151
return nil, err
148152
}

internal/store/postgres/repository_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,41 @@ func TestRepository_UseArtifactMarksSingleUse(t *testing.T) {
110110
t.Fatalf("artifact state = %q, want %q", artifact.State, core.ArtifactStateUsed)
111111
}
112112
}
113+
114+
func TestRepository_ListGrantsBySessionIsBounded(t *testing.T) {
115+
t.Parallel()
116+
117+
mock, err := pgxmock.NewPool()
118+
if err != nil {
119+
t.Fatalf("pgxmock.NewPool() error = %v", err)
120+
}
121+
defer mock.Close()
122+
123+
repo := postgres.NewRepository(mock)
124+
createdAt := time.Date(2026, 4, 15, 18, 0, 0, 0, time.UTC)
125+
expiresAt := createdAt.Add(30 * time.Minute)
126+
127+
mock.ExpectQuery("SELECT id, tenant_id, session_id, tool, capability, resource_ref, delivery_mode, connector_kind, approval_id, artifact_ref, state, requested_ttl_seconds, effective_ttl_seconds, expires_at, created_at, reason\\s+FROM grants\\s+WHERE session_id = \\$1\\s+ORDER BY created_at ASC, id ASC\\s+LIMIT \\$2").
128+
WithArgs("sess_abc", pgxmock.AnyArg()).
129+
WillReturnRows(pgxmock.NewRows([]string{
130+
"id", "tenant_id", "session_id", "tool", "capability", "resource_ref", "delivery_mode", "connector_kind", "approval_id", "artifact_ref", "state", "requested_ttl_seconds", "effective_ttl_seconds", "expires_at", "created_at", "reason",
131+
}).AddRow(
132+
"gr_123", "t_acme", "sess_abc", "github", "repo.read", "repo:evalops/asb", "direct", "github", nil, nil,
133+
string(core.GrantStateIssued), int32(300), int32(300), expiresAt, createdAt, "cleanup",
134+
))
135+
136+
grants, err := repo.ListGrantsBySession(context.Background(), "sess_abc")
137+
if err != nil {
138+
t.Fatalf("ListGrantsBySession() error = %v", err)
139+
}
140+
if len(grants) != 1 {
141+
t.Fatalf("len(grants) = %d, want 1", len(grants))
142+
}
143+
if grants[0].ID != "gr_123" {
144+
t.Fatalf("grant id = %q, want %q", grants[0].ID, "gr_123")
145+
}
146+
147+
if err := mock.ExpectationsWereMet(); err != nil {
148+
t.Fatalf("ExpectationsWereMet() error = %v", err)
149+
}
150+
}

0 commit comments

Comments
 (0)