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
21 changes: 20 additions & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,30 @@ jobs:
- run: npm ci --prefix tests/prompts
- run: npm test --prefix tests/prompts
- run: python3 tests/release/test_release.py
- run: python3 tests/release/test_web_minify.py
- name: Install Chrome for actual-page regressions
working-directory: tests/prompts
run: npx playwright install --with-deps chrome
- run: npm run test:browser --prefix tests/prompts

runtime-tests:
name: Runtime and fan regression tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Fetch matching ESP-IDF cJSON sources for host tests
run: |
export IDF_PATH="$RUNNER_TEMP/runtime-idf"
echo "IDF_PATH=$IDF_PATH" >> "$GITHUB_ENV"
git clone --depth 1 --branch "$IDF_VERSION" --filter=blob:none --sparse https://github.com/espressif/esp-idf.git "$IDF_PATH"
git -C "$IDF_PATH" sparse-checkout set components/json
git -C "$IDF_PATH" submodule update --init --depth 1 components/json/cJSON
- uses: actions/setup-node@v4
with:
node-version: '22'
- run: bash tests/runtime/run_all.sh
- run: bash tests/fan_monitor/run_host.sh

build:
name: Build ESP32-S3 Firmware
runs-on: ubuntu-latest
Expand Down Expand Up @@ -154,7 +173,7 @@ jobs:
# 编译成功后自动创建或更新 Release:tag 推送、main 推送或手动发布 Release
release:
name: Create or Update Release
needs: [build, web-tests]
needs: [build, web-tests, runtime-tests]
if: github.repository == 'RMinte-AI/TianshanOS' && (github.event_name == 'release' || startsWith(github.ref, 'refs/tags/v') || (github.ref == 'refs/heads/main' && github.event_name == 'push'))
runs-on: ubuntu-latest
permissions:
Expand Down
Binary file modified build/TianShanOS.bin
Binary file not shown.
Binary file modified build/bootloader/bootloader.bin
Binary file not shown.
Binary file modified build/www.bin
Binary file not shown.
29 changes: 24 additions & 5 deletions components/ts_api/src/ts_api_ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,9 @@ static esp_err_t api_ssh_test(const cJSON *params, ts_api_result_t *result)
* 2. 验证主机指纹(Known Hosts)
* 3. 部署公钥到 authorized_keys
* 4. 使用公钥认证验证部署是否成功
* 5. 登记主机到 NVS;登记失败保留 deployed/verified 并返回业务错误
*
* Result data adds host_id, registered (NVS committed), registration_error (on failure).
*
* Params: {
* "host": "192.168.1.100",
Expand Down Expand Up @@ -846,10 +849,11 @@ static esp_err_t api_ssh_copyid(const cJSON *params, ts_api_result_t *result)

free(pubkey_data);

/* 部署成功后,自动注册到 SSH 主机配置(无论验证是否成功) */
if (deploy_ok) {
/* Registration is independent of remote deployment and login verification. */
esp_err_t add_ret;
char auto_id[TS_SSH_HOST_ID_MAX];
{
/* 生成主机 ID:user@host:port */
char auto_id[TS_SSH_HOST_ID_MAX];
if (ssh_port == 22) {
snprintf(auto_id, sizeof(auto_id), "%s@%s",
user->valuestring, host->valuestring);
Expand All @@ -868,9 +872,12 @@ static esp_err_t api_ssh_copyid(const cJSON *params, ts_api_result_t *result)
strncpy(host_config.username, user->valuestring, sizeof(host_config.username) - 1);
strncpy(host_config.keyid, keyid->valuestring, sizeof(host_config.keyid) - 1);

esp_err_t add_ret = ts_ssh_hosts_config_add(&host_config);
add_ret = ts_ssh_hosts_config_add(&host_config);
if (add_ret == ESP_OK) {
TS_LOGI(TAG, "Auto-registered SSH host: %s", auto_id);
} else {
TS_LOGW(TAG, "Public key deployed but host %s registration failed: %s",
auto_id, esp_err_to_name(add_ret));
}
}

Expand All @@ -882,8 +889,20 @@ static esp_err_t api_ssh_copyid(const cJSON *params, ts_api_result_t *result)
cJSON_AddNumberToObject(data, "port", ssh_port);
cJSON_AddStringToObject(data, "user", user->valuestring);
cJSON_AddStringToObject(data, "keyid", keyid->valuestring);
cJSON_AddStringToObject(data, "host_id", auto_id);
cJSON_AddBoolToObject(data, "registered", add_ret == ESP_OK);

ts_api_result_ok(result, data);
if (add_ret == ESP_OK) {
ts_api_result_ok(result, data);
} else {
cJSON_AddStringToObject(data, "registration_error", esp_err_to_name(add_ret));
ts_api_result_code_t code = add_ret == ESP_ERR_INVALID_STATE ? TS_API_ERR_BUSY
: add_ret == ESP_ERR_NO_MEM ? TS_API_ERR_NO_MEM
: TS_API_ERR_INTERNAL;
ts_api_result_error(result, code, "host_registration_failed");
result->data = data;
}
/* Keep partial-result data in the existing HTTP response serializer. */
return ESP_OK;
}

Expand Down
18 changes: 3 additions & 15 deletions components/ts_drivers/src/ts_fan.c
Original file line number Diff line number Diff line change
Expand Up @@ -620,19 +620,9 @@ static void fan_update_callback(void *arg)
ts_temp_data_t temp_data = {0};
bool have_temp_data = false;
bool basic_temp_data_valid = false;
bool needs_temp_data = false;

for (int i = 0; i < TS_FAN_MAX; i++) {
if (s_fans[i].initialized &&
(s_fans[i].mode == TS_FAN_MODE_CURVE ||
s_fans[i].mode == TS_FAN_MODE_AUTO)) {
needs_temp_data = true;
break;
}
}

/* 主动获取最新温度(确保曲线模式能及时响应温度变化) */
if (s_auto_temp_enabled && needs_temp_data) {
/* 温度监控独立于风扇模式,手动/关闭模式下也保持有效温度快照更新。 */
if (s_auto_temp_enabled) {
int16_t current_temp = ts_temp_get_effective_nonblocking(&temp_data);
have_temp_data = true;
basic_temp_data_valid = is_temp_data_basic_valid(&temp_data);
Expand All @@ -647,9 +637,7 @@ static void fan_update_callback(void *arg)

if (basic_temp_data_valid) {
for (int i = 0; i < TS_FAN_MAX; i++) {
if (s_fans[i].initialized &&
(s_fans[i].mode == TS_FAN_MODE_CURVE ||
s_fans[i].mode == TS_FAN_MODE_AUTO)) {
if (s_fans[i].initialized) {
s_fans[i].temperature = current_temp;
}
}
Expand Down
2 changes: 2 additions & 0 deletions components/ts_security/include/ts_ssh_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ bool ts_ssh_service_start_admissible(const char *id);

bool ts_ssh_service_command_protected(const char *id);
bool ts_ssh_service_host_protected(const char *host_id);
/* Missing-host recovery: inspect runtime ownership, not historical command references. */
bool ts_ssh_service_host_runtime_protected(const char *host_id);

void ts_ssh_service_cancel_observation(const char *id, uint32_t generation);
bool ts_ssh_service_any_in_use(void);
Expand Down
Loading
Loading