feat: make the update source one repository address, the official repo by default

The update source used to be three things - a remote name or an address, plus an
optional branch - and unset it followed whatever this directory's remotes and
upstream happened to say. That asked people to understand git topology before
they could update, and the person it was built for could not tell what "follow
the remote this tree tracks" meant. It is now one field: config.yaml update.repo,
an address, empty meaning the official repository
(https://github.com/AIPentest/CyberStrikeAI.git). Point it at a mirror (GitHub is
hard to reach in some places) or at your own fork and that is the whole
configuration.

The branch nothing is any more: an update follows the source repository's own
default branch, resolved from the source itself (ls-remote --symref HEAD), so a
fork whose default is not "main" still works and nobody has to name a branch.
Remote names, the mine/origin/upstream ranking, @{upstream} tracking and the
adopt flow's branch argument are all gone with it.

The console page loses two input fields: the source section is one address, a
hint that empty means the official repository, and a save button; clearing the
address is the way back to the default. The install facts drop the remote name,
the check section shows the source's default branch once the network answer
arrives, and the adopt entry no longer requires saving an address first - the
official default makes connecting a tarball install a zero-configuration action.

The CLI now reads the same update.repo field the page saves (LoadUpdateRepo reads
just that field, without validating the rest of the file - a broken unrelated
section must not block the path that fixes the tree), so the keyboard and the
button cannot update from different repositories. -check-update prints the source
it is about to use.

Tests: the source suite now pins the default (official), the single-address save
(including the empty-string reset), and that the followed branch comes from the
source's own default branch rather than a hardcoded "main"; the console suite
posts the one field and renders the default hint; docs, config.example.yaml and
upgrade.sh describe the one-field story.
This commit is contained in:
Sycun committed 2026-10-08 13:46:14 +08:00
1 parent e80668b2e9
commit 94a18263b9
28 files changed
+602 -584

No files matched your search

+13 -12
View File
@@ -78,13 +78,14 @@ proxy_set_header Connection "upgrade";
## Upgrading
**Prefer the platform's own one-click update** (console System settings -> One-click update,
`POST /api/system/update/apply`, or `./cyberstrike-ai -update` at a keyboard). It pulls **the remote
this install directory already tracks**: fetch, fast-forward, `go build`, atomic binary swap (the old
binary is kept as `cyberstrike-ai.prev`), while operator content - `roles/ skills/ tools/ agents/
knowledge_base/ data/ config.yaml` - is put aside and restored, and the result names every file it
kept. For a fork this is the only path that does not overwrite you with somebody else's code; when
source is modified locally or the branch has diverged it refuses and says why instead of forcing.
See [the developer guide](developer-guide.md) for the full semantics.
`POST /api/system/update/apply`, or `./cyberstrike-ai -update` at a keyboard). It pulls the newest
commit of the **update source repository**'s default branch (the official repository
`https://github.com/AIPentest/CyberStrikeAI.git` by default; one setting points it at your own fork
or a mirror): fetch, fast-forward, `go build`, atomic binary swap (the old binary is kept as
`cyberstrike-ai.prev`), while operator content - `roles/ skills/ tools/ agents/ knowledge_base/
data/ config.yaml` - is put aside and restored, and the result names every file it kept. When source
is modified locally or the local history has diverged from the source it refuses and says why
instead of forcing. See [the developer guide](developer-guide.md) for the full semantics.
When a supervisor is detected (systemd/launchd startup markers in the environment), the "exit after
updating" tick is pre-ticked: the process stands down after a successful update, the supervisor brings
@@ -92,11 +93,11 @@ the new binary back, and the page reloads itself once the service answers (sessi
one fresh login follows). Forgot the tick, or swapped the binary from the CLI? The console carries a
persistent banner with **Restart now** - no shell login needed.
The source is chosen either in the `update` section of `config.yaml` (`remote` or `remote_url`, plus
an optional `branch`) or right on the console page: the official repository, your own fork, or
somebody else's second-development repository are all just this one setting; unset, it follows the
remote this directory already tracks. An installation unpacked from a Release archive (no `.git`)
can be connected from the same page: the preview lists the files the target would replace and the
The update source is a single repository address in the `update` section of `config.yaml` (`repo`),
or right on the console page: the official repository, your own fork, somebody else's repository or a
mirror are all just this one setting; empty means the official repository. An installation unpacked
from a Release archive (no `.git`) can be connected from the same page (no configuration needed - the
default official repository applies): the preview lists the files the target would replace and the
operator content that is kept, replaced files are backed up under
`.update-backup/<timestamp>/overwritten/`, and confirming turns the directory into a normal
installation with one-click updates.
+16 -18
View File
@@ -58,34 +58,32 @@ additionally requires a global (`all` scope) session: one machine has one source
### Where the code comes from
From **the remote this directory already tracks**; no third-party repository is hardcoded. The remote
is picked from the ones this tree has, in the order `mine`, `origin`, `upstream` (falling back to the
first remote when none of those names exists), and the branch defaults to what the current branch's
`@{upstream}` names (the current branch itself when there is no upstream). `upgrade.sh` is now a thin
shell over the same implementation: when this directory is a git work tree it just calls
`./cyberstrike-ai -update`.
From **the update source repository**: one address, the official repository
`https://github.com/AIPentest/CyberStrikeAI.git` by default, and the update follows that repository's
**own default branch** (nothing about branches is configured, and "main" is not hardcoded), so an
installation with no configuration at all still has exactly one answer to "where does an update come
from". `upgrade.sh` is now a thin shell over the same implementation: when this directory is a git
work tree it just calls `./cyberstrike-ai -update`.
### Choosing the source (the update section of config.yaml)
### Changing the source (the update section of config.yaml)
Unset, the rules above apply; set, the explicit choice wins:
The update source is a single field: a repository address. Empty means the official repository; to
follow your own fork, a mirror (when GitHub is hard to reach), or somebody else's repository, this is
the one place to change:
```yaml
update:
remote: origin # an existing remote name (mine/origin/upstream/anything), or remote_url instead
# remote_url: https://github.com/AIPentest/CyberStrikeAI.git
branch: main # optional; defaults to @{upstream} / the current branch
repo: https://github.com/AIPentest/CyberStrikeAI.git # one repository address; empty/absent = the official repository
```
The console page edits and saves all three. Saving validates: remote and branch names go through the
same allowlist an update uses, and the address allowlist is https/http/ssh/git/file plus local
absolute paths - git's `ext::` transport executes commands and is rejected outright. Following the
official repository, your own fork, or somebody else's second-development repository is exactly the
choice this section expresses.
The console's "Update source" block edits and saves this address (saving it empty goes back to the
official repository). Saving validates the address against an allowlist: https/http/ssh/git/file plus
local absolute paths - git's `ext::` transport executes commands and is rejected outright.
### Connecting a non-git installation (the tarball kind)
An installation that started as an unpacked Release archive has no `.git`; once a source is saved it
can be connected from the same page: the preview fetches in a throwaway repository and first lists
An installation that started as an unpacked Release archive has no `.git`; it can be connected from
the same page (the default official repository works without any configuration): the preview fetches in a throwaway repository and first lists
**the local files the target would replace** and **the operator content that will be kept**; on
confirm the directory becomes a git work tree (`git init`, origin added, the target branch checked
out), every replaced file is kept under `.update-backup/<timestamp>/overwritten/`, operator content
+2 -2
View File
@@ -101,8 +101,8 @@ Important distinctions:
- `fofa:execute` is kept for backward compatibility, but it now protects the Reconnaissance page for FOFA, ZoomEye, Quake, and Shodan searches.
- `mcp:write` manages external MCP configuration; it is separate from external tool execution.
- One-click update is two permissions: `update:read` shows the installed version and the gap against
the remote, while `update:apply` pulls this installation's own repository, rebuilds the platform
binary and swaps it. The mutating side additionally requires the session to hold that permission
the update source, while `update:apply` pulls the configured source repository's default branch
(the official repository by default), rebuilds the platform binary and swaps it. The mutating side additionally requires the session to hold that permission
with `all` scope - one machine has one source tree, so an `assigned`/`own` session must not be able
to move the code everybody else is running.
- `robot:write` manages robot configuration and the test endpoint. Chatbot conversations use the bound user or configured service account's business permissions.
+11 -10
View File
@@ -180,21 +180,22 @@ SQLite 热备份时最好先停止服务,或至少复制 `*.db`、`*.db-wal`
## 升级
**优先用平台自带的「一键更新」**(控制台「系统设置 → 一键更新」、`POST /api/system/update/apply`、
或键盘上的 `./cyberstrike-ai -update`)。它拉的是**这个安装目录自己跟踪的远端**:fetch → 快进合并 →
`go build` → 原子换二进制(旧的留作 `cyberstrike-ai.prev`),并把 `roles/ skills/ tools/ agents/
knowledge_base/ data/ config.yaml` 等运维者内容先暂存再放回,结果里点名保留了哪些文件。
跑 fork 时这是唯一不会"用别人的代码覆盖自己"的路径;本地源码有改动或分支已分叉时它会拒绝并说明原因,
而不是硬来。细节见 [开发者指南](developer-guide.md) 的「一键更新」一节。
或键盘上的 `./cyberstrike-ai -update`)。它从**更新源仓库**(默认官方仓库
`https://github.com/AIPentest/CyberStrikeAI.git`,可一处配置改成自己的二开或镜像)拉取该仓库默认分支的
最新代码:fetch → 快进合并 → `go build` → 原子换二进制(旧的留作 `cyberstrike-ai.prev`),并把
`roles/ skills/ tools/ agents/ knowledge_base/ data/ config.yaml` 等运维者内容先暂存再放回,结果里点名
保留了哪些文件。本地源码有改动、或本地历史与更新源分叉时它会拒绝并说明原因,而不是硬来。
细节见 [开发者指南](developer-guide.md) 的「一键更新」一节。
检测到 systemd/launchd(环境里有对应启动标记)时,"更新完成后退出进程"默认勾选:更新成功后进程退出、
由守护拉起新二进制,页面会在服务回来时自动刷新(会话在内存里,需要重新登录一次)。忘勾、或在命令行
换过二进制时,控制台顶部有常驻横幅和「立即重启服务」补上这一步——不必再登录服务器手动重启。
更新源可以在 `config.yaml` 的 `update` 段指定(`remote` 或 `remote_url`,可带 `branch`),也可以直接在
控制台「一键更新」页填写保存:想跟随官方仓库、自己的二开或别人的二开,改的都是这一处;不配置时跟随
本目录自己跟踪的远端。**用 Release 包解压安装、目录里没有 git 的**,配好地址后在同一页点「预览并接入」:
预览先列出会被目标版本替换的文件与会保留的运维者内容,被替换的都会备份在
`.update-backup/<时间戳>/overwritten/`,确认后目录成为可一键更新的正常安装。
更新源是 `config.yaml` `update` 段里的**一个仓库地址**(`repo`),也可以直接在控制台「一键更新」页填写保存:
想跟随官方仓库、自己的二开、别人的二开或镜像,改的都是这一处;不写就是官方仓库。**用 Release 包解压安装、
目录里没有 git 的**,在同一页点「预览并接入」(不配置也能用默认的官方仓库):预览先列出会被目标版本替换的
文件与会保留的运维者内容,被替换的都会备份在 `.update-backup/<时间戳>/overwritten/`,确认后目录成为可一键
更新的正常安装。
`upgrade.sh` 仍然可用,它现在只是这条实现的薄壳,并按安装形态分两条路:
+11 -12
View File
@@ -63,28 +63,27 @@ go run ./cmd/server --config config.yaml
### 它从哪里取代码
从**这个目录自己的远端**,没有任何写死的第三方仓库地址。远端按 `mine → origin → upstream` 的次序在这个目录已有的
remote 里取(都不在时取第一个 remote),分支默认取当前分支 `@{upstream}` 指向的名字(没有 upstream 时用当前分支名)。
`upgrade.sh` 现在只是这条实现的薄壳:本目录是 git 工作树时它直接调 `./cyberstrike-ai -update`。
从**更新源仓库**:一个仓库地址,默认就是官方仓库 `https://github.com/AIPentest/CyberStrikeAI.git`;
更新跟随该仓库**自己的默认分支**(不用配置分支,也不写死 main),所以对一套没做过任何配置的安装,
「从哪更新」永远有一个明确答案。`upgrade.sh` 现在只是这条实现的薄壳:本目录是 git 工作树时它直接调
`./cyberstrike-ai -update`。
### 选择更新源(config.yaml 的 update 段)
### 更换更新源(config.yaml 的 update 段)
不配置时按上面的规则跟随本树;配置后显式来源优先:
更新源只有一个字段:仓库地址。留空 = 官方仓库;想跟随自己的二开、镜像(GitHub 访问不畅时)或别人的仓库,
只改这一处:
```yaml
update:
remote: origin # 已有远端名(mine/origin/upstream/任意名),与 remote_url 二选一
# remote_url: https://github.com/AIPentest/CyberStrikeAI.git
branch: main # 可选;留空按 upstream/当前分支推断
repo: https://github.com/AIPentest/CyberStrikeAI.git # 一个仓库地址;留空/不写 = 官方仓库
```
控制台的「一键更新」页可以直接编辑并保存这三项。服务端保存时校验:远端名与分支名走与更新同一套白名单,
地址只允许 https/http/ssh/git/file:// 与本机绝对路径——git 的 `ext::` 传输会执行命令,一律拒绝。
想让这套安装跟随官方仓库、自己的二开或别人的二开,改的都是这一处。
控制台的「一键更新 → 更新源」区块可以直接编辑并保存这个地址(留空保存 = 回到官方仓库)。
服务端保存时校验地址:只允许 https/http/ssh/git/file:// 与本机绝对路径——git 的 `ext::` 传输会执行命令,一律拒绝。
### 接入非 git 安装(解压/打包装的那类)
一开始用 Release 包解压安装、目录里没有 `.git` 的,配好上面的地址后可在同一页执行「预览并接入」:
一开始用 Release 包解压安装、目录里没有 `.git` 的,可在同一页执行「预览并接入」(不配置也能用默认的官方仓库):
预览在临时仓库里 fetch,先列出**会被目标版本替换的本机文件**与**会保留的运维者内容**;确认后目录接入
成为 git 工作树(`git init` + 添加 origin + 落地目标分支),被替换的文件全部留底在
`.update-backup/<时间戳>/overwritten/`,运维者内容照旧先暂存再放回,随后重编译二进制。
+2 -2
View File
@@ -108,8 +108,8 @@ AI 测试角色不是安全授权边界。即使选择了“渗透测试”角
- `mcp:execute` 用于访问认证后的 MCP HTTP 入口。
- `mcp:external:execute` 用于 Agent 调用外部 MCP 工具,当前还要求该权限的 Scope 为 `all`。
- 管理外部 MCP 配置使用 `mcp:write`,与执行外部工具是两项权限。
- 一键更新是**两项**:`update:read` 看本机安装的版本与远端差集;`update:apply` 拉自己的远端、重编译并换掉
平台二进制。写侧还要求会话是 `all` scope——一台机器一份源码,`assigned`/`own` 不该能移动别人正在跑的代码。
- 一键更新是**两项**:`update:read` 看本机安装的版本与更新源差集;`update:apply` 拉取更新源仓库(默认官方仓库)
的默认分支、重编译并换掉平台二进制。写侧还要求会话是 `all` scope——一台机器一份源码,`assigned`/`own` 不该能移动别人正在跑的代码。
- `robot:write` 管理机器人配置和测试入口;机器人聊天本身使用绑定用户或服务账号的业务权限。
---