Skip to content

building assets fix - #11

Open
zs-dima wants to merge 1 commit into
zhukeev:mainfrom
zs-dima:main
Open

building assets fix#11
zs-dima wants to merge 1 commit into
zhukeev:mainfrom
zs-dima:main

Conversation

@zs-dima

@zs-dima zs-dima commented Jan 11, 2026

Copy link
Copy Markdown

This pull request fixes #10 but I tested only WebpKit().encode for Windows for now.

Copilot AI review requested due to automatic review settings January 11, 2026 18:02
@gemini-code-assist

Copy link
Copy Markdown

Summary of Changes

Hello @zs-dima, 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 native asset building process, particularly for Windows, by integrating proper Visual Studio environment management and ensuring correct static library linking. It also addresses a critical dependency for libpng by adding zlib compilation and refines the WebP build to improve cross-platform compatibility and stability.

Highlights

  • Windows Build Environment Setup: Introduced robust logic to detect and load the Visual Studio environment on Windows, ensuring CMake and native compilers have the correct paths and variables set for successful builds. This includes finding vcvars64.bat and dynamically capturing its environment.
  • Static CRT Linkage for Windows: Implemented explicit CMake flags and linker options to force static C Runtime (CRT) linkage on Windows for libpng, libjpeg-turbo, and libwebp. This resolves potential conflicts and ensures self-contained static libraries.
  • Zlib Dependency for LibPNG: Added a new build step to compile zlib as a prerequisite for libpng across all supported platforms, ensuring libpng can correctly link against its required compression library.
  • WebP Glue Layer Compilation Refinement: Refactored the WebP build process to use direct cl.exe calls for Windows, leveraging the Visual Studio environment, and introduced IK_EXPORT macros for proper DLL symbol export, addressing Windows-specific linking challenges.
  • Dependency Updates and Test Changes: Updated Dart SDK constraint, hooks, code_assets, and lints dependencies to their latest major versions. The existing test file imagekit_ffi_test.dart has been commented out.
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 significant improvements for building on Windows by properly setting up the Visual Studio environment and handling static library linking. It also refactors the build process for libpng to include zlib as a dependency. However, there are several critical issues that need to be addressed. The tests have been completely disabled, which is a major concern. There's a critical C-Runtime mismatch in the WebP Windows build that will likely cause linker errors or runtime instability. There are also several other bugs and regressions in the build scripts that could lead to build failures on different configurations.

'/O2',
'/DRELEASE',
'/DNDEBUG',
'/MD', // Use dynamic CRT (matches how libwebp was built)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

critical

There's a mismatch in the C Runtime (CRT) linkage. You're using /MD (dynamic CRT) to compile the glue DLL, but the static libraries (libwebp, libsharpyuv) are built with /MT (static CRT) in buildWindowsStatic. Additionally, you are linking against libcmt.lib, which is the static CRT library. This will lead to linker errors or runtime crashes. The glue DLL must be compiled with the same CRT setting as the static libraries it links to. Please change /MD to /MT.

Suggested change
'/MD', // Use dynamic CRT (matches how libwebp was built)
'/MT', // Use static CRT to match how libwebp was built

Comment on lines +1 to +5
// import 'package:test/test.dart';

void main() {
group('A group of tests', () {}, skip: true);
}
// void main() {
// group('A group of tests', () {}, skip: 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.

critical

The tests have been completely commented out. Introducing significant changes to the build logic, especially for a new platform, without running tests is very risky. Please re-enable the tests and ensure they pass on all supported platforms before merging.

}

final env = <String, String>{};
for (final line in (result.stdout as String).split('\n')) {

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 split('\n') is not robust for handling Windows-style line endings (\r\n). This can lead to lines with a trailing \r which might affect parsing of the environment variables. It's safer to use LineSplitter from dart:convert or a regular expression that accounts for the optional \r.

Suggested change
for (final line in (result.stdout as String).split('\n')) {
for (final line in (result.stdout as String).split(RegExp(r'\r?\n'))) {

Comment on lines +201 to +203
logger.info('VS environment loaded successfully');
logger.info('LIB: ${env['LIB']?.substring(0, 80)}...');

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 line can cause a RangeError if the LIB environment variable has a length less than 80. The substring method requires the end index to be less than or equal to the string length. You should ensure you don't try to access an index out of bounds when logging this information.

      logger.info('VS environment loaded successfully');
      final lib = env['LIB'];
      if (lib != null) {
        final snippet = lib.length > 80 ? lib.substring(0, 80) : lib;
        logger.info('LIB: $snippet...');
      }

Comment on lines +152 to +159
final platformTag = switch (os) {
OS.windows => 'windows-${arch == Architecture.x64 ? 'x64' : arch.toString()}',
OS.macOS => 'macos-${arch == Architecture.arm64 ? 'arm64' : 'x86_64'}',
OS.linux => 'linux-${arch == Architecture.x64 ? 'x86_64' : arch.toString()}',
OS.iOS => 'ios-${arch == Architecture.arm64 ? 'arm64' : 'x86_64'}',
OS.android => 'android-${abiForAndroid(arch)}',
_ => 'unknown',
};

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 logic for constructing platformTag is inconsistent with the logic inside the build...Static methods in lib_builder.dart. For example, for Windows ARM64, arch.toString() will produce 'Architecture.arm64', but buildWindowsStatic internally uses 'ARM64'. This will cause a mismatch in the expected directory names and the build will fail to find the installed libraries. You should unify this logic, perhaps by having the build...Static methods return the created installation path to avoid this kind of discrepancy.

Comment on lines +205 to +208
final actualInstallDir = Directory(p.join(zlibWs.path, 'install'))
.listSync()
.whereType<Directory>()
.firstWhere((d) => p.basename(d.path).contains(_zlibVersion));

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 logic to find the installation directory is fragile. It relies on searching for a directory whose name contains the version string. This can fail if there are other directories matching this condition. A more robust approach is to construct the exact path, since the build...Static methods create directories with predictable names. The path should be p.join(zlibWs.path, 'install', '$platformTag-$_zlibVersion'). Note that this depends on fixing the platformTag inconsistency mentioned in another comment.

Comment on lines 157 to 176
Future<String> _stageSources(Directory ws) async {
final srcRoot = Directory(p.join(ws.path, 'src'))..createSync(recursive: true);
final dst = Directory(p.join(srcRoot.path, 'libwebp-${defines.version}'));
if (dst.existsSync()) return dst.path;

if (defines.vendoredPath != null) {
final from = Directory(defines.vendoredPath!);
if (!from.existsSync()) {
throw StateError('Vendored path not found: ${from.path}');
}
logger.info('Using vendored sources at ${from.path}');
await copyTree(from, dst);
return dst.path;
final version = defines.version;
final cacheDir = Directory(p.join(ws.path, 'cache'))..createSync(recursive: true);
final tarball = File(p.join(cacheDir.path, 'libwebp-$version.tar.gz'));

if (!tarball.existsSync()) {
final url = defines.tarballUri ?? defines.downloadUrl;
await downloadTo(tarball, Uri.parse(url));
}

final url = Uri.parse(defines.downloadUrl);
final cache = Directory(p.join(ws.path, 'cache'))..createSync(recursive: true);
final tar = File(p.join(cache.path, 'libwebp-${defines.version}.tar.gz'));
await downloadTo(tar, url);
await extractTarGz(tar, srcRoot);

final extractedTop = Directory(
srcRoot.path,
).listSync().whereType<Directory>().firstWhere((d) => p.basename(d.path).startsWith('libwebp-'));
if (extractedTop.path != dst.path) {
await extractedTop.rename(dst.path);
final srcDir = Directory(p.join(ws.path, 'src'));
final webpSrcDir = Directory(p.join(srcDir.path, 'libwebp-$version'));

if (!webpSrcDir.existsSync()) {
await extractTarGz(tarball, srcDir);
}
logger.info('Sources staged → ${dst.path}');
return dst.path;

logger.info('Sources staged → ${webpSrcDir.path}');
return webpSrcDir.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

This refactoring of _stageSources has removed the logic to handle vendored sources (defines.vendoredPath). This is a feature regression, as the WebpDefines class still seems to support it. Please restore the logic for using vendored sources if they are specified.

Comment on lines +103 to +117
try {
final cc = (input.json['config'] as Map?)?['extensions']?['code_assets']?['c_compiler'];
if (cc is Map) {
final windows = cc['windows'] as Map?;
if (windows != null) {
final devPrompt = windows['developer_command_prompt'] as Map?;
if (devPrompt != null) {
final script = devPrompt['script'] as String?;
if (script != null && File(script).existsSync()) {
return script;
}
}
}
}
} catch (_) {}

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 try { ... } catch (_) {} block for parsing input.json is very broad. It silently swallows any error, which could make debugging difficult if the configuration is malformed. Consider catching more specific exceptions (like TypeError or StateError) or at least logging the error, even if only in a debug build, to aid in troubleshooting configuration issues.


// Find MSVC bin directory and move it to the front
final msvcBins = pathParts.where((p) => p.contains('MSVC') && p.contains('bin')).toList();
final otherPaths = pathParts.where((p) => !p.toLowerCase().contains('llvm')).toList();

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

Filtering the PATH by removing any entry containing "llvm" is a bit aggressive and could have unintended side effects if a legitimate, non-clang path happens to contain that substring. A more targeted approach would be to identify the specific LLVM/Clang path added by tools like Flutter and remove only that. While this is a pragmatic solution for a common problem, it's worth noting its potential brittleness.

Comment on lines +167 to 172
final srcDir = Directory(p.join(ws.path, 'src'));
final webpSrcDir = Directory(p.join(srcDir.path, 'libwebp-$version'));

if (!webpSrcDir.existsSync()) {
await extractTarGz(tarball, srcDir);
}

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 new implementation of _stageSources assumes the name of the extracted directory inside the tarball is libwebp-$version. The previous implementation was more robust as it searched for a directory starting with libwebp- and renamed it. This made it resilient to minor variations in the tarball structure. Consider restoring the more robust directory discovery logic.

Copilot AI 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.

Pull request overview

This PR addresses Windows build failures for the imagekit_ffi package by fixing path handling issues and adding Windows-specific build configurations for native libraries (WebP, JPEG, PNG). The main issue was that URI-to-path conversion on Windows was causing "The filename, directory name, or volume label syntax is incorrect" errors.

Changes:

  • Updated dependencies (SDK to 3.10.1, hooks and code_assets to 1.0.0) and disabled tests temporarily
  • Added Windows DLL export macros to native C headers and fixed a subsampling enum bug
  • Implemented Windows-specific build logic with Visual Studio environment handling and CRT linkage configuration
  • Added zlib dependency building for PNG support

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 23 comments.

Show a summary per file
File Description
test/imagekit_ffi_test.dart All tests commented out (testing disabled)
pubspec.yaml Updated SDK to 3.10.1, upgraded dependencies to 1.0.0, disabled test framework
native/webp/ik_webp.h Added Windows DLL export macros (IK_EXPORT) for API functions
native/webp/ik_webp.c Applied export macros, fixed subsampling enum value bug (S444=0 not 2)
native/png/ik_png.h Removed duplicate ik_png_free declaration
helpers/defines/png_defines.dart Added blank line for formatting
helpers/builders/webp_build.dart Major refactor: fixed URI-to-path conversion, added Windows DLL build with cl.exe, separated build logic per platform
helpers/builders/turbo_jpeg_build.dart Fixed URI-to-path conversion, added Windows-specific SIMD disable and library naming
helpers/builders/png_build.dart Fixed URI-to-path conversion, integrated zlib building, added Windows CRT configuration
helpers/builders/lib_builder.dart Fixed URI-to-path conversion, added VS environment detection/setup, improved CMake Windows build with toolchain file and CRT flags

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +108 to +112
// Add required Windows/CRT libraries
'libcmt.lib', // C runtime (static)
'libvcruntime.lib', // VC runtime
'libucrt.lib', // Universal CRT
'/NODEFAULTLIB:msvcrt.lib', // Avoid CRT conflicts

Copilot AI Jan 11, 2026

Copy link

Choose a reason for hiding this comment

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

Mixing static CRT libraries (libcmt.lib, libvcruntime.lib, libucrt.lib) with dynamic CRT linkage (/MD flag) will cause linker conflicts. The /MD flag specifies dynamic CRT linking, but then libcmt.lib (static C runtime) is explicitly linked. Additionally, /NODEFAULTLIB:msvcrt.lib prevents the dynamic runtime that /MD expects. Either use /MT with static libraries, or use /MD without the static CRT libraries.

Suggested change
// Add required Windows/CRT libraries
'libcmt.lib', // C runtime (static)
'libvcruntime.lib', // VC runtime
'libucrt.lib', // Universal CRT
'/NODEFAULTLIB:msvcrt.lib', // Avoid CRT conflicts

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +5
// import 'package:test/test.dart';

void main() {
group('A group of tests', () {}, skip: true);
}
// void main() {
// group('A group of tests', () {}, skip: true);
// }

Copilot AI Jan 11, 2026

Copy link

Choose a reason for hiding this comment

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

All test code has been commented out, which removes test coverage for the package. This is problematic even though the PR description states it was only tested for WebpKit().encode on Windows. The tests should be updated to work with the new changes rather than being completely disabled.

Copilot uses AI. Check for mistakes.
Comment thread pubspec.yaml
hooks: ^0.20.1
code_assets: ^0.19.7
hooks: ^1.0.0
code_assets: ^1.0.0

Copilot AI Jan 11, 2026

Copy link

Choose a reason for hiding this comment

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

The version update from code_assets ^0.19.7 to ^1.0.0 represents a major version bump which may include breaking changes. Ensure all usages of the code_assets package have been verified to work with version 1.0.0, as major version changes typically indicate API-breaking changes.

Suggested change
code_assets: ^1.0.0
code_assets: ^0.19.7

Copilot uses AI. Check for mistakes.
} else {
libPath = p.join(libDir, 'libz.a');
}

Copilot AI Jan 11, 2026

Copy link

Choose a reason for hiding this comment

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

The zlib library path determination falls back from 'zlibstatic.lib' to 'zlib.lib', but doesn't verify that the fallback file exists. If neither file exists, the function will return a non-existent path without any error, which will cause cryptic linker errors later. Add a check to throw an error if neither library file is found.

Suggested change
if (!File(libPath).existsSync()) {
throw StateError(
'$_logTag: zlib library not found in $libDir. '
'Tried ${os == OS.windows ? 'zlibstatic.lib and zlib.lib' : 'libz.a'}.',
);
}

Copilot uses AI. Check for mistakes.
Comment on lines +140 to +145
/// Build glue DLL on non-Windows using CBuilder
Future<void> _buildGlueDllCBuilder({
required String nativeSrc,
required String includeDir,
required String libDir,
}) async {

Copilot AI Jan 11, 2026

Copy link

Choose a reason for hiding this comment

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

The new method _buildGlueDllCBuilder lacks documentation. While it has a simple purpose, a doc comment explaining that it's the non-Windows build path and how it differs from the Windows approach would be helpful.

Copilot uses AI. Check for mistakes.
Comment thread pubspec.yaml
logging: ^1.2.0
hooks: ^0.20.1
code_assets: ^0.19.7
hooks: ^1.0.0

Copilot AI Jan 11, 2026

Copy link

Choose a reason for hiding this comment

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

The version update from hooks ^0.20.1 to ^1.0.0 represents a major version bump which may include breaking changes. Ensure all usages of the hooks package have been verified to work with version 1.0.0, as major version changes typically indicate API-breaking changes.

Suggested change
hooks: ^1.0.0
hooks: ^0.20.1

Copilot uses AI. Check for mistakes.
Comment on lines +77 to +82
/// Build glue DLL on Windows using cl.exe directly with VS environment
Future<void> _buildGlueDllWindows({
required String nativeSrc,
required String includeDir,
required String libDir,
}) async {

Copilot AI Jan 11, 2026

Copy link

Choose a reason for hiding this comment

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

The new method _buildGlueDllWindows lacks documentation explaining its purpose, parameters, and behavior. Given the complexity of the Windows build process with specific compiler flags and library linkage, a doc comment would help future maintainers understand the build configuration choices.

Copilot uses AI. Check for mistakes.
Comment on lines +100 to +213
/// Get the vcvars script path from hooks input or find it
String? _getVcVarsScript() {
// First try from input.json
try {
final cc = (input.json['config'] as Map?)?['extensions']?['code_assets']?['c_compiler'];
if (cc is Map) {
final windows = cc['windows'] as Map?;
if (windows != null) {
final devPrompt = windows['developer_command_prompt'] as Map?;
if (devPrompt != null) {
final script = devPrompt['script'] as String?;
if (script != null && File(script).existsSync()) {
return script;
}
}
}
}
} catch (_) {}

// Fallback: search for vcvars64.bat in common VS locations
final vsLocations = [
r'C:\Program Files\Microsoft Visual Studio\18\Community\VC\Auxiliary\Build\vcvars64.bat',
r'C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvars64.bat',
r'C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Auxiliary\Build\vcvars64.bat',
r'C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat',
r'C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat',
];

for (final loc in vsLocations) {
if (File(loc).existsSync()) {
return loc;
}
}

return null;
}

/// Public method to get VS environment for Windows builds
Future<Map<String, String>> getVsEnvironment() async {
if (!Platform.isWindows) {
return Platform.environment;
}
return _getVsEnvironment();
}

/// Build environment map by running vcvars64.bat and capturing variables
Future<Map<String, String>> _getVsEnvironment() async {
final vcvars = _getVcVarsScript();
if (vcvars == null) {
logger.warning('vcvars script path not found in input.json, using current environment');
return Platform.environment;
}

final vcvarsFile = File(vcvars);
if (!vcvarsFile.existsSync()) {
logger.warning('vcvars script not found at: $vcvars, using current environment');
return Platform.environment;
}

logger.info('Running vcvars: $vcvars');

// Use a batch file approach - write a temp batch that calls vcvars then outputs env
final tempDir = Directory.systemTemp;
final batchFile = File(p.join(tempDir.path, 'flutter_vcvars_${DateTime.now().millisecondsSinceEpoch}.bat'));

try {
// Write batch file that calls vcvars and then outputs all environment variables
await batchFile.writeAsString('''
@echo off
call "$vcvars" >nul 2>&1
if errorlevel 1 exit /b 1
set
''');

final result = await Process.run('cmd.exe', ['/c', batchFile.path]);

if (result.exitCode != 0) {
logger.warning('Failed to run vcvars batch (exit ${result.exitCode})');
logger.warning('stderr: ${result.stderr}');
return Platform.environment;
}

final env = <String, String>{};
for (final line in (result.stdout as String).split('\n')) {
final idx = line.indexOf('=');
if (idx > 0) {
final key = line.substring(0, idx).trim();
final value = line.substring(idx + 1).trim();
if (key.isNotEmpty && !key.startsWith('*')) {
env[key] = value;
}
}
}

// Verify we got the LIB variable
if (env['LIB'] == null || env['LIB']!.isEmpty) {
logger.warning('LIB not set after vcvars, environment may be incomplete');
logger.info('Available keys: ${env.keys.take(20).join(', ')}...');
return Platform.environment;
}

logger.info('VS environment loaded successfully');
logger.info('LIB: ${env['LIB']?.substring(0, 80)}...');

return env;
} finally {
// Clean up temp batch file
try {
if (batchFile.existsSync()) {
batchFile.deleteSync();
}
} catch (_) {}
}
}

Copilot AI Jan 11, 2026

Copy link

Choose a reason for hiding this comment

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

The new public method getVsEnvironment and private methods _getVcVarsScript and _getVsEnvironment lack documentation. These are critical for Windows builds and should have doc comments explaining their purpose, especially the fallback behavior and error handling.

Copilot uses AI. Check for mistakes.
Comment on lines +162 to +171
if (!tarball.existsSync()) {
final url = defines.tarballUri ?? defines.downloadUrl;
await downloadTo(tarball, Uri.parse(url));
}

final url = Uri.parse(defines.downloadUrl);
final cache = Directory(p.join(ws.path, 'cache'))..createSync(recursive: true);
final tar = File(p.join(cache.path, 'libwebp-${defines.version}.tar.gz'));
await downloadTo(tar, url);
await extractTarGz(tar, srcRoot);

final extractedTop = Directory(
srcRoot.path,
).listSync().whereType<Directory>().firstWhere((d) => p.basename(d.path).startsWith('libwebp-'));
if (extractedTop.path != dst.path) {
await extractedTop.rename(dst.path);
final srcDir = Directory(p.join(ws.path, 'src'));
final webpSrcDir = Directory(p.join(srcDir.path, 'libwebp-$version'));

if (!webpSrcDir.existsSync()) {
await extractTarGz(tarball, srcDir);

Copilot AI Jan 11, 2026

Copy link

Choose a reason for hiding this comment

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

_stageSources downloads and extracts a third-party libwebp source tarball (defines.tarballUri / defines.downloadUrl) without any integrity verification (e.g., checksum or signature) before building it into your native library. If the upstream host, mirror, or connection is compromised, attackers can supply a modified tarball that gets compiled and shipped as part of your application, enabling a supply-chain compromise. Add a strong integrity check (such as verifying a pinned SHA-256 hash or vendor signature for the tarball) before calling extractTarGz and using the resulting sources.

Copilot uses AI. Check for mistakes.
Comment on lines +244 to +251
final url = Uri.parse(_zlibUrl);
final cacheDir = Directory(p.join(ws.path, 'cache'))..createSync(recursive: true);
final tmpTar = File(p.join(cacheDir.path, 'zlib-$_zlibVersion.tar.gz'));

if (!tmpTar.existsSync()) {
await downloadTo(tmpTar, url);
}
await extractTarGz(tmpTar, srcRoot);

Copilot AI Jan 11, 2026

Copy link

Choose a reason for hiding this comment

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

_stageZlibSources downloads zlib source code from _zlibUrl and immediately extracts and builds it without any integrity verification (checksum or signature). This creates a supply-chain risk where a compromised upstream server or TLS termination could deliver a tampered tarball that is compiled into your native library, potentially leading to code execution in consuming applications. Introduce a strong integrity check (for example, verifying the tarball against a pinned SHA-256 hash or official vendor signature) before extractTarGz and using the unpacked sources.

Copilot uses AI. Check for mistakes.
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.

Building assets for package:imagekit_ffi failed

2 participants