mirror of
https://github.com/esengine/DeepSeek-Reasonix.git
synced 2026-11-07 10:45:59 -10:00
Merge pull request #10271 from SivanCola/fix/v1.38.8-manual-desktop-release
fix(release): recover v1.38.8 manual downloads / 恢复桌面版手动下载发布
This commit is contained in:
5 files changed
+103
-7
No files matched your search
@@ -94,6 +94,11 @@ on:
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
desktop_manual_only:
|
||||
description: "One-time approved v1.38.8 manual Desktop recovery"
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
concurrency:
|
||||
# A channel pointer is a monotonic public state machine. Serialize every
|
||||
@@ -225,6 +230,12 @@ jobs:
|
||||
env:
|
||||
PREFLIGHT_ARTIFACT_PREFIX: ${{ inputs.preflight_artifact_prefix }}
|
||||
run: |
|
||||
if [ "${{ inputs.desktop_manual_only }}" = "true" ]; then
|
||||
if [ "${{ inputs.orchestrated }}" != "true" ] || [ "${{ inputs.channel }}" != "stable" ] || [ "${{ needs.resolve.outputs.tag }}" != "desktop-v1.38.8" ] || [ "${{ needs.resolve.outputs.sha }}" != "7278072720a2dc7a31cce0eec18c1eacc149c0e0" ]; then
|
||||
echo "::error::manual Desktop exception is restricted to the approved immutable v1.38.8 candidate"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
if [ "${{ inputs.production_signing_smoke }}" = "true" ] && [ "${{ inputs.signing_preflight }}" = "true" ]; then
|
||||
echo "::error::production_signing_smoke and signing_preflight are mutually exclusive"
|
||||
exit 1
|
||||
@@ -316,7 +327,7 @@ jobs:
|
||||
env:
|
||||
# Windows Authenticode signing engages only when the SignPath token is set, so
|
||||
# forks / token-less runs still build (unsigned), mirroring the APPLE_* gate.
|
||||
HAS_SIGNPATH: ${{ secrets.SIGNPATH_API_TOKEN != '' }}
|
||||
HAS_SIGNPATH: ${{ secrets.SIGNPATH_API_TOKEN != '' && !inputs.desktop_manual_only }}
|
||||
SIGNPATH_SOURCE_SHA: ${{ needs.resolve.outputs.sha }}
|
||||
SIGNPATH_CONTROL_SHA: ${{ github.workflow_sha }}
|
||||
SIGNPATH_FINGERPRINT: ${{ needs.signing-contract.outputs.fingerprint }}
|
||||
@@ -399,11 +410,10 @@ jobs:
|
||||
echo "$APPLE_API_KEY_P8" | base64 --decode > "$RUNNER_TEMP/notary.p8"
|
||||
rm -f "$RUNNER_TEMP/cert.p12"
|
||||
|
||||
# Official Windows releases must fail closed. Forks can still exercise
|
||||
# unsigned packaging without repository secrets, but esengine releases
|
||||
# may never publish an unsigned payload or installer.
|
||||
# Official automatic-update releases require Authenticode. The guarded
|
||||
# v1.38.8 manual-only recovery retains minisign without advancing updates.
|
||||
- name: Require Windows Authenticode signing
|
||||
if: runner.os == 'Windows' && github.repository == 'esengine/DeepSeek-Reasonix'
|
||||
if: runner.os == 'Windows' && github.repository == 'esengine/DeepSeek-Reasonix' && !inputs.desktop_manual_only
|
||||
run: |
|
||||
if [ "$HAS_SIGNPATH" != "true" ]; then
|
||||
echo "::error::SIGNPATH_API_TOKEN is required for public Windows Preview and Stable releases"
|
||||
@@ -733,6 +743,20 @@ jobs:
|
||||
if-no-files-found: error
|
||||
retention-days: 30
|
||||
|
||||
- name: Bind manual Windows payload and rebuild packages
|
||||
if: runner.os == 'Windows' && inputs.desktop_manual_only
|
||||
env:
|
||||
MINISIGN_PRIVATE_KEY: ${{ secrets.MINISIGN_PRIVATE_KEY }}
|
||||
MINISIGN_PASSWORD: ${{ secrets.MINISIGN_PASSWORD }}
|
||||
REASONIX_REQUIRE_PAYLOAD_MANIFEST: "1"
|
||||
run: |
|
||||
cd desktop
|
||||
go run ./cmd/sign windows-payload build/windows/signing-payload "${{ needs.resolve.outputs.version }}"
|
||||
go run ./cmd/sign sign build/windows/signing-payload/reasonix-payload.json
|
||||
go run ./cmd/sign verify build/windows/signing-payload/reasonix-payload.json
|
||||
cd ..
|
||||
scripts/package-windows-desktop.sh "${{ matrix.platform == 'windows/arm64' && 'arm64' || 'amd64' }}" desktop/build/windows/signing-payload
|
||||
|
||||
- name: Sign artifacts (minisign)
|
||||
working-directory: desktop
|
||||
env:
|
||||
@@ -915,10 +939,23 @@ jobs:
|
||||
APPROVED_SHA: ${{ inputs.approved_sha }}
|
||||
run: bash scripts/verify-release-tag.sh
|
||||
|
||||
- name: Disclose manual Desktop distribution
|
||||
if: ${{ inputs.desktop_manual_only }}
|
||||
run: |
|
||||
cat >> /tmp/release-notes.md <<'NOTES'
|
||||
|
||||
## Manual desktop downloads / 桌面版手动下载
|
||||
|
||||
This v1.38.8 desktop release is manual-download only on every platform. Windows packages do not carry Reasonix Authenticode signatures because SignPath signing is unavailable; Windows may show an unknown-publisher warning. Detached minisign signatures and SHA-256 checksums remain available. Desktop automatic-update channels remain on v1.38.7. CLI and npm distribution are unaffected.
|
||||
|
||||
本次 v1.38.8 桌面版所有平台均需手动下载安装。因 SignPath 签名服务暂不可用,Windows 包不含 Reasonix Authenticode 签名,系统可能显示未知发布者提示;仍提供 minisign 签名和 SHA-256 校验。桌面自动更新通道保留在 v1.38.7,CLI 和 npm 正常发布。
|
||||
NOTES
|
||||
|
||||
- name: Publish GitHub release
|
||||
if: needs.resolve.outputs.channel != 'preview'
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
DESKTOP_MANUAL_ONLY: ${{ inputs.desktop_manual_only || false }}
|
||||
# Keep the repository homepage focused on the installable desktop app;
|
||||
# the CLI release line is configured not to claim repository-wide latest.
|
||||
run: >-
|
||||
@@ -1093,6 +1130,7 @@ jobs:
|
||||
id: mirror_r2
|
||||
if: env.HAS_R2 == 'true'
|
||||
env:
|
||||
DESKTOP_MANUAL_ONLY: ${{ inputs.desktop_manual_only || false }}
|
||||
CHANNEL: ${{ needs.resolve.outputs.channel }}
|
||||
PRERELEASE: ${{ needs.resolve.outputs.prerelease }}
|
||||
R2_ACCOUNT_ID: ${{ secrets.R2_ACCOUNT_ID }}
|
||||
@@ -1228,6 +1266,12 @@ jobs:
|
||||
bash release-control/scripts/compare-desktop-release-manifests.sh \
|
||||
assets/latest.json /tmp/reasonix-desktop-tag-latest.json
|
||||
|
||||
if [ "$DESKTOP_MANUAL_ONLY" = "true" ]; then
|
||||
echo "pointer_moved=false" >> "$GITHUB_OUTPUT"
|
||||
echo "Manual Desktop release: immutable downloads verified; automatic update pointers unchanged"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Internal RCs retain their immutable record but never move a public
|
||||
# channel pointer.
|
||||
if [ "$PRERELEASE" = "true" ] && [ "$CHANNEL" != "preview" ]; then
|
||||
@@ -1477,7 +1521,7 @@ jobs:
|
||||
esac
|
||||
|
||||
- name: Attach desktop manifest to matching CLI release
|
||||
if: env.HAS_R2 == 'true' && needs.resolve.outputs.channel != 'preview' && needs.resolve.outputs.prerelease != 'true'
|
||||
if: env.HAS_R2 == 'true' && needs.resolve.outputs.channel != 'preview' && needs.resolve.outputs.prerelease != 'true' && !inputs.desktop_manual_only
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
VERSION: ${{ needs.resolve.outputs.version }}
|
||||
|
||||
@@ -38,6 +38,11 @@ on:
|
||||
required: false
|
||||
default: true
|
||||
type: boolean
|
||||
desktop_manual_only:
|
||||
description: "One-time v1.38.8 recovery: unsigned Windows, manual Desktop downloads only"
|
||||
required: false
|
||||
default: false
|
||||
type: boolean
|
||||
|
||||
concurrency:
|
||||
group: stable-release-${{ inputs.tag || github.ref_name }}
|
||||
@@ -82,6 +87,12 @@ jobs:
|
||||
RELEASE_TAG: ${{ inputs.tag || github.ref_name }}
|
||||
ALLOW_STABLE_RECOVERY: ${{ inputs.allow_recovery }}
|
||||
run: bash scripts/resolve-stable-release.sh
|
||||
- name: Restrict manual Desktop recovery
|
||||
if: ${{ inputs.desktop_manual_only }}
|
||||
run: |
|
||||
test "${{ inputs.allow_recovery }}" = "true"
|
||||
test "${{ steps.release.outputs.cli_tag }}" = "v1.38.8"
|
||||
test "${{ steps.release.outputs.sha }}" = "7278072720a2dc7a31cce0eec18c1eacc149c0e0"
|
||||
- name: Revalidate normal release candidate and exact push CI
|
||||
if: ${{ !inputs.allow_recovery }}
|
||||
env:
|
||||
@@ -182,6 +193,7 @@ jobs:
|
||||
approved_sha: ${{ needs.authorize.outputs.sha }}
|
||||
orchestrated: true
|
||||
signing_preflight: true
|
||||
desktop_manual_only: ${{ inputs.desktop_manual_only || false }}
|
||||
secrets: inherit
|
||||
|
||||
desktop:
|
||||
@@ -196,6 +208,7 @@ jobs:
|
||||
approved_sha: ${{ needs.authorize.outputs.sha }}
|
||||
orchestrated: true
|
||||
signing_preflight_verified: true
|
||||
desktop_manual_only: ${{ inputs.desktop_manual_only || false }}
|
||||
preflight_artifact_prefix: ${{ needs.signpath-preflight.outputs.artifact_prefix }}
|
||||
secrets: inherit
|
||||
|
||||
@@ -247,6 +260,7 @@ jobs:
|
||||
RELEASE_VERSION: ${{ needs.authorize.outputs.version }}
|
||||
CLI_TAG: ${{ needs.authorize.outputs.cli_tag }}
|
||||
DESKTOP_TAG: ${{ needs.authorize.outputs.desktop_tag }}
|
||||
DESKTOP_MANUAL_ONLY: ${{ inputs.desktop_manual_only || false }}
|
||||
run: bash scripts/verify-stable-release-artifacts.sh
|
||||
- name: Publish exact Stable release record
|
||||
env:
|
||||
|
||||
@@ -60,7 +60,10 @@ if ! gh api "$release_endpoint" >"$release_json" 2>"$release_error"; then
|
||||
exit 1
|
||||
fi
|
||||
args=(--title "$title" --notes-file "$notes_file")
|
||||
if [ "$prerelease" = "true" ]; then
|
||||
if [ "${DESKTOP_MANUAL_ONLY:-false}" = "true" ]; then
|
||||
[ "$tag" = "desktop-v1.38.8" ] || { echo "manual exception is restricted to v1.38.8" >&2; exit 1; }
|
||||
args+=(--latest=false)
|
||||
elif [ "$prerelease" = "true" ]; then
|
||||
args+=(--prerelease --latest=false)
|
||||
else
|
||||
args+=(--latest)
|
||||
|
||||
@@ -13,6 +13,32 @@ trap cleanup EXIT
|
||||
|
||||
# Stable tags have one entrypoint and one protected environment. Reusable
|
||||
# publishers must verify that only that entrypoint can claim prior approval.
|
||||
# The manual exception is immutable-candidate scoped and cannot advance any
|
||||
# Desktop update entry point. Keep normal signing as the default.
|
||||
python3 - "$repo_root" <<'PY'
|
||||
import pathlib, sys
|
||||
root = pathlib.Path(sys.argv[1])
|
||||
stable = (root / '.github/workflows/release-stable.yml').read_text()
|
||||
desktop = (root / '.github/workflows/release-desktop.yml').read_text()
|
||||
publisher = (root / 'scripts/publish-desktop-github-release.sh').read_text()
|
||||
for workflow in (stable, desktop):
|
||||
block = workflow.split(' desktop_manual_only:', 1)[1].split('\n\n', 1)[0]
|
||||
assert 'default: false' in block
|
||||
assert '7278072720a2dc7a31cce0eec18c1eacc149c0e0' in workflow
|
||||
assert stable.count('desktop_manual_only: ${{ inputs.desktop_manual_only || false }}') == 2
|
||||
assert "HAS_SIGNPATH: ${{ secrets.SIGNPATH_API_TOKEN != '' && !inputs.desktop_manual_only }}" in desktop
|
||||
assert desktop.index('name: Validate signing mode') < desktop.index('name: Build and package')
|
||||
assert "inputs.orchestrated }}\" != \"true\"" in desktop
|
||||
assert 'manual-download only' in desktop
|
||||
manual_exit = desktop.index('if [ "$DESKTOP_MANUAL_ONLY" = "true" ]; then', desktop.index('name: Mirror immutable assets'))
|
||||
assert manual_exit < desktop.index('validate_current_pointer()', manual_exit)
|
||||
assert 'pointer_moved=false' in desktop[manual_exit:manual_exit + 350]
|
||||
attach = desktop.split('name: Attach desktop manifest to matching CLI release', 1)[1].split('env:', 1)[0]
|
||||
assert '!inputs.desktop_manual_only' in attach
|
||||
manual_publish = publisher.split('if [ "${DESKTOP_MANUAL_ONLY:-false}" = "true" ]; then', 1)[1].split('elif', 1)[0]
|
||||
assert 'desktop-v1.38.8' in manual_publish and 'args+=(--latest=false)' in manual_publish
|
||||
assert 'name: Sign artifacts (minisign)' in desktop
|
||||
PY
|
||||
[ "$(grep -Ec '^ environment: release$' "$repo_root/.github/workflows/release-stable.yml")" = "1" ]
|
||||
relay="$repo_root/.github/workflows/release-stable-trigger.yml"
|
||||
grep -Eq 'actions: write' "$relay"
|
||||
|
||||
@@ -50,6 +50,15 @@ jq -e '
|
||||
all(. as $required | ($names | index($required)) and ($names | index($required + ".minisig")))))
|
||||
' "$tmp_dir/desktop.json" >/dev/null
|
||||
|
||||
if [ "${DESKTOP_MANUAL_ONLY:-false}" = "true" ]; then
|
||||
[ "$version" = "1.38.8" ] || exit 1
|
||||
# Both updater entry points must still serve the prior signed release.
|
||||
gh api "repos/$repository/releases/latest" --jq .tag_name | grep -Fx 'desktop-v1.38.7'
|
||||
curl -fsSL https://dl.reasonix.io/latest/latest.json > "$tmp_dir/desktop-pointer.json"
|
||||
jq -e '.version == "v1.38.7"' "$tmp_dir/desktop-pointer.json" >/dev/null
|
||||
gh release view "$desktop_tag" --repo "$repository" --json body --jq .body | grep -F 'manual-download only'
|
||||
fi
|
||||
|
||||
for attempt in $(seq 1 "$attempts"); do
|
||||
latest="$(npm view reasonix dist-tags.latest 2>/dev/null || true)"
|
||||
if [ "$latest" = "$version" ]; then
|
||||
|
||||
Reference in new issue
Block a user