feat: add independent managed SSH agent packages
Managed SSH previously tied remote Agent and Runtime artifacts to desktop packaging and Host activation. Settings now manages verified Linux x64 and arm64 .gbagent packages explicitly, with source-aligned download and update plus offline import and export. Each package contains the signed Agent, pinned Node, and compatible OpenCode Runtime, and project activation never downloads one automatically. Dedicated native CI and a protected release workflow publish deterministic, signed cumulative catalogs to GitHub and Beijing OSS without replacing the desktop Latest release. Desktop packaging is metadata-only, remains independent of Agent artifacts and signing credentials, and Linux desktop releases add RPM installers. The managed SSH path also keeps model credentials in Main, enforces Ask as read-only, verifies signed Agent and Runtime inputs, preserves ACP recovery, and reports Host update cancellation and failures accurately. Release note: 远程项目现可在“设置”中手动下载、更新或离线导入签名 Agent 包,桌面安装包与远程组件发布相互独立;Linux 桌面版同时新增 RPM 安装包。
This commit is contained in:
+13
-195
@@ -60,8 +60,8 @@ jobs:
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
authorize-agent-signing:
|
||||
name: Authorize production Agent signing
|
||||
authorize-release:
|
||||
name: Authorize desktop packaging
|
||||
if: >-
|
||||
github.ref_type == 'tag' ||
|
||||
(github.event_name == 'workflow_dispatch' && github.ref == 'refs/heads/main')
|
||||
@@ -106,194 +106,21 @@ jobs:
|
||||
test "$GITHUB_SHA" = "$(git rev-parse refs/remotes/origin/main)"
|
||||
;;
|
||||
*)
|
||||
echo "Production Agent signing is limited to immutable version-tag pushes or a manual run of refs/heads/main." >&2
|
||||
echo "Desktop packaging is limited to immutable version-tag pushes or a manual run of refs/heads/main." >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "authorized=true" >> "$GITHUB_OUTPUT"
|
||||
|
||||
agent-runtime:
|
||||
name: Acquire Linux ${{ matrix.arch }} Agent runtime
|
||||
if: >-
|
||||
needs.authorize-agent-signing.result == 'success' &&
|
||||
needs.authorize-agent-signing.outputs.authorized == 'true'
|
||||
needs:
|
||||
- validate
|
||||
- authorize-agent-signing
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: x64
|
||||
node-url: https://nodejs.org/dist/v24.19.0/node-v24.19.0-linux-x64.tar.gz
|
||||
node-archive: node-v24.19.0-linux-x64.tar.gz
|
||||
node-sha256: f625d97cd707df4ff96254916fbc5ff014f09c09effe5a1e0ca8f6d41a8789d4
|
||||
- arch: arm64
|
||||
node-url: https://nodejs.org/dist/v24.19.0/node-v24.19.0-linux-arm64.tar.gz
|
||||
node-archive: node-v24.19.0-linux-arm64.tar.gz
|
||||
node-sha256: d28c8a5bf0a808f0ed434a1dce8c54ae98f0371c0bd86ac58abc613f73e6643f
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 10
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
|
||||
- name: Verify locked Node runtime metadata
|
||||
env:
|
||||
AGENT_ARCH: ${{ matrix.arch }}
|
||||
NODE_ARCHIVE: ${{ matrix.node-archive }}
|
||||
NODE_SHA256: ${{ matrix.node-sha256 }}
|
||||
NODE_URL: ${{ matrix.node-url }}
|
||||
run: |
|
||||
node - <<'NODE'
|
||||
const lock = require('./agent-runtime-lock.json')
|
||||
const input = lock.node?.targets?.[`linux-${process.env.AGENT_ARCH}`]
|
||||
const expectedUrl = `${lock.node?.source ?? ''}${input?.archive ?? ''}`
|
||||
if (
|
||||
input?.archive !== process.env.NODE_ARCHIVE ||
|
||||
input?.sha256 !== process.env.NODE_SHA256 ||
|
||||
expectedUrl !== process.env.NODE_URL ||
|
||||
!expectedUrl.startsWith('https://')
|
||||
) {
|
||||
throw new Error('Agent runtime acquisition metadata does not match agent-runtime-lock.json')
|
||||
}
|
||||
NODE
|
||||
|
||||
- name: Restore verified Node runtime cache
|
||||
id: node-runtime-cache
|
||||
uses: actions/cache/restore@v6
|
||||
with:
|
||||
path: ${{ runner.temp }}/goodbuddy-agent-node
|
||||
key: goodbuddy-agent-node-${{ matrix.arch }}-${{ matrix.node-sha256 }}
|
||||
|
||||
- name: Download locked official Node runtime
|
||||
if: steps.node-runtime-cache.outputs.cache-hit != 'true'
|
||||
shell: bash
|
||||
env:
|
||||
NODE_ARCHIVE: ${{ matrix.node-archive }}
|
||||
NODE_URL: ${{ matrix.node-url }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
directory="$RUNNER_TEMP/goodbuddy-agent-node"
|
||||
archive="$directory/$NODE_ARCHIVE"
|
||||
mkdir -p "$directory"
|
||||
curl --proto '=https' --tlsv1.2 \
|
||||
--fail --silent --show-error --location \
|
||||
--retry 3 --retry-all-errors \
|
||||
--connect-timeout 15 --max-time 300 \
|
||||
--max-filesize 104857600 \
|
||||
"$NODE_URL" --output "$archive.partial"
|
||||
mv "$archive.partial" "$archive"
|
||||
|
||||
- name: Verify locked Node runtime digest
|
||||
shell: bash
|
||||
env:
|
||||
NODE_ARCHIVE: ${{ matrix.node-archive }}
|
||||
NODE_SHA256: ${{ matrix.node-sha256 }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
archive="$RUNNER_TEMP/goodbuddy-agent-node/$NODE_ARCHIVE"
|
||||
test -f "$archive"
|
||||
printf '%s %s\n' "$NODE_SHA256" "$archive" |
|
||||
sha256sum --check --strict -
|
||||
|
||||
- name: Save verified Node runtime cache
|
||||
if: steps.node-runtime-cache.outputs.cache-hit != 'true'
|
||||
uses: actions/cache/save@v6
|
||||
with:
|
||||
path: ${{ runner.temp }}/goodbuddy-agent-node
|
||||
key: goodbuddy-agent-node-${{ matrix.arch }}-${{ matrix.node-sha256 }}
|
||||
|
||||
- name: Upload verified Node runtime input
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: goodbuddy-agent-node-${{ matrix.arch }}
|
||||
path: ${{ runner.temp }}/goodbuddy-agent-node/${{ matrix.node-archive }}
|
||||
if-no-files-found: error
|
||||
compression-level: 0
|
||||
retention-days: 1
|
||||
|
||||
agent-signing:
|
||||
name: Linux ${{ matrix.arch }} signed Agent bundle
|
||||
if: >-
|
||||
needs.authorize-agent-signing.result == 'success' &&
|
||||
needs.authorize-agent-signing.outputs.authorized == 'true'
|
||||
needs:
|
||||
- validate
|
||||
- authorize-agent-signing
|
||||
- agent-runtime
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- arch: x64
|
||||
runner: ubuntu-24.04
|
||||
node-archive: node-v24.19.0-linux-x64.tar.gz
|
||||
node-sha256: f625d97cd707df4ff96254916fbc5ff014f09c09effe5a1e0ca8f6d41a8789d4
|
||||
- arch: arm64
|
||||
runner: ubuntu-24.04-arm
|
||||
node-archive: node-v24.19.0-linux-arm64.tar.gz
|
||||
node-sha256: d28c8a5bf0a808f0ed434a1dce8c54ae98f0371c0bd86ac58abc613f73e6643f
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 20
|
||||
environment:
|
||||
name: agent-signing
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 24.19.0
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Preflight production Agent signing registry
|
||||
env:
|
||||
GOODBUDDY_AGENT_SIGNING_KEY_ID: ${{ vars.GOODBUDDY_AGENT_SIGNING_KEY_ID }}
|
||||
run: node build/agent-bundle.cjs preflight
|
||||
|
||||
- name: Download verified official Node runtime input
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
name: goodbuddy-agent-node-${{ matrix.arch }}
|
||||
path: ${{ runner.temp }}/goodbuddy-agent-node
|
||||
|
||||
- name: Build and sign Agent bundle
|
||||
shell: bash
|
||||
env:
|
||||
GOODBUDDY_AGENT_SIGNING_KEY_ID: ${{ vars.GOODBUDDY_AGENT_SIGNING_KEY_ID }}
|
||||
GOODBUDDY_AGENT_SIGNING_PRIVATE_KEY: ${{ secrets.GOODBUDDY_AGENT_SIGNING_PRIVATE_KEY }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
set +x
|
||||
node build/agent-bundle.cjs build \
|
||||
--arch "${{ matrix.arch }}" \
|
||||
--runtime-archive "$RUNNER_TEMP/goodbuddy-agent-node/${{ matrix.node-archive }}" \
|
||||
--archive "dist/agent-bundles/goodbuddy-agent-linux-${{ matrix.arch }}.tar"
|
||||
|
||||
- name: Upload signed Agent bundle
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: goodbuddy-agent-linux-${{ matrix.arch }}
|
||||
path: dist/agent-bundles/goodbuddy-agent-linux-${{ matrix.arch }}.tar
|
||||
if-no-files-found: error
|
||||
compression-level: 0
|
||||
retention-days: 1
|
||||
|
||||
package:
|
||||
name: ${{ matrix.platform }} ${{ matrix.arch }}
|
||||
if: >-
|
||||
needs.authorize-agent-signing.result == 'success' &&
|
||||
needs.authorize-agent-signing.outputs.authorized == 'true'
|
||||
needs.authorize-release.result == 'success' &&
|
||||
needs.authorize-release.outputs.authorized == 'true'
|
||||
needs:
|
||||
- validate
|
||||
- authorize-agent-signing
|
||||
- agent-signing
|
||||
- authorize-release
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
@@ -347,23 +174,14 @@ jobs:
|
||||
name: goodbuddy-production-bundle
|
||||
path: out
|
||||
|
||||
- name: Download signed Agent bundles
|
||||
uses: actions/download-artifact@v8
|
||||
with:
|
||||
pattern: goodbuddy-agent-linux-*
|
||||
path: dist/agent-downloads
|
||||
merge-multiple: true
|
||||
|
||||
- name: Import and verify both Agent bundles
|
||||
- name: Install RPM packaging tools
|
||||
if: matrix.platform == 'linux'
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
node build/agent-bundle.cjs import \
|
||||
--arch x64 \
|
||||
--archive dist/agent-downloads/goodbuddy-agent-linux-x64.tar
|
||||
node build/agent-bundle.cjs import \
|
||||
--arch arm64 \
|
||||
--archive dist/agent-downloads/goodbuddy-agent-linux-arm64.tar
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends --yes rpm
|
||||
rpmbuild --version
|
||||
|
||||
- name: Resolve macOS signing mode
|
||||
id: macos-signing
|
||||
@@ -482,9 +300,9 @@ jobs:
|
||||
if: >-
|
||||
github.event_name == 'push' &&
|
||||
github.ref_type == 'tag' &&
|
||||
needs.authorize-agent-signing.outputs.authorized == 'true'
|
||||
needs.authorize-release.outputs.authorized == 'true'
|
||||
needs:
|
||||
- authorize-agent-signing
|
||||
- authorize-release
|
||||
- package
|
||||
runs-on: ubuntu-24.04
|
||||
timeout-minutes: 35
|
||||
|
||||
Reference in New Issue
Block a user