Merge branch 'main' into ci/self-hosted-runner-signing
This commit is contained in:
241 files changed
+7211
-5170
No files matched your search
+18
-13
@@ -4,29 +4,25 @@ on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
# A release-please pull request only rewrites these three files, and its pull_request run would
|
||||
# be created in action_required and never execute: GITHUB_TOKEN may not start workflows, so
|
||||
# anything it triggers waits for a human. Skipping it here keeps an unapprovable run out of the
|
||||
# checks list. The release workflow dispatches this workflow on the release branch instead,
|
||||
# which is the one trigger GITHUB_TOKEN is allowed to fire, so the version bump still gets a
|
||||
# full build and the checks land on the same commit.
|
||||
paths-ignore:
|
||||
- version.txt
|
||||
- CHANGELOG.md
|
||||
- .release-please-manifest.json
|
||||
workflow_dispatch:
|
||||
|
||||
merge_group:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: ci-${{ github.event.pull_request.head.ref || github.ref_name }}
|
||||
group: ci-${{ github.event_name }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
quality:
|
||||
uses: ./.github/workflows/quality.yml
|
||||
|
||||
lock:
|
||||
name: Product inputs
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
# The dictionary validator is compared against the engine's copy of it, so this job needs the
|
||||
# submodule's contents and not just its gitlink.
|
||||
@@ -37,6 +33,10 @@ jobs:
|
||||
run: python3 scripts/check-dictionary-contract.py
|
||||
- name: Test rejection of changed or mismatched inputs
|
||||
run: python3 -m unittest discover -s tests -p 'test_product_lock.py'
|
||||
- name: Test local environment setup in a moved checkout
|
||||
run: python3 -m unittest discover -s tests -p 'test_prepare_env.py'
|
||||
- name: Test the automatic release CI gate
|
||||
run: python3 -m unittest discover -s tests -p 'test_release_pr_ci.py'
|
||||
- name: Read the reviewed lock
|
||||
id: lock
|
||||
run: |
|
||||
@@ -46,6 +46,7 @@ jobs:
|
||||
windows:
|
||||
name: Windows ${{ matrix.name }}
|
||||
runs-on: windows-2025
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -86,7 +87,7 @@ jobs:
|
||||
shell: pwsh
|
||||
run: cmake --build windows/build --config Release --parallel
|
||||
- name: Test the wire contract on this architecture
|
||||
run: ctest --test-dir windows/build -C Release --output-on-failure
|
||||
run: ctest --no-tests=error --test-dir windows/build -C Release --output-on-failure
|
||||
|
||||
# Architecture-independent, so it runs once rather than on both matrix legs.
|
||||
- name: Check the installer language file lands where ISCC looks
|
||||
@@ -157,7 +158,7 @@ jobs:
|
||||
run: cmake --build ui/build --config Release --parallel
|
||||
- name: Test
|
||||
shell: pwsh
|
||||
run: ctest --test-dir ui/build -C Release --verbose --timeout 60
|
||||
run: ctest --no-tests=error --test-dir ui/build -C Release --verbose --timeout 60
|
||||
|
||||
pages:
|
||||
name: Settings page
|
||||
@@ -213,3 +214,7 @@ jobs:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
- name: Test full and light package contents without registering or installing
|
||||
run: ./installer/tests/package-files.ps1
|
||||
- name: Stop local packaging after failed component builds
|
||||
run: ./installer/tests/build-failures.ps1
|
||||
- name: Test local Server test entrypoints in a moved checkout
|
||||
run: ./tests/server-test-entrypoints.ps1
|
||||
@@ -0,0 +1,37 @@
|
||||
name: CodeQL
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
pull_request:
|
||||
schedule:
|
||||
- cron: '11 3 * * 1'
|
||||
workflow_dispatch:
|
||||
permissions:
|
||||
contents: read
|
||||
concurrency:
|
||||
group: codeql-${{ github.event_name }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
jobs:
|
||||
analyze:
|
||||
name: CodeQL / ${{ matrix.language }}
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
language: [actions, c-cpp, javascript-typescript, python]
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# C/C++ source analysis complements, rather than replaces, native build CI.
|
||||
build-mode: none
|
||||
- uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4
|
||||
with:
|
||||
category: '/language:${{ matrix.language }}'
|
||||
@@ -12,16 +12,21 @@ on:
|
||||
paths:
|
||||
- 'vendor/MetasequoiaImeEngine'
|
||||
|
||||
# Read-only by default, matching every other workflow here. The write scopes this job needs to merge
|
||||
# the bump are granted on the job instead, so a second job added later starts from the same floor
|
||||
# rather than inheriting write.
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
triage:
|
||||
if: github.actor == 'dependabot[bot]'
|
||||
name: Classify the engine range
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
env:
|
||||
SUBMODULE: vendor/MetasequoiaImeEngine
|
||||
ENGINE: metasequoiaime/MSIME-Engine
|
||||
@@ -36,9 +41,11 @@ jobs:
|
||||
|
||||
- name: Resolve the engine range
|
||||
id: range
|
||||
env:
|
||||
BASE_REF: ${{ github.base_ref }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
base=$(git rev-parse "origin/${{ github.base_ref }}:$SUBMODULE")
|
||||
base=$(git rev-parse "origin/$BASE_REF:$SUBMODULE")
|
||||
head=$(git rev-parse "HEAD:$SUBMODULE")
|
||||
echo "base=$base" >> "$GITHUB_OUTPUT"
|
||||
echo "head=$head" >> "$GITHUB_OUTPUT"
|
||||
@@ -46,17 +53,47 @@ jobs:
|
||||
|
||||
- name: Classify the changed files
|
||||
id: classify
|
||||
env:
|
||||
BASE: ${{ steps.range.outputs.base }}
|
||||
HEAD: ${{ steps.range.outputs.head }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
base='${{ steps.range.outputs.base }}'
|
||||
head='${{ steps.range.outputs.head }}'
|
||||
base="$BASE"
|
||||
head="$HEAD"
|
||||
if [ "$base" = "$head" ]; then
|
||||
echo "verdict=inert" >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Fail closed on anything but a plain fast-forward. The compare API answers with an empty
|
||||
# file list whenever head is already an ancestor of base, which the emptiness test below
|
||||
# would otherwise read as "nothing suspicious changed" and auto-merge — silently accepting
|
||||
# a downgrade that reverts engine source the frontend depends on.
|
||||
status=$(gh api "repos/$ENGINE/compare/$base...$head" --jq '.status')
|
||||
echo "compare status: $status"
|
||||
if [ "$status" != "ahead" ]; then
|
||||
echo "verdict=review" >> "$GITHUB_OUTPUT"
|
||||
delimiter="EOF_$(openssl rand -hex 16)"
|
||||
{
|
||||
echo "reason<<$delimiter"
|
||||
echo "引擎范围不是单纯的快进(compare status: $status),需要人工确认。"
|
||||
echo "$delimiter"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
files=$(gh api --paginate "repos/$ENGINE/compare/$base...$head" --jq '.files[].filename')
|
||||
echo "改动文件:"; echo "$files" | sed 's/^/ /'
|
||||
if [ -z "$files" ]; then
|
||||
echo "verdict=review" >> "$GITHUB_OUTPUT"
|
||||
delimiter="EOF_$(openssl rand -hex 16)"
|
||||
{
|
||||
echo "reason<<$delimiter"
|
||||
echo "compare 没有返回任何文件,无法判定这次 bump 是否安全。"
|
||||
echo "$delimiter"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Provably inert: documentation, CI wiring, dependency manifests, licence text. Everything
|
||||
# else - sources, build files, and bare paths such as a nested submodule pointer - needs a
|
||||
@@ -68,10 +105,13 @@ jobs:
|
||||
echo "verdict=inert" >> "$GITHUB_OUTPUT"
|
||||
else
|
||||
echo "verdict=review" >> "$GITHUB_OUTPUT"
|
||||
# A random delimiter: the file names come from another repository, so a path that
|
||||
# happened to be the literal delimiter could otherwise close the block early.
|
||||
delimiter="EOF_$(openssl rand -hex 16)"
|
||||
{
|
||||
echo 'reason<<EOF'
|
||||
echo "reason<<$delimiter"
|
||||
echo "$suspicious"
|
||||
echo EOF
|
||||
echo "$delimiter"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
fi
|
||||
|
||||
@@ -90,18 +130,33 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Enable auto-merge
|
||||
if: steps.classify.outputs.verdict == 'inert' && steps.lock.outputs.locked == 'yes'
|
||||
if: steps.classify.outputs.verdict == 'inert'
|
||||
env:
|
||||
BASE: ${{ steps.range.outputs.base }}
|
||||
HEAD: ${{ steps.range.outputs.head }} && steps.lock.outputs.locked == 'yes'
|
||||
run: |
|
||||
set -euo pipefail
|
||||
gh pr merge --auto --squash "$PR_URL"
|
||||
gh pr comment "$PR_URL" --body "引擎 \`${{ steps.range.outputs.base }}\` → \`${{ steps.range.outputs.head }}\` 的改动全部落在文档、CI 配置和依赖清单里,没有源码、构建文件或嵌套 submodule 指针。已开启自动合并,CI 通过后自行合入。"
|
||||
body="$RUNNER_TEMP/engine-bump-comment.md"
|
||||
printf '引擎 `%s` → `%s` 的改动全部落在文档、CI 配置和依赖清单里,没有源码、构建文件或嵌套 submodule 指针。已开启自动合并,CI 通过后自行合入。\n' "$BASE" "$HEAD" > "$body"
|
||||
gh pr comment "$PR_URL" --body-file "$body"
|
||||
|
||||
# Every value below reaches the shell through the environment, never through ${{ }}
|
||||
# interpolation. REASON is a list of file names from another repository: spliced into the
|
||||
# command text, a path containing a single quote would have closed the quoting and run as a
|
||||
# command, on a runner holding a contents:write token for this repository.
|
||||
- name: Hold for review
|
||||
if: steps.classify.outputs.verdict == 'review'
|
||||
env:
|
||||
BASE: ${{ steps.range.outputs.base }}
|
||||
HEAD: ${{ steps.range.outputs.head }}
|
||||
REASON: ${{ steps.classify.outputs.reason }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
gh pr edit "$PR_URL" --add-label "needs-review" || true
|
||||
gh pr comment "$PR_URL" --body "$(printf '引擎 `%s` → `%s` 的改动里有需要人看一眼的部分,未开启自动合并:\n\n```\n%s\n```\n\n源码、`CMakeLists.txt` 或嵌套 submodule 指针的变化都可能改变行为,而前端 CI 未必覆盖得到——`helpcode_enabled()` 与 `handle_character()` 的语义变更就是这样漏过去的。' '${{ steps.range.outputs.base }}' '${{ steps.range.outputs.head }}' '${{ steps.classify.outputs.reason }}')"
|
||||
body="$RUNNER_TEMP/engine-bump-comment.md"
|
||||
printf '引擎 `%s` → `%s` 的改动里有需要人看一眼的部分,未开启自动合并:\n\n```\n%s\n```\n\n源码、`CMakeLists.txt` 或嵌套 submodule 指针的变化都可能改变行为,而前端 CI 未必覆盖得到——`helpcode_enabled()` 与 `handle_character()` 的语义变更就是这样漏过去的。\n' "$BASE" "$HEAD" "$REASON" > "$body"
|
||||
gh pr comment "$PR_URL" --body-file "$body"
|
||||
|
||||
- name: Ask for the lock to follow
|
||||
if: steps.lock.outputs.locked == 'no'
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
name: Repository quality
|
||||
# Called by CI so release-please's workflow_dispatch receives these checks too.
|
||||
on:
|
||||
workflow_call:
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
workflows:
|
||||
name: Workflow validation
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6
|
||||
with:
|
||||
go-version: '1.26'
|
||||
cache: false
|
||||
- name: Install actionlint
|
||||
run: go install github.com/rhysd/actionlint/cmd/actionlint@v1.7.12
|
||||
- name: Validate workflows and embedded shell scripts
|
||||
env:
|
||||
# Ignore style suggestions, but fail on shell correctness warnings and errors.
|
||||
SHELLCHECK_OPTS: --severity=warning
|
||||
run: actionlint -color
|
||||
# Part of "Workflow validation" rather than a job of its own: it is a two-second grep, and this
|
||||
# job is already a required check, so the guard starts protecting main immediately.
|
||||
- name: Reject developer-specific paths in build inputs
|
||||
run: bash scripts/ci/check-developer-paths.sh
|
||||
# Formatting is platform independent, so it runs here on Ubuntu rather than costing a Windows
|
||||
# runner. Cheap and early: a formatting slip fails in seconds instead of after the full compile.
|
||||
- name: Check formatting
|
||||
run: scripts/format.sh --check
|
||||
dependencies:
|
||||
name: Dependency review
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
# This job must not skip. It is one of main's required status checks, and a required check that reports "skipped" blocks a merge instead of passing it. Guarding it on the pull_request event left the release pull request unmergeable by its own automation: ci.yml ignores that pull request by path and the release workflow dispatches ci.yml on the release branch instead, so this job saw workflow_dispatch and skipped, and land-release-pr.sh got "the base branch policy prohibits the merge" after everything else came back green.
|
||||
#
|
||||
# A pull_request event supplies both refs on its own. Every other trigger has to be told what to compare, and comparing the default branch against the checked-out commit is the same question the pull request asks.
|
||||
- uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4
|
||||
with:
|
||||
fail-on-severity: high
|
||||
base-ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.base.sha || github.event.repository.default_branch }}
|
||||
head-ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
|
||||
@@ -1,10 +1,12 @@
|
||||
name: Release
|
||||
|
||||
# Building and publishing only ever happens on workflow_dispatch. The code signing certificate
|
||||
# has a limited number of signatures, so a release costs something real and is not something a merge
|
||||
# to main should spend on its own. The push trigger only keeps release-please's pull request current
|
||||
# and green; merging that pull request creates the draft, and dispatching this workflow against the
|
||||
# draft's tag is what builds, signs and publishes it.
|
||||
# Releasing is automatic. A push to main that carries a fix or a feat ends with a published installer, without anybody merging or dispatching anything: this workflow refreshes release-please's pull request, tests it, merges it, turns the merge into a draft release, then builds, signs and publishes that draft.
|
||||
#
|
||||
# The whole cycle runs inside the one run that the original push started. land-release-pr.sh merges with GITHUB_TOKEN, whose pushes do not start workflow runs, so the merge cannot produce a second Release run queued behind this one on the concurrency group.
|
||||
#
|
||||
# This spends a code signing signature on every releasable merge to main. The certificate allows 3000 signatures a month, so the quota is not what constrains this; what it spends is release hygiene -- see docs/product-release.md.
|
||||
#
|
||||
# workflow_dispatch stays, and is now a repair path rather than the normal one. It builds an existing draft, which is what a run that failed after creating the draft leaves behind.
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
@@ -27,38 +29,83 @@ jobs:
|
||||
prepare:
|
||||
name: Prepare release metadata
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
# actions: write lets check-release-pr.sh dispatch ci.yml on the release branch, which is the
|
||||
# only trigger GITHUB_TOKEN is allowed to fire.
|
||||
actions: write
|
||||
# Read the PR-triggered run; merging stays scoped to GITHUB_TOKEN.
|
||||
actions: read
|
||||
contents: write
|
||||
pull-requests: write
|
||||
outputs:
|
||||
# Never true on push: see the comment above the triggers. release-please still creates the
|
||||
# draft release there, it just does not get built until somebody asks for it.
|
||||
should_publish: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
tag_name: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || steps.release.outputs.tag_name }}
|
||||
version: ${{ github.event_name == 'workflow_dispatch' && steps.requested_release.outputs.version || steps.release.outputs.version }}
|
||||
target_sha: ${{ github.event_name == 'workflow_dispatch' && steps.requested_release.outputs.target_sha || steps.release.outputs.sha }}
|
||||
should_publish: ${{ github.event_name == 'workflow_dispatch' || steps.target.outputs.release_created == 'true' }}
|
||||
tag_name: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || steps.target.outputs.tag_name }}
|
||||
version: ${{ github.event_name == 'workflow_dispatch' && steps.requested_release.outputs.version || steps.target.outputs.version }}
|
||||
target_sha: ${{ github.event_name == 'workflow_dispatch' && steps.requested_release.outputs.target_sha || steps.target.outputs.target_sha }}
|
||||
steps:
|
||||
- name: Check out release automation
|
||||
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Prepare release
|
||||
# Separate release metadata from PR updates to preserve release-please ordering.
|
||||
# Recover an already-merged release before calculating the next PR, matching release-please's
|
||||
# normal releases-then-pull-requests ordering.
|
||||
- name: Require the release metadata credential
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
id: release
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN }}
|
||||
run: |
|
||||
if [[ -z "$RELEASE_TOKEN" ]]; then
|
||||
echo '::error::RELEASE_PLEASE_TOKEN must allow contents and workflows writes to create release tags.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Recover releases from previously merged pull requests
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
id: release_pr
|
||||
uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
|
||||
skip-github-pull-request: true
|
||||
|
||||
- name: Test the release pull request
|
||||
- name: Refresh the release pull request
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
id: release_update
|
||||
uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5
|
||||
with:
|
||||
# A trusted credential starts normal PR checks without manual workflow approval.
|
||||
token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
|
||||
skip-github-release: true
|
||||
|
||||
- name: Test and merge the release pull request
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
GH_REPO: ${{ github.repository }}
|
||||
run: bash scripts/ci/check-release-pr.sh
|
||||
run: bash scripts/ci/land-release-pr.sh
|
||||
|
||||
- name: Create the release for the merged pull request
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
id: release
|
||||
uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5
|
||||
with:
|
||||
# Creating a tag at a historical workflow-changing commit needs workflows:write.
|
||||
# Only GITHUB_TOKEN merges to main, preventing a second Release run.
|
||||
token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
|
||||
skip-github-pull-request: true
|
||||
|
||||
- name: Resolve the release this run publishes
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
id: target
|
||||
env:
|
||||
FIRST_CREATED: ${{ steps.release_pr.outputs.release_created }}
|
||||
FIRST_TAG: ${{ steps.release_pr.outputs.tag_name }}
|
||||
FIRST_VERSION: ${{ steps.release_pr.outputs.version }}
|
||||
FIRST_SHA: ${{ steps.release_pr.outputs.sha }}
|
||||
SECOND_CREATED: ${{ steps.release.outputs.release_created }}
|
||||
SECOND_TAG: ${{ steps.release.outputs.tag_name }}
|
||||
SECOND_VERSION: ${{ steps.release.outputs.version }}
|
||||
SECOND_SHA: ${{ steps.release.outputs.sha }}
|
||||
run: bash scripts/ci/resolve-auto-release.sh
|
||||
|
||||
- name: Validate requested draft release
|
||||
if: ${{ github.event_name == 'workflow_dispatch' }}
|
||||
@@ -74,6 +121,7 @@ jobs:
|
||||
needs: prepare
|
||||
if: ${{ needs.prepare.outputs.should_publish == 'true' }}
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 60
|
||||
outputs:
|
||||
dictionary_tag: ${{ steps.lock.outputs.dictionary_tag }}
|
||||
steps:
|
||||
@@ -264,6 +312,11 @@ jobs:
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
contents: write
|
||||
# Build provenance. Unlike Authenticode this costs nothing and needs no certificate, and the
|
||||
# Sigstore transparency log it writes to is outside this organisation's control, so it is the
|
||||
# one integrity signal a repository admin cannot forge by swapping a release asset.
|
||||
id-token: write
|
||||
attestations: write
|
||||
env:
|
||||
DICTIONARY_TAG: ${{ needs.dependencies.outputs.dictionary_tag }}
|
||||
# download-dictionaries.sh stages MetasequoiaImeDict/out under this root, and
|
||||
@@ -391,6 +444,11 @@ jobs:
|
||||
installer/app_data/product-manifest.json
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Attest the installer's build provenance
|
||||
uses: actions/attest-build-provenance@4d101475d8b20a2381f78447822ac1eab6504dd8 # v4.2.2
|
||||
with:
|
||||
subject-path: ${{ steps.asset.outputs.asset_path }}
|
||||
|
||||
- name: Revalidate the draft release target
|
||||
shell: bash
|
||||
env:
|
||||
@@ -411,4 +469,25 @@ jobs:
|
||||
ASSET_SHA256: ${{ steps.asset.outputs.asset_sha256 }}
|
||||
SIGNING_ENABLED: ${{ steps.signing.outputs.signing_enabled }}
|
||||
PRODUCT_MANIFEST: installer/app_data/product-manifest.json
|
||||
RELEASE_TRIGGER: ${{ github.event_name }}
|
||||
run: bash scripts/ci/publish-release.sh
|
||||
|
||||
# msime.app/update.json is what the settings page's "检查更新" reads, and MSIME-Web only
|
||||
# regenerated it from a */30 cron. Scheduled events on public repositories are delayed heavily
|
||||
# -- measured runs sat roughly two hours apart -- so the site advertised an old version for
|
||||
# hours after every release. MSIME-Web already declares a repository_dispatch trigger for
|
||||
# exactly this and nothing was ever sending it.
|
||||
#
|
||||
# This runs after publishing on purpose. If the dispatch fails the release is already out and
|
||||
# correct; what the failure means is that the website is now stale and someone has to act, so
|
||||
# it is reported as a failure rather than swallowed.
|
||||
- name: Refresh the download manifest on msime.app
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.RELEASE_PLEASE_TOKEN }}
|
||||
run: |
|
||||
if [[ -z "$GH_TOKEN" ]]; then
|
||||
echo '::error::RELEASE_PLEASE_TOKEN is required to notify MSIME-Web; msime.app/update.json will stay on the previous version until its cron catches up.'
|
||||
exit 1
|
||||
fi
|
||||
gh api --method POST repos/metasequoiaime/MSIME-Web/dispatches -f event_type=update-manifest
|
||||
Reference in new issue
Block a user