Skip to content

Commit 54fe273

Browse files
committed
fix ci
1 parent 624dcd3 commit 54fe273

1 file changed

Lines changed: 35 additions & 77 deletions

File tree

.github/workflows/build-foryc-binaries.yml

Lines changed: 35 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ on:
2626
description: "True if all 5 foryc binaries built and validated."
2727
value: ${{ jobs.build-complete.outputs.ready }}
2828

29-
# FIX 7: Narrowed from "v*" to "foryc-v*" to avoid triggering on Java/Rust/Go release tags
3029
push:
3130
tags: ["foryc-v*"]
3231

@@ -60,9 +59,15 @@ env:
6059
# 10 MB constraint:
6160
# Each binary must remain under 10 MB after UPX compression.
6261
# This is a hard gate for crates.io embedding in Phase 2.
63-
# Enforced with an explicit assertion step in each build job.
6462
# macOS binaries are uncompressed but remain under 10 MB because
6563
# fory_compiler has zero third-party pip dependencies (pure stdlib only).
64+
#
65+
# Windows Defender note:
66+
# Set-MpPreference -DisableRealtimeMonitoring $true is required in BOTH
67+
# the build and validate jobs. Add-MpPreference -ExclusionPath is NOT
68+
# sufficient — it only excludes file system scans, not the memory-level
69+
# LoadLibrary interception that causes PYI-3104 / ERROR_NOACCESS failures
70+
# when PyInstaller extracts and maps python311.dll at runtime.
6671
# ─────────────────────────────────────────────────────────────────────────────
6772
jobs:
6873
build:
@@ -104,10 +109,6 @@ jobs:
104109
use_upx: false
105110
codesign: true
106111

107-
# LATEST FIX: windows-2019 is deprecated and runners no longer provision.
108-
# windows-latest (Server 2022) works correctly when combined with the
109-
# Defender exclusion step below. The DLL issue was always caused by
110-
# Defender scanning PyInstaller's extracted temp files, not the runner version.
111112
- target: windows-x86_64
112113
os: windows-latest
113114
artifact_name: foryc-windows-x86_64
@@ -117,13 +118,9 @@ jobs:
117118
codesign: false
118119

119120
steps:
120-
# Full checkout required: needs compiler/foryc.spec,
121-
# compiler/requirements-dev.txt, and the full compiler/ package
122-
# for pip install and pyinstaller to work.
123121
- name: Checkout
124122
uses: actions/checkout@v5
125123

126-
# FIX 8: Added pip cache to avoid cold installs on every run (~60-120s saved per target)
127124
- name: Set up Python ${{ env.PYTHON_VERSION }}
128125
uses: actions/setup-python@v5
129126
with:
@@ -155,19 +152,16 @@ jobs:
155152
upx --version
156153
157154
# ── Install build dependencies ──────────────────────────────────────────
158-
# pyinstaller version is pinned in requirements-dev.txt.
159-
# fory_compiler is installed from source so PyInstaller's import
160-
# tracer can walk the actual installed package tree.
161155
- name: Install PyInstaller and fory_compiler
162156
run: |
163157
python -m pip install --upgrade pip
164158
pip install -r compiler/requirements-dev.txt
165159
pip install ./compiler
166160
167-
# FIX 9: Verify all hiddenimports are importable before PyInstaller runs.
168-
# PyInstaller silently ignores nonexistent hiddenimports — this step
169-
# catches renamed or removed modules before they silently disappear
170-
# from the binary.
161+
# ── Verify all hiddenimports are importable ─────────────────────────────
162+
# PyInstaller silently ignores nonexistent hiddenimports entries.
163+
# This step catches renamed or removed modules before they silently
164+
# disappear from the binary.
171165
- name: Verify all hiddenimports are importable
172166
working-directory: compiler
173167
run: |
@@ -198,30 +192,24 @@ jobs:
198192
print('All hiddenimports verified.')
199193
"
200194
201-
# LATEST FIX (build job): Defender exclusions instead of full disable.
202-
# Targets GITHUB_WORKSPACE and RUNNER_TEMP — the two paths PyInstaller
203-
# writes to during build and extraction. This is sufficient and more
204-
# targeted than disabling real-time monitoring globally.
205-
- name: Disable Windows Defender for PyInstaller paths
195+
# ── Windows Defender (build job) ────────────────────────────────────────
196+
# Full real-time monitoring disable is required — not just path exclusions.
197+
# Add-MpPreference -ExclusionPath only covers filesystem scans.
198+
# The PYI-3104 / LoadLibrary: Invalid access to memory location error
199+
# is caused by Defender intercepting the memory-mapping of python311.dll
200+
# during PyInstaller bootloader execution. Only DisableRealtimeMonitoring
201+
# stops that interception.
202+
- name: Disable Windows Defender real-time monitoring (PyInstaller workaround)
206203
if: runner.os == 'Windows'
207204
shell: pwsh
208-
run: |
209-
Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE"
210-
Add-MpPreference -ExclusionPath "$env:RUNNER_TEMP"
211-
Add-MpPreference -ExclusionProcess "foryc.exe"
205+
run: Set-MpPreference -DisableRealtimeMonitoring $true
212206

213207
# ── Build ───────────────────────────────────────────────────────────────
214-
# Must run from compiler/ so pathex=['.'] in foryc.spec resolves
215-
# fory_compiler/__main__.py correctly.
216208
- name: Build standalone binary with PyInstaller
217209
working-directory: compiler
218210
run: pyinstaller foryc.spec
219211

220-
# FIX 3 (occurrence 1/3): Use BINARY_PATH env var instead of inline matrix
221-
# expression inside Python string — safe against paths with spaces or quotes.
222212
# ── Pre-compression smoke test ──────────────────────────────────────────
223-
# Confirms the binary is functional before UPX touches it.
224-
# A broken binary here gives a cleaner error than post-UPX.
225213
- name: Smoke test (pre-UPX)
226214
shell: bash
227215
env:
@@ -236,11 +224,7 @@ jobs:
236224
"
237225
"$BINARY_PATH" --help
238226
239-
# FIX 3 (occurrence 2/3): Same env var fix.
240227
# ── UPX compression ─────────────────────────────────────────────────────
241-
# --best --lzma: maximum compression, ~10% better ratio than default.
242-
# UPX on PyInstaller --onefile binaries is well-supported on Linux/Windows.
243-
# macOS is excluded entirely (UPX 4.x+ dropped Mach-O support).
244228
- name: Compress with UPX
245229
if: matrix.use_upx
246230
shell: bash
@@ -256,30 +240,23 @@ jobs:
256240
print(f'Size: {s:,} bytes ({s/1024/1024:.2f} MB)')
257241
"
258242
259-
# FIX 2: Renamed step — UPX is disabled for macOS targets so "after UPX"
260-
# was misleading. PyInstaller-built Apple Silicon binaries require a valid
261-
# code signature regardless of UPX. Ad-hoc signing requires no Developer ID
262-
# and is sufficient for binaries distributed via crates.io (not quarantined).
243+
# ── macOS aarch64: ad-hoc codesign ───────────────────────────────────────
244+
# PyInstaller-built Apple Silicon binaries require valid code signatures.
245+
# UPX is disabled for macOS — this step runs regardless of UPX.
246+
# --sign - creates an ad-hoc signature; no Apple Developer ID required.
263247
- name: Ad-hoc codesign binary (macOS aarch64, required for Apple Silicon)
264248
if: matrix.codesign
265249
run: |
266250
codesign --force --deep --sign - "${{ matrix.binary_path }}"
267251
codesign --verify --verbose "${{ matrix.binary_path }}"
268252
269253
# ── Post-compression smoke test ─────────────────────────────────────────
270-
# Critical test: the UPX-compressed (and re-signed) binary must execute.
271-
# Failure here means UPX broke the binary on this platform.
272254
- name: Smoke test (post-UPX)
273255
shell: bash
274256
run: |
275257
"${{ matrix.binary_path }}" --help
276258
277-
# FIX 3 (occurrence 3/3): Same env var fix.
278259
# ── crates.io 10 MB size gate ────────────────────────────────────────────
279-
# Each per-platform foryc-bin-* crate (Phase 2) embeds exactly one binary.
280-
# crates.io hard limit is 10 MB per crate.
281-
# If this assertion fails: add more entries to excludes[] in foryc.spec,
282-
# investigate why binary grew, or reconsider distribution strategy.
283260
- name: Assert binary is under 10 MB (crates.io hard limit)
284261
shell: bash
285262
env:
@@ -316,7 +293,7 @@ jobs:
316293
# Python is NOT set up in this job — binary must be fully self-contained.
317294
# 2. End-to-end compile of compiler/examples/demo.fdl to Rust output.
318295
# 3. End-to-end compile of compiler/examples/demo.fdl to Java output.
319-
# Validates that all 5 language generators are correctly embedded in binary.
296+
# Validates that all 5 language generators are correctly embedded.
320297
# ─────────────────────────────────────────────────────────────────────────────
321298
validate:
322299
name: validate / ${{ matrix.target }}
@@ -346,12 +323,6 @@ jobs:
346323
artifact_name: foryc-macos-aarch64
347324
binary_name: foryc
348325

349-
# windows-latest (Server 2022) — intentionally different from
350-
# build runner (windows-2019 was deprecated). Binary built on
351-
# Server 2022 and validated on Server 2022 for consistency.
352-
# Defender exclusions below are required for PyInstaller onefile
353-
# extraction — without them, DLL load fails as Defender quarantines
354-
# files extracted to RUNNER_TEMP mid-execution.
355326
- target: windows-x86_64
356327
os: windows-latest
357328
artifact_name: foryc-windows-x86_64
@@ -366,35 +337,28 @@ jobs:
366337
sparse-checkout: compiler/examples
367338
sparse-checkout-cone-mode: true
368339

369-
# FIX 1: Changed from download-artifact@v5 to @v4.
370-
# upload-artifact@v4 and download-artifact@v5 use incompatible artifact
371-
# storage APIs — mismatched versions cause artifact-not-found failures.
372340
- name: Download artifact
373341
uses: actions/download-artifact@v4
374342
with:
375343
name: ${{ matrix.artifact_name }}
376344
path: ./artifact
377345

378-
# FIX 10 (NEW): Defender exclusions in validate job.
379-
# The original PR had Defender disable only in the build job.
380-
# PyInstaller onefile binaries extract their payload to RUNNER_TEMP on
381-
# first run. Without Defender exclusions, real-time scanning quarantines
382-
# the extracted DLLs mid-execution, causing DLL load failed errors.
383-
# This was the actual root cause of the "windows DLL failure" — not the
384-
# runner version.
385-
- name: Disable Windows Defender for PyInstaller extraction paths
346+
# ── Windows Defender (validate job) ────────────────────────────────────
347+
# MUST appear before the binary is executed — not just before the build.
348+
# PyInstaller onefile extracts python311.dll to RUNNER_TEMP on first run.
349+
# Defender intercepts the LoadLibrary call at the memory level, causing
350+
# PYI-3104: Invalid access to memory location.
351+
# Path exclusions (Add-MpPreference) do NOT fix this — full real-time
352+
# monitoring disable is required in this job exactly as in the build job.
353+
- name: Disable Windows Defender real-time monitoring (PyInstaller extraction workaround)
386354
if: runner.os == 'Windows'
387355
shell: pwsh
388-
run: |
389-
Add-MpPreference -ExclusionPath "$env:RUNNER_TEMP"
390-
Add-MpPreference -ExclusionProcess "foryc.exe"
356+
run: Set-MpPreference -DisableRealtimeMonitoring $true
391357

392358
- name: Make executable (Unix)
393359
if: runner.os != 'Windows'
394360
run: chmod +x ./artifact/${{ matrix.binary_name }}
395361

396-
# FIX 4: Tightened from broad keyword grep to specific usage line check.
397-
# Previous pattern matched "fory" anywhere including crash tracebacks.
398362
# ── Test 1: --help ───────────────────────────────────────────────────────
399363
- name: Validate --help output
400364
shell: bash
@@ -406,8 +370,6 @@ jobs:
406370
exit 1
407371
}
408372
409-
# FIX 5: Changed from file count check to non-empty .rs file check.
410-
# Previous check passed if foryc produced a 0-byte file or an error log.
411373
# ── Test 2: End-to-end FDL → Rust ────────────────────────────────────────
412374
- name: End-to-end compile demo.fdl to Rust
413375
shell: bash
@@ -430,11 +392,7 @@ jobs:
430392
fi
431393
echo "PASS: ${RS_COUNT} .rs file(s) generated"
432394
433-
# FIX 6: Added Java generator validation.
434-
# The foryc.spec embeds all 5 language backends (java, python, cpp, rust, go).
435-
# Without this test, a silent module drop in any non-Rust generator would
436-
# be invisible and the broken binary would be promoted to Phase 2 crates.
437-
# ── Test 3: End-to-end FDL → Java ────────────────────────────────────────
395+
# ── Test 3: End-to-end FDL → Java ─────────────────────────────────────────
438396
- name: End-to-end compile demo.fdl to Java
439397
shell: bash
440398
run: |

0 commit comments

Comments
 (0)