[agent/claude:opus] DX audit and fix. 1) Review CLAUDE.md — update any outdate... #1
5 changed files with 120 additions and 2 deletions
1
html.go
1
html.go
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-Licence-Identifier: EUPL-1.2
|
||||
package session
|
||||
|
||||
import (
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-Licence-Identifier: EUPL-1.2
|
||||
package session
|
||||
|
||||
import (
|
||||
|
|
@ -238,7 +239,7 @@ func (s *Session) IsExpired(maxAge time.Duration) bool {
|
|||
// It ensures the ID does not contain path traversal characters.
|
||||
func FetchSession(projectsDir, id string) (*Session, *ParseStats, error) {
|
||||
if strings.Contains(id, "..") || strings.ContainsAny(id, `/\`) {
|
||||
return nil, nil, coreerr.E("FetchSession", "invalid session id")
|
||||
return nil, nil, coreerr.E("FetchSession", "invalid session id", nil)
|
||||
}
|
||||
|
||||
path := filepath.Join(projectsDir, id+".jsonl")
|
||||
|
|
|
|||
114
parser_test.go
114
parser_test.go
|
|
@ -1330,3 +1330,117 @@ func TestListSessions_TruncatedFile_Good(t *testing.T) {
|
|||
// End time should reflect the last valid timestamp.
|
||||
assert.True(t, sessions[0].EndTime.After(sessions[0].StartTime))
|
||||
}
|
||||
|
||||
// --- PruneSessions tests ---
|
||||
|
||||
func TestPruneSessions_DeletesOld_Good(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
writeJSONL(t, dir, "old-session.jsonl", userTextEntry(ts(0), "old"))
|
||||
writeJSONL(t, dir, "new-session.jsonl", userTextEntry(ts(0), "new"))
|
||||
|
||||
// Touch old-session to make it appear old (1 hour ago).
|
||||
oldPath := filepath.Join(dir, "old-session.jsonl")
|
||||
past := time.Now().Add(-2 * time.Hour)
|
||||
require.NoError(t, os.Chtimes(oldPath, past, past))
|
||||
|
||||
deleted, err := PruneSessions(dir, 1*time.Hour)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 1, deleted)
|
||||
|
||||
// Only new-session should remain.
|
||||
sessions, err := ListSessions(dir)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, sessions, 1)
|
||||
assert.Equal(t, "new-session", sessions[0].ID)
|
||||
}
|
||||
|
||||
func TestPruneSessions_NoneExpired_Good(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
writeJSONL(t, dir, "fresh.jsonl", userTextEntry(ts(0), "fresh"))
|
||||
|
||||
deleted, err := PruneSessions(dir, 24*time.Hour)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, deleted)
|
||||
|
||||
sessions, err := ListSessions(dir)
|
||||
require.NoError(t, err)
|
||||
require.Len(t, sessions, 1)
|
||||
}
|
||||
|
||||
func TestPruneSessions_EmptyDir_Good(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
deleted, err := PruneSessions(dir, 1*time.Hour)
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, deleted)
|
||||
}
|
||||
|
||||
// --- IsExpired tests ---
|
||||
|
||||
func TestIsExpired_Expired_Good(t *testing.T) {
|
||||
s := &Session{
|
||||
EndTime: time.Now().Add(-2 * time.Hour),
|
||||
}
|
||||
assert.True(t, s.IsExpired(1*time.Hour))
|
||||
}
|
||||
|
||||
func TestIsExpired_NotExpired_Good(t *testing.T) {
|
||||
s := &Session{
|
||||
EndTime: time.Now().Add(-30 * time.Minute),
|
||||
}
|
||||
assert.False(t, s.IsExpired(1*time.Hour))
|
||||
}
|
||||
|
||||
func TestIsExpired_ZeroEndTime_Bad(t *testing.T) {
|
||||
s := &Session{}
|
||||
assert.False(t, s.IsExpired(1*time.Hour))
|
||||
}
|
||||
|
||||
// --- FetchSession tests ---
|
||||
|
||||
func TestFetchSession_ValidID_Good(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
writeJSONL(t, dir, "abc123.jsonl",
|
||||
userTextEntry(ts(0), "Hello"),
|
||||
assistantTextEntry(ts(1), "Hi"),
|
||||
)
|
||||
|
||||
sess, stats, err := FetchSession(dir, "abc123")
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, sess)
|
||||
require.NotNil(t, stats)
|
||||
assert.Equal(t, "abc123", sess.ID)
|
||||
assert.Len(t, sess.Events, 2)
|
||||
}
|
||||
|
||||
func TestFetchSession_PathTraversal_Bad(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
_, _, err := FetchSession(dir, "../etc/passwd")
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "invalid session id")
|
||||
}
|
||||
|
||||
func TestFetchSession_BackslashTraversal_Bad(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
_, _, err := FetchSession(dir, `..\\windows\\system32`)
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "invalid session id")
|
||||
}
|
||||
|
||||
func TestFetchSession_SlashInID_Bad(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
_, _, err := FetchSession(dir, "sub/dir")
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "invalid session id")
|
||||
}
|
||||
|
||||
func TestFetchSession_NotFound_Bad(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
|
||||
_, _, err := FetchSession(dir, "nonexistent")
|
||||
require.Error(t, err)
|
||||
assert.Contains(t, err.Error(), "open transcript")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-Licence-Identifier: EUPL-1.2
|
||||
package session
|
||||
|
||||
import (
|
||||
|
|
|
|||
3
video.go
3
video.go
|
|
@ -1,3 +1,4 @@
|
|||
// SPDX-Licence-Identifier: EUPL-1.2
|
||||
package session
|
||||
|
||||
import (
|
||||
|
|
@ -12,7 +13,7 @@ import (
|
|||
// RenderMP4 generates an MP4 video from session events using VHS (charmbracelet).
|
||||
func RenderMP4(sess *Session, outputPath string) error {
|
||||
if _, err := exec.LookPath("vhs"); err != nil {
|
||||
return coreerr.E("RenderMP4", "vhs not installed (go install github.com/charmbracelet/vhs@latest)")
|
||||
return coreerr.E("RenderMP4", "vhs not installed (go install github.com/charmbracelet/vhs@latest)", nil)
|
||||
}
|
||||
|
||||
tape := generateTape(sess, outputPath)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue