Files
LinkPort/internal/protocol/mysqlproxy/policy_monitoring_test.go
T

73 lines
3.1 KiB
Go

package mysqlproxy
import "testing"
func TestReadOnlyMonitoringQueries(t *testing.T) {
wave := `SELECT id, code, startPickUploadSts, startPickUploadRetryCount,
pickingGuideUploadSts, pickingGuideUploadRetryCount, completeTaskUploadSts, completeTaskUploadRetryCount
FROM shopee_wave WHERE created >= FROM_UNIXTIME(?) AND created < FROM_UNIXTIME(?)
AND (startPickUploadSts = 950 OR pickingGuideUploadSts = 950 OR completeTaskUploadSts = 950)
ORDER BY created DESC,id DESC LIMIT 200`
allowed := []string{
"SELECT UNIX_TIMESTAMP('2026-10-12 00:00:00'), TIME_TO_SEC('00:00:05'), SEC_TO_TIME(5), LEFT('abc', 2)",
`EXPLAIN FORMAT=TRADITIONAL SELECT thread_id,UNIX_TIMESTAMP(start_time),CAST(TIME_TO_SEC(query_time) AS CHAR),
db,LEFT(CONVERT(sql_text USING utf8mb4),2000),rows_examined,rows_sent
FROM mysql.slow_log WHERE start_time>=FROM_UNIXTIME(?) AND start_time<FROM_UNIXTIME(?) AND db=DATABASE() AND query_time>=SEC_TO_TIME(?)
ORDER BY start_time DESC LIMIT 200`,
"SELECT FROM_UNIXTIME(0)",
"SELECT FROM_UNIXTIME(0, '%Y-%m-%d')",
"SELECT CHAR(39)",
"SELECT CHAR(65, 66 USING utf8mb4)",
"SELECT SUBSTRING_INDEX('a@b', '@', 1)",
wave,
"EXPLAIN " + wave,
"EXPLAIN FORMAT=TRADITIONAL " + wave,
`SELECT COUNT(*) FROM information_schema.USER_PRIVILEGES
WHERE PRIVILEGE_TYPE IN ('INSERT','UPDATE','DELETE','CREATE','DROP','ALTER','SUPER','GRANT OPTION')
AND GRANTEE=CONCAT(CHAR(39),SUBSTRING_INDEX(CURRENT_USER(),'@',1),CHAR(39),'@',CHAR(39),SUBSTRING_INDEX(CURRENT_USER(),'@',-1),CHAR(39))`,
"SELECT @@version,@@slow_query_log,@@log_output,CAST(@@long_query_time AS CHAR)",
`SELECT TABLE_NAME,COUNT(*) FROM information_schema.STATISTICS
WHERE TABLE_SCHEMA=DATABASE() AND SEQ_IN_INDEX=1 AND
((TABLE_NAME='shopee_wave' AND COLUMN_NAME='created') OR (TABLE_NAME='location_inventory' AND COLUMN_NAME='lastUpdated')) GROUP BY TABLE_NAME`,
}
for _, query := range allowed {
t.Run(query, func(t *testing.T) {
if err := CheckReadOnly(query); err != nil {
t.Fatalf("read-only monitoring query rejected: %v", err)
}
})
}
}
func TestReadOnlyMonitoringFunctionsStillCheckArguments(t *testing.T) {
denied := []string{
"SELECT UNIX_TIMESTAMP(SLEEP(1))",
"SELECT TIME_TO_SEC(LOAD_FILE('/tmp/time'))",
"SELECT SEC_TO_TIME(GET_LOCK('x', 1))",
"SELECT LEFT('abc', (SELECT SLEEP(1)))",
"SELECT app.unix_timestamp()",
"SELECT app.time_to_sec('00:00:05')",
"SELECT app.sec_to_time(5)",
"SELECT app.left('abc', 2)",
"SELECT FROM_UNIXTIME(SLEEP(1))",
"SELECT FROM_UNIXTIME(0, LOAD_FILE('/tmp/format'))",
"SELECT CHAR(SLEEP(1))",
"SELECT CHAR(65, (SELECT SLEEP(1)) USING utf8mb4)",
"SELECT CHAR(@x := 65)",
"SELECT SUBSTRING_INDEX(LOAD_FILE('/tmp/file'), '@', 1)",
"SELECT SUBSTRING_INDEX('a@b', '@', GET_LOCK('x', 1))",
"SELECT app.from_unixtime(0)",
"SELECT app.substring_index('a@b', '@', 1)",
"EXPLAIN ANALYZE SELECT FROM_UNIXTIME(0)",
"EXPLAIN FORMAT=TRADITIONAL SELECT CHAR(SLEEP(1))",
"SELECT CHAR(65); DELETE FROM t",
}
for _, query := range denied {
t.Run(query, func(t *testing.T) {
if err := CheckReadOnly(query); err == nil {
t.Fatal("unsafe query accepted")
}
})
}
}