Skip to content

build: Improve security by pinning auto-build dependencies by hash#5076

Open
lgritz wants to merge 1 commit intoAcademySoftwareFoundation:mainfrom
lgritz:lg-buildsafety
Open

build: Improve security by pinning auto-build dependencies by hash#5076
lgritz wants to merge 1 commit intoAcademySoftwareFoundation:mainfrom
lgritz:lg-buildsafety

Conversation

@lgritz
Copy link
Collaborator

@lgritz lgritz commented Mar 8, 2026

The files that match the pattern "src/cmake/build_.cmake" are all similar and each one is called by our build system if a dependency is not found, to download and built it locally to be incorporated into our build. One example is src/cmake/build_TIFF.cmake.

Within these files, the version to be retrieved is determined by a pair of lines such as

set_cache (TIFF_BUILD_VERSION 4.7.1 "TIFF version for local builds")
set_cache (TIFF_GIT_TAG "v${TIFF_BUILD_VERSION}" "Git branch or tag")

The tag is passed to build_dependency_with_cmake with the GIT_TAG argument. There is also an optional GIT_COMMIT argument, that we usually do not use (previously, only needed if we wanted to build from a commit that didn't have a version tag).

But it turns out that it's probably not safe to blindly retrieve a tag, in case the dependency's repo has been hijacked and the tag reset to point to a malicious commit.

So here is how to address this:

  • build_dependency_with_cmake modifies its internal logic:

    • If only the GIT_COMMIT is passed and GIT_TAG is blank, use the commit.
    • If both GIT_COMMIT and GIT_TAG are passed, check out the tag but verify that it is the commit specified, and if not, then consider it an error and do not proceed with building the dependency.
    • If only GIT_TAG is passed and not GIT_COMMIT, warn about the potential safety problem.
    • But as a special option for dangerous tasks, an override called OpenImageIO_DEPENDENCY_BUILD_ALLOW_UNVERIFIED_TAGS allows an unverified git tag to be checked out. This is how we make the "bleeding edge" test still build against dependecy main/masters.
  • For each of the build_<dependency>.cmake files, change it as follows:

    • Determine the commit hash of the specified version by checking the repository.
    • Add a line setting <dependency>_GIT_COMMIT to the corresponding hash.
    • Pass both arguments to build_dependency_with_cmake.

This patch was made with the help of Claude Code using Opus 4.6. I started the dialog with a prompt that was substantially similar to the description above, detailing my proposed plan.

I first suggested that if only the TAG is present, to allow it as long as it turned out to be an immutable git release tag, but it pointed out that (a) this requires a build-time dependency on the gh command line util, (b) not all our dependencies are on GitHub (such as libtiff on GitLab), so we modified the plan to warn in that case rather than try to determine if it's immutable. The rest proceeded more or less as expected, with a few rounds of back and forth and corrections.

The files that match the pattern "src/cmake/build_<dependency>.cmake"
are all similar and each one is called by our build system if a
dependency is not found, to download and built it locally to be
incorporated into our build.  One example is src/cmake/build_TIFF.cmake.

Within these files, the version to be retrieved is determined by a
pair of lines such as
```
set_cache (TIFF_BUILD_VERSION 4.7.1 "TIFF version for local builds")
set_cache (TIFF_GIT_TAG "v${TIFF_BUILD_VERSION}" "Git branch or tag")
```

The tag is passed to `build_dependency_with_cmake` with the `GIT_TAG`
argument. There is also an optional `GIT_COMMIT` argument, that we
usually do not use (previously, only needed if we wanted to build from
a commit that didn't have a version tag).

But it turns out that it's probably not safe to blindly retrieve a
tag, in case the dependency's repo has been hijacked and the tag reset
to point to a malicious commit.

So here is how to address this:

- `build_dependency_with_cmake` modifies its internal logic:
  - If only the GIT_COMMIT is passed and GIT_TAG is blank, use the commit.
  - If both GIT_COMMIT and GIT_TAG are passed, check out the tag but
    verify that it is the commit specified, and if not, then consider
    it an error and do not proceed with building the dependency.
  - If only GIT_TAG is passed and not GIT_COMMIT, warn about the
    potential safety problem.
  - But as a special option for dangerous tasks, an override called
    OpenImageIO_DEPENDENCY_BUILD_ALLOW_UNVERIFIED_TAGS allows an
    unverified git tag to be checked out. This is how we make the
    "bleeding edge" test still build against dependecy main/masters.

- For each of the `build_<dependency>.cmake` files, change it as follows:
  - Determine the commit hash of the specified version by checking the
    repository.
  - Add a line setting `<dependency>_GIT_COMMIT` to the corresponding
    hash.
  - Pass both arguments to build_dependency_with_cmake.

This patch was made with the help of Claude Code using Opus 4.6.
I started the dialog with a prompt that was substantially similar
to the description above, detailing my proposed plan.

I first suggested that if only the TAG is present, to allow it as long
as it turned out to be an immutable git release tag, but it pointed
out that (a) this requires a build-time dependency on the `gh` command
line util, (b) not all our dependencies are on GitHub (such as libtiff
on GitLab), so we modified the plan to warn in that case rather than
try to determine if it's immutable. The rest proceeded more or less
as expected, with a few rounds of back and forth and corrections.

Signed-off-by: Larry Gritz <lg@larrygritz.com>
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