Repository navigation
Major Refactoring of Azure DevOps Pipelines - #26008
Conversation
| for tgz in tgz_files: | ||
| print(f"Extracting {tgz.name}...") | ||
| with tarfile.open(tgz) as tar: | ||
| tar.extractall(path=".") |
Check failure
Code scanning / CodeQL
Arbitrary file write during tarfile extraction
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 1 year ago
To fix the vulnerability, we should sanitize the paths of all tarfile members before extraction. Specifically, before extracting each file, check that its member path does not contain "..", is not absolute, and does not escape the intended extraction directory. This requires iterating through tarfile members, validating each one, and then extracting them individually.
The recommended fix is:
- In the block starting with
with tarfile.open(tgz) as tar:, replacetar.extractall(path=".")with a loop that iterates over all members, validates each member's path, and extracts only safe entries usingtar.extract. - To validate, use
os.path.isabs(member.name)or".." in pathlib.Path(member.name).parts(to check for path traversal), and optionally check that the resolved final path remains inside the extraction directory. - Make minimal changes to the function in question; don't alter current logic elsewhere.
- Use only imports already present (i.e., use
os,pathlib).
This change will only affect the extraction logic in the shown file tools/ci_build/prepare_macos_package.py, specifically in the main() function.
| @@ -80,7 +80,15 @@ | ||
| for tgz in tgz_files: | ||
| print(f"Extracting {tgz.name}...") | ||
| with tarfile.open(tgz) as tar: | ||
| tar.extractall(path=".") | ||
| for member in tar.getmembers(): | ||
| # Only extract safe paths: no absolute paths, no '..' | ||
| member_path = pathlib.Path(member.name) | ||
| if member_path.is_absolute() or ".." in member_path.parts: | ||
| raise ValueError(f"Unsafe path in tar archive: {member.name}") | ||
| target_path = (staging_dir / member_path).resolve() | ||
| if not str(target_path).startswith(str(staging_dir)): | ||
| raise ValueError(f"Tar extraction escapes staging dir: {member.name}") | ||
| tar.extract(member, path=staging_dir) | ||
| tgz.unlink() # Delete the archive | ||
| print("##[endgroup]") | ||
|
|
There was a problem hiding this comment.
lintrunner found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.
b20c339 to
e1891a9
Compare
|
|
||
| print("Writing GnuPG key and passphrase to temporary files.") | ||
| private_key_file.write_text(gpg_private_key, encoding="utf-8") | ||
| passphrase_file.write_text(gpg_passphrase, encoding="utf-8") |
Check failure
Code scanning / CodeQL
Clear-text storage of sensitive information
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 1 year ago
To address the clear-text storage of sensitive information, we should ensure that the temporary file passphrase.txt containing the GPG passphrase is created with restrictive permissions (owner read/write only, mode 0o600). This reduces the risk of exposure from other local users or processes. Instead of using Path.write_text, which does not set file permissions, we should use os.open with the appropriate mode, then write the passphrase, and close the file. This change should be made in the main function where the temporary file is created and written. No change is needed for the key file (private.key), as it is not flagged as a password. The GPG command should continue to read from the secure file.
This may require importing os (already present). The code block to replace concerns the writing of the passphrase file.
| @@ -101,7 +101,12 @@ | ||
|
|
||
| print("Writing GnuPG key and passphrase to temporary files.") | ||
| private_key_file.write_text(gpg_private_key, encoding="utf-8") | ||
| passphrase_file.write_text(gpg_passphrase, encoding="utf-8") | ||
| # Write the passphrase to the file with restrictive permissions (owner read/write only) | ||
| passphrase_fd = os.open(passphrase_file, os.O_WRONLY | os.O_CREAT | os.O_TRUNC, 0o600) | ||
| try: | ||
| os.write(passphrase_fd, gpg_passphrase.encode("utf-8")) | ||
| finally: | ||
| os.close(passphrase_fd) | ||
|
|
||
| print("Importing GnuPG private key.") | ||
| run_command([str(gpg_exe_path), "--batch", "--import", str(private_key_file)]) |
a1c6a3f to
7908114
Compare
| try: | ||
| import semver | ||
| except ImportError: | ||
| print("Error: The 'semver' package is not installed. Please add it to your requirements.txt.", file=sys.stderr) |
Check notice
Code scanning / CodeQL
Use of a print statement at module level
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI about 1 year ago
To fix this, the module-level print should be replaced by a logging call, specifically using the logging module, as recommended. We should add an import for logging (if not already present) at the top of the file, and replace line 23 with logging.error(...). This will avoid writing directly to standard out/consoles during import, and allow users to configure log handling. All other print statements in this file (lines 51, 64, 70, 71, 77, 92, 97, 98) are inside functions—not at module level—so only module-level code needs to be changed. Only change file tools/ci_build/github/windows/jar_packaging.py, specifically lines near 23; add import logging after standard imports if necessary, and replace the print.
| @@ -15,12 +15,12 @@ | ||
| import sys | ||
| from pathlib import Path | ||
| from typing import Any | ||
|
|
||
| import logging | ||
| # Add semver as a dependency | ||
| try: | ||
| import semver | ||
| except ImportError: | ||
| print("Error: The 'semver' package is not installed. Please add it to your requirements.txt.", file=sys.stderr) | ||
| logging.error("The 'semver' package is not installed. Please add it to your requirements.txt.") | ||
| sys.exit(1) | ||
|
|
||
| # --- Helper Functions for Archiving --- |
57e4ad5 to
fba7436
Compare
69ac20b to
47f9827
Compare
4100d16 to
1cb83b9
Compare
d37f2bf to
5986105
Compare
|
should we also update this react-native-ci.yml job to use an older CMake for the MacOS build? |
Will address it after this PR. |
|
Should be fairly easy to migrate the pipeline to GH by employing an AI agent. |
This PR cherry-picks several commits from the main branch to the rel-1.23.0 release branch as part of the release process. ### Changes included: * **Major Refactoring of Azure DevOps Pipelines (#26008)** * Commit: `2e6d7ccfdff55aaf7b0799d7e28b041e607dce2b` * **Disables failing test to unblock Python DML Pipeline (#26043)** * Commit: `64c8f40d01bf14b3cf7ac4cf8606ad9e0e56feb0` * **Pin cmake version in macOS github Actions (#25998)** * Commit: `148f13cc6b44cae156226cd4e0dcfc154691c5b4` * **Bump actions/setup-python from 5 to 6 (#25979)** * Commit: `97a8d332595c974ad24be133df216565493ffb95` * **Remove CACHE_URL settings from Github Actions (#25989)** * Commit: `e2a0999ba4b224ab90ef7a8768dd4941fcc19b17` * **Bump actions/checkout from 4 to 5 (#25771)** * Commit: `f19215db21f8e1a8fc93090748e455f41076f456` * **Bump ruff from 0.12.8 to 0.12.9 (#25772)** * Commit: `78df404871fa2f3fbbb7f1902f9623787ba8dc86` * **Bump ruff from 0.12.4 to 0.12.8 (#25713)** * Commit: `7204746e709005d2c7294e7a24d63a2df4a1aee8` * **Update macOS target version from 13.3 to 13.4 (#25616)** * Commit: `65bd82564cd31e0acf9139cdd826d08193212c6e` --------- Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Prathik Rao <prathik.rao@gmail.com>
This pull request introduces a significant refactoring of the Azure Pipelines CI/CD infrastructure. The primary goals of these changes are to: 1. Solve the problem that vcpkg/cmake version can get changed when the CI build machine image changes, which can make pipeline suddenly broken and interrupt our release process. 2. Reduce the `Zip-Nuget-Java-Nodejs Packaging Pipeline`'s running time by changing how macOS universal2 binaries are built. 3. Add the support for RC releases for Java packages. **1. Standardized Build Tool Setup (`setup-build-tools.yml`)** A new reusable template, `setup-build-tools.yml`, has been created to centralize the setup of essential build tools. * **Pinned Dependencies:** This new template allows us to pin specific versions of `cmake` and `vcpkg`, which was not previously possible. This ensures a more stable and predictable build environment across all pipelines. * **Reduced Redundancy:** By consolidating the setup logic into a single template, we have significantly reduced code duplication across numerous pipeline files, making them cleaner and easier to maintain. Currently this file is only used in macOS and Windows pipelines since most Linux pipelines use docker to manage their environment. **2. Reworked macOS Universal Binary Build Process** The methodology for building macOS `universal2` binaries has been fundamentally changed to improve reliability and flexibility. * **Python Packaging:** The Python packaging pipeline will no longer produce `universal2` wheels. Instead, it will generate separate wheels for `x86_64` and `arm64` architectures. * **NuGet C-API Packaging:** The NuGet C-API pipeline has been updated to first build the `x86_64` and `arm64` binaries independently. These single-architecture binaries are then combined to create the final universal package, rather than building a `universal2` package in a single pass. The change is made mainly because: - Building for both ARCHs in a single pass is too slow, which may take about 5 hours in the ADO machine pool. - A lot of MLAS features are disabled when ORT is built in such a way. **3. Java Packaging and Testing Overhaul** The Download_Java_Tools stage in "Zip-Nuget-Java-Nodejs Packaging Pipeline" is deleted because it is no longer used. Previously it was added to reduce the times of downloading the same java packages again and again , which was to reduce download errors. Now we have setup a private ADO feed for this. Besides, there are some major changes to the pipeline that: 1. MD5 and SHA1 checksum files are provided along with the java package files instead of SHA256. This is because Sonatype's official docs says MD5/SHA1 checkcums are required while the others are optional. See: https://central.sonatype.org/publish/requirements/#supply-javadoc-and-sources . Now the publishing would fail if we don't have the MD5/SHA1 checksum files. 2. The format of the checksum files is changed. Previously we used Linux's sha256sum command to generate such files, so each checksum file contains a hash value and a filename in the file content. However, it was not the expected format. Sonatype expects that the file only contains a hash value. This PR fixes the issue. 3. A few powershell scripts were rewritten in python to improve error check and robustness 4. Added the support for generating RC packages. Previously we had to manually modify the version numbers and manually do GPG sign. 5. Two new files `jar-packaging.yml` and `setup-maven.yml` were added. We will use maven to fetch dependent packages(instead of directly HTTP fetching) to improve supply chain security, because maven allows us using a private feed to do so. **4. Dockerfile Enhancements** The Dockerfiles used in the CI have been updated to use a `BASEIMAGE` argument. This makes them more flexible, allowing the base image to be specified at build time, which simplifies maintenance and updates. It will allow us to using different base image repos in different CI environments. In the future we will change the Github Actions to only fetch base images from public docker repos. Meanwhile, ADO packaging pipelines will continue to use private repos. **5. Improved Release Management** The run_packaging_pipelines.py script has been updated to provide more robust and explicit control over the package versioning for different build scenarios. This clarifies the process for generating nightly, release candidate (RC), and final release packages. The script now handles three distinct cases for package versioning: * Nightly Packages: For regular CI builds (e.g., on the main branch), the script triggers the packaging pipelines in "nightly" mode. This sets the IsReleaseBuild parameter to false and results in packages with a development version suffix (e.g., 1.2.3-dev-20250909-abcdef). * Release Candidate (RC) Builds: To create a pre-release or RC build, the script is run with the --build-mode release flag, along with the --pre-release-suffix-string (e.g., rc) and --pre-release-suffix-number (e.g., 1) arguments. This sets the IsReleaseBuild parameter to true and passes the suffix information to the pipelines, resulting in a semantically versioned pre-release package (e.g., 1.2.3-rc.1). * Final Release Builds: For a final release, the script is run with --build-mode release without any pre-release suffix arguments. This sets IsReleaseBuild to true, and the resulting package will have a clean, final version number (e.g., 1.2.3) based on the VERSION_NUMBER file. Please note: - Java packages still only support the second and third mode. - Python packages only support the first and the last mode.
- **Major Refactoring of Azure DevOps Pipelines (#26008)** - **Convert QNN x64 pipeline to GH (#26047)** - **Upgrade com.diffplug.spotless to 7.2.1 in Java build (#26051)** - **Fix Mac Catalyst build options. (#25970)** - **Update Podfile.template: update macOS target version from 13.3 to 13.4 (#25699) **
This pull request introduces a significant refactoring of the Azure Pipelines CI/CD infrastructure. The primary goals of these changes are to:
Zip-Nuget-Java-Nodejs Packaging Pipeline's running time by changing how macOS universal2 binaries are built.Key Changes:
1. Standardized Build Tool Setup (
setup-build-tools.yml)A new reusable template,
setup-build-tools.yml, has been created to centralize the setup of essential build tools.cmakeandvcpkg, which was not previously possible. This ensures a more stable and predictable build environment across all pipelines.Currently this file is only used in macOS and Windows pipelines since most Linux pipelines use docker to manage their environment.
2. Reworked macOS Universal Binary Build Process
The methodology for building macOS
universal2binaries has been fundamentally changed to improve reliability and flexibility.universal2wheels. Instead, it will generate separate wheels forx86_64andarm64architectures.x86_64andarm64binaries independently. These single-architecture binaries are then combined to create the final universal package, rather than building auniversal2package in a single pass.The change is made mainly because:
3. Java Packaging and Testing Overhaul
The Download_Java_Tools stage in "Zip-Nuget-Java-Nodejs Packaging Pipeline" is deleted because it is no longer used. Previously it was added to reduce the times of downloading the same java packages again and again , which was to reduce download errors. Now we have setup a private ADO feed for this.
Besides, there are some major changes to the pipeline that:
jar-packaging.ymlandsetup-maven.ymlwere added. We will use maven to fetch dependent packages(instead of directly HTTP fetching) to improve supply chain security, because maven allows us using a private feed to do so.4. Dockerfile Enhancements
The Dockerfiles used in the CI have been updated to use a
BASEIMAGEargument. This makes them more flexible, allowing the base image to be specified at build time, which simplifies maintenance and updates. It will allow us to using different base image repos in different CI environments. In the future we will change the Github Actions to only fetch base images from public docker repos. Meanwhile, ADO packaging pipelines will continue to use private repos.5. Improved Release Management
The run_packaging_pipelines.py script has been updated to provide more robust and explicit control over
the package versioning for different build scenarios. This clarifies the process for generating nightly,
release candidate (RC), and final release packages.
The script now handles three distinct cases for package versioning:
Nightly Packages: For regular CI builds (e.g., on the main branch), the script triggers the packaging
pipelines in "nightly" mode. This sets the IsReleaseBuild parameter to false and results in packages with
a development version suffix (e.g., 1.2.3-dev-20250909-abcdef).
Release Candidate (RC) Builds: To create a pre-release or RC build, the script is run with the
--build-mode release flag, along with the --pre-release-suffix-string (e.g., rc) and
--pre-release-suffix-number (e.g., 1) arguments. This sets the IsReleaseBuild parameter to true and
passes the suffix information to the pipelines, resulting in a semantically versioned pre-release package
(e.g., 1.2.3-rc.1).
Final Release Builds: For a final release, the script is run with --build-mode release without any
pre-release suffix arguments. This sets IsReleaseBuild to true, and the resulting package will have a
clean, final version number (e.g., 1.2.3) based on the VERSION_NUMBER file.
Please note: