Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions kernelboard/api/leaderboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,13 @@ def _get_query():
FROM leaderboard.submission s
JOIN leaderboard.runs r ON r.submission_id = s.id
WHERE s.leaderboard_id = %(leaderboard_id)s
AND s.status <> 'hacked'
AND NOT EXISTS (
SELECT 1
FROM leaderboard.submission_job_status sjs
WHERE sjs.submission_id = s.id
AND sjs.status = 'hacked'
)
GROUP BY s.user_id, r.runner
),

Expand All @@ -181,6 +188,13 @@ def _get_query():
AND r.score IS NOT NULL
AND r.passed
AND s.leaderboard_id = %(leaderboard_id)s
AND s.status <> 'hacked'
AND NOT EXISTS (
SELECT 1
FROM leaderboard.submission_job_status sjs
WHERE sjs.submission_id = s.id
AND sjs.status = 'hacked'
)
AND EXISTS (
SELECT 1
FROM leaderboard.runs sr
Expand Down Expand Up @@ -280,6 +294,13 @@ def get_custom_trend(leaderboard_id: int):
AND r.score IS NOT NULL
AND r.passed = true
AND NOT r.secret
AND s.status <> 'hacked'
AND NOT EXISTS (
SELECT 1
FROM leaderboard.submission_job_status sjs
WHERE sjs.submission_id = s.id
AND sjs.status = 'hacked'
)
AND EXISTS (
SELECT 1
FROM leaderboard.runs sr
Expand Down Expand Up @@ -418,6 +439,13 @@ def get_user_trend(leaderboard_id: int):
AND r.score IS NOT NULL
AND r.passed = true
AND NOT r.secret
AND s.status <> 'hacked'
AND NOT EXISTS (
SELECT 1
FROM leaderboard.submission_job_status sjs
WHERE sjs.submission_id = s.id
AND sjs.status = 'hacked'
)
AND EXISTS (
SELECT 1
FROM leaderboard.runs sr
Expand Down Expand Up @@ -521,6 +549,13 @@ def get_fastest_trend(leaderboard_id: int):
AND r.score IS NOT NULL
AND r.passed = true
AND NOT r.secret
AND s.status <> 'hacked'
AND NOT EXISTS (
SELECT 1
FROM leaderboard.submission_job_status sjs
WHERE sjs.submission_id = s.id
AND sjs.status = 'hacked'
)
AND EXISTS (
SELECT 1
FROM leaderboard.runs sr
Expand Down Expand Up @@ -618,6 +653,13 @@ def search_users(leaderboard_id: int):
FROM leaderboard.user_info u
JOIN leaderboard.submission s ON s.user_id = u.id
WHERE s.leaderboard_id = %s
AND s.status <> 'hacked'
AND NOT EXISTS (
SELECT 1
FROM leaderboard.submission_job_status sjs
WHERE sjs.submission_id = s.id
AND sjs.status = 'hacked'
)
AND u.user_name ILIKE %s
ORDER BY u.user_name
LIMIT %s
Expand All @@ -629,6 +671,13 @@ def search_users(leaderboard_id: int):
FROM leaderboard.user_info u
JOIN leaderboard.submission s ON s.user_id = u.id
WHERE s.leaderboard_id = %s
AND s.status <> 'hacked'
AND NOT EXISTS (
SELECT 1
FROM leaderboard.submission_job_status sjs
WHERE sjs.submission_id = s.id
AND sjs.status = 'hacked'
)
ORDER BY u.user_name
LIMIT %s
"""
Expand Down
16 changes: 15 additions & 1 deletion kernelboard/api/leaderboard_summaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
leaderboard_summaries_bp = Blueprint("leaderboard_summaries_bp", __name__, url_prefix="/leaderboard-summaries")

# Redis cache key prefix for ended leaderboard top_users
CACHE_KEY_PREFIX = "lb_top_users:"
CACHE_KEY_PREFIX = "lb_top_users:v2:"


# =============================================================================
Expand Down Expand Up @@ -370,6 +370,13 @@ def _get_query_for_ids():
AND r.score IS NOT NULL
AND r.passed
AND s.leaderboard_id IN %s
AND s.status <> 'hacked'
AND NOT EXISTS (
SELECT 1
FROM leaderboard.submission_job_status sjs
WHERE sjs.submission_id = s.id
AND sjs.status = 'hacked'
)
AND EXISTS (
SELECT 1
FROM leaderboard.runs sr
Expand Down Expand Up @@ -483,6 +490,13 @@ def _get_query():
WHERE NOT r.secret
AND r.score IS NOT NULL
AND r.passed
AND s.status <> 'hacked'
AND NOT EXISTS (
SELECT 1
FROM leaderboard.submission_job_status sjs
WHERE sjs.submission_id = s.id
AND sjs.status = 'hacked'
)
AND EXISTS (
SELECT 1
FROM leaderboard.runs sr
Expand Down
7 changes: 7 additions & 0 deletions kernelboard/index.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,13 @@ def index():
WHERE NOT r.secret
AND r.score IS NOT NULL
AND r.passed
AND s.status <> 'hacked'
AND NOT EXISTS (
SELECT 1
FROM leaderboard.submission_job_status sjs
WHERE sjs.submission_id = s.id
AND sjs.status = 'hacked'
)
AND EXISTS (
SELECT 1
FROM leaderboard.runs sr
Expand Down
7 changes: 7 additions & 0 deletions kernelboard/leaderboard.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,13 @@ def leaderboard(leaderboard_id: int):
AND r.score IS NOT NULL
AND r.passed
AND s.leaderboard_id = %(leaderboard_id)s
AND s.status <> 'hacked'
AND NOT EXISTS (
SELECT 1
FROM leaderboard.submission_job_status sjs
WHERE sjs.submission_id = s.id
AND sjs.status = 'hacked'
)
AND EXISTS (
SELECT 1
FROM leaderboard.runs sr
Expand Down
7 changes: 7 additions & 0 deletions ranking_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,13 @@ def ensure_snapshot_table(conn):
WHERE NOT r.secret
AND r.score IS NOT NULL
AND r.passed
AND s.status <> 'hacked'
AND NOT EXISTS (
SELECT 1
FROM leaderboard.submission_job_status sjs
WHERE sjs.submission_id = s.id
AND sjs.status = 'hacked'
)
AND EXISTS (
SELECT 1
FROM leaderboard.runs sr
Expand Down
117 changes: 117 additions & 0 deletions tests/api/test_leaderboard_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,120 @@ def test_failed_secret_benchmark_hides_public_leaderboard_run(client, app):
assert "hidden_secret_fail.py" not in ranked_files
assert "hidden_missing_secret.py" not in ranked_files
assert "visible_public_pass.py" in ranked_files


def test_hacked_submissions_are_hidden_from_public_leaderboard(client, app):
with app.app_context():
conn = get_db_connection()
with conn.cursor() as cur:
submissions = [
(
900011,
"hidden_submission_status_hacked.py",
"123456789012345",
"hacked",
),
(900012, "hidden_job_status_hacked.py", "234567890123456", "active"),
(900013, "visible_clean_status.py", "345678901234567", "active"),
]
for submission_id, file_name, user_id, status in submissions:
cur.execute(
"""
INSERT INTO leaderboard.submission
(
id,
leaderboard_id,
file_name,
user_id,
code_id,
submission_time,
done,
status
)
VALUES
(%s, 339, %s, %s, 13, NOW(), TRUE, %s)
""",
(submission_id, file_name, user_id, status),
)
cur.execute(
"""
INSERT INTO leaderboard.runs
(
id,
submission_id,
start_time,
end_time,
mode,
secret,
runner,
score,
passed,
compilation,
meta,
result,
system_info
)
VALUES
(
%s,
%s,
NOW(),
NOW(),
'leaderboard',
FALSE,
'H100',
%s,
TRUE,
'{}',
'{}',
'{}',
'{}'
),
(
%s,
%s,
NOW(),
NOW(),
'leaderboard',
TRUE,
'H100',
%s,
TRUE,
'{}',
'{}',
'{}',
'{}'
)
""",
(
submission_id * 10,
submission_id,
-submission_id,
submission_id * 10 + 1,
submission_id,
-submission_id,
),
)

cur.execute(
"""
INSERT INTO leaderboard.submission_job_status
(submission_id, status, created_at, last_heartbeat)
VALUES
(900012, 'hacked', NOW(), NOW())
"""
)
conn.commit()

response = client.get("/api/leaderboard/339")
assert response.status_code == 200

payload = response.get_json()
ranked_files = {
row["file_name"]
for row in payload["data"]["rankings"]["H100"]
}

assert "hidden_submission_status_hacked.py" not in ranked_files
assert "hidden_job_status_hacked.py" not in ranked_files
assert "visible_clean_status.py" in ranked_files
15 changes: 14 additions & 1 deletion tests/data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,18 @@ CREATE SEQUENCE leaderboard.leaderboard_id_seq
ALTER SEQUENCE leaderboard.leaderboard_id_seq OWNED BY leaderboard.leaderboard.id;


--
-- Name: templates; Type: TABLE; Schema: leaderboard; Owner: -
--

CREATE TABLE leaderboard.templates (
id SERIAL PRIMARY KEY,
leaderboard_id integer NOT NULL,
lang text NOT NULL,
code text NOT NULL
);


--
-- Name: runs; Type: TABLE; Schema: leaderboard; Owner: -
--
Expand Down Expand Up @@ -157,7 +169,8 @@ CREATE TABLE leaderboard.submission (
user_id text NOT NULL,
code_id integer NOT NULL,
submission_time timestamp with time zone NOT NULL,
done boolean DEFAULT false
done boolean DEFAULT false,
status text DEFAULT 'active'::text NOT NULL
);


Expand Down
20 changes: 20 additions & 0 deletions tests/test_hacked_submission_filters.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
SUBMISSION_STATUS_FILTER = "s.status <> 'hacked'"
JOB_STATUS_FILTER = "sjs.status = 'hacked'"


def test_leaderboard_queries_filter_hacked_submissions():
expected_counts = {
"kernelboard/api/leaderboard.py": 7,
"kernelboard/api/leaderboard_summaries.py": 2,
"kernelboard/index.py": 1,
"kernelboard/leaderboard.py": 1,
"ranking_worker.py": 1,
}

for relative_path, expected_count in expected_counts.items():
source = (ROOT / relative_path).read_text(encoding="utf-8")
assert source.count(SUBMISSION_STATUS_FILTER) == expected_count
assert source.count(JOB_STATUS_FILTER) == expected_count
Loading