Skip to content

feat: add --engine-path flag for local engine development - #11

Merged
apotema merged 1 commit into
mainfrom
feature/local-engine-path-10
Jan 14, 2026
Merged

apotema merged 1 commit into
mainfrom
feature/local-engine-path-10

Conversation

@apotema

@apotema apotema commented Jan 14, 2026

Copy link
Copy Markdown
Contributor

Summary

Add support for using a local labelle-engine checkout instead of fetching from the package registry. This is useful for:

  • CI testing against the current branch of labelle-engine
  • Local development with modified engine code

Changes

  • Add --engine-path=PATH option to CLI
  • Add LABELLE_ENGINE_PATH environment variable support
  • Create bootstrap build.zig.zon with .path instead of .url/.hash when using local engine
  • Compute relative path from bootstrap dir to engine path automatically

Usage

# Using flag
labelle build --engine-path=/path/to/labelle-engine

# Using environment variable
LABELLE_ENGINE_PATH=/path/to/engine labelle build

Example CI Usage

- name: Build with CLI
  env:
    LABELLE_ENGINE_PATH: ${{ github.workspace }}
  run: |
    labelle build -Dtarget=aarch64-linux-android

Test plan

  • Build CLI successfully
  • Test --engine-path flag with absolute path
  • Test LABELLE_ENGINE_PATH environment variable
  • Verify generated build.zig.zon has correct relative path
  • Verify project builds with local engine

Closes #10

🤖 Generated with Claude Code

@cursor

cursor Bot commented Jan 14, 2026 •

Copy link
Copy Markdown

PR Summary

Enables local engine development and CI by bootstrapping against a filesystem path instead of a remote release.

  • CLI: parse --engine-path, read LABELLE_ENGINE_PATH, route generate to local engine; help text updated
  • Engine bootstrap: new runEngineGeneratorWithLocalPath, createBootstrapBuildZonWithLocalPath, forward-slash normalization, and computeRelativePath (with tests); build.zig.zon uses .path when local
  • Process handling: improved exit/abnormal termination checks for generator and fetchPackageHash
  • CI: GitHub Actions matrix (ubuntu/macos/windows) with separate build and test steps
  • Config: introduce WindowConfig aggregation in project_config

Written by Cursor Bugbot for commit 2d373e8. This will update automatically on new commits. Configure here.

@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello @apotema, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the labelle CLI by introducing robust support for using a local labelle-engine checkout. This feature is crucial for developers working on the engine itself, allowing them to test changes against the CLI without publishing new versions, and for CI environments to validate compatibility with specific engine branches. It achieves this by dynamically configuring the build system to reference a local path rather than a remote package.

Highlights

  • Local Engine Support: Introduced the --engine-path CLI flag and LABELLE_ENGINE_PATH environment variable to specify a local labelle-engine checkout for development and CI.
  • Dynamic build.zig.zon Generation: Implemented logic to generate a bootstrap build.zig.zon file that uses a local .path dependency instead of a remote .url/.hash when a local engine path is provided.
  • Relative Path Calculation: Added a utility function to compute the correct relative path from the bootstrap directory to the specified local engine path, handling both absolute and relative input paths.
  • Generator Execution Flow: Modified the runGenerate command to conditionally invoke a new runEngineGeneratorWithLocalPath function, enabling the use of the local engine for project generation.
  • Documentation Updates: Updated CLI help messages and examples to reflect the new --engine-path flag and LABELLE_ENGINE_PATH environment variable usage.
  • Project Configuration Enhancement (Minor): Added a WindowConfig struct and integrated it into ProjectConfig to better structure window-related settings, consolidating window_width, window_height, and window_title into a nested object.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a valuable feature for local development and CI by adding support for a local engine path via the --engine-path flag and LABELLE_ENGINE_PATH environment variable. However, it also introduces a critical command injection vulnerability due to improper sanitization of the user-provided engine path, which could allow arbitrary code execution. Additionally, there are areas for improvement concerning cross-platform compatibility with path separators and environment variable access, and some unrelated changes to src/project_config.zig that should be moved to a separate pull request.

Comment thread src/engine_resolver.zig
Comment on lines +278 to +282
} else {
// Already relative - just add ../ to go up from bootstrap dir
relative_path = try std.fmt.allocPrint(allocator, "../{s}", .{local_path});
needs_free = true;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

security-critical critical

The local_path variable, which is user-controlled via the --engine-path argument or LABELLE_ENGINE_PATH environment variable, is used to construct a file path without proper sanitization. When a relative path is provided, it is prepended with ../, which allows for path traversal. An attacker could provide a malicious path (e.g., ../../../../../../tmp/evil-project) that points to an arbitrary location on the file system. This path is then written into the build.zig.zon file. Subsequently, the zig build run command is executed, which will use this malicious path, leading to arbitrary code execution. This is a critical command injection vulnerability.

Comment thread src/engine_resolver.zig Outdated

// Resolve engine path to absolute
var engine_buf: [std.fs.max_path_bytes]u8 = undefined;
const engine_abs = std.fs.cwd().realpath(local_path, &engine_buf) catch local_path;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

The catch local_path fallback is risky. computeRelativePath requires absolute paths, but if realpath fails, engine_abs could be a relative path, causing incorrect behavior. It would be safer to propagate the error from realpath.

        const engine_abs = try std.fs.cwd().realpath(local_path, &engine_buf);

Comment thread src/engine_resolver.zig

/// Compute relative path from `from` directory to `to` path.
/// Both paths must be absolute.
fn computeRelativePath(allocator: std.mem.Allocator, from: []const u8, to: []const u8) ![]const u8 {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

This function hardcodes / as the path separator, which will not work on Windows. Please use std.fs.path.sep for cross-platform compatibility. This will require adjusting the logic to treat the separator as a variable character.

Comment thread src/main.zig Outdated

// Check for LABELLE_ENGINE_PATH environment variable
if (options.engine_path == null) {
options.engine_path = std.posix.getenv("LABELLE_ENGINE_PATH");

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

high

Using std.posix.getenv is not portable and will not work on Windows. For cross-platform environment variable access, please use std.process.getEnvVarOwned. Note that getEnvVarOwned allocates memory that you will be responsible for freeing.

Comment thread src/engine_resolver.zig Outdated
/// Create a bootstrap build.zig.zon using a local engine path.
/// The path needs to be relative to the bootstrap directory.
fn createBootstrapBuildZonWithLocalPath(allocator: std.mem.Allocator, dir: std.fs.Dir, local_path: []const u8) !void {
_ = dir;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The dir parameter is ignored here. Instead, the directory is opened again on line 303. Please use the passed dir handle to create the file, which is more efficient and consistent with createBootstrapBuildZon.

Comment thread src/engine_resolver.zig Outdated

/// Run the engine's generator using a local engine path.
/// This is useful for CI testing against a local checkout.
pub fn runEngineGeneratorWithLocalPath(allocator: std.mem.Allocator, local_path: []const u8, project_path: []const u8) !void {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The project_path parameter is unused in this function (discarded on the next line) and also in createBootstrapBuildZig which it calls. Please remove it from the function signatures to simplify the code. This will require updating the call site in src/main.zig.

pub fn runEngineGeneratorWithLocalPath(allocator: std.mem.Allocator, local_path: []const u8) !void {

Comment thread src/project_config.zig
Comment on lines +8 to +12
pub const WindowConfig = struct {
title: ?[]const u8 = null,
width: ?i32 = null,
height: ?i32 = null,
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

The introduction of WindowConfig and related changes in this file seem unrelated to the main purpose of this pull request (adding --engine-path). To keep pull requests focused and easier to review, it's best practice to submit unrelated changes in a separate PR.

@apotema
apotema force-pushed the feature/local-engine-path-10 branch 3 times, most recently from 62a34d2 to a5c5507 Compare January 14, 2026 17:09
Comment thread src/engine_resolver.zig
Comment thread src/engine_resolver.zig
Comment thread src/engine_resolver.zig
Comment thread src/engine_resolver.zig
_ = result.pop();
}

return try result.toOwnedSlice(allocator);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cross-drive paths on Windows produce invalid relative paths

Low Severity

On Windows, computeRelativePath produces invalid paths when the source and destination are on different drives (e.g., project on C:\ and engine on D:\). Since no common root exists, the function generates output like ..\..\D:\engine which is not a valid relative path. There's no way to navigate between drives using relative paths, so the function would need to detect this case and either return an error or the absolute destination path.

Fix in Cursor Fix in Web

@apotema
apotema force-pushed the feature/local-engine-path-10 branch from a5c5507 to b15ca10 Compare January 14, 2026 17:23
Add support for using a local labelle-engine checkout instead of
fetching from the package registry. This is useful for:

- CI testing against the current branch of labelle-engine
- Local development with modified engine code

Usage:
  labelle build --engine-path=/path/to/labelle-engine
  LABELLE_ENGINE_PATH=/path/to/engine labelle build

The implementation:
- Adds --engine-path=PATH option to CLI
- Adds LABELLE_ENGINE_PATH env var support
- Creates bootstrap build.zig.zon with .path instead of .url/.hash
- Computes relative path from bootstrap dir to engine path

Closes #10

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@apotema
apotema force-pushed the feature/local-engine-path-10 branch from b15ca10 to 2d373e8 Compare January 14, 2026 17:31
@apotema
apotema merged commit a462cad into main Jan 14, 2026
4 checks passed
@apotema
apotema deleted the feature/local-engine-path-10 branch January 14, 2026 17:38
apotema added a commit that referenced this pull request Apr 14, 2026
Point the CLI at the freshly-tagged labelle-assembler v0.6.0,
which ships the full #8–#13 cluster of backend/ECS bug fixes
plus the absorbed plugins and examples.

Changes:

  - DEFAULT_ASSEMBLER_VERSION: 0.5.1 → 0.6.0
    New projects scaffolded via \`labelle init\` now pin to
    v0.6.0 and auto-download that release binary on first
    generate.

  - build.zig.zon labelle_assembler dep: a610afd → 295021cd
    (the v0.6.0 tag's commit SHA). The Zig package hash
    happens to match the previous pin because the hash is
    content-hashed over the assembler's
    paths = {build.zig, build.zig.zon, src}, and the
    plugins/examples absorbs didn't touch src/.

Assembler v0.6.0 fixes shipping to users:

  - #8  SDL portable paths (Linux/Windows/Intel Mac fixed)
  - #9  bgfx native window handle per platform
  - #10 sokol audio sample buffer leak on unload
  - #11 raylib audio slot recycling
  - #12 wgpu WAV parser integer overflow + truncation tolerance
  - #13 zig-ecs view zero-alloc (borrows storage slice)

Plus: sokol HiDPI, Android detection via ABI, iOS build.zig
0.15 compat, sokol-zig / zbgfx / zglfw / nuklear / rlImGui /
raylib-zig dep pinning.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@apotema apotema mentioned this pull request Apr 14, 2026
1 of 2 tasks
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.

Support local engine path for CI testing

1 participant