Files
msime-windows/scripts/ci/validate-draft-release.sh
T
Evan f70f64acaa fix(ci,ui): 修掉 6 条 CodeQL high 告警,补上发布目标的祖先校验
- validate-draft-release.sh 增加「target_sha 必须在 main 历史上」的校验。此前有 write 权限的人可以
  建一个指向任意 commit 的 draft release 再 dispatch,那份代码就会被编译并签进正式安装包;唯一的
  祖先检查跑在 checkout 之后的不可信工作树里,而负责编译的 TSF job 根本没有这道检查。校验放在
  prepare(默认分支上下文)里,所有构建 job 都 needs 它。
- 字体名引用只转义了 `"` 没转义反斜线,以 `\` 结尾的字体名能吃掉闭合引号让后续内容按 CSS 解析。
  两处(appearance.ts、shared.ts)都改为先转义转义符。
- voice_input_service.cpp: float 平方先提升到 double
- engine-bump-triage.yml 顶层权限从 write 收到 read,写权限下放到 job;runner 与同仓其他 workflow
  统一为 ubuntu-24.04

新增 CONTRIBUTING.md,把散在各 AGENTS.md / 组件 README 里的环境要求、构建顺序、打包步骤和提交前
检查串成外部贡献者能照着走完的一条路径,并从 README 首屏链出。
2026-09-06 12:09:50 +09:00

54 lines
2.5 KiB
Bash
Executable File

#!/usr/bin/env bash
# Check that a manually requested tag names an unpublished draft release pinned to an immutable
# commit whose version.txt agrees with the tag, then report the commit and version for the build
# jobs to use. Nothing is built until this passes.
#
# Requires GH_TOKEN, GH_REPO, TAG_NAME. Writes target_sha and version to GITHUB_OUTPUT.
set -euo pipefail
if [[ ! "$TAG_NAME" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "Tag must use the vMAJOR.MINOR.PATCH format, got '$TAG_NAME'." >&2
exit 1
fi
release_json=$(gh release view "$TAG_NAME" --json isDraft,targetCommitish)
if [[ "$(jq -er .isDraft <<< "$release_json")" != true ]]; then
echo "Release $TAG_NAME is not an unpublished draft." >&2
exit 1
fi
target_sha=$(jq -er .targetCommitish <<< "$release_json")
if [[ ! "$target_sha" =~ ^[0-9a-f]{40}$ ]]; then
echo "Draft release target must be an immutable full commit SHA, got '$target_sha'." >&2
exit 1
fi
# The target has to be on main. Without this, anyone able to create a draft release could point it
# at an arbitrary commit -- a fork's branch, an abandoned branch, a commit that never passed review --
# and dispatch this workflow to get that code compiled and signed into a published installer.
#
# The check belongs here rather than in the build jobs. This runs in the prepare job, which checks
# out the default branch, so both this script and the answer it gets come from trusted code. The
# equivalent check in the package job runs after the untrusted commit is already checked out, which
# means the script performing it is itself supplied by the commit under test; the TSF job, which
# compiles, had no such check at all. Those remain as defence in depth, not as the gate.
#
# compare/main...<sha> reports "behind" when the commit is an ancestor of main and "identical" when
# it is main's tip. Anything else means it is not in main's history.
comparison=$(gh api "repos/$GH_REPO/compare/main...$target_sha" --jq .status)
if [[ "$comparison" != "behind" && "$comparison" != "identical" ]]; then
echo "Draft release target $target_sha is not in main's history (compare status: $comparison)." >&2
exit 1
fi
version=$(gh api "repos/$GH_REPO/contents/version.txt?ref=$target_sha" --jq .content | base64 --decode | tr -d '[:space:]')
if [[ "$TAG_NAME" != "v$version" ]]; then
echo "Release $TAG_NAME does not match version.txt ($version)." >&2
exit 1
fi
printf 'target_sha=%s\n' "$target_sha" >> "$GITHUB_OUTPUT"
printf 'version=%s\n' "$version" >> "$GITHUB_OUTPUT"
echo "Draft $TAG_NAME is valid: version $version at $target_sha"