Skip to content

feat: build Boris and Oliver helpers from main source and bundle into app - #218

Merged
drawmeanelephant merged 1 commit into
mainfrom
feat/build-helpers-from-source
Aug 26, 2026
Merged

drawmeanelephant merged 1 commit into
mainfrom
feat/build-helpers-from-source

Conversation

@drawmeanelephant

Copy link
Copy Markdown
Owner

Summary

  • Automatically fetch and compile Boris and Oliver from their main GitHub source repositories (drawmeanelephant/boris and drawmeanelephant/oliver) when local checkouts are absent.
  • Build universal (x86_64 + arm64) macOS binaries via zig build -Doptimize=ReleaseSafe into Contents/Helpers for both make app and Xcode builds.
  • Update OliverLocator and BorisLocator to resolve built helper binaries during development, CLI runs (banal doctor), and test execution.
  • Added test coverage in BorisLocatorTests and OliverClientTests.

Verification

  • swift test passes 100% (all suites).
  • lipo -info verifies universal fat binaries.
  • make app successfully bundles and signs helper binaries into Contents/Helpers.
  • make smoke passes end-to-end.
  • swift run banal doctor verifies Boris and Oliver detection.

@drawmeanelephant
drawmeanelephant merged commit 891ca9f into main Aug 26, 2026
3 checks passed
@drawmeanelephant
drawmeanelephant deleted the feat/build-helpers-from-source branch August 26, 2026 19:07
@itoqa

itoqa Bot commented Aug 26, 2026

Copy link
Copy Markdown

Ito QA test results
Commit: 5c638dc: 19 test cases ran, 1 failed ❌, 18 passed ✅.

Summary

Coverage spans successful and failure-recovery helper builds, app packaging and signing, helper discovery and priority rules, recipe rendering and publishing fallbacks, and security and concurrency edge cases. Overall behavior is healthy across normal and degraded conditions, with platform-specific macOS interface behavior not fully exercised.

Merge with caution — overlapping helper builds can publish a mismatched set of engines while still reporting success, creating a medium-severity release-integrity risk. The remaining findings do not indicate additional merge-blocking behavior.

Tests run by Ito

View full run

Result Severity Type Description
Medium severity General Starting two helper builds together left Oliver from one build and Boris containing slices from both builds. The expected result was one complete, internally consistent helper pair with no cross-build mixing.
General The app bundle matched the current helper files after the available helpers changed between builds. The second build added Boris without keeping stale bundle contents, while Oliver remained present.
General Recipe reading checks that Oliver can return recipe data before using it. Normal rendering can still use an Oliver that only renders text.
General The build completes and keeps the working Oliver helper when Boris source cannot be fetched. Boris is left out as designed, so one missing helper does not stop the other from being bundled.
General When both compiler attempts failed, the build removed the old helper files and left no temporary files behind.
Build The helper build completed successfully and produced executable Boris and Oliver files from valid local source directories.
Build When cross-target builds fail, the helper build still creates executable host-version helpers for both tools and finishes successfully.
Build An invalid source folder was ignored, and the helper was built from the first valid fallback folder.
Bundle The app build completed successfully. The finished BANAL app included executable Boris and Oliver helpers, and final signing verification passed.
Bundle The app build completed successfully with one available helper. The app contained an executable Oliver helper and did not create a fake Boris helper.
Locate The native recipe and publishing screens could not run in the Linux workbench, but source checks confirm that built Oliver and Boris helpers are found and used by both flows.
Locate A render-only Oliver helper remains usable for idle recipe rendering. Recipe Read separately asks for recipe data and shows a clear message when the helper cannot provide it, instead of treating the helper as crashed.
Locate When no helper engine can be found, the app reports that clearly and uses its built-in site compiler instead of crashing.
Precedence The configured helper paths are checked before bundled, environment, PATH, and relative helper files. The native app could not run in this Linux container, so the Recipe Read, publishing, and doctor screens were not exercised.
Precedence The candidate-resolution flow could not start because the native macOS app and command-line tool were unavailable in the Linux test environment. Source review confirms invalid helper paths are skipped so a later working helper can still be selected.
Security The build used the two explicitly selected source folders and created executable Oliver and Boris helpers from them. An unselected writable sibling folder was not used.
Security The security check could not run because the native macOS app and command-line tool were unavailable in the Linux test environment. Source review shows the intended configured and bundled helpers are checked before lower-priority environment, PATH, and relative locations.
Xcode The Xcode build could not run on this Linux runner, but source review found the helper build and embedding steps required by this test.
Xcode The invalid helper entries were prepared, but the required Mac build could not run in this Linux environment. The build configuration checks that each entry is both a regular file and executable before copying it.

Tip

Reply with @itoqa to send us feedback on this test run.

Comment thread Scripts/helpers.sh
return 1
fi

tmp="$(mktemp -d)"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

View All Evidence

Medium severity Concurrent builds create mismatched helpers

What failed: Starting two helper builds together left Oliver from one build and Boris containing slices from both builds. The expected result was one complete, internally consistent helper pair with no cross-build mixing.

Impact · Steps · Stub / mock · Analysis · Why this is likely a bug
  • Severity: Medium Medium severity
  • Impact: A release built while two helper jobs overlap can contain a mismatched helper pair. The app may fail or behave incorrectly even though the build reports success.
  • Steps to Reproduce:
    1. Prepare two valid Boris and Oliver source trees with distinct provenance markers.
    2. Start two make helpers commands at the same time, each using one source tree and the same dist/helpers destination.
    3. Wait for both commands to finish, then inspect the Boris and Oliver output files.
    4. Compare the provenance markers and confirm that the pair contains output from both source trees even though both commands returned success.
  • Stub / mock content: The test used deterministic local Zig and lipo stand-ins to mark each build's source and timing; no application network requests or production data were used.
  • Code Analysis: Scripts/helpers.sh:107-117 loops over oliver and boris and calls build_helper independently for each invocation. In build_helper at lines 73-82, the compiler output uses a private mktemp directory, but lipo writes the combined binary to the shared $HELPERS/$name.tmp path and then moves it to the shared $HELPERS/$name path. The host fallback at lines 91-98 copies directly to the same shared final path, while cleanup at lines 99-103 can remove that path. There is no lock around the invocation and no invocation-specific staging directory or pair-level publication. Makefile:33-35 exposes this script directly through make helpers, so two independent commands share these paths. The PR diff specifically introduced the helpers target and the changed build_helper publication flow in Scripts/helpers.sh, making the changed publication behavior the direct cause. A targeted fix is to hold a lock for the whole helper build, or stage both helper outputs under a unique directory and replace the destination set only after both tools finish.
  • Why this is likely a bug: The failure is not only a test artifact: the script's shared destination names are real paths consumed by later app-bundling and helper-resolution flows, and separate invocations can write them concurrently. The recorded run reproduced the organic overlap condition with two successful commands and found mixed A/B provenance in the final outputs, with no temporary files left to reveal the problem. Because the final files remain executable and the command exits 0, downstream users can receive a wrong helper pair without a clear error. Serializing the script or atomically publishing an invocation's complete pair would prevent the specific corruption without requiring a broad redesign.
Relevant code

Scripts/helpers.sh:73-85

tmp="$(mktemp -d)"
...
lipo -create "$arm/bin/$name" "$x86/bin/$name" -output "$HELPERS/$name.tmp" ...
  mv "$HELPERS/$name.tmp" "$HELPERS/$name"

Scripts/helpers.sh:90-104

tmp="$(mktemp -d)"
if (cd "$src" && "$ZIG" build --prefix "$tmp" ...); then
  cp "$tmp/bin/$name" "$HELPERS/$name"
...
  rm -f "$HELPERS/$name"

Scripts/helpers.sh:107-117

for tool in oliver boris; do
...
  if src="$(find_or_fetch_source "$tool" "$src_override")"; then
    build_helper "$tool" "$src"
  fi
done

Makefile:33-35

helpers:
	@$(BASH) Scripts/helpers.sh "$(DIST)"
Evidence Package
Copy prompt for an agent
Ito QA identified the following failure during automated PR testing. Please investigate and propose a fix.

**Medium severity — Concurrent builds create mismatched helpers**

**What failed:** Starting two helper builds together left Oliver from one build and Boris containing slices from both builds. The expected result was one complete, internally consistent helper pair with no cross-build mixing.

- **Impact:** A release built while two helper jobs overlap can contain a mismatched helper pair. The app may fail or behave incorrectly even though the build reports success.
- **Steps to reproduce:**
  1. Prepare two valid Boris and Oliver source trees with distinct provenance markers.
  2. Start two `make helpers` commands at the same time, each using one source tree and the same `dist/helpers` destination.
  3. Wait for both commands to finish, then inspect the Boris and Oliver output files.
  4. Compare the provenance markers and confirm that the pair contains output from both source trees even though both commands returned success.
- **Stub / mock content:** The test used deterministic local Zig and lipo stand-ins to mark each build's source and timing; no application network requests or production data were used.
- **Code analysis:** Scripts/helpers.sh:107-117 loops over `oliver` and `boris` and calls `build_helper` independently for each invocation. In `build_helper` at lines 73-82, the compiler output uses a private `mktemp` directory, but `lipo` writes the combined binary to the shared `$HELPERS/$name.tmp` path and then moves it to the shared `$HELPERS/$name` path. The host fallback at lines 91-98 copies directly to the same shared final path, while cleanup at lines 99-103 can remove that path. There is no lock around the invocation and no invocation-specific staging directory or pair-level publication. Makefile:33-35 exposes this script directly through `make helpers`, so two independent commands share these paths. The PR diff specifically introduced the `helpers` target and the changed `build_helper` publication flow in Scripts/helpers.sh, making the changed publication behavior the direct cause. A targeted fix is to hold a lock for the whole helper build, or stage both helper outputs under a unique directory and replace the destination set only after both tools finish.
- **Why this is likely a bug:** The failure is not only a test artifact: the script's shared destination names are real paths consumed by later app-bundling and helper-resolution flows, and separate invocations can write them concurrently. The recorded run reproduced the organic overlap condition with two successful commands and found mixed A/B provenance in the final outputs, with no temporary files left to reveal the problem. Because the final files remain executable and the command exits 0, downstream users can receive a wrong helper pair without a clear error. Serializing the script or atomically publishing an invocation's complete pair would prevent the specific corruption without requiring a broad redesign.

**Relevant code:**

`Scripts/helpers.sh:73-85`

~~~bash
tmp="$(mktemp -d)"
...
lipo -create "$arm/bin/$name" "$x86/bin/$name" -output "$HELPERS/$name.tmp" ...
  mv "$HELPERS/$name.tmp" "$HELPERS/$name"
~~~

`Scripts/helpers.sh:90-104`

~~~bash
tmp="$(mktemp -d)"
if (cd "$src" && "$ZIG" build --prefix "$tmp" ...); then
  cp "$tmp/bin/$name" "$HELPERS/$name"
...
  rm -f "$HELPERS/$name"
~~~

`Scripts/helpers.sh:107-117`

~~~bash
for tool in oliver boris; do
...
  if src="$(find_or_fetch_source "$tool" "$src_override")"; then
    build_helper "$tool" "$src"
  fi
done
~~~

`Makefile:33-35`

~~~make
helpers:
	@$(BASH) Scripts/helpers.sh "$(DIST)"
~~~

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant