mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-04 00:17:45 +08:00
ci: guard rust scope detection against false green
- changes 脚本加 set -euo pipefail,git fetch/diff 失败即中止,避免写出 rust=false/shell=false 让下游误判为“无需测试”。 - changed_paths 为空(异常事件)时保守置 rust=true/shell=true,宁可多跑不漏测。 - check 与 data_db_smoke 增加 needs.changes.result 兜底。 - 恢复 push/pull_request 的 paths 白名单,并补齐 rust-toolchain.toml、 .cargo/**、*.sql,workflow 触发规则与分类脚本对齐,避免“分类正确但 workflow 未启动”的漏测。 - nextest 删除硬编码 test-threads,改用默认 num-cpus,避免在大规格 runner 上主动压低并发;保留 slow-timeout 卡死保护。 - 补真实 TCP smoke test,覆盖管理员安全接口的监听端口与 HTTP/JSON 链路。
This commit is contained in:
@@ -1,8 +1,6 @@
|
|||||||
# GitHub-hosted ubuntu runner 当前按 4 vCPU 配置;固定线程数可避免 runner
|
# 不固定 test-threads:nextest 默认按 num-cpus 并发,固定值会在更大规格的
|
||||||
# 规格变化时测试并发和内存峰值随之漂移。
|
# runner 或本地开发机上主动压低并发、反而变慢,且无法表达 min(4, num-cpus)。
|
||||||
|
# 这里只保留卡死保护,避免单个挂起用例拖满整个 job。
|
||||||
[profile.default]
|
[profile.default]
|
||||||
test-threads = 4
|
# 60 秒后标记慢测试,连续两轮仍未结束则终止;超时结果保持失败,不隐藏回归。
|
||||||
|
|
||||||
# 60 秒后标记慢测试,连续两轮仍未结束则终止,避免单个卡死用例拖满整个 job。
|
|
||||||
# 真实连接/数据库测试仍有足够时间完成;超时结果保持失败,不隐藏回归。
|
|
||||||
slow-timeout = { period = "60s", terminate-after = 2, grace-period = "10s" }
|
slow-timeout = { period = "60s", terminate-after = 2, grace-period = "10s" }
|
||||||
|
|||||||
@@ -12,7 +12,61 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- master
|
- master
|
||||||
- main
|
- main
|
||||||
|
paths:
|
||||||
|
- "Cargo.toml"
|
||||||
|
- "Cargo.lock"
|
||||||
|
- "rust-toolchain.toml"
|
||||||
|
- ".cargo/**"
|
||||||
|
- "crates/**"
|
||||||
|
- "apps/**"
|
||||||
|
- "*.sql"
|
||||||
|
- "install.sh"
|
||||||
|
- "deploy.sh"
|
||||||
|
- "update.sh"
|
||||||
|
- "generate_keys.sh"
|
||||||
|
- ".env.example"
|
||||||
|
- "README.md"
|
||||||
|
- "Dockerfile.app"
|
||||||
|
- "docker-compose.yml"
|
||||||
|
- "docker-compose.single-node.yml"
|
||||||
|
- "docker-compose.local.yml"
|
||||||
|
- "docker-compose.release-local.yml"
|
||||||
|
- "tests/compose_database_config_test.py"
|
||||||
|
- "tests/install_*_test.sh"
|
||||||
|
- "tests/deploy_*_test.sh"
|
||||||
|
- "tests/update_*_test.sh"
|
||||||
|
- "tests/release_supply_chain_test.sh"
|
||||||
|
- "tests/tunnel_installer_config_security_test.sh"
|
||||||
|
- ".github/workflows/*.yml"
|
||||||
|
- ".github/workflows/*.yaml"
|
||||||
pull_request:
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- "Cargo.toml"
|
||||||
|
- "Cargo.lock"
|
||||||
|
- "rust-toolchain.toml"
|
||||||
|
- ".cargo/**"
|
||||||
|
- "crates/**"
|
||||||
|
- "apps/**"
|
||||||
|
- "*.sql"
|
||||||
|
- "install.sh"
|
||||||
|
- "deploy.sh"
|
||||||
|
- "update.sh"
|
||||||
|
- "generate_keys.sh"
|
||||||
|
- ".env.example"
|
||||||
|
- "README.md"
|
||||||
|
- "Dockerfile.app"
|
||||||
|
- "docker-compose.yml"
|
||||||
|
- "docker-compose.single-node.yml"
|
||||||
|
- "docker-compose.local.yml"
|
||||||
|
- "docker-compose.release-local.yml"
|
||||||
|
- "tests/compose_database_config_test.py"
|
||||||
|
- "tests/install_*_test.sh"
|
||||||
|
- "tests/deploy_*_test.sh"
|
||||||
|
- "tests/update_*_test.sh"
|
||||||
|
- "tests/release_supply_chain_test.sh"
|
||||||
|
- "tests/tunnel_installer_config_security_test.sh"
|
||||||
|
- ".github/workflows/*.yml"
|
||||||
|
- ".github/workflows/*.yaml"
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: rust-ci-${{ github.event_name }}-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
group: rust-ci-${{ github.event_name }}-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
@@ -45,6 +99,10 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
RUST_CI_FULL_SCOPE: ${{ inputs.full_scope || false }}
|
RUST_CI_FULL_SCOPE: ${{ inputs.full_scope || false }}
|
||||||
run: |
|
run: |
|
||||||
|
# 任何命令失败都必须让本 job 失败,否则 git fetch/diff 出错后仍会写出
|
||||||
|
# rust=false/shell=false,下游会误判为“无需测试”而假绿放行。
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
# Nightly 通过 workflow_call 显式传入 full_scope;普通 push/PR 只按源码和构建
|
# Nightly 通过 workflow_call 显式传入 full_scope;普通 push/PR 只按源码和构建
|
||||||
# 指纹触发 Rust jobs,安装脚本、Compose、README 等由 shell scope 覆盖。
|
# 指纹触发 Rust jobs,安装脚本、Compose、README 等由 shell scope 覆盖。
|
||||||
if [ "$RUST_CI_FULL_SCOPE" = "true" ]; then
|
if [ "$RUST_CI_FULL_SCOPE" = "true" ]; then
|
||||||
@@ -67,6 +125,14 @@ jobs:
|
|||||||
changed_paths=$(git ls-files)
|
changed_paths=$(git ls-files)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# 防御性兜底:diff 结果为空(异常事件或比较失败)时按全量运行,
|
||||||
|
# 宁可多跑也不能漏测。
|
||||||
|
if [ -z "$changed_paths" ]; then
|
||||||
|
echo "rust=true" >> "$GITHUB_OUTPUT"
|
||||||
|
echo "shell=true" >> "$GITHUB_OUTPUT"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
rust=false
|
rust=false
|
||||||
shell=false
|
shell=false
|
||||||
while IFS= read -r path; do
|
while IFS= read -r path; do
|
||||||
@@ -652,6 +718,10 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Verify database smoke jobs
|
- name: Verify database smoke jobs
|
||||||
run: |
|
run: |
|
||||||
|
if [ "${{ needs.changes.result }}" != "success" ]; then
|
||||||
|
echo "Scope detection failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
if [ "${{ needs.changes.outputs.rust }}" != "true" ]; then
|
if [ "${{ needs.changes.outputs.rust }}" != "true" ]; then
|
||||||
echo "Rust scope unchanged; database smoke jobs skipped"
|
echo "Rust scope unchanged; database smoke jobs skipped"
|
||||||
exit 0
|
exit 0
|
||||||
@@ -675,6 +745,11 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- name: Verify required jobs
|
- name: Verify required jobs
|
||||||
run: |
|
run: |
|
||||||
|
# changes 失败或未产出 scope 时不允许直接放行,避免假绿。
|
||||||
|
if [ "${{ needs.changes.result }}" != "success" ]; then
|
||||||
|
echo "Scope detection failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
rust="${{ needs.changes.outputs.rust }}"
|
rust="${{ needs.changes.outputs.rust }}"
|
||||||
shell="${{ needs.changes.outputs.shell }}"
|
shell="${{ needs.changes.outputs.shell }}"
|
||||||
|
|
||||||
|
|||||||
@@ -387,6 +387,42 @@ async fn gateway_handles_admin_security_blacklist_add_locally_with_trusted_admin
|
|||||||
assert_eq!(upstream_count, 0);
|
assert_eq!(upstream_count, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 真实 TCP 冒烟测试:其余安全用例已改为进程内 Router 调用以提速,这里保留一条
|
||||||
|
/// 覆盖网络层装配(真实监听端口、HTTP 请求头传递、JSON 收发)的端到端路径。
|
||||||
|
///
|
||||||
|
/// `/api/admin/security/*` 在路由分类中是本地管理端点
|
||||||
|
/// (`execution_runtime_candidate: false`),架构上不经过任何可注入 base_url 的上游,
|
||||||
|
/// 因此这里不构造无意义的“上游计数器”,只验证真实链路下本地处理结果正确。
|
||||||
|
#[tokio::test]
|
||||||
|
async fn gateway_serves_admin_security_blacklist_over_real_tcp() {
|
||||||
|
let gateway = build_router_with_state(AppState::new().expect("gateway should build"));
|
||||||
|
let (gateway_url, gateway_handle) = start_server(gateway).await;
|
||||||
|
|
||||||
|
let response = reqwest::Client::new()
|
||||||
|
.post(format!("{gateway_url}/api/admin/security/ip/blacklist"))
|
||||||
|
.header(GATEWAY_HEADER, "rust-phase3b")
|
||||||
|
.header(TRUSTED_ADMIN_USER_ID_HEADER, "admin-user-123")
|
||||||
|
.header(TRUSTED_ADMIN_USER_ROLE_HEADER, "admin")
|
||||||
|
.header(TRUSTED_ADMIN_SESSION_ID_HEADER, "session-123")
|
||||||
|
.json(&json!({ "ip_address": "1.2.3.4", "reason": "manual", "ttl": 60 }))
|
||||||
|
.send()
|
||||||
|
.await
|
||||||
|
.expect("request should reach the gateway over TCP");
|
||||||
|
|
||||||
|
let status = response.status();
|
||||||
|
let payload: serde_json::Value = response
|
||||||
|
.json()
|
||||||
|
.await
|
||||||
|
.expect("gateway response should be json");
|
||||||
|
assert_eq!(status, StatusCode::OK);
|
||||||
|
assert_eq!(payload["success"], true);
|
||||||
|
assert_eq!(payload["message"], "IP 1.2.3.4 已加入黑名单");
|
||||||
|
assert_eq!(payload["reason"], "manual");
|
||||||
|
assert_eq!(payload["ttl"], 60);
|
||||||
|
|
||||||
|
gateway_handle.abort();
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn gateway_rejects_invalid_admin_security_blacklist_ip() {
|
async fn gateway_rejects_invalid_admin_security_blacklist_ip() {
|
||||||
let gateway = build_router_with_state(AppState::new().expect("gateway should build"));
|
let gateway = build_router_with_state(AppState::new().expect("gateway should build"));
|
||||||
|
|||||||
Reference in New Issue
Block a user