-
Notifications
You must be signed in to change notification settings - Fork 1
181 lines (151 loc) · 7.08 KB
/
submit.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
name: Problem Submission
on:
issues:
types: [opened]
jobs:
process-submission:
runs-on: ubuntu-latest
if: contains(github.event.issue.title, '题目提交')
steps:
- uses: actions/checkout@v2
- name: Setup Python
uses: actions/setup-python@v2
with:
python-version: '3.9'
- name: Install dependencies
run: |
pip install cryptography
- name: Process submission
env:
PRIVATE_KEY: ${{ secrets.RSA_PRIVATE_KEY }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BODY: ${{ github.event.issue.body }}
TITLE: ${{ github.event.issue.title }}
run: |
# 保存私钥
echo "$PRIVATE_KEY" > private.pem
FILE_URL=$(echo "$BODY" | grep -oP 'https?://\S+')
curl -L $FILE_URL -o b64
base64 -d b64 > encrypted_content
# 解密issue内容
# echo "$BODY" | base64 -d > encrypted_content
python3 - <<'EOF'
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
import json
import os
import subprocess
import tempfile
# 读取私钥
with open('private.pem', 'rb') as f:
private_key = serialization.load_pem_private_key(f.read(), password=None)
# 读取加密数据
with open('encrypted_content', 'rb') as f:
encrypted_data = f.read()
# 解密过程
encrypted_key = encrypted_data[:256]
iv = encrypted_data[256:272]
encrypted_content = encrypted_data[272:]
aes_key = private_key.decrypt(
encrypted_key,
padding.OAEP(
mgf=padding.MGF1(algorithm=hashes.SHA256()),
algorithm=hashes.SHA256(),
label=None
)
)
if os.path.exists('private.pem'):
os.remove('private.pem')
if os.path.exists('encrypted_content'):
os.remove('encrypted_content')
cipher = Cipher(algorithms.AES(aes_key), modes.CBC(iv), backend=default_backend())
decryptor = cipher.decryptor()
decrypted_padded = decryptor.update(encrypted_content) + decryptor.finalize()
pad_length = decrypted_padded[-1]
decrypted = decrypted_padded[:-pad_length].decode('utf-8')
# 解析解密后的内容
content_parts = decrypted.split('---SEPARATOR---')
problem_json = json.loads(content_parts[0])
readme_content = content_parts[1]
test_data = content_parts[2]
spj_source = content_parts[3]
# 获取题目名称
problem_name = problem_json['title']
problem_id = problem_json['id']
problem_dir = f'problems/{problem_id}'
# 创建题目目录
os.makedirs(problem_dir, exist_ok=True)
# 保存problem.json
with open(f'{problem_dir}/problem.json', 'w', encoding='utf-8') as f:
json.dump(problem_json, f, ensure_ascii=False, indent=2)
# 保存README.md
with open(f'{problem_dir}/README.md', 'w', encoding='utf-8') as f:
f.write(readme_content)
# 保存spj.cpp
with open(f'{problem_dir}/spj.cpp', 'w', encoding='utf-8') as f:
f.write(spj_source)
# 创建临时目录处理测试数据
with tempfile.TemporaryDirectory() as temp_dir:
# 判断测试数据类型并处理
if '---SOURCE---' in test_data:
# 第一种情况:源代码和输入
source_code, inputs = test_data.split('---SOURCE---')[1].split('---INPUTS---')
# 保存源代码
with open(f'{temp_dir}/solution.cpp', 'w') as f:
f.write(source_code)
# 编译源代码
subprocess.run(['g++', f'{temp_dir}/solution.cpp', '-o', f'{temp_dir}/solution', '-O2'])
# 处理每组输入
for idx, input_data in enumerate(inputs.strip().split('---CASE---'), 1):
if not input_data.strip():
continue
# 保存输入
with open(f'{temp_dir}/{idx}.in', 'w') as f:
f.write(input_data.strip())
# 运行程序获取输出
with open(f'{temp_dir}/{idx}.in', 'r') as fin, \
open(f'{temp_dir}/{idx}.out', 'w') as fout:
subprocess.run([f'{temp_dir}/solution'],
stdin=fin,
stdout=fout)
else:
# 第二种情况:直接提供输入输出
cases = test_data.split('---CASE---')
for idx, case in enumerate(cases, 1):
if not case.strip():
continue
input_data, output_data = case.split('---OUTPUT---')
with open(f'{temp_dir}/{idx}.in', 'w') as f:
f.write(input_data.strip())
with open(f'{temp_dir}/{idx}.out', 'w') as f:
f.write(output_data.strip())
# 加密测试数据
subprocess.run(['python', 'encrypt.py', temp_dir])
# 移动加密后的文件到题目目录
for f in os.listdir(temp_dir):
if f.endswith('.enc'):
os.rename(f'{temp_dir}/{f}', f'{problem_dir}/{f}')
# 创建分支名
branch_name = f'problem-submission-{problem_name}'
# 设置git配置
os.system('git config user.name "GitHub Action"')
os.system('git config user.email "action@github.com"')
# 创建新分支
os.system(f'git checkout -b {branch_name}')
# 只添加problems目录
os.system(f'git add problems/{problem_id}')
os.system('git commit -m "Add new problem: ' + problem_name + '"')
os.system(f'git push origin {branch_name}')
# 创建PR
os.system(f'gh pr create --title "Add new problem: {problem_name}" '
f'--body "Automatically created PR for new problem submission." '
f'--base main --head {branch_name}')
EOF
- name: Close issue
env:
GH_TOKEN: ${{ github.token }}
run: |
gh issue close ${{ github.event.issue.number }} --comment "题目提交已处理,PR已创建。"