security: rustdesk出库+ignore;nginx静态location补齐安全头(修add_header继承丢失);tasks.py原子写;backup.sh可选异地;拍板清单落盘
vscode-planning-ci / planning-smoke (push) Canceled after 0s

This commit is contained in:
2026-09-25 04:27:42 +08:00
parent 54422f44ba
commit 02d27401b0
14 changed files with 73 additions and 749 deletions
+3 -1
View File
@@ -6,6 +6,9 @@
(服务器数据)重要!!!禁止上传git/
*.pem
id_ed25519*
# 远控配置(含中转服务器地址与永久密码哈希,绝不入库)
rustdesk-config-export/
.dsh/
.dsh-runtime-backup/
.pnpm-store/
@@ -14,7 +17,6 @@ node_modules/
android-chunyu/
chunyu_project/
chunyu_project_react/
node_modules/
shots/
docker.env
backups/
+15 -3
View File
@@ -21,8 +21,10 @@ from __future__ import annotations
import argparse
import json
import os
import re
import sys
import tempfile
from datetime import date
from pathlib import Path
@@ -56,9 +58,19 @@ def load_state() -> dict:
def save_state(state: dict) -> None:
STATE.write_text(
json.dumps(state, ensure_ascii=False, indent=2) + "\n", encoding="utf-8"
)
# 原子写:先落同目录临时文件再 os.replace,避免并发写或中断产生半截 state.json
payload = json.dumps(state, ensure_ascii=False, indent=2) + "\n"
fd, tmp = tempfile.mkstemp(dir=str(STATE.parent), prefix=".state-", suffix=".tmp")
try:
with os.fdopen(fd, "w", encoding="utf-8") as f:
f.write(payload)
os.replace(tmp, STATE)
except BaseException:
try:
os.unlink(tmp)
except OSError:
pass
raise
def effective_status(task: dict, state: dict) -> str:
+37
View File
@@ -0,0 +1,37 @@
# 安全遗留拍板清单 / SECURITY_DECISIONS.md
日期: 2026-09-25 · 前置: 全局检测报告(架构/安全/业务/部署四方向)
## 本轮已修(仅本仓库,不触碰线上运行)
1. **rustdesk-config-export 出库 + ignore**:远控中转服务器地址与永久密码哈希不再随 HEAD 分发(历史对象仍在,见 D1)。磁盘文件已保留。
2. **nginx-docker.conf**:4 个自带 `add_header` 的 location(/api-directory/、/assets、静态资源、/index.html)补齐 nosniff / X-Frame-Options / Referrer-Policy,修复 add_header 层级覆盖继承导致的静态响应裸奔。
- 生效条件:服务器上 `docker compose restart frontend`(pull 本仓不会热生效,线上运行不受影响)。
3. **PLANNING/tasks.py**:state.json 改为临时文件 + `os.replace` 原子写(防并发/中断写坏;多进程同时读改写的丢失更新窗口仍在,量级可接受)。
4. **infra/backup.sh**:新增可选 `BACKUP_REMOTE_DIR`(设置后自动 rsync 异地副本,不设则行为不变)。
5. **B6 产物出库复核**:当前跟踪的 png/log/tar.gz 为 0,88 项实际已在 6d22fb1 完成,SECURITY_FIX 文档该条滞后。
## 待拍板(不可逆 / 涉及线上或远程仓库,一句话确认即可执行对应项)
### D1 git 历史清理(docker.env 真实密码 + rustdesk 配置仍可从历史取回)
```bash
pip install git-filter-repo
git filter-repo --invert-paths --path docker.env --path rustdesk-config-export --force
git remote add origin https://gitea.mymoyu.top/root/vscode-workbench.git # filter-repo 会移除 remote
git push origin master --force
```
影响:改写远程历史,所有 clone 需重新拉取;需确认无其他协作者持有旧 clone。
### D2 RustDesk 服务器侧加固(需操作远控,改即生效)
- 被控端更换永久密码(客户端 设置→安全→永久密码),更换后本机 rustdesk-config-export 重新导出才会更新。
- 103.40.14.100 的 hbbs/hbbr(51116-51118)加来源 IP 白名单或防火墙限制。
### D3 线上 B1-B5(沿用 SECURITY_FIX_SPEC.md deferred 清单,均需停机/线上授权)
B1 线上密钥全量轮换(含 DJANGO_SECRET_KEY,会使现有 session 失效) / B2 生产 TLS+HSTS / B3 服务器防火墙收紧 / B5 容器 USER 非 root。
### D4 model-registry.json 分值基准(六维合计 42 vs total_max=36)
修哪边决定 grade 换算基准(dim5<50% veto 的分母含义不同),需评分口径拍板后改,未拍板前不动。
### D5 主工程源码仓库归属
chunyu_project / chunyu_project_react 不在本仓版本控制与备份范围(.gitignore),compose build 与 task-manifest 均指向本地目录。需确认是否已有独立 repo;若无,建仓并纳入备份。
## 注意事项
- 本轮提交推送后,其他机器 `git pull` 会从其工作区移除 rustdesk-config-export 目录(git rm --cached 语义);若服务器上有引用请先拷贝。
- nginx-docker.conf 属已跟踪文件,本仓修改不会自动影响线上;需在服务器手动 restart frontend 才生效。
+5
View File
@@ -12,5 +12,10 @@ sha256sum "$ARCHIVE" > "$ARCHIVE.sha256"
# 保留策略:只留最近 7 个归档
ls -1t "$OUT_DIR"/planning-backup-*.tar.gz 2>/dev/null | tail -n +8 | xargs -r rm -f
ls -1t "$OUT_DIR"/planning-backup-*.tar.gz.sha256 2>/dev/null | tail -n +8 | xargs -r rm -f
# 可选异地副本:设置 BACKUP_REMOTE_DIR(形如 user@host:/backups/planning)即同步,不设则跳过
if [ -n "${BACKUP_REMOTE_DIR:-}" ] && command -v rsync >/dev/null 2>&1; then
rsync -a "$OUT_DIR"/planning-backup-*.tar.gz "$OUT_DIR"/planning-backup-*.tar.gz.sha256 "$BACKUP_REMOTE_DIR/"
echo "offsite: $BACKUP_REMOTE_DIR"
fi
echo "backup: $ARCHIVE"
cat "$ARCHIVE.sha256"
+13
View File
@@ -15,6 +15,10 @@ server {
try_files $uri =404;
expires 1y;
add_header Cache-Control "public, max-age=31536000, immutable" always;
# nginx 的 add_header 按层级整体覆盖继承:自带 add_header 的 location 必须重复安全头
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
types {
image/avif avif;
image/gif gif;
@@ -237,6 +241,9 @@ server {
location ~* ^/assets/.*\.(js|css|png|jpg|jpeg|gif|webp|avif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
access_log off;
}
@@ -244,12 +251,18 @@ server {
location ~* \.(png|jpg|jpeg|gif|webp|ico|svg|woff|woff2|ttf|eot)$ {
expires 7d;
add_header Cache-Control "public";
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
access_log off;
}
# index.html 不缓存,保证发版后立即生效
location = /index.html {
add_header Cache-Control "no-cache, no-store, must-revalidate";
add_header X-Content-Type-Options "nosniff" always;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
}
# SPA 路由回退(放在最后,避免拦截上面的 API 请求)
-112
View File
@@ -1,112 +0,0 @@
# RustDesk 配置导出包
## 导出的文件说明
### 核心配置文件(必须)
1. **RustDesk.toml** - 包含你的设备ID、密码和密钥对
- nc_id = 你的设备ID(编码形式)
- password = 你的连接密码
- salt = 密码盐值
- key_pair = 你的密钥对(公钥+私钥)
2. **RustDesk2.toml** - 包含服务器配置和连接选项
- ␍endezvous_server = 中继服务器地址(103.40.14.100:51116)
- custom-rendezvous-server = 自定义服务器地址
- pi-server = API服务器地址
- ␍elay-server = 中继服务器地址
### 连接配置文件(可选)
3. **RustDesk_local.toml** - 本地界面设置和最近连接记录
4. **peers.toml** - 连接质量默认设置
5. **peers/172260841.toml** - 连接到 debian (172260841) 的配置
6. **peers/510231016.toml** - 连接到 chunyu (510231016) 的配置
## 在另一台电脑上使用
### 方法1:直接替换配置文件(推荐)
1. **安装相同版本的RustDesk**
- 确保新电脑安装的是相同或相近版本的RustDesk
2. **完全退出RustDesk**
- 右键系统托盘中的RustDesk图标 → 退出
3. **备份原有配置**
- 在新电脑上备份原有配置:
`ash
# Windows路径
C:\Users\你的用户名\AppData\Roaming\RustDesk\config\
# 或者直接重命名config文件夹
`
4. **复制配置文件**
- 将本目录下的 config 文件夹内容复制到:
`ash
# Windows
C:\Users\你的用户名\AppData\Roaming\RustDesk\config\
# Linux
~/.config/rustdesk/
# macOS
~/Library/Preferences/com.carriez.RustDesk/
`
- ⚠️ **注意:复制前确保RustDesk已完全退出**
5. **启动RustDesk**
- 重新启动RustDesk
- 你应该会看到相同的设备ID和密码
### 方法2:手动导入关键配置
如果只想迁移设备ID和密码:
1. 启动新电脑上的RustDesk
2. 进入设置 → 网络
3. 修改以下字段:
- **ID/密码**: 使用 RustDesk.toml 中的值
- **中继服务器**: 103.40.14.100:51116
- **API服务器**: http://103.40.14.100:51114
- **中继服务器**: 103.40.14.100:51117
## 重要安全提醒
⚠️ **安全警告**
- 这个配置包包含你的**私钥**和**密码**
- **不要**公开分享这个文件夹
- **不要**上传到公共网站或云存储
- 传输完成后建议**删除**这个导出包
- 如果泄露,立即在RustDesk中生成新的ID/密钥
## 服务器配置信息
你的RustDesk使用自建服务器:
- **中继服务器**: 103.40.14.100:51116
- **API服务器**: http://103.40.14.100:51114
- **中继服务器**: 103.40.14.100:51117
确保新电脑可以访问这些服务器。
## 故障排除
### 问题1:设备ID不同
- 如果新电脑显示不同的ID,说明配置没有正确复制
- 确保复制的是 config 文件夹内的文件,而不是整个RustDesk安装目录
### 问题2:无法连接服务器
- 检查防火墙是否允许RustDesk访问 103.40.14.100
- 确保新电脑的网络可以访问该IP地址
### 问题3:密码错误
- 确保 RustDesk.toml 中的 password 字段完整复制
- 检查是否有额外的空格或换行符
### 问题4:配置文件被锁定
- 确保RustDesk完全退出后再复制
- Windows任务管理器中结束所有RustDesk进程
## 文件创建时间
导出时间:2026-08-24 22:49:06
原电脑:Windows (12914@chunyu)
-112
View File
@@ -1,112 +0,0 @@
enc_id = '00AQz/5CY35TG97g2QnrGBGFsYEPcU0mHWXNqu1mn7FhqFBYrXCDMaPV0wNEo2B2CPTHQ='
password = '01Ab4HU3UU0KEF/+Aq0tvRdzVzyFCXRBF9COn6BhmCSB1xeDu0DExLdhGg4Z/xMRhjTX8kr9Af6P1ysKG3I+p3brcTyWBaG7fcoSKhERsh9BGXilRmkdz7'
salt = 'c74xsa4r45h6eytgnezjbbfp78n4ej67'
key_pair = [
[
51,
67,
177,
97,
114,
230,
142,
216,
112,
30,
104,
178,
162,
136,
90,
176,
13,
7,
6,
132,
20,
78,
149,
84,
232,
117,
40,
16,
194,
90,
156,
7,
126,
106,
99,
23,
248,
115,
242,
178,
35,
108,
236,
135,
165,
174,
113,
178,
145,
87,
24,
12,
65,
135,
47,
136,
84,
84,
144,
222,
60,
237,
157,
100,
],
[
126,
106,
99,
23,
248,
115,
242,
178,
35,
108,
236,
135,
165,
174,
113,
178,
145,
87,
24,
12,
65,
135,
47,
136,
84,
84,
144,
222,
60,
237,
157,
100,
],
]
key_confirmed = true
[keys_confirmed]
rs-ny = true
"192.168.5.7:21116" = true
"103.40.14.100:51116" = true
"103.40.14.100:18782" = true
@@ -1,15 +0,0 @@
rendezvous_server = '103.40.14.100:51116'
nat_type = 2
serial = 0
unlock_pin = ''
trusted_devices = '00AVi/cTFeUBdZy7xkGGuk/nSSPBBH+YRKewuMGnqPwr4VKQvcyL4Eb/U69w=='
[options]
key = 'aZLZystmHh7GFNZJrGZ0gpvp9y3OyQFKdEgtfaZzO8c='
local-ip-addr = '192.168.5.14'
custom-rendezvous-server = '103.40.14.100:51116'
api-server = 'http://103.40.14.100:51114'
av1-test = 'Y'
verification-method = 'use-permanent-password'
disable-udp = 'N'
relay-server = '103.40.14.100:51117'
@@ -1,3 +0,0 @@
[options]
codec-preference = 'h264'
image_quality = 'low'
@@ -1,19 +0,0 @@
remote_id = '172260841'
kb_layout_type = ''
size = [
0,
0,
0,
0,
]
fav = []
[options]
remote-menubar-drag-right = '1.0'
remote-menubar-drag-left = '0.0'
[ui_flutter]
wm_RemoteDesktop = '{"width":1300.0,"height":740.0,"offsetWidth":874.0,"offsetHeight":384.0,"isMaximized":true,"isFullscreen":false}'
peer-tab-index = '0'
wm_Main = '{"width":800.0,"height":600.0,"offsetWidth":951.0,"offsetHeight":284.0,"isMaximized":false,"isFullscreen":false}'
peer-sorting = 'Remote ID'
-61
View File
@@ -1,61 +0,0 @@
password = []
size = [
0,
0,
0,
0,
]
size_ft = [
0,
0,
0,
0,
]
size_pf = [
0,
0,
0,
0,
]
view_style = 'original'
scroll_style = 'scrollauto'
edge_scroll_edge_thickness = 100
image_quality = 'best'
custom_image_quality = [50]
show_remote_cursor = false
lock_after_session_end = false
terminal-persistent = false
privacy_mode = false
allow_swap_key = false
port_forwards = []
direct_failures = 0
disable_audio = false
disable_clipboard = false
enable-file-copy-paste = true
show_quality_monitor = false
follow_remote_cursor = false
follow_remote_window = false
view_only = false
show_my_cursor = false
sync-init-clipboard = false
trackpad-speed = 100
[options]
codec-preference = 'av1'
collapse_toolbar = ''
custom-fps = '30'
zoom-cursor = ''
i444 = 'Y'
swap-left-right-mouse = ''
[ui_flutter]
wm_RemoteDesktop = '{"width":874.0,"height":384.0,"offsetWidth":874.0,"offsetHeight":384.0,"isMaximized":true,"isFullscreen":false}'
[info]
username = ''
hostname = ''
platform = ''
[transfer]
write_jobs = []
read_jobs = []
@@ -1,167 +0,0 @@
password = [
48,
48,
65,
89,
66,
87,
50,
75,
52,
101,
99,
89,
105,
115,
84,
116,
107,
120,
51,
83,
115,
120,
79,
51,
121,
78,
108,
74,
69,
47,
74,
65,
117,
113,
49,
52,
74,
43,
89,
89,
103,
47,
81,
115,
68,
85,
98,
48,
70,
56,
106,
71,
73,
116,
86,
82,
98,
108,
76,
75,
72,
112,
113,
107,
81,
49,
115,
48,
97,
112,
116,
65,
67,
90,
82,
113,
118,
82,
53,
120,
69,
74,
97,
84,
121,
47,
43,
108,
88,
87,
116,
98,
110,
78,
77,
105,
105,
74,
109,
65,
61,
61,
]
size = [
0,
0,
0,
0,
]
size_ft = [
0,
0,
0,
0,
]
size_pf = [
0,
0,
0,
0,
]
view_style = 'original'
scroll_style = 'scrollauto'
edge_scroll_edge_thickness = 100
image_quality = 'balanced'
custom_image_quality = [50]
show_remote_cursor = false
lock_after_session_end = false
terminal-persistent = false
privacy_mode = false
allow_swap_key = false
port_forwards = []
direct_failures = 1
disable_audio = false
disable_clipboard = false
enable-file-copy-paste = true
show_quality_monitor = false
follow_remote_cursor = false
follow_remote_window = false
keyboard_mode = 'map'
view_only = false
show_my_cursor = false
sync-init-clipboard = false
trackpad-speed = 100
[options]
zoom-cursor = ''
collapse_toolbar = ''
codec-preference = 'auto'
i444 = ''
swap-left-right-mouse = ''
custom-fps = '30'
remote-menubar-edge = 'top'
remote-menubar-frac = '0.5'
[ui_flutter]
wm_RemoteDesktop = '{"width":1300.0,"height":740.0,"offsetWidth":874.0,"offsetHeight":384.0,"isMaximized":true,"isFullscreen":false}'
[info]
username = 'chunyu'
hostname = 'debian'
platform = 'Linux'
[transfer]
write_jobs = []
read_jobs = []
@@ -1,167 +0,0 @@
password = [
48,
48,
65,
97,
47,
43,
106,
103,
47,
78,
98,
66,
87,
114,
66,
112,
76,
50,
43,
55,
84,
81,
112,
102,
54,
54,
103,
43,
105,
73,
79,
53,
68,
87,
108,
116,
101,
83,
69,
98,
121,
53,
54,
47,
105,
101,
48,
56,
56,
67,
115,
81,
100,
87,
80,
100,
57,
79,
121,
71,
102,
49,
118,
57,
73,
122,
117,
47,
108,
108,
52,
99,
49,
113,
103,
109,
76,
120,
47,
84,
48,
121,
116,
66,
66,
76,
119,
78,
120,
68,
82,
104,
106,
75,
50,
105,
111,
120,
72,
81,
61,
61,
]
size = [
0,
0,
0,
0,
]
size_ft = [
0,
0,
0,
0,
]
size_pf = [
0,
0,
0,
0,
]
view_style = 'original'
scroll_style = 'scrollauto'
edge_scroll_edge_thickness = 100
image_quality = 'low'
custom_image_quality = [50]
show_remote_cursor = false
lock_after_session_end = false
terminal-persistent = false
privacy_mode = false
allow_swap_key = false
port_forwards = []
direct_failures = 0
disable_audio = false
disable_clipboard = false
enable-file-copy-paste = true
show_quality_monitor = false
follow_remote_cursor = false
follow_remote_window = false
keyboard_mode = 'map'
view_only = false
show_my_cursor = false
sync-init-clipboard = false
trackpad-speed = 100
[options]
custom-fps = '30'
remote-menubar-frac = '0.5'
i444 = ''
collapse_toolbar = ''
zoom-cursor = ''
swap-left-right-mouse = ''
codec-preference = 'h264'
remote-menubar-edge = 'top'
[ui_flutter]
wm_RemoteDesktop = '{"width":874.0,"height":384.0,"offsetWidth":874.0,"offsetHeight":384.0,"isMaximized":true,"isFullscreen":false}'
[info]
username = '12914'
hostname = 'chunyu'
platform = 'Windows'
[transfer]
write_jobs = []
read_jobs = []
-89
View File
@@ -1,89 +0,0 @@
# RustDesk 配置自动导入脚本
# 用法:以管理员身份运行 PowerShell,然后执行此脚本
param(
[string] = "C:\Users\12914\AppData\Roaming\RustDesk\config"
)
Write-Host "RustDesk 配置导入工具" -ForegroundColor Green
Write-Host "=====================" -ForegroundColor Green
# 检查RustDesk是否在运行
$rustdeskProcess = Get-Process -Name "rustdesk" -ErrorAction SilentlyContinue
if ($rustdeskProcess) {
Write-Host "警告:RustDesk正在运行,需要先退出" -ForegroundColor Yellow
$response = Read-Host "是否强制结束RustDesk进程?(y/n)"
if ($response -eq 'y') {
Stop-Process -Name "rustdesk" -Force
Start-Sleep -Seconds 2
Write-Host "RustDesk已退出" -ForegroundColor Green
} else {
Write-Host "请手动退出RustDesk后重新运行此脚本" -ForegroundColor Red
exit 1
}
}
# 创建备份目录
$backupDir = "$RustDeskPath\..\config_backup_20260824_224929"
if (Test-Path $RustDeskPath) {
Write-Host "备份原有配置到:$backupDir" -ForegroundColor Yellow
Copy-Item -Path $RustDeskPath -Destination $backupDir -Recurse -Force
Write-Host "备份完成" -ForegroundColor Green
} else {
Write-Host "原有配置目录不存在,跳过备份" -ForegroundColor Yellow
}
# 确保目标目录存在
if (!(Test-Path $RustDeskPath)) {
New-Item -ItemType Directory -Path $RustDeskPath -Force | Out-Null
New-Item -ItemType Directory -Path "$RustDeskPath\peers" -Force | Out-Null
}
# 获取脚本所在目录(假设配置文件在同级目录)
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$sourceConfig = "$scriptDir\config"
if (!(Test-Path $sourceConfig)) {
Write-Host "错误:找不到配置文件目录 $sourceConfig" -ForegroundColor Red
Write-Host "请确保此脚本与config文件夹在同一目录" -ForegroundColor Red
exit 1
}
# 复制配置文件
Write-Host "复制配置文件..." -ForegroundColor Cyan
$files = @(
"RustDesk.toml",
"RustDesk2.toml",
"RustDesk_local.toml",
"peers.toml",
"RustDesk_default.toml"
)
foreach ($file in $files) {
$sourceFile = "$sourceConfig\$file"
$destFile = "$RustDeskPath\$file"
if (Test-Path $sourceFile) {
Copy-Item -Path $sourceFile -Destination $destFile -Force
Write-Host " ✓ $file" -ForegroundColor Green
} else {
Write-Host " ✗ $file (未找到)" -ForegroundColor Red
}
}
# 复制peers目录
$peersSource = "$sourceConfig\peers"
$peersDest = "$RustDeskPath\peers"
if (Test-Path $peersSource) {
if (!(Test-Path $peersDest)) {
New-Item -ItemType Directory -Path $peersDest -Force | Out-Null
}
Copy-Item -Path "$peersSource\*" -Destination $peersDest -Recurse -Force
Write-Host " ✓ peers目录" -ForegroundColor Green
}
Write-Host "
配置导入完成!" -ForegroundColor Green
Write-Host "现在可以启动RustDesk,应该会显示原来的设备ID和密码。" -ForegroundColor Cyan
Write-Host "
按任意键退出..." -ForegroundColor Gray
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")