Skip to content
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
8382ea9
refactor(test): partition Vitest suites
GuXinghai Aug 10, 2026
ebfb444
chore(deps): refresh browserslist data
GuXinghai Aug 10, 2026
6333a44
fix(ci): evaluate optional live smoke availability
GuXinghai Aug 12, 2026
3295da2
fix(workspace): quiesce branch before destructive mutation
GuXinghai Aug 12, 2026
3729fb0
fix(openai-compatible): bound nonstream response bodies
GuXinghai Aug 12, 2026
ec05999
fix(openai-responses): skip URL images in file preflight
GuXinghai Aug 12, 2026
d65ca4a
feat(security): harden credential storage authority
GuXinghai Aug 12, 2026
0ca9918
perf(richtext): load syntax highlighting on demand
GuXinghai Aug 12, 2026
e655ad4
feat(magika): add portable managed detection plugin
GuXinghai Aug 13, 2026
a8b5be5
fix(ci): configure Electron sandbox for Magika smoke
GuXinghai Aug 13, 2026
9311d35
fix(ci): install Electron before sandbox setup
GuXinghai Aug 13, 2026
98149f1
fix(ci): run Linux Electron smoke under Xvfb
GuXinghai Aug 13, 2026
3ef3eb8
fix(ci): isolate Magika release dependencies
GuXinghai Aug 13, 2026
ed1442e
fix(build): normalize Magika package text assets
GuXinghai Aug 13, 2026
b71b48c
chore(magika): cut catalog over to v0.2.0
GuXinghai Aug 13, 2026
4525aad
fix(release): anchor Magika tag to build commit
GuXinghai Aug 13, 2026
adcc8ef
refactor(model-identity): remove legacy compatibility paths
GuXinghai Aug 13, 2026
7af717b
fix(credentials): harden safe-storage lease handling
GuXinghai Aug 13, 2026
5f2d743
ci(macos): add preliminary arm64 probe
GuXinghai Aug 13, 2026
341b5de
docs(identity): freeze provider identity decisions
GuXinghai Aug 13, 2026
0f0cad0
refactor(identity): enforce provider namespace boundaries
GuXinghai Aug 13, 2026
eccc9a2
docs(identity): record implementation closeout
GuXinghai Aug 13, 2026
92de0f8
refactor(identity): close provider boundary findings
GuXinghai Aug 14, 2026
63448e5
docs(identity): close post-audit findings
GuXinghai Aug 14, 2026
860cc34
fix(ci): stabilize accumulated branch checks
GuXinghai Aug 14, 2026
b006cb2
docs: reorganize documentation and add docs governance gate
GuXinghai Aug 14, 2026
46f0986
docs: correct current architecture entry routing
GuXinghai Aug 14, 2026
90d3cc3
test(ci): stabilize Windows integration partition
GuXinghai Aug 14, 2026
02b76f9
fix(credentials): reject cross-platform plaintext leases
GuXinghai Aug 14, 2026
8cae7d6
fix(ci): honor overridden test ownership for sources
GuXinghai Aug 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
84 changes: 82 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,25 @@ on:
branches: [main]

jobs:
changes:
name: resolve conditional test scope
runs-on: ubuntu-latest
outputs:
ui: ${{ steps.scope.outputs.ui }}
integration: ${{ steps.scope.outputs.integration }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
- id: scope
name: Classify changed paths
env:
GITHUB_BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.before }}
run: node scripts/resolve-test-ci-scope.mjs

verify-ssot:
name: verify:ssot
runs-on: ubuntu-latest
Expand Down Expand Up @@ -46,11 +65,72 @@ jobs:
name: verify-ssot-log
path: verify.log

test-ui:
name: UI partition
runs-on: ubuntu-latest
needs: changes
if: ${{ needs.changes.outputs.ui == 'true' }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm
- run: npm ci
- name: Run UI partition
run: bash -lc "npm run test:ui | tee test-ui.log"
- uses: actions/upload-artifact@v4
if: always()
with:
name: test-ui-log
path: test-ui.log

test-integration:
name: Integration partition
runs-on: windows-latest
needs: changes
if: ${{ needs.changes.outputs.integration == 'true' }}
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm
- run: npm ci
- name: Prepare Node native ABI
shell: pwsh
run: npm run test:prepare
- name: Run integration partition
shell: pwsh
run: npm run test:integration | Tee-Object -FilePath test-integration.log
- uses: actions/upload-artifact@v4
if: always()
with:
name: test-integration-log
path: test-integration.log

live-smoke-availability:
name: resolve optional live smoke availability
runs-on: ubuntu-latest
outputs:
enabled: ${{ steps.secret.outputs.enabled }}
steps:
- id: secret
name: Check optional live smoke secret
env:
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
run: |
if [ -n "$OPENROUTER_API_KEY" ]; then
echo "enabled=true" >> "$GITHUB_OUTPUT"
else
echo "enabled=false" >> "$GITHUB_OUTPUT"
fi

live-smoke:
name: tc14 live smoke (optional)
runs-on: ubuntu-latest
needs: verify-ssot
if: ${{ secrets.OPENROUTER_API_KEY != '' }}
needs: [verify-ssot, live-smoke-availability]
if: ${{ needs.verify-ssot.result == 'success' && needs.live-smoke-availability.outputs.enabled == 'true' }}
steps:
- uses: actions/checkout@v4
with:
Expand Down
80 changes: 80 additions & 0 deletions .github/workflows/macos-preliminary.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: macOS preliminary probe

on:
workflow_dispatch:

permissions:
contents: read

concurrency:
group: macos-preliminary-${{ github.ref }}
cancel-in-progress: true

jobs:
compile-and-platform-neutral-tests:
name: macOS arm64 compile and platform-neutral tests
runs-on: macos-15
timeout-minutes: 45

steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm

- name: Record runner environment
run: |
sw_vers
uname -a
node --version
npm --version

- name: Install dependencies and prepare Node native ABI
run: npm ci

- name: Verify better-sqlite3 macOS arm64 binary
run: |
file node_modules/better-sqlite3/build/Release/better_sqlite3.node
node --input-type=module -e "import Database from 'better-sqlite3'; const db = new Database(':memory:'); db.prepare('SELECT 1').get(); db.close()"

- name: Check TypeScript
run: npx tsc --noEmit --pretty false

- name: Check Vue TypeScript
run: npx vue-tsc --noEmit --pretty false

- name: Check test partition ownership
run: node scripts/check-test-partitions.mjs

- name: Run unit partition
run: npm run test:unit

- name: Run UI partition
run: npm run test:ui

- name: Run platform-neutral credential and native-boundary tests
run: >-
npx vitest --run --config vitest.integration.config.ts
electron/credentials/credentialSafeStorageBackend.test.ts
electron/credentials/openAICompatibleCredentialV2Service.test.ts
electron/data-epoch/epochNativeBoundary.test.ts

- name: Build renderer artifacts
run: npx vite build

- name: Record probe scope
if: always()
run: |
cat >> "$GITHUB_STEP_SUMMARY" <<'EOF'
## macOS preliminary probe scope

This manually triggered probe checks dependency installation, the Node native ABI,
TypeScript, Vue TypeScript, unit tests, platform-neutral credential boundaries, and
renderer compilation on a standard macOS arm64 runner.

It does not claim macOS runtime or release support. Electron startup, Epoch2 startup,
safeStorage/Keychain persistence, signing, notarization, and DMG packaging are outside
this probe because the Epoch2 runtime platform dispatcher does not yet support darwin.
EOF
142 changes: 97 additions & 45 deletions .github/workflows/release-magika-plugin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,75 +6,127 @@ on:
version:
description: Magika official plugin version to release.
required: true
default: 0.1.1
default: 0.2.0
dryRun:
description: Build and sign without creating or updating the GitHub Release.
description: Build, compare, and sign without publishing the GitHub Release.
required: true
default: 'false'
default: 'true'

permissions:
contents: write

jobs:
release:
name: Build, sign, and publish Magika plugin
runs-on: windows-latest
environment: plugin-release-production
portable-build:
name: Build and smoke (${{ matrix.runner }})
strategy:
fail-fast: false
matrix:
runner: [windows-latest, windows-11-arm, ubuntu-24.04, ubuntu-24.04-arm, macos-15-intel, macos-15]
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v4

- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
cache: npm

- run: npm ci

- name: Install release tooling dependencies
run: npm ci --ignore-scripts
- name: Validate release input
shell: pwsh
shell: bash
run: test "${{ inputs.version }}" = "0.2.0" || (echo "This workflow packages only Magika v0.2.0." && exit 1)
- name: Build deterministic any/any package
run: node scripts/dev/package-official-magika-v020.mjs
- name: Node classification smoke
run: node scripts/dev/smoke-magika-package-v020.mjs
- name: Install Electron binary for utility-process smoke
run: node node_modules/electron/install.js
- name: Configure Electron sandbox helper
if: ${{ runner.os == 'Linux' }}
shell: bash
run: |
if ("${{ inputs.version }}" -ne "0.1.1") {
throw "This workflow currently packages only Magika v0.1.1."
}
sudo chown root:root node_modules/electron/dist/chrome-sandbox
sudo chmod 4755 node_modules/electron/dist/chrome-sandbox
- name: Electron utility-process classification smoke (Linux)
if: ${{ runner.os == 'Linux' }}
run: xvfb-run -a node scripts/dev/smoke-magika-utility-process-v020.mjs
- name: Electron utility-process classification smoke
if: ${{ runner.os != 'Linux' }}
run: node scripts/dev/smoke-magika-utility-process-v020.mjs
- name: Record package hash
shell: bash
run: node -e "const fs=require('fs'),c=require('crypto');const p='.artifacts/plugin-packages/starverse-plugin-magika-0.2.0-any-any.zip';fs.writeFileSync('.artifacts/magika-sha256.txt',c.createHash('sha256').update(fs.readFileSync(p)).digest('hex')+'\n')"
- uses: actions/upload-artifact@v4
with:
name: magika-${{ inputs.version }}-${{ matrix.runner }}
path: |
.artifacts/plugin-packages/starverse-plugin-magika-0.2.0-any-any.zip
.artifacts/plugin-packages/starverse-plugin-magika-0.2.0-any-any.summary.json
.artifacts/magika-sha256.txt

- name: Build official Magika package
shell: pwsh
run: node scripts/dev/package-official-magika-v011.mjs
compare-portable-artifacts:
name: Compare portable packages
needs: portable-build
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
- uses: actions/download-artifact@v4
with:
pattern: magika-${{ inputs.version }}-*
path: .artifacts/matrix
- name: Require all six packages to be identical
shell: bash
run: node scripts/dev/verify-magika-matrix-v020.mjs .artifacts/matrix .artifacts/plugin-packages
- uses: actions/upload-artifact@v4
with:
name: magika-plugin-${{ inputs.version }}-canonical-dry-run
path: |
.artifacts/plugin-packages/starverse-plugin-magika-0.2.0-any-any.zip
.artifacts/plugin-packages/starverse-plugin-magika-0.2.0-any-any.summary.json

- name: Sign official Magika package
shell: pwsh
sign-and-publish:
name: Sign and publish canonical package
needs: compare-portable-artifacts
if: ${{ inputs.dryRun != 'true' }}
runs-on: ubuntu-24.04
environment: plugin-release-production
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: .nvmrc
- uses: actions/download-artifact@v4
with:
name: magika-plugin-${{ inputs.version }}-canonical-dry-run
path: .artifacts/plugin-packages
- name: Sign canonical package and generate release metadata
env:
STARVERSE_PLUGIN_SIGNING_PRIVATE_KEY: ${{ secrets.STARVERSE_PLUGIN_SIGNING_PRIVATE_KEY }}
STARVERSE_PLUGIN_SIGNING_KEY_ID: ${{ secrets.STARVERSE_PLUGIN_SIGNING_KEY_ID }}
run: |
$zip = ".artifacts/plugin-packages/starverse-plugin-magika-${{ inputs.version }}-win32-x64.zip"
$sig = ".artifacts/plugin-packages/signatures/starverse-plugin-magika-${{ inputs.version }}-win32-x64.sig.json"
$summary = ".artifacts/plugin-packages/starverse-plugin-magika-${{ inputs.version }}-win32-x64.release-summary.json"
node scripts/plugin-signing/sign-official-plugin-release.mjs --zip $zip --out $sig --summary-out $summary

run: >-
node scripts/plugin-signing/sign-official-plugin-release.mjs
--zip .artifacts/plugin-packages/starverse-plugin-magika-0.2.0-any-any.zip
--out .artifacts/plugin-packages/signatures/starverse-plugin-magika-0.2.0-any-any.sig.json
--summary-out .artifacts/plugin-packages/starverse-plugin-magika-0.2.0-any-any.release-summary.json
- uses: actions/upload-artifact@v4
with:
name: magika-plugin-${{ inputs.version }}-release-metadata
path: |
.artifacts/plugin-packages/starverse-plugin-magika-${{ inputs.version }}-win32-x64.summary.json
.artifacts/plugin-packages/starverse-plugin-magika-${{ inputs.version }}-win32-x64.release-summary.json
.artifacts/plugin-packages/signatures/starverse-plugin-magika-${{ inputs.version }}-win32-x64.sig.json

- name: Publish GitHub Release
if: ${{ inputs.dryRun != 'true' }}
shell: pwsh
.artifacts/plugin-packages/starverse-plugin-magika-0.2.0-any-any.summary.json
.artifacts/plugin-packages/starverse-plugin-magika-0.2.0-any-any.release-summary.json
.artifacts/plugin-packages/signatures/starverse-plugin-magika-0.2.0-any-any.sig.json
- name: Publish GitHub Release asset
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
$version = "${{ inputs.version }}"
$tag = "starverse-plugin-magika-v$version"
$zip = ".artifacts/plugin-packages/starverse-plugin-magika-$version-win32-x64.zip"
$sig = ".artifacts/plugin-packages/signatures/starverse-plugin-magika-$version-win32-x64.sig.json"
$title = "Starverse Magika official plugin v$version"
$notes = "Self-contained Magika managed runtime package for Starverse."
gh release view $tag --repo $env:GITHUB_REPOSITORY *> $null
if ($LASTEXITCODE -eq 0) {
gh release upload $tag $zip $sig --repo $env:GITHUB_REPOSITORY --clobber
} else {
gh release create $tag $zip $sig --repo $env:GITHUB_REPOSITORY --title $title --notes $notes
}
tag="starverse-plugin-magika-v${{ inputs.version }}"
zip=".artifacts/plugin-packages/starverse-plugin-magika-0.2.0-any-any.zip"
sig=".artifacts/plugin-packages/signatures/starverse-plugin-magika-0.2.0-any-any.sig.json"
if gh release view "$tag" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then
gh release upload "$tag" "$zip" "$sig" --repo "$GITHUB_REPOSITORY" --clobber
else
gh release create "$tag" "$zip" "$sig" --repo "$GITHUB_REPOSITORY" --target "$GITHUB_SHA" --title "Starverse Magika official plugin v${{ inputs.version }}" --notes "Portable pure-JavaScript any/any Magika plugin."
fi
22 changes: 18 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,18 @@ npm run dev
| `npm run electron:dev` | 重建 Electron ABI,并启动完整桌面开发环境 |
| `npm run dev` | 启动 Renderer/Vite 开发服务器 |
| `npm run build` | 类型检查、构建数据库 Worker、构建 Renderer 并调用 electron-builder |
| `npm test` | 重建 Node ABI,并运行全部 Vitest 测试 |
| `npm run test:watch` | 监听模式运行测试 |
| `npm run test:ui` | 启动 Vitest UI |
| `npm run test:coverage` | 生成测试覆盖率 |
| `npm run test:prepare` | 手动重建 Node native ABI(数据库/native 测试前按需执行) |
| `npm test` | 仅运行 unit partition(不会自动重建 ABI) |
| `npm run test:unit` | 显式运行 unit partition(与 `npm test` 相同范围) |
| `npm run test:watch` | 监听模式运行 unit partition |
| `npm run test:ui` | 运行 jsdom UI partition |
| `npm run test:integration` | 运行 integration partition |
| `npm run test:model-picker:smoke` | 按 unit/UI/integration 三阶段运行 model-picker mixed smoke |
| `npm run test:ui:slow -- path/to/one.slow.test.ts` | 一次运行一个 slow UI 文件 |
| `npm run test:integration:slow -- path/to/one.slow.test.ts` | 一次运行一个 slow integration 文件 |
| `npm run test:coverage` | 生成 unit partition 覆盖率 |
| `npm run test:runner-ui` | 启动 Vitest dashboard(不是 UI partition) |
| `node scripts/check-test-partitions.mjs` | 校验测试发现、owner、override 和 slow 规则 |
| `npm run lint` | 运行 ESLint |
| `npm run db:verify` | 使用 Node ABI 验证数据库 |
| `npm run test:electron-smoke` | 构建并运行 Electron shell smoke |
Expand All @@ -89,6 +97,12 @@ npm run rebuild:electron

如果看到 `NODE_MODULE_VERSION` 或 `better-sqlite3` native binding 错误,请为即将运行的环境重建,然后重试原命令。不要提交 `node_modules`、native binary 或仅由重建产生的锁文件变化。

测试准备是手动步骤:数据库/native Node 测试前按需执行 `npm run test:prepare`。`npm test` 保持 unit-only 且不会隐式切换 native ABI;Electron smoke 仍需在运行前明确执行 `npm run rebuild:electron`。

测试分层规则、slow 单文件约束、已删除的 `infra/db/worker.filePipeline.test.ts`
边界,以及 model-picker 的 mixed split 说明见
[`docs/maintenance/test-strategy.md`](docs/maintenance/test-strategy.md)。

## 架构概览

```text
Expand Down
2 changes: 1 addition & 1 deletion config/appCsp.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe('csp regression guards', () => {
})

it('does not reintroduce main-process CSP header injection', () => {
const mainTs = readFileSync(path.join(ROOT_DIR, 'electron', 'main.ts'), 'utf8')
const mainTs = readFileSync(path.join(ROOT_DIR, 'electron', 'mainV2.ts'), 'utf8')
expect(mainTs).not.toContain('onHeadersReceived(')
expect(mainTs).not.toContain('registerDevCspHeaders(')
})
Expand Down
Loading
Loading