Repository navigation
fix: restore v5.4.11 release consistency #60
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | |
| on: | |
| pull_request: | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| node: | |
| name: Node 22 full suite | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| with: | |
| fetch-depth: 0 | |
| - name: Install zsh for macOS shell contract tests | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install --no-install-recommends -y zsh | |
| test -x /bin/zsh | |
| /bin/zsh -c '[[ $ZSH_VERSION == 5.9 ]]' | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 | |
| with: | |
| node-version: "22.22.3" | |
| cache: npm | |
| - run: npm ci | |
| - run: npm test | |
| - run: node scripts/check-asset-provenance.mjs --check | |
| - name: Require a clean worktree | |
| if: always() | |
| run: test -z "$(git status --porcelain)" | |
| macos: | |
| name: macOS lifecycle and launchd | |
| runs-on: macos-15 | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 | |
| with: | |
| node-version: "22.22.3" | |
| cache: npm | |
| - run: npm ci | |
| - name: Rebuild the exact tracked candidate on macOS | |
| run: | | |
| node scripts/package-skill.mjs --output "$RUNNER_TEMP/macos.skill" --source-date-epoch 1704067200 | |
| cmp "$RUNNER_TEMP/macos.skill" output/heige-codex-skin-studio.skill | |
| shasum -a 256 "$RUNNER_TEMP/macos.skill" | |
| - name: Run macOS unit tests | |
| run: >- | |
| node --test | |
| test/codex-app.test.mjs | |
| test/controller.test.mjs | |
| test/macos-launch-agent.test.mjs | |
| test/scripts.test.mjs | |
| test/state-store.test.mjs | |
| - name: Parse every zsh entrypoint | |
| run: | | |
| for file in scripts/*.command scripts/lib/*.zsh; do | |
| /bin/zsh -n "$file" | |
| done | |
| - name: Run isolated random-label launchd integration | |
| env: | |
| HEIGE_RUN_LAUNCHD_INTEGRATION: "1" | |
| run: node --test test/macos-launch-agent.integration.test.mjs | |
| - name: Require integration cleanup and a clean worktree | |
| if: always() | |
| run: | | |
| test -z "$(find "$RUNNER_TEMP" -maxdepth 2 \( -name '*.journal' -o -name '*.staged' -o -name '*.removing' -o -name '*.detached' \) -print -quit)" | |
| test -z "$(git status --porcelain)" | |
| windows: | |
| name: Windows PowerShell parity | |
| runs-on: windows-2025 | |
| timeout-minutes: 25 | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 | |
| with: | |
| node-version: "22.22.3" | |
| cache: npm | |
| - run: npm ci | |
| - name: Windows PowerShell 5.1 suites | |
| shell: pwsh | |
| run: powershell.exe -NoLogo -NoProfile -ExecutionPolicy Bypass -File test/windows/run-tests.ps1 | |
| - name: PowerShell 7 suites | |
| shell: pwsh | |
| run: pwsh -NoLogo -NoProfile -File test/windows/run-tests.ps1 | |
| - name: 32-bit Windows PowerShell resolver | |
| shell: pwsh | |
| run: >- | |
| & "$env:WINDIR\SysWOW64\WindowsPowerShell\v1.0\powershell.exe" | |
| -NoLogo -NoProfile -ExecutionPolicy Bypass | |
| -File test/windows/resolver.test.ps1 | |
| - name: Rebuild and install the exact tracked Windows candidate | |
| shell: pwsh | |
| run: | | |
| $ErrorActionPreference = "Stop" | |
| $tracked = Join-Path $env:GITHUB_WORKSPACE "output\heige-codex-skin-studio.skill" | |
| $rebuilt = Join-Path $env:RUNNER_TEMP "windows-rebuilt.skill" | |
| node scripts/package-skill.mjs --output $rebuilt --source-date-epoch 1704067200 | |
| if ($LASTEXITCODE -ne 0) { throw "Windows candidate rebuild failed." } | |
| $trackedHash = (Get-FileHash -LiteralPath $tracked -Algorithm SHA256).Hash | |
| $rebuiltHash = (Get-FileHash -LiteralPath $rebuilt -Algorithm SHA256).Hash | |
| if ($trackedHash -cne $rebuiltHash) { | |
| throw "Tracked candidate differs from the Windows rebuild: $trackedHash != $rebuiltHash" | |
| } | |
| $sandbox = Join-Path $env:RUNNER_TEMP "heige-packaged-windows" | |
| $archive = Join-Path $sandbox "candidate.zip" | |
| $unpacked = Join-Path $sandbox "unpacked" | |
| $installRoot = Join-Path $sandbox "installed" | |
| $startMenuRoot = Join-Path $sandbox "start-menu" | |
| $profileRoot = Join-Path $sandbox "profile" | |
| New-Item -ItemType Directory -Path $sandbox, $profileRoot -Force | Out-Null | |
| Copy-Item -LiteralPath $tracked -Destination $archive | |
| Expand-Archive -LiteralPath $archive -DestinationPath $unpacked -Force | |
| $candidateRoot = Join-Path $unpacked "heige-codex-skin-studio" | |
| $env:HOME = $profileRoot | |
| $env:USERPROFILE = $profileRoot | |
| $env:LOCALAPPDATA = Join-Path $profileRoot "AppData\Local" | |
| $env:APPDATA = Join-Path $profileRoot "AppData\Roaming" | |
| New-Item -ItemType Directory -Path $env:LOCALAPPDATA, $env:APPDATA -Force | Out-Null | |
| $fakeApp = Join-Path $sandbox "fake-app\ChatGPT.exe" | |
| New-Item -ItemType Directory -Path (Split-Path $fakeApp -Parent) -Force | Out-Null | |
| [System.IO.File]::WriteAllBytes($fakeApp, [byte[]]@()) | |
| $env:HEIGE_CODEX_APP = $fakeApp | |
| & (Join-Path $candidateRoot "scripts\install.ps1") ` | |
| -InstallRoot $installRoot -StartMenuRoot $startMenuRoot -SkipApply | |
| if ($LASTEXITCODE -ne 0) { throw "Packaged Windows install failed." } | |
| foreach ($required in @( | |
| (Join-Path $installRoot "src\cli.mjs"), | |
| (Join-Path $installRoot "scripts\windows\controller.ps1"), | |
| (Join-Path $installRoot "scripts\windows\restore.ps1"), | |
| (Join-Path $startMenuRoot "HeiGe Codex Skin Studio\HeiGe 皮肤启动器.lnk") | |
| )) { | |
| if (-not (Test-Path -LiteralPath $required -PathType Leaf)) { | |
| throw "Packaged Windows install is missing: $required" | |
| } | |
| } | |
| & node (Join-Path $installRoot "src\cli.mjs") list | Out-Null | |
| if ($LASTEXITCODE -ne 0) { throw "Installed Windows CLI smoke test failed." } | |
| & (Join-Path $installRoot "scripts\windows\restore.ps1") | |
| $statePath = Join-Path $env:APPDATA "HeiGeCodexSkinStudio\state.json" | |
| $state = Get-Content -LiteralPath $statePath -Raw -Encoding UTF8 | ConvertFrom-Json | |
| if ($state.persistenceEnabled -isnot [bool] -or [bool]$state.persistenceEnabled) { | |
| throw "Packaged offline restore did not persist the disabled choice." | |
| } | |
| if (Get-ScheduledTask -TaskName "HeiGe Codex Skin Studio Controller" -ErrorAction SilentlyContinue) { | |
| throw "Packaged offline restore retained the production Scheduled Task." | |
| } | |
| - name: Isolated current-user Scheduled Task integration | |
| shell: pwsh | |
| run: | | |
| $name = "HeiGe Codex Skin Studio Test $([guid]::NewGuid())" | |
| Set-Content -LiteralPath "$env:RUNNER_TEMP\heige-task-name.txt" -Value $name -Encoding UTF8 | |
| pwsh -NoLogo -NoProfile -File test/windows/scheduled-task.test.ps1 -Integration -TaskName $name | |
| - name: Unconditionally remove the isolated test task | |
| if: always() | |
| shell: pwsh | |
| run: | | |
| $path = "$env:RUNNER_TEMP\heige-task-name.txt" | |
| if (Test-Path -LiteralPath $path) { | |
| $name = (Get-Content -LiteralPath $path -Raw).Trim() | |
| if ($name -match '^HeiGe Codex Skin Studio Test [0-9a-f-]{36}$') { | |
| Unregister-ScheduledTask -TaskName $name -Confirm:$false -ErrorAction SilentlyContinue | |
| if (Get-ScheduledTask -TaskName $name -ErrorAction SilentlyContinue) { | |
| throw "Isolated Scheduled Task cleanup failed: $name" | |
| } | |
| } | |
| } | |
| - name: Require a clean worktree | |
| if: always() | |
| shell: pwsh | |
| run: | | |
| $dirty = git status --porcelain | |
| if ($dirty) { $dirty; exit 1 } | |
| package: | |
| name: Reproducible skill package | |
| runs-on: ubuntu-24.04 | |
| timeout-minutes: 15 | |
| steps: | |
| - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6 | |
| - name: Install zsh for package launcher tests | |
| run: | | |
| sudo apt-get update | |
| sudo apt-get install --no-install-recommends -y zsh | |
| test -x /bin/zsh | |
| /bin/zsh -c '[[ $ZSH_VERSION == 5.9 ]]' | |
| - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6 | |
| with: | |
| node-version: "22.22.3" | |
| cache: npm | |
| - run: npm ci | |
| - name: Build identical temporary candidates | |
| run: | | |
| node scripts/package-skill.mjs --output "$RUNNER_TEMP/a.skill" --source-date-epoch 1704067200 | |
| node scripts/package-skill.mjs --output "$RUNNER_TEMP/b.skill" --source-date-epoch 1704067200 | |
| cmp "$RUNNER_TEMP/a.skill" "$RUNNER_TEMP/b.skill" | |
| cmp "$RUNNER_TEMP/a.skill" output/heige-codex-skin-studio.skill | |
| sha256sum "$RUNNER_TEMP/a.skill" "$RUNNER_TEMP/b.skill" | |
| - name: Verify allowlist legal files and archive metadata | |
| run: node --test test/skill-package.test.mjs test/release-governance.test.mjs | |
| - name: Install the extracted copy without launching Codex | |
| run: | | |
| mkdir -p "$RUNNER_TEMP/unpacked" "$RUNNER_TEMP/home" | |
| unzip -q "$RUNNER_TEMP/a.skill" -d "$RUNNER_TEMP/unpacked" | |
| HOME="$RUNNER_TEMP/home" HEIGE_SKIP_APPLY=1 /bin/zsh "$RUNNER_TEMP/unpacked/heige-codex-skin-studio/scripts/install.command" | |
| node "$RUNNER_TEMP/home/.codex/heige-codex-skin-studio/src/cli.mjs" list >/dev/null | |
| - name: Require a clean worktree | |
| if: always() | |
| run: test -z "$(git status --porcelain)" |