Files
at-container-registry/pkg/appview/db/readonly_test.go
2025-10-28 20:39:57 -05:00

103 lines
3.4 KiB
Go

package db
import (
"database/sql"
"os"
"path/filepath"
"testing"
)
func TestAuthorizerBlocksSensitiveTables(t *testing.T) {
// Create temporary database
tmpDir := t.TempDir()
dbPath := filepath.Join(tmpDir, "test.db")
// Set environment for database path
if err := os.Setenv("ATCR_UI_DATABASE_PATH", dbPath); err != nil {
t.Fatalf("Failed to set environment variable: %v", err)
}
defer os.Unsetenv("ATCR_UI_DATABASE_PATH")
// Initialize database (creates schema)
database, err := InitDB(dbPath, true)
if err != nil {
t.Fatalf("Failed to initialize database: %v", err)
}
defer database.Close()
// Create some test data in sensitive tables
_, err = database.Exec(`
INSERT INTO oauth_sessions (session_key, account_did, session_id, session_data, created_at, updated_at)
VALUES ('test-key', 'did:plc:test', 'test-session', 'secret-token-data', datetime('now'), datetime('now'))
`)
if err != nil {
t.Fatalf("Failed to insert test data: %v", err)
}
_, err = database.Exec(`
INSERT INTO users (did, handle, pds_endpoint, avatar, last_seen)
VALUES ('did:plc:test', 'test.user', 'https://pds.example.com', '', datetime('now'))
`)
if err != nil {
t.Fatalf("Failed to insert test user: %v", err)
}
// Open read-only connection with authorizer (using our custom driver)
readOnlyDB, err := sql.Open(ReadOnlyDriverName, "file:"+dbPath+"?mode=ro")
if err != nil {
t.Fatalf("Failed to open read-only database: %v", err)
}
defer readOnlyDB.Close()
// Test 1: Should be able to read from public tables (users)
t.Run("AllowPublicTableRead", func(t *testing.T) {
var handle string
err := readOnlyDB.QueryRow("SELECT handle FROM users WHERE did = ?", "did:plc:test").Scan(&handle)
if err != nil {
t.Errorf("Should be able to read from public table 'users': %v", err)
}
if handle != "test.user" {
t.Errorf("Expected handle 'test.user', got '%s'", handle)
}
})
// Test 2: Should NOT be able to read from sensitive tables (oauth_sessions)
t.Run("BlockSensitiveTableRead", func(t *testing.T) {
var sessionData string
err := readOnlyDB.QueryRow("SELECT session_data FROM oauth_sessions WHERE session_key = ?", "test-key").Scan(&sessionData)
if err == nil {
t.Errorf("Should NOT be able to read from sensitive table 'oauth_sessions', but got data: %s", sessionData)
}
// SQLite returns "not authorized" error when authorizer denies access
if err != nil && err.Error() != "not authorized" {
t.Logf("Got expected error (but different message): %v", err)
}
})
// Test 3: Should NOT be able to read from ui_sessions
t.Run("BlockUISessionsTableRead", func(t *testing.T) {
rows, err := readOnlyDB.Query("SELECT * FROM ui_sessions LIMIT 1")
if err == nil {
rows.Close()
t.Error("Should NOT be able to read from sensitive table 'ui_sessions'")
}
})
// Test 4: Should NOT be able to read from devices
t.Run("BlockDevicesTableRead", func(t *testing.T) {
rows, err := readOnlyDB.Query("SELECT * FROM devices LIMIT 1")
if err == nil {
rows.Close()
t.Error("Should NOT be able to read from sensitive table 'devices'")
}
})
// Test 5: Should NOT be able to write to any table (read-only mode + authorizer)
t.Run("BlockAllWrites", func(t *testing.T) {
_, err := readOnlyDB.Exec("INSERT INTO users (did, handle, pds_endpoint, avatar, last_seen) VALUES ('did:plc:test2', 'test2', 'https://pds.example.com', '', datetime('now'))")
if err == nil {
t.Error("Should NOT be able to write to any table in read-only mode")
}
})
}