mirror of
https://github.com/Ed1s0nZ/CyberStrikeAI.git
synced 2026-10-21 14:52:05 +02:00
feat: let an installation choose its update source, and adopt a plain directory
config.yaml gains an optional update section (remote / remote_url / branch). The resolver keeps its default - whatever remote this tree already tracks - and the explicit choice wins when set, which is also what lets a tarball installation that never saw git get on the update rails at all. - RemoteURL is fetched straight into a ref namespace of its own, so a URL source cannot be shadowed by a same-named remote's stale refs. ValidRemoteURL allowlists https/http/ssh/git/file and local absolute paths, and rejects git's ext:: transport (which executes commands) before anything reaches argv. - Adopt connects a plain directory to the source. Preview is side-effect free (the fetch happens in a throwaway bare repository) and lists every local file whose content the target would replace, plus the operator content that is put aside. The confirmed run inits, adds origin, stashes operator content, keeps every replaced file under .update-backup/<ts>/overwritten/ so "the update ate my edit" has an address, lands the target content, sets upstream, rebuilds the binary. A failure removes only the .git it created itself; once the content has landed the tree stays adopted even if the build fails. - Console/API: the status envelope carries the configured source; POST /system/update/source writes it through the same config path every other setting uses (validated, audited); POST /system/update/adopt is preview-then-job, with the job's kind recorded. OpenAPI updated; RBAC rides the existing update:apply prefix and the route inventory stays green. Tests: URL-mode check/apply against real repositories (including the address beating a remote name), URL validation table, and the full adoption story - preview touches nothing, operator content survives, the replaced edit is in the backup, and the adopted tree updates and rolls back like any other installation.
This commit is contained in:
1 parent
dc5c4d6a75
commit
acd84cd525
12 files changed
+1125
-50
No files matched your search
@@ -3418,6 +3418,61 @@ func (h *OpenAPIHandler) GetOpenAPISpec(c *gin.Context) {
|
||||
},
|
||||
},
|
||||
},
|
||||
"/api/system/update/source": map[string]interface{}{
|
||||
"post": map[string]interface{}{
|
||||
"tags": []string{"系统更新"},
|
||||
"summary": "配置更新源(本安装从哪个仓库更新)",
|
||||
"description": "把更新源写进 config.yaml 的 update 段:remote(已有远端名)与 remote_url(仓库地址)二选一,branch 可选。不配置时更新跟随本目录自己跟踪的远端;地址白名单为 https/http/ssh/git/file:// 与本机绝对路径(git 的 ext:: 传输会执行命令,一律拒绝)。",
|
||||
"operationId": "saveUpdateSource",
|
||||
"requestBody": map[string]interface{}{
|
||||
"content": map[string]interface{}{
|
||||
"application/json": map[string]interface{}{
|
||||
"schema": map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"remote": map[string]interface{}{"type": "string", "description": "安装树里已有的远端名(mine/origin/upstream/任意名)"},
|
||||
"remoteUrl": map[string]interface{}{"type": "string", "description": "仓库地址(与 remote 二选一)"},
|
||||
"branch": map[string]interface{}{"type": "string", "description": "要跟踪的分支;留空按 upstream/当前分支推断"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"responses": map[string]interface{}{
|
||||
"200": map[string]interface{}{"description": "已保存(返回生效的更新源)"},
|
||||
"400": map[string]interface{}{"description": "远端名/地址/分支不合法,或两者同时给出"},
|
||||
"401": map[string]interface{}{"description": "未授权"},
|
||||
},
|
||||
},
|
||||
},
|
||||
"/api/system/update/adopt": map[string]interface{}{
|
||||
"post": map[string]interface{}{
|
||||
"tags": []string{"系统更新"},
|
||||
"summary": "把非 git 目录接入更新源",
|
||||
"description": "解压/打包安装所在的目录接入配置好的更新源:不带 confirm 做无副作用预览(在临时仓库里 fetch,列出会被目标版本替换的文件与会保留的运维者内容);confirm=true 时异步执行(202 + job_id,用 /api/system/update/job 轮询):git init、添加 origin、落地目标分支内容,运维者内容先暂存再放回,被替换的文件全部留底到 .update-backup/<时间戳>/overwritten/。已是 git 工作树时返回 409(用一键更新而不是接入)。",
|
||||
"operationId": "adoptUpdateSource",
|
||||
"requestBody": map[string]interface{}{
|
||||
"content": map[string]interface{}{
|
||||
"application/json": map[string]interface{}{
|
||||
"schema": map[string]interface{}{
|
||||
"type": "object",
|
||||
"properties": map[string]interface{}{
|
||||
"confirm": map[string]interface{}{"type": "boolean", "description": "false/缺省=只预览;true=确认执行"},
|
||||
"restart": map[string]interface{}{"type": "boolean", "description": "接入成功后退出进程交给外部守护拉起,默认 false"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"responses": map[string]interface{}{
|
||||
"200": map[string]interface{}{"description": "预览结果(plan:将被替换/保留的文件清单与总数)"},
|
||||
"202": map[string]interface{}{"description": "接入任务已受理,返回 job_id"},
|
||||
"400": map[string]interface{}{"description": "没有配置更新源、地址不合法、分支不合法,或要求重启但没有重启钩子"},
|
||||
"409": map[string]interface{}{"description": "目录已是 git 工作树;或有任务在进行中"},
|
||||
"401": map[string]interface{}{"description": "未授权"},
|
||||
},
|
||||
},
|
||||
},
|
||||
"/api/config": map[string]interface{}{
|
||||
"get": map[string]interface{}{
|
||||
"tags": []string{"配置管理"},
|
||||
|
||||
Reference in new issue
Block a user