从 Redmine 导入时可以保留用户密码
此前,从 Redmine 导入的账户没有可用密码,所有人都得重设一次。现在运行导入时加上 --import-passwords,Redmine 的密码哈希也会一并带过来。每个人首次登录时,哈希会自动升级为 bcrypt,用户完全无感。此选项默认关闭。管理员和 LDAP 账户仍需重设密码。
导入工具现在也会把 Redmine 的匿名访问和非成员访问迁移过来。它落到每个项目的公开访问设置上,不会打开实例级总开关,所以除非你主动决定,否则访客看不到任何内容。完整流程见从 Redmine 迁移指南和用户指南中的对应页面。
密码哈希和导入源插件
如果你要从 Redmine 以外的系统迁移,新增的两个扩展点能帮上忙。通过插件或 PASSWORD_HASHERS 设置可以支持其他系统的密码哈希,每种算法需用 LEGACY_PASSWORD_ALGORITHMS 显式启用。插件还可以添加迁移源,用 python -m specivo.cli.import_data --source NAME 即可运行任意一个。旧的 specivo.cli.import_redmine 命令已被 import_data --source redmine 取代。详见密码哈希插件和导入源插件。
搜索修复,并支持按工作项编号搜索
搜索 ACME-42 现在能在所有搜索模式下找到该工作项以及所有提到它的地方,包括工作项在项目间移动后留下的旧编号。
早期版本的多个搜索问题已修复:
- 新评论无法被任何搜索找到,编辑后也不会重新索引。
- 已删除的维基页面仍会出现在关键词搜索结果中。
- 关键词搜索在第一页之后,每页返回的结果偏少。
- 语义搜索可能漏掉排在隐藏结果之后的可见匹配项,而且会扫描全部向量嵌入。现在改用向量索引。
- 嵌入模型配置错误会导致索引和搜索整体失效。现在语义搜索会自行关闭。
- 搜索回填在没有模型时也报告成功,并且跳过了部分附件。现在它会如实报告实际嵌入的内容。
内容现在在保存时即被索引,关键词搜索可以立刻找到新建和编辑过的内容。语义搜索所需的向量嵌入随后由 worker 生成。这个 worker 是新增的 celery-embeddings 服务,它在单个进程中运行嵌入任务,模型只需加载一次。现在只支持内置的本地嵌入模型,注册其他模型的端点已移除。新增的 python -m specivo.cli.download_model 命令会按固定修订版本下载模型,并校验其 SHA-256。
角色和追踪器新增可见性设置
新增的两个管理页面——角色和追踪器——开放了以往固定不变的设置。角色可以设为看到所有用户或只看到所属项目的成员,看到所有工时记录或只看到自己的。追踪器可以让新建的工作项默认私有。现有角色和追踪器在你修改之前保持现有行为。
工时记录权限现已严格执行
如果你用 Specivo 记录工时,请留意这一条。查看工时记录、记录工时和编辑/删除任意工时记录这三项权限现在在所有地方都生效。此前,能打开项目的人就能查看其工时记录,而且可以在任何项目中启动计时器。
使用默认角色时,Reporter(报告者)和 Non member(非成员)不再能看到工时记录。升级会为 Agent(智能体)授予查看工时记录权限,这样服务账户就能读回自己记录的工时。自定义角色若只有记录工时而没有查看工时记录,仍然可以记录工时,但之后看不到这些记录。
按文件名链接附件
在工作项、评论、预览和维基中,现在可以直接用文件名链接附件:[spec](spec.pdf) 生成链接, 插入图片。
安全修复
附件。读者无权打开的工作项,其附件仍可通过 id 下载,并能显示在维基页面上。已删除维基页面的附件也仍可被搜索到。
工时记录和版本。没有相应权限也能读取、记录和编辑工时记录。私有项目的共享版本未按访问权限过滤。
MCP 会话。任何知道会话 id 的人都可以用另一个 API 密钥恢复 MCP 会话,甚至在密钥被撤销后仍可恢复。MCP 工具报错时还可能暴露内部异常文本。现在统一报告“Internal error while executing tool”,请求体上限为 4 MiB,serverInfo.version 会报告 Specivo 的版本号。
拒绝服务问题。精心构造的 Markdown 每次查看都能让 worker 忙上几分钟,深层嵌套列表会导致报错。含有大量未闭合 <!-- 的文本需要数分钟才能完成索引并显示在搜索结果中。过长的搜索查询可能失败,极深的搜索偏移量会让数据库对数百万行排序。现在 Markdown 字段限制为 262,144 个字符,无法快速渲染的复杂文本改以纯文本显示。渲染限制按字段和按请求统计 CPU 时间,并根据主机的实测速度缩放,因此在繁忙服务器上大型维基页面不会再被降级为纯文本显示。
其他。索引出错时可能把内容写入日志。修改密码、退出登录和撤销会话在使用会话 cookie 调用时,现在需要 CSRF 令牌。
容器不再以 root 运行。应用容器现在以 UID 10001 运行,该用户只拥有数据目录下属于自己的子目录。一次性的 init-data 服务负责准备这些目录,过程中不会跟随符号链接或硬链接。
所有依赖也已升级到最新版本,包括 MCP SDK 2.x、Pillow 13 和 PyJWT 2.15,清除了全部未处理的安全公告。CI 现在会运行 Trivy 扫描,镜像中存在可修复的 HIGH 或 CRITICAL 漏洞时将阻止推送到 Docker Hub。
其他小改动
- 相对时间在前 24 小时内保持相对显示,而不是一过午夜就变成“昨天”。
- 剩余未翻译的界面文本已全部翻译,日期格式跟随界面语言。
- 同一时刻保存的评论不再出现顺序错乱。
- 发布包中的
configure.py不再向包外写入文件,模型下载也不再指向不存在的发布资源。 - 模型下载、回填、重建索引和导入的
make目标可以在发布包中直接使用。
升级时要做什么
先备份数据库和数据目录。升级会在启动时应用 8 个迁移(0033 到 0040)。
- 执行
docker compose up -d前先停掉应用容器。新的init-data服务不能在旧 worker 仍在运行时执行。如果你维护自己的 Compose 文件,请加入init-data,并加入celery-embeddings或设置EMBEDDING_QUEUE=celery。 - 升级后重建搜索索引(管理 → 设置)。如果使用语义搜索,还要运行一次
python -m specivo.cli.backfill_embeddings,让旧评论和编辑内容获得向量嵌入。 - 检查自定义角色是否具有查看工时记录权限,见上文说明。
- 依赖会话 cookie 的脚本在调用修改密码、退出登录和撤销会话接口时,现在必须带上
X-CSRF-Token请求头。 - 有一个迁移会用
CREATE INDEX CONCURRENTLY构建向量索引。期间 Specivo 可以正常使用,但api容器要等它完成后才会启动。几万个分块只需几秒,几百万个则要更久。
升级指南有完整细节,包括容器权限和向量索引。
如何获取
用 docker pull specivo/specivo:0.9.0 拉取 Docker 镜像。没有互联网访问的服务器可以使用 GitHub Release 中附带的离线包。安装和升级步骤见用户指南。