diff --git a/.github/workflows/build_release_assets.yml b/.github/workflows/build_release_assets.yml index 8d2e021503..d21526ed4e 100644 --- a/.github/workflows/build_release_assets.yml +++ b/.github/workflows/build_release_assets.yml @@ -1,43 +1,46 @@ name: Build release assets -# This workflow is used by the tag workflow to build all release assets. It -# can also be triggered manually. +# This workflow is used by the ci and tag workflows to build all release +# assets. It can also be triggered manually. on: workflow_call: + inputs: + release_mode: + description: 'Release mode (signed binaries, no commit sha in version number)' + type: boolean + default: false workflow_dispatch: + inputs: + release_mode: + description: 'Release mode (signed binaries, no commit sha in version number)' + type: boolean + default: false jobs: - build_packages: + build_wheel_sdist: runs-on: ubuntu-22.04 steps: - name: Checkout uses: actions/checkout@v4 - with: - fetch-depth: 0 - name: Install packaging tools - shell: bash run: | - curl -L https://github.com/goreleaser/nfpm/releases/download/v2.15.0/nfpm_amd64.deb -o nfpm_amd64.deb - sudo dpkg -i nfpm_amd64.deb - - pip install shiv==1.0.1 build + pip install build - name: Create packages - shell: bash - run: scripts/build-packages/build-packages + run: | + python -m build - name: Upload packages uses: actions/upload-artifact@v4 with: - name: packages + name: dist path: | dist - packages - build_standalone_binaries: - name: Build signed, standalone binaries + build_os_packages: + name: Build packages runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -103,21 +106,33 @@ jobs: # Make it available cp rcodesign /usr/local/bin - - name: Install normal dependencies + - name: Install dependencies + shell: bash run: | python -m pip install --upgrade pip - python -m pip install --upgrade pipenv==2023.10.3 + python -m pip install --upgrade \ + pipenv==2023.10.3 \ + pyinstaller==6.5.0 pipenv install --system --dev env: # Disable lock otherwise Windows-only dependencies like colorama are not installed PIPENV_SKIP_LOCK: 1 - - name: Install standalone-specific dependencies + - name: Install Linux specific dependencies + if: matrix.os == 'ubuntu-22.04' run: | - python -m pip install pyinstaller==6.5.0 + NFPM_VERSION=2.36.1 + NFPM_CHECKSUM=05c17a1e09c470807b149fdd7bcd8f600eea044f459fc3ce81aa230103c0baf5 + + scripts/download \ + https://github.com/goreleaser/nfpm/releases/download/v${NFPM_VERSION}/nfpm_${NFPM_VERSION}_amd64.deb \ + nfpm.deb \ + $NFPM_CHECKSUM + + sudo dpkg -i nfpm.deb - name: Prepare macOS secrets - if: startsWith(matrix.os, 'macos-') + if: startsWith(matrix.os, 'macos-') && inputs.release_mode run: | set -euo pipefail SECRETS_DIR=$TMPDIR/secrets @@ -142,7 +157,12 @@ jobs: - name: Build shell: bash run: | - scripts/build-standalone-exe --sign + if [ "${{ inputs.release_mode }}" = "true" ] ; then + args="--sign" + else + args="--git-version" + fi + scripts/build-os-packages/build-os-packages $args - name: Override base Docker image used for functional tests on Windows if: matrix.os == 'windows-2022' @@ -157,7 +177,7 @@ jobs: # See note about steps requiring the GITGUARDIAN_API at the top of this file if: ${{ !github.event.pull_request.head.repo.fork }} run: | - scripts/build-standalone-exe functests + scripts/build-os-packages/build-os-packages functests env: GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }} GITGUARDIAN_API_URL: ${{ secrets.GITGUARDIAN_API_URL }} @@ -166,8 +186,10 @@ jobs: - name: Upload artifacts uses: actions/upload-artifact@v4 with: - name: standalone-binaries-${{ matrix.os }} + name: os-packages-${{ matrix.os }} path: | - dist/ggshield-*.gz - dist/ggshield-*.pkg - dist/ggshield-*.zip + packages/ggshield-*.gz + packages/ggshield-*.pkg + packages/ggshield-*.zip + packages/ggshield-*.rpm + packages/ggshield_*.deb diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a924a58bc2..eb8c66b293 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -153,113 +153,9 @@ jobs: GITGUARDIAN_API_URL: ${{ secrets.GITGUARDIAN_API_URL }} TEST_KNOWN_SECRET: ${{ secrets.TEST_KNOWN_SECRET }} - build-standalone: - name: Standalone exe - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: - - ubuntu-22.04 - - macos-13 - - windows-2022 - - macos-14 - steps: - - uses: actions/checkout@v4 - with: - # Get enough commits to run `ggshield secret scan commit-range` on ourselves - fetch-depth: 10 - - - name: Set up Python 3.10 - uses: actions/setup-python@v4 - with: - python-version: '3.10' - - - name: Install normal dependencies - run: | - python -m pip install --upgrade pip - python -m pip install --upgrade pipenv==2023.10.3 - pipenv install --system --dev - env: - # Disable lock otherwise Windows-only dependencies like colorama are not installed - PIPENV_SKIP_LOCK: 1 - - - name: Install standalone-specific dependencies - run: | - python -m pip install pyinstaller==6.5.0 - - - name: Build - shell: bash - run: | - scripts/build-standalone-exe - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: ggshield-${{ matrix.os }} - path: | - dist/ggshield-*.gz - dist/ggshield-*.pkg - dist/ggshield-*.zip - - - name: Override base Docker image used for functional tests on Windows - if: matrix.os == 'windows-2022' - # This is required because GitHub Windows runner is not configured to - # run Linux-based Docker images - shell: bash - run: | - echo "GGTEST_DOCKER_IMAGE=mcr.microsoft.com/windows/nanoserver:ltsc2022" >> $GITHUB_ENV - - - name: Functional tests - shell: bash - # See note about steps requiring the GITGUARDIAN_API at the top of this file - if: ${{ !github.event.pull_request.head.repo.fork }} - run: | - scripts/build-standalone-exe functests - env: - GITGUARDIAN_API_KEY: ${{ secrets.GITGUARDIAN_API_KEY }} - GITGUARDIAN_API_URL: ${{ secrets.GITGUARDIAN_API_URL }} - TEST_KNOWN_SECRET: ${{ secrets.TEST_KNOWN_SECRET }} - - build_packages: - # This job ensures the build-packages script is tested on each build, not only at release time - runs-on: ubuntu-22.04 - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - # Warning: changes on this step should be reflected in workflows/tag.yml - - name: Install packaging tools - shell: bash - run: | - curl -L https://github.com/goreleaser/nfpm/releases/download/v2.15.0/nfpm_amd64.deb -o nfpm_amd64.deb - sudo dpkg -i nfpm_amd64.deb - - pip install shiv==1.0.1 build - - # Append the abbreviated git sha1 to the version number to avoid confusing - # these packages with those produced at release time - - name: Fake version number - shell: bash - run: | - version=$(git describe --tags | sed -e 's/^v//' -e 's/-[0-9]*-g/+/') - echo "Set version number to '$version'" - sed -i "s/__version__ = .*/__version__ = \"$version\"/" ggshield/__init__.py - - - name: Create packages - shell: bash - run: scripts/build-packages/build-packages - - # Make packages downloadable from the workflow page - - name: Upload packages - uses: actions/upload-artifact@v3 - with: - name: packages - path: | - dist - packages + build_os_packages: + uses: ./.github/workflows/build_release_assets.yml + secrets: inherit test_github_secret_scan_action: name: Test GitHub action for `secret scan` diff --git a/.github/workflows/tag.yml b/.github/workflows/tag.yml index 627de9d71a..ecf0b89f64 100644 --- a/.github/workflows/tag.yml +++ b/.github/workflows/tag.yml @@ -9,6 +9,8 @@ jobs: build_release_assets: uses: ./.github/workflows/build_release_assets.yml secrets: inherit + with: + release_mode: true push_to_pypi: needs: build_release_assets @@ -21,10 +23,11 @@ jobs: with: python-version: '3.x' - - name: Download packages + - name: Download wheel and sdist uses: actions/download-artifact@v4 with: - name: packages + name: dist + path: dist - name: Publish distribution 📦 to PyPI uses: pypa/gh-action-pypi-publish@release/v1 @@ -54,16 +57,11 @@ jobs: run: | echo "tag=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT - - name: Download packages - uses: actions/download-artifact@v4 - with: - name: packages - - - name: Download standalone binaries + - name: Download OS packages uses: actions/download-artifact@v4 with: - pattern: standalone-binaries-* - path: standalone-binaries + pattern: os-packages-* + path: packages merge-multiple: true - name: Create release @@ -78,10 +76,10 @@ jobs: run: | gh release upload \ ${{ steps.tags.outputs.tag }} \ - packages/ggshield-*.pyz \ + packages/ggshield-*.pkg \ packages/ggshield_*.deb \ packages/ggshield-*.rpm \ - standalone-binaries/ggshield-*.pkg + packages/ggshield-*.gz push_to_docker_hub: name: Push Docker image to Docker Hub @@ -155,7 +153,9 @@ jobs: - name: Download packages uses: actions/download-artifact@v4 with: - name: packages + pattern: os-packages-* + path: packages + merge-multiple: true - name: Install Cloudsmith CLI run: pip install cloudsmith-cli diff --git a/changelog.d/20240417_180529_ggshield-test_standalone_linux_packages.md b/changelog.d/20240417_180529_ggshield-test_standalone_linux_packages.md new file mode 100644 index 0000000000..dba2c6373c --- /dev/null +++ b/changelog.d/20240417_180529_ggshield-test_standalone_linux_packages.md @@ -0,0 +1,3 @@ +### Changed + +- Linux .deb and .rpm packages now use the binaries produced by pyinstaller. They no longer depend on Python. diff --git a/doc/dev/standalone-executables.md b/doc/dev/os-packages.md similarity index 72% rename from doc/dev/standalone-executables.md rename to doc/dev/os-packages.md index fa023003e0..476f181db9 100644 --- a/doc/dev/standalone-executables.md +++ b/doc/dev/os-packages.md @@ -1,4 +1,4 @@ -# Building standalone executables +# Building OS packages ## Introduction @@ -6,11 +6,29 @@ To solve those deployment issues, we provide standalone `ggshield` executables, that do not require a Python interpreter. This documentation explains how these executables are produced. -The process of generating the executable is handled by the `scripts/build-standalone-exe` script. This script runs a series of "steps". It has a default list of steps, but you can tell it to run only specific steps using `scripts/build-standalone-exe step1 step2...`. - -All functions in the script starting with `step_` can be used as a step. This means you can get a list of all available steps with: `grep -o '^step_[a-z_]*' scripts/build-standalone-exe`. - -## Generating the executable +The process of generating the packages is handled by the `scripts/build-os-packages/build-os-packages` script. This script runs a series of "steps". It has a default list of steps, but you can tell it to run only specific steps using `scripts/build-os-packages/build-os-packages step1 step2...`. + +All functions in the script starting with `step_` can be used as a step. This means you can get a list of all available steps with: `grep -o '^step_[a-z_]*' scripts/build-os-packages/build-os-packages`. + +Here is a high-level overview of the main steps (square boxes are steps): + +```mermaid +flowchart TD + src[/source code/] --> build --> pyinstaller_dir[/"pyinstaller output + (dist/ggshield)"/] + pyinstaller_dir --> copy_files --> archive_dir[/"dir ready to be archived + (packages/ggshield-$version-$target)"/] + archive_dir --> test["test (run functional tests on archive dir)"] + test --> signing{Called with --sign?} -->|yes| sign + signing -->|no| create_archive + sign --> create_archive --> pkg[/"pkg 🍏"/] + create_archive --> zip[/"zip 🪟"/] + create_archive --> tar.gz[/"tar.gz 🐧"/] + create_archive --> deb[/"deb 🐧"/] + create_archive --> rpm[/"rpm 🐧"/] +``` + +## Generating the standalone executable We use [PyInstaller](https://pyinstaller.org) to generate `ggshield` standalone executable. diff --git a/scripts/standalone-exe/README.md b/scripts/build-os-packages/README.md.tmpl similarity index 100% rename from scripts/standalone-exe/README.md rename to scripts/build-os-packages/README.md.tmpl diff --git a/scripts/build-standalone-exe b/scripts/build-os-packages/build-os-packages similarity index 66% rename from scripts/build-standalone-exe rename to scripts/build-os-packages/build-os-packages index db011c72c6..ea5d511215 100755 --- a/scripts/build-standalone-exe +++ b/scripts/build-os-packages/build-os-packages @@ -2,18 +2,24 @@ set -euo pipefail PROGNAME=$(basename "$0") -ROOT_DIR=$(cd "$(dirname "$0")/.." ; pwd) -RESOURCES_DIR="$ROOT_DIR/scripts/standalone-exe" +SCRIPT_DIR=$(cd "$(dirname "$0")" ; pwd) +ROOT_DIR=$(cd "$SCRIPT_DIR/../.." ; pwd) DEFAULT_STEPS="req build copy_files test sign create_archive" -DIST_DIR=$PWD/dist +PYINSTALLER_OUTPUT_DIR=$ROOT_DIR/dist/ggshield +PACKAGES_DIR=$ROOT_DIR/packages REQUIREMENTS="pyinstaller" # Whether we want a signed binary or not DO_SIGN=0 +# Where to find the version: +# - 0: read it from ggshield/__init__.py +# - 1: generate it using `git describe` +USE_GIT_VERSION=0 + MACOS_P12_FILE=${MACOS_P12_FILE:-} MACOS_P12_PASSWORD_FILE=${MACOS_P12_PASSWORD_FILE:-} @@ -49,15 +55,16 @@ usage() { cat << EOF Usage: $PROGNAME [OPTION ...] [STEPS] -Build a standalone executable for ggshield. +Build OS specific packages for ggshield. Default steps are: $DEFAULT_STEPS Options: -h, --help Display this usage message and exit. --sign Sign the binary, on supported OSes. + --git-version Append "+COMMIT_SHA" to the version number. -For more details, see doc/dev/standalone-executables.md. +For more details, see doc/dev/os-packages.md. EOF exit 1 @@ -65,6 +72,12 @@ EOF read_version() { VERSION=$(grep -o "[0-9]*\.[0-9]*\.[0-9]*" "$ROOT_DIR/ggshield/__init__.py") + if [ "$USE_GIT_VERSION" -eq 1 ] ; then + local commit_sha + commit_sha=$(git rev-parse --short HEAD) + VERSION="$VERSION+$commit_sha" + fi + info "VERSION=$VERSION" } init_system_vars() { @@ -94,6 +107,7 @@ init_system_vars() { EXE_EXT="" TARGET="$arch-unknown-linux-gnu" HUMAN_OS=Linux + REQUIREMENTS="$REQUIREMENTS nfpm" ;; Darwin) EXE_EXT="" @@ -137,42 +151,55 @@ step_req() { step_build() { rm -rf build/ggshield - rm -rf "$DIST_DIR/ggshield" + rm -rf "$PYINSTALLER_OUTPUT_DIR" + + local extra_args="" + if [ "$HUMAN_OS" != Windows ] ; then + # Only strip on Linux and macOS: pyinstaller docs says it's not + # recommended on Windows. + extra_args="--strip" + fi + + pyinstaller ggshield/__main__.py --name ggshield --noupx $extra_args - pyinstaller ggshield/__main__.py --name ggshield --noupx + if [ "$HUMAN_OS" != Windows ] ; then + # Libraries do not need to be executable + find "$PYINSTALLER_OUTPUT_DIR" \( -name "*.so.*" -o -name "*.so" -o -name "*.dylib" \) \ + -exec chmod -x '{}' ';' + fi } step_copy_files() { - local pyinstaller_output_dir=$DIST_DIR/ggshield - if ! [ -d "$pyinstaller_output_dir" ] ; then - die "$pyinstaller_output_dir does not exist" + if ! [ -d "$PYINSTALLER_OUTPUT_DIR" ] ; then + die "$PYINSTALLER_OUTPUT_DIR does not exist" fi - local pyinstaller_ggshield=$pyinstaller_output_dir/ggshield$EXE_EXT + local pyinstaller_ggshield=$PYINSTALLER_OUTPUT_DIR/ggshield$EXE_EXT if ! [ -f "$pyinstaller_ggshield" ] ; then die "Can't find '$pyinstaller_ggshield', maybe 'build' step did not run?" fi + mkdir -p "$PACKAGES_DIR" case "$HUMAN_OS" in Linux|Windows) - local output_dir="$DIST_DIR/$ARCHIVE_DIR_NAME" + local output_dir="$PACKAGES_DIR/$ARCHIVE_DIR_NAME" info "Copying files to $output_dir" rm -rf "$output_dir" - cp -R "$pyinstaller_output_dir" "$output_dir" + cp -R "$PYINSTALLER_OUTPUT_DIR" "$output_dir" info "Generating README.md" sed \ -e "s/@HUMAN_OS@/$HUMAN_OS/" \ -e "s/@HUMAN_ARCH@/$HUMAN_ARCH/" \ - "$RESOURCES_DIR/README.md" \ + "$SCRIPT_DIR/README.md.tmpl" \ > "$output_dir/README.md" ;; macOS) - local output_dir="$DIST_DIR/$ARCHIVE_DIR_NAME/$INSTALL_PREFIX" - local bin_dir="$DIST_DIR/$ARCHIVE_DIR_NAME/usr/local/bin" + local output_dir="$PACKAGES_DIR/$ARCHIVE_DIR_NAME/$INSTALL_PREFIX" + local bin_dir="$PACKAGES_DIR/$ARCHIVE_DIR_NAME/usr/local/bin" info "Copying files to $output_dir" rm -rf "$output_dir" "$bin_dir" mkdir -p "$(dirname $output_dir)" - cp -R "$pyinstaller_output_dir" "$output_dir" + cp -R "$PYINSTALLER_OUTPUT_DIR" "$output_dir" info "Creating launcher symlink" mkdir -p "$bin_dir" @@ -197,7 +224,7 @@ sign_file() { } list_files_to_sign() { - local archive_dir="$DIST_DIR/$ARCHIVE_DIR_NAME" + local archive_dir="$PACKAGES_DIR/$ARCHIVE_DIR_NAME" echo "$archive_dir/$INSTALL_PREFIX/ggshield" find "$archive_dir" -name '*.so' -o -name '*.dylib' } @@ -219,42 +246,59 @@ step_sign() { step_test() { for args in --help --version ; do info "test: running $args" - "$DIST_DIR/$ARCHIVE_DIR_NAME/$INSTALL_PREFIX/ggshield${EXE_EXT}" $args + "$PACKAGES_DIR/$ARCHIVE_DIR_NAME/$INSTALL_PREFIX/ggshield${EXE_EXT}" $args info "test: running $args: OK" done } step_functests() { - PATH=$DIST_DIR/$ARCHIVE_DIR_NAME/$INSTALL_PREFIX:$PATH pytest tests/functional + PATH=$PACKAGES_DIR/$ARCHIVE_DIR_NAME/$INSTALL_PREFIX:$PATH pytest tests/functional +} + +create_linux_packages() { + for format in rpm deb ; do + info "Building $format" + + PYINSTALLER_OUTPUT_DIR=$PYINSTALLER_OUTPUT_DIR \ + VERSION=$VERSION \ + nfpm package \ + --packager $format \ + --config "$SCRIPT_DIR/nfpm.yaml" \ + --target "$PACKAGES_DIR" + done } step_create_archive() { local archive_path - cd "$DIST_DIR" case "$HUMAN_OS" in Linux) - archive_path="$DIST_DIR/$ARCHIVE_DIR_NAME.tar.gz" + archive_path="$PACKAGES_DIR/$ARCHIVE_DIR_NAME.tar.gz" + pushd "$PACKAGES_DIR" tar -czf "$archive_path" "$ARCHIVE_DIR_NAME" + popd + create_linux_packages ;; macOS) - archive_path="$DIST_DIR/$ARCHIVE_DIR_NAME.pkg" - + archive_path="$PACKAGES_DIR/$ARCHIVE_DIR_NAME.pkg" + pushd "$PACKAGES_DIR" pkgbuild \ --identifier com.gitguardian.ggshield \ --version "$VERSION" \ - --root "$DIST_DIR/$ARCHIVE_DIR_NAME" \ + --root "$PACKAGES_DIR/$ARCHIVE_DIR_NAME" \ "$archive_path" + popd if [ "$DO_SIGN" -eq 1 ] ; then sign_file "$archive_path" fi ;; Windows) - archive_path="$DIST_DIR/$ARCHIVE_DIR_NAME.zip" + archive_path="$PACKAGES_DIR/$ARCHIVE_DIR_NAME.zip" + pushd "$PACKAGES_DIR" 7z a "$archive_path" "$ARCHIVE_DIR_NAME" + popd ;; esac - cd - info "Archive created in $archive_path" } @@ -266,7 +310,7 @@ step_notarize() { rcodesign notary-submit \ --api-key-file "$MACOS_API_KEY_FILE" \ --staple \ - "$DIST_DIR/$ARCHIVE_DIR_NAME.pkg" + "$PACKAGES_DIR/$ARCHIVE_DIR_NAME.pkg" } steps="" @@ -278,6 +322,9 @@ while [ $# -gt 0 ] ; do --sign) DO_SIGN=1 ;; + --git-version) + USE_GIT_VERSION=1 + ;; -*) usage "Unknown option '$1'" ;; diff --git a/scripts/build-os-packages/nfpm.yaml b/scripts/build-os-packages/nfpm.yaml new file mode 100644 index 0000000000..762b18a54b --- /dev/null +++ b/scripts/build-os-packages/nfpm.yaml @@ -0,0 +1,44 @@ +name: ggshield +section: utils +vendor: GitGuardian +maintainer: GitGuardian +license: MIT +homepage: https://github.com/GitGuardian/ggshield +description: |- + Detect leaked secrets and other potential security vulnerabilities + ggshield runs in your local environment or in a CI environment to help you + detect leaked secrets, as well as other potential security vulnerabilities or + policy breaks. + +arch: amd64 +platform: linux +version: ${VERSION} +version_schema: semver +release: 1 + +depends: + - git + +# Make sure files are not group-writable. lintian does not like that. +umask: 0o022 + +contents: + - src: ../libexec/ggshield/ggshield + dst: /usr/bin/ggshield + type: symlink + + - src: ${PYINSTALLER_OUTPUT_DIR} + dst: /usr/libexec/ggshield + expand: true + + - src: README.md + dst: /usr/share/doc/ggshield/README.md + + - src: LICENSE + dst: /usr/share/doc/ggshield/LICENSE + +overrides: + deb: + depends: + - libc6 + - git diff --git a/scripts/build-packages/build-packages b/scripts/build-packages/build-packages deleted file mode 100755 index 00d11c0f25..0000000000 --- a/scripts/build-packages/build-packages +++ /dev/null @@ -1,80 +0,0 @@ -#!/usr/bin/bash -set -euo pipefail - -# This script creates ggshield packages in various formats. -# -# It expects [nfpm][] and [shiv][] to be installed. -# -# Packages are created in the `packages` directory. -# -# [nfpm]: https://github.com/goreleaser/nfpm/ -# [shiv]: https://github.com/linkedin/shiv - -cd $(dirname $0) -NFPM_YAML_TMPL=$PWD/nfpm.yaml.tmpl -GGSHIELD_WRAPPER=$PWD/ggshield-wrapper - -# Move to the work-tree root -cd $(git rev-parse --show-toplevel) - -# Where `python -m build ...` places its packages -DIST_DIR=$PWD/dist - -# Where npfm places its packages. We do not use $DIST_DIR to ensure the "upload -# to pypi" build step does not try to upload them. -PKG_DIR=$PWD/packages - -VERSION=$(python -c 'import ggshield; print(ggshield.__version__)') - -GGSHIELD_WHL=$DIST_DIR/ggshield-$VERSION-py3-none-any.whl -GGSHIELD_SDIST=$DIST_DIR/ggshield-$VERSION.tar.gz -GGSHIELD_PYZ=$PKG_DIR/ggshield-$VERSION.pyz - -log_progress() { - local cstart="\e[35m" - local cend="\e[0m" - echo -e "${cstart}$*${cend}" -} - -build_whl_sdist() { - log_progress "Building wheel and sdist" - python -m build -} - -build_pyz() { - log_progress "Building $GGSHIELD_PYZ" - shiv -c ggshield --reproducible --compile-pyc --compressed -o "$GGSHIELD_PYZ" "$GGSHIELD_WHL" -} - -run_nfpm() { - # nfpm supports environment variables in its configuration file, but only - # in certain fields. It does not support them in `contents/src` [1], so we - # need to do a search-and-replace for this field. To be consistent, we do - # this for the `version` field as well, even if this one supports - # environment variables. - # [1]: https://github.com/goreleaser/nfpm/issues/449 - local nfpm_yaml=$(mktemp --tmpdir nfpm-XXXXX.yaml) - sed \ - -e "s,@VERSION@,$VERSION," \ - -e "s,@GGSHIELD_WRAPPER@,$GGSHIELD_WRAPPER," \ - -e "s,@GGSHIELD_PYZ@,$GGSHIELD_PYZ," \ - "$NFPM_YAML_TMPL" > "$nfpm_yaml" - - for format in rpm deb ; do - log_progress "Building $format" - nfpm package --packager $format --config "$nfpm_yaml" --target "$PKG_DIR" - done - rm "$nfpm_yaml" -} - -mkdir -p $PKG_DIR - -if [ ! -f "$GGSHIELD_WHL" ] || [ ! -f "$GGSHIELD_SDIST" ] ; then - build_whl_sdist -fi - -if [ ! -f "$GGSHIELD_PYZ" ] ; then - build_pyz -fi - -run_nfpm diff --git a/scripts/build-packages/ggshield-wrapper b/scripts/build-packages/ggshield-wrapper deleted file mode 100755 index 77028ada95..0000000000 --- a/scripts/build-packages/ggshield-wrapper +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# This wrapper looks for a recent enough Python interpreter and exits with a -# user-friendly message if it can't find one. -# This is useful when the `python3` interpreter is too old, but the system -# has a more recent `python3.x` interpreter installed. - -# The minimum Python version we need -MAJOR=3 -MINOR=8 - -GGSHIELD_PYZ=/usr/lib/ggshield/ggshield.pyz - -POSSIBLE_PYTHONS=\ -"python311 python3.11 -python310 python3.10 -python39 python3.9 -python38 python3.8 -python3 -python -" - -is_python_usable() { - local python_cmd=$1 - if ! command -v "$python_cmd" > /dev/null ; then - return 1 - fi - $python_cmd -c "import sys; sys.exit(0 if sys.version_info >= ($MAJOR, $MINOR) else 1)" -} - -for python_cmd in $POSSIBLE_PYTHONS ; do - if is_python_usable "$python_cmd" ; then - exec "$python_cmd" $GGSHIELD_PYZ "$@" - fi -done - -echo "Error: could not find a usable Python interpreter. ggshield needs at least Python $MAJOR.$MINOR." >&2 -exit 1 diff --git a/scripts/build-packages/nfpm.yaml.tmpl b/scripts/build-packages/nfpm.yaml.tmpl deleted file mode 100644 index 0a20b4783c..0000000000 --- a/scripts/build-packages/nfpm.yaml.tmpl +++ /dev/null @@ -1,30 +0,0 @@ -name: ggshield -section: default -vendor: GitGuardian -maintainer: GitGuardian -license: MIT -homepage: https://github.com/GitGuardian/ggshield -description: 'CLI application that runs in your local environment or in a CI environment to help you detect leaked secrets, as well as other potential security vulnerabilities or policy breaks.' - -arch: amd64 -platform: linux -version: @VERSION@ -version_schema: semver -release: 1 - -depends: - - git - - python3 -contents: - - src: @GGSHIELD_WRAPPER@ - dst: /usr/bin/ggshield - file_info: - mode: 0755 - - src: @GGSHIELD_PYZ@ - dst: /usr/lib/ggshield/ggshield.pyz - file_info: - mode: 0755 - - src: README.md - dst: /usr/share/doc/ggshield/README.md - - src: LICENSE - dst: /usr/share/doc/ggshield/LICENSE