Skip to content

Commit 088323d

Browse files
authored
fix: store expires_at in UTC format compatible with SQLite datetime() (#4)
expires_at was stored using Go's sql.NullTime which serializes time.Time in Go's default format (local timezone + monotonic clock suffix). This made all datetime comparisons with SQLite's datetime('now') fail in non-UTC timezones, causing temporary rules to appear expired immediately. This broke "Allow this time", "Allow for 1h", etc: the rule was created but FindMatchingRule and GetRules both filtered it out, so waiting connections were never released. Also hides the "Allow this time" UI option when no connections are actively waiting, since the 30s rule is only useful during the grace period.
1 parent 3713317 commit 088323d

File tree

3 files changed

+41
-2
lines changed

3 files changed

+41
-2
lines changed

internal/greyproxy/crud.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,10 @@ func CreateRule(db *DB, input RuleCreateInput) (*Rule, error) {
4747
input.CreatedBy = "admin"
4848
}
4949

50-
var expiresAt sql.NullTime
50+
var expiresAt sql.NullString
5151
if input.ExpiresInSeconds != nil && *input.ExpiresInSeconds > 0 {
52-
expiresAt = sql.NullTime{Time: time.Now().Add(time.Duration(*input.ExpiresInSeconds) * time.Second), Valid: true}
52+
t := time.Now().UTC().Add(time.Duration(*input.ExpiresInSeconds) * time.Second)
53+
expiresAt = sql.NullString{String: t.Format("2006-01-02 15:04:05"), Valid: true}
5354
}
5455

5556
var notes sql.NullString

internal/greyproxy/crud_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,42 @@ func TestCreateRuleWithExpiration(t *testing.T) {
112112
}
113113
}
114114

115+
func TestTemporaryRuleVisibleInGetRules(t *testing.T) {
116+
db := setupTestDB(t)
117+
118+
// Create a temporary rule with 1h expiry
119+
expires := int64(3600)
120+
_, err := CreateRule(db, RuleCreateInput{
121+
ContainerPattern: "myapp",
122+
DestinationPattern: "example.com",
123+
ExpiresInSeconds: &expires,
124+
Action: "allow",
125+
})
126+
if err != nil {
127+
t.Fatal(err)
128+
}
129+
130+
// The rule should be visible in GetRules (not filtered as expired)
131+
rules, total, err := GetRules(db, RuleFilter{Limit: 10})
132+
if err != nil {
133+
t.Fatal(err)
134+
}
135+
if total != 1 {
136+
t.Errorf("expected 1 rule, got %d (temporary rule incorrectly filtered as expired)", total)
137+
}
138+
if len(rules) != 1 {
139+
t.Errorf("expected 1 rule in list, got %d", len(rules))
140+
}
141+
142+
// The rule should also be found by FindMatchingRule
143+
found := FindMatchingRule(db, "myapp", "example.com", 443, "")
144+
if found == nil {
145+
t.Error("expected FindMatchingRule to find the temporary rule")
146+
} else if found.Action != "allow" {
147+
t.Errorf("expected allow action, got %s", found.Action)
148+
}
149+
}
150+
115151
func TestGetRules(t *testing.T) {
116152
db := setupTestDB(t)
117153

internal/greyproxy/ui/templates/partials/pending_list.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,13 @@ <h4 class="text-sm font-medium text-destructive mb-3">Deny — block this destin
106106
<!-- Dropdown menu -->
107107
<div id="allow-menu-{{.ID}}" class="hidden absolute right-0 top-full mt-1 w-40 bg-card rounded-md shadow-lg border border-border z-50">
108108
<div class="py-1">
109+
{{if gt .WaitingCount 0}}
109110
<button hx-post="{{$.Prefix}}/htmx/pending/{{.ID}}/allow" hx-vals='{"scope": "exact", "duration": "once"}'
110111
hx-target="#pending-list" hx-swap="innerHTML"
111112
class="btn-menu-item w-full text-left px-3 py-1.5 text-xs text-foreground hover:bg-muted transition-colors">
112113
Allow this time
113114
</button>
115+
{{end}}
114116
<button hx-post="{{$.Prefix}}/htmx/pending/{{.ID}}/allow" hx-vals='{"scope": "exact", "duration": "1h"}'
115117
hx-target="#pending-list" hx-swap="innerHTML"
116118
class="btn-menu-item w-full text-left px-3 py-1.5 text-xs text-foreground hover:bg-muted transition-colors">

0 commit comments

Comments
 (0)