Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
374 changes: 370 additions & 4 deletions .github/workflows/build.yml

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,12 @@ jobs:

# 三平台各自独立调用同一个可复用工作流,互不阻塞。
# 拆成三个 job(而非一个 matrix)是为了让 snap 只等待 Linux,而不是等整组矩阵完成。
# secrets: inherit 让签名密钥 SIGNATURE_KEYS 透传给可复用工作流。
build-linux:
name: Build linux-x64
needs: meta
uses: ./.github/workflows/build.yml
secrets: inherit
with:
os: ubuntu-24.04
platform: linux
Expand All @@ -93,6 +95,7 @@ jobs:
name: Build win32-x64
needs: meta
uses: ./.github/workflows/build.yml
secrets: inherit
with:
os: windows-2025
platform: win32
Expand All @@ -103,6 +106,7 @@ jobs:
name: Build darwin-arm64
needs: meta
uses: ./.github/workflows/build.yml
secrets: inherit
with:
os: macos-26
platform: darwin
Expand Down
20 changes: 19 additions & 1 deletion build/darwin/sign.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,10 +79,23 @@ export async function retryOnTransientSignError<T>(fn: () => Promise<T>, maxAtte
}
}

/**
* `security find-identity` appends trust-evaluation diagnostics such as
* `(CSSMERR_TP_NOT_TRUSTED)` to an identity's display name. If such a name is
* passed to `codesign --sign`, codesign looks for the whole string and fails
* with "no identity found", so strip the suffix before signing.
*/
export function normalizeSigningIdentity(identity: string | undefined): string | undefined {
return identity?.replace(/\s*\(CSSMERR_[A-Z0-9_]+\)\s*$/, '');
}

async function main(buildDir?: string): Promise<void> {
const tempDir = process.env['AGENT_TEMPDIRECTORY'];
const arch = process.env['VSCODE_ARCH'];
const identity = process.env['CODESIGN_IDENTITY'];
const identity = normalizeSigningIdentity(process.env['CODESIGN_IDENTITY']);
// Apple 的时间戳服务不保证支持非 Apple 签发的身份,使用自签名/私有 CA 证书时
// 工作流会传 `none` 显式关闭时间戳;未设置时沿用 osx-sign 的默认行为。
const timestamp = process.env['CODESIGN_TIMESTAMP'];

if (!buildDir) {
throw new Error('$AGENT_BUILDDIRECTORY not set');
Expand All @@ -106,12 +119,17 @@ async function main(buildDir?: string): Promise<void> {
optionsForFile: (filePath) => ({
entitlements: getEntitlementsForFile(filePath),
hardenedRuntime: true,
timestamp,
}),
preAutoEntitlements: false,
preEmbedProvisioningProfile: false,
keychain: getKeychainPath(tempDir),
version: getElectronVersion(),
identity,
// 工作流的“Prepare signing certificate”步骤已经校验过证书链并确认身份可用,
// 且 CODESIGN_IDENTITY 传的是证书 SHA-1 指纹。这里跳过 osx-sign 自己的
// find-identity 名称匹配,避免展示名与指纹的格式差异再次导致身份匹配失败。
identityValidation: false,
};

// Only overwrite plist entries for x64 and arm64 builds,
Expand Down
3 changes: 2 additions & 1 deletion build/lib/download.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ export async function download(url: string, options: IDownloadOptions = {}): Pro
lastError = error instanceof Error ? error : new Error(String(error));
if (attempt < attempts) {
options.onRetry?.(lastError);
await new Promise(resolve => setTimeout(resolve, retryDelay));
// 指数退避:1x, 2x, 4x ... 避免连续打同一个源
await new Promise(resolve => setTimeout(resolve, retryDelay * 2 ** (attempt - 1)));
}
}
}
Expand Down
26 changes: 25 additions & 1 deletion build/lib/test/darwinSign.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

import assert from 'node:assert/strict';
import { suite, test } from 'node:test';
import { retryOnTransientSignError } from '../../darwin/sign.ts';
import { normalizeSigningIdentity, retryOnTransientSignError } from '../../darwin/sign.ts';

function codesignError(stderr: string): Error {
return new Error(`Command failed: codesign --sign ABC --force --timestamp --options runtime locale.pak\nlocale.pak: ${stderr}`);
Expand Down Expand Up @@ -47,3 +47,27 @@ suite('darwin sign', () => {
assert.deepStrictEqual(await sign([timestampError, timestampError, timestampError], 3), { attempts: 3, error: 'locale.pak: A timestamp was expected but was not found.' });
});
});

suite('normalize signing identity', () => {
test('strips trust diagnostics appended by find-identity', () => {
assert.strictEqual(
normalizeSigningIdentity('ZIT Studio BlockIDE Code Signing (CSSMERR_TP_NOT_TRUSTED)'),
'ZIT Studio BlockIDE Code Signing');
assert.strictEqual(
normalizeSigningIdentity('ZIT Studio BlockIDE Code Signing (CSSMERR_TP_CERT_EXPIRED)'),
'ZIT Studio BlockIDE Code Signing');
});

test('keeps names and hashes that have no diagnostics', () => {
assert.strictEqual(
normalizeSigningIdentity('ZIT Studio BlockIDE Code Signing'),
'ZIT Studio BlockIDE Code Signing');
assert.strictEqual(
normalizeSigningIdentity('C7D5DE396508C18020A30E6C4E41764B97EA0490'),
'C7D5DE396508C18020A30E6C4E41764B97EA0490');
});

test('preserves undefined', () => {
assert.strictEqual(normalizeSigningIdentity(undefined), undefined);
});
});
31 changes: 29 additions & 2 deletions build/npm/electronTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,35 @@ export async function ensureElectronTypes(): Promise<void> {
}

const { electronVersion } = getElectronVersion();
const url = `https://github.com/electron/electron/releases/download/v${electronVersion}/electron.d.ts`;
const contents = await download(url, { checksumSha256: expectedChecksum });

// GitHub Releases 偶发 504,依次尝试多个镜像;所有镜像都会校验 SHA-256,
// 与 build/checksums/electron.txt 比对,保证内容一致。
const urls = [
`https://github.com/electron/electron/releases/download/v${electronVersion}/electron.d.ts`,
`https://registry.npmmirror.com/-/binary/electron/v${electronVersion}/electron.d.ts`,
`https://npmmirror.com/mirrors/electron/v${electronVersion}/electron.d.ts`
];

let contents: Uint8Array | undefined;
let lastError: Error | undefined;
for (const url of urls) {
try {
contents = await download(url, {
checksumSha256: expectedChecksum,
attempts: 3,
retryDelay: 2000,
timeout: 60_000,
onRetry: error => console.warn(`Retrying ${url}: ${error.message}`)
});
break;
} catch (error) {
lastError = error instanceof Error ? error : new Error(String(error));
console.warn(`Mirror failed, trying next: ${url}`);
}
}
if (!contents) {
throw lastError ?? new Error('Failed to download electron.d.ts from all mirrors');
}

fs.mkdirSync(path.dirname(electronTypesPath), { recursive: true });
fs.writeFileSync(electronTypesPath, contents);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"test-node": "mocha test/unit/node/index.js --delay --ui=tdd --exit",
"test-extension": "vscode-test",
"test-build-scripts": "cd build && npm run test",
"test-agent-host-e2e": "node test/integration/agentHost/runner.ts",
"test-agent-host-e2e": "node te st/integration/agentHost/runner.ts",
"markdown-editor-package-json-check": "npm --prefix extensions/markdown-language-features run check-markdown-editor-package-json",
"test-agent-host-e2e-coverage": "node test/integration/agentHost/coverage.ts",
"check-cyclic-dependencies": "node build/lib/checkCyclicDependencies.ts out",
Expand Down
Loading